@@ -29,26 +29,8 @@ struct RunCommand: ParsableCommand {
2929 @Flag ( help: " Whether to open the server in your preferred web browser immediately. " )
3030 var preview = false
3131
32- /// Whether to automatically terminate any existing web
33- /// server running on the port, if there is one. Defaults to false.
34- @Flag ( help: " Whether to force quit any existing server on the current port number before starting a new one. " )
35- var force = false
36-
3732 /// Runs this command. Automatically called by Argument Parser.
3833 func run( ) throws {
39- // Immediately kill any server if applicable, but only
40- // if they asked us to.
41- if force {
42- try terminateAnyExistingServer ( )
43- }
44-
45- // If we're still here and a server is already running
46- // on their current port, we can't proceed.
47- guard try isServerRunning ( ) == false else {
48- print ( " ❌ A local web server is already running on port \( port) . " )
49- return
50- }
51-
5234 // Make sure we actually have a folder to serve up.
5335 guard FileManager . default. fileExists ( atPath: " ./ \( directory) " ) else {
5436 print ( " ❌ Failed to find directory named ' \( directory) '. " )
@@ -64,46 +46,39 @@ struct RunCommand: ParsableCommand {
6446 }
6547 }
6648
67- print ( " ✅ Starting local web server on http://localhost: \( port) " )
68- print ( " Press ↵ Return to exit. " )
49+ // Find an available port
50+ var currentPort = port
51+ while try isServerRunning ( on: currentPort) {
52+ currentPort += 1
53+ if currentPort >= 9000 {
54+ print ( " ❌ No available ports found in range 8000-8999. " )
55+ return
56+ }
57+ }
6958
70- let previewCommand : String
59+ print ( " ✅ Starting local web server on http://localhost: \( currentPort) " )
60+ print ( " Press ↵ Return to exit. " )
7161
72- // Automatically open a web browser pointing to their
73- // local server if requested.
74- if preview {
75- previewCommand = " open http://localhost: \( port ) "
62+ let previewCommand = if preview {
63+ // Automatically open a web browser pointing to their
64+ // local server if requested.
65+ " open http://localhost: \( currentPort ) "
7666 } else {
7767 // Important: The empty space below is enough to
7868 // make the Process.execute() wait for a key press
7969 // before exiting.
80- previewCommand = " "
70+ " "
8171 }
8272
8373 try Process . execute (
84- command: " python3 -m http.server -d \( directory) \( port ) " ,
74+ command: " python3 -m http.server -d \( directory) \( currentPort ) " ,
8575 then: previewCommand
8676 )
8777 }
8878
89- /// Locates and terminates any server running on the user's port.
90- private func terminateAnyExistingServer( ) throws {
91- if try isServerRunning ( ) {
92- let pid = try getRunningServerPID ( )
93- try Process . execute ( command: " kill \( pid) " )
94- }
95- }
96-
97- /// Finds the process ID for any server running on the user's port.
98- /// - Returns: The process ID (PID) for the server, or empty/
99- private func getRunningServerPID( ) throws -> String {
79+ /// Returns true if there is a server running on the specified port.
80+ private func isServerRunning( on port: Int ) throws -> Bool {
10081 let result = try Process . execute ( command: " lsof -t -i tcp: \( port) " )
101- return result. output
102- }
103-
104- /// Returns true if there is a server running on the user's port.
105- /// - Returns: True if there is a server running there, otherwise false.
106- private func isServerRunning( ) throws -> Bool {
107- try getRunningServerPID ( ) . isEmpty == false
82+ return !result. output. isEmpty
10883 }
10984}
0 commit comments