@@ -71,7 +71,7 @@ struct FormatPlugin: CommandPlugin {
7171 formatArguments += allSourceFiles. map { $0. path ( percentEncoded: false ) }
7272
7373 // Print what we're about to do
74- print ( " Formatting \( allSourceFiles. count) Swift files in \( targetsToFormat. count) target(s)... " )
74+ Diagnostics . remark ( " Formatting \( allSourceFiles. count) Swift files in \( targetsToFormat. count) target(s)... " )
7575
7676 // Execute swift-format
7777 let process = Process ( )
@@ -83,50 +83,61 @@ struct FormatPlugin: CommandPlugin {
8383 process. standardOutput = outputPipe
8484 process. standardError = errorPipe
8585
86- try process . run ( )
87- process. waitUntilExit ( )
86+ do {
87+ try process. run ( )
8888
89- // Handle output
90- let outputData = outputPipe . fileHandleForReading . readDataToEndOfFile ( )
91- let errorData = errorPipe . fileHandleForReading . readDataToEndOfFile ( )
89+ // Wait for process with 5-minute timeout
90+ let timeout : TimeInterval = 300 // 5 minutes
91+ let deadline = Date ( ) . addingTimeInterval ( timeout )
9292
93- if let output = String ( data : outputData , encoding : . utf8 ) , !output . isEmpty {
94- print ( output )
95- }
93+ while process . isRunning && Date ( ) < deadline {
94+ try await Task . sleep ( nanoseconds : 100_000_000 ) // 0.1 seconds
95+ }
9696
97- if let errorOutput = String ( data: errorData, encoding: . utf8) , !errorOutput. isEmpty {
98- printError ( errorOutput)
99- }
97+ if process. isRunning {
98+ process. terminate ( )
99+ Diagnostics . error ( " swift-format timed out after \( Int ( timeout) ) s and was terminated " )
100+ return
101+ }
100102
101- if process. terminationStatus == 0 {
102- print ( " ✅ Formatting completed successfully! " )
103- } else {
104- Diagnostics . error ( " swift-format failed with exit code \( process. terminationStatus) " )
103+ // Handle output
104+ let outputData = outputPipe. fileHandleForReading. readDataToEndOfFile ( )
105+ let errorData = errorPipe. fileHandleForReading. readDataToEndOfFile ( )
106+
107+ if let output = String ( data: outputData, encoding: . utf8) , !output. isEmpty {
108+ Diagnostics . remark ( output)
109+ }
110+
111+ if let errorOutput = String ( data: errorData, encoding: . utf8) , !errorOutput. isEmpty {
112+ Diagnostics . warning ( errorOutput)
113+ }
114+
115+ if process. terminationStatus == 0 {
116+ Diagnostics . remark ( " Formatting completed successfully! " )
117+ } else {
118+ Diagnostics . error ( " swift-format failed with exit code \( process. terminationStatus) " )
119+ }
120+ } catch {
121+ Diagnostics . error ( " Failed to execute swift-format: \( error. localizedDescription) " )
105122 }
106123 }
107124
108125 /// Finds configuration file in package root.
109126 /// Supports both .swiftformat and .swift-format naming conventions.
110127 private func findConfigurationFile( in packageDirectory: URL ) -> URL ? {
128+ let fileManager = FileManager . default
111129 let swiftformatConfig = packageDirectory. appending ( path: " .swiftformat " )
112130 let swiftFormatConfig = packageDirectory. appending ( path: " .swift-format " )
113131
114132 // Prefer .swiftformat first
115- if FileManager . default . fileExists ( atPath: swiftformatConfig. path) {
133+ if fileManager . fileExists ( atPath: swiftformatConfig. path) {
116134 return swiftformatConfig
117135 }
118136 // Fall back to .swift-format
119- if FileManager . default . fileExists ( atPath: swiftFormatConfig. path) {
137+ if fileManager . fileExists ( atPath: swiftFormatConfig. path) {
120138 return swiftFormatConfig
121139 }
122140
123141 return nil
124142 }
125143}
126-
127- // Helper for printing to stderr
128- fileprivate func printError( _ message: String ) {
129- if let data = message. data ( using: . utf8) {
130- FileHandle . standardError. write ( data)
131- }
132- }
0 commit comments