Skip to content

Commit fe4ecd4

Browse files
committed
Add support for publish port ranges
1 parent 671725c commit fe4ecd4

File tree

1 file changed

+91
-11
lines changed

1 file changed

+91
-11
lines changed

Sources/ContainerClient/Parser.swift

Lines changed: 91 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,7 @@ public struct Parser {
554554
/// Parse --publish-port arguments into PublishPort objects
555555
/// The format of each argument is `[host-ip:]host-port:container-port[/protocol]`
556556
/// (e.g., "127.0.0.1:8080:80/tcp")
557+
/// host-port and container-port can be ranges (e.g., "127.0.0.1:3456-4567:3456-4567/tcp`
557558
///
558559
/// - Parameter rawPublishPorts: Array of port arguments
559560
/// - Returns: Array of PublishPort objects
@@ -563,14 +564,14 @@ public struct Parser {
563564

564565
// Process each raw port string
565566
for socket in rawPublishPorts {
566-
let parsedSocket = try Parser.publishPort(socket)
567-
sockets.append(parsedSocket)
567+
let parsedSockets = try Parser.publishPort(socket)
568+
sockets.append(contentsOf: parsedSockets)
568569
}
569570
return sockets
570571
}
571572

572-
// Parse a single `--publish-port` argument into a `PublishPort`.
573-
public static func publishPort(_ portText: String) throws -> PublishPort {
573+
// Parse a single `--publish-port` argument into a `[PublishPort]`.
574+
public static func publishPort(_ portText: String) throws -> [PublishPort] {
574575
let protoSplit = portText.split(separator: "/")
575576
let proto: PublishProtocol
576577
let addressAndPortText: String
@@ -607,19 +608,98 @@ public struct Parser {
607608
}
608609

609610
guard let hostPort = Int(hostPortText) else {
610-
throw ContainerizationError(.invalidArgument, message: "invalid publish host port: \(hostPortText)")
611+
let hostPortRangeStart: Int
612+
let hostPortRangeEnd: Int
613+
let containerPortRangeStart: Int
614+
let containerPortRangeEnd: Int
615+
616+
let hostPortParts = hostPortText.split(separator: "-")
617+
switch hostPortParts.count {
618+
case 2:
619+
guard let start = Int(hostPortParts[0]) else {
620+
throw ContainerizationError(.invalidArgument, message: "invalid publish host port \(hostPortText)")
621+
}
622+
623+
guard let end = Int(hostPortParts[1]) else {
624+
throw ContainerizationError(.invalidArgument, message: "invalid publish host port \(hostPortText)")
625+
}
626+
627+
hostPortRangeStart = start
628+
hostPortRangeEnd = end
629+
default:
630+
throw ContainerizationError(.invalidArgument, message: "invalid publish host port \(hostPortText)")
631+
}
632+
633+
let containerPortParts = containerPortText.split(separator: "-")
634+
switch containerPortParts.count {
635+
case 2:
636+
guard let start = Int(containerPortParts[0]) else {
637+
throw ContainerizationError(.invalidArgument, message: "invalid publish container port \(containerPortText)")
638+
}
639+
640+
guard let end = Int(containerPortParts[1]) else {
641+
throw ContainerizationError(.invalidArgument, message: "invalid publish container port \(containerPortText)")
642+
}
643+
644+
containerPortRangeStart = start
645+
containerPortRangeEnd = end
646+
default:
647+
throw ContainerizationError(.invalidArgument, message: "invalid publish container port \(containerPortText)")
648+
}
649+
650+
guard hostPortRangeStart > 1,
651+
hostPortRangeEnd > 1,
652+
hostPortRangeStart < hostPortRangeEnd,
653+
hostPortRangeEnd > hostPortRangeStart
654+
else {
655+
throw ContainerizationError(.invalidArgument, message: "invalid publish host port range \(hostPortText)")
656+
}
657+
658+
guard containerPortRangeStart > 1,
659+
containerPortRangeEnd > 1,
660+
containerPortRangeStart < containerPortRangeEnd,
661+
containerPortRangeEnd > containerPortRangeStart
662+
else {
663+
throw ContainerizationError(.invalidArgument, message: "invalid publish container port range \(containerPortText)")
664+
}
665+
666+
let hostRange = hostPortRangeEnd - hostPortRangeStart
667+
let containerRange = containerPortRangeEnd - containerPortRangeStart
668+
669+
guard hostRange == containerRange else {
670+
throw ContainerizationError(.invalidArgument, message: "publish host and container port range are not equal \(addressAndPortText)")
671+
}
672+
673+
var publishPorts = [PublishPort]()
674+
for i in 0..<hostPortRangeEnd - hostPortRangeStart + 1 {
675+
let hostPort = hostPortRangeStart + i
676+
let containerPort = containerPortRangeStart + i
677+
678+
publishPorts.append(
679+
PublishPort(
680+
hostAddress: hostAddress,
681+
hostPort: hostPort,
682+
containerPort: containerPort,
683+
proto: proto
684+
)
685+
)
686+
}
687+
688+
return publishPorts
611689
}
612690

613691
guard let containerPort = Int(containerPortText) else {
614692
throw ContainerizationError(.invalidArgument, message: "invalid publish container port: \(containerPortText)")
615693
}
616694

617-
return PublishPort(
618-
hostAddress: hostAddress,
619-
hostPort: hostPort,
620-
containerPort: containerPort,
621-
proto: proto
622-
)
695+
return [
696+
PublishPort(
697+
hostAddress: hostAddress,
698+
hostPort: hostPort,
699+
containerPort: containerPort,
700+
proto: proto
701+
)
702+
]
623703
}
624704

625705
/// Parse --publish-socket arguments into PublishSocket objects

0 commit comments

Comments
 (0)