@@ -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