Skip to content

Commit a7629d7

Browse files
committed
feat: Integrate SKProcessRunner for improved process handling in Shell commands
1 parent 10ed0a3 commit a7629d7

3 files changed

Lines changed: 93 additions & 51 deletions

File tree

Package.resolved

Lines changed: 11 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ let package = Package(
1010
.library(name: "SwiftGit", targets: ["SwiftGit"])
1111
],
1212
dependencies: [
13-
.package(url: "https://github.com/linhay/STFilePath.git", from: "1.2.4")
13+
.package(url: "https://github.com/linhay/SKProcessRunner.git", from: "0.0.2"),
14+
.package(url: "https://github.com/linhay/STFilePath.git", from: "1.3.1"),
1415
],
1516
targets: [
1617
.target(
1718
name: "SwiftGit",
1819
dependencies: [
19-
.product(name: "STFilePath", package: "STFilePath")
20+
.product(name: "STFilePath", package: "STFilePath"),
21+
.product(name: "SKProcessRunner", package: "SKProcessRunner"),
2022
],
2123
resources: [
2224
.copy("Resource/git-instance.bundle")
@@ -27,6 +29,7 @@ let package = Package(
2729
dependencies: [
2830
"SwiftGit",
2931
.product(name: "STFilePath", package: "STFilePath"),
32+
.product(name: "SKProcessRunner", package: "SKProcessRunner"),
3033
]),
3134
]
3235
)

Sources/SwiftGit/Custom/Shell.swift

Lines changed: 77 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#if os(macOS)
99
import Foundation
1010
import Combine
11+
import SKProcessRunner
1112

1213
@available(macOS 11, *)
1314
public struct Shell {}
@@ -176,38 +177,63 @@
176177
public func data(_ args: Shell.Arguments) throws -> Data {
177178
var args = args
178179
changedArgsBeforeRun?(&args)
179-
let process = self.setupProcess(args.exec, args.commands, context: args.context)
180-
let output = Shell.Standard(publisher: args.context?.standardOutput).append(
181-
to: &process.standardOutput)
182-
let error = Shell.Standard(publisher: args.context?.standardError).append(
183-
to: &process.standardError)
184-
try process.run()
185-
process.waitUntilExit()
186-
return try result(process, output: output.availableData, error: error.availableData)
187-
.get()
180+
guard let exec = args.exec else {
181+
throw Shell.Error.processFailed(message: "Missing executable.", code: -1)
182+
}
183+
184+
let stdoutPublisher = args.context?.standardOutput
185+
let stderrPublisher = args.context?.standardError
186+
187+
do {
188+
let result = try SKProcessRunner.runSync(
189+
executableURL: exec,
190+
arguments: args.commands,
191+
configuration: .init(
192+
cwd: args.context?.currentDirectory,
193+
environment: args.context?.environment ?? [:],
194+
timeoutMs: 5 * 60 * 1000,
195+
maxOutputBytes: 4 * 1024 * 1024
196+
),
197+
onStdout: { stdoutPublisher?.send($0) },
198+
onStderr: { stderrPublisher?.send($0) },
199+
throwOnNonZeroExit: true
200+
)
201+
return result.stdoutData
202+
} catch let error as SKProcessRunner.RunError {
203+
throw Shell.Error.processFailed(message: error.localizedDescription, code: -1)
204+
}
188205
}
189206

190207
@discardableResult
191208
public func data(_ args: Shell.Arguments, input: Data?) throws -> Data {
192209
var args = args
193210
changedArgsBeforeRun?(&args)
194-
let process = self.setupProcess(args.exec, args.commands, context: args.context)
195-
196-
if let input = input {
197-
let inputPipe = Pipe()
198-
process.standardInput = inputPipe
199-
try inputPipe.fileHandleForWriting.write(contentsOf: input)
200-
try inputPipe.fileHandleForWriting.close()
211+
guard let exec = args.exec else {
212+
throw Shell.Error.processFailed(message: "Missing executable.", code: -1)
201213
}
202214

203-
let output = Shell.Standard(publisher: args.context?.standardOutput).append(
204-
to: &process.standardOutput)
205-
let error = Shell.Standard(publisher: args.context?.standardError).append(
206-
to: &process.standardError)
207-
try process.run()
208-
process.waitUntilExit()
209-
return try result(process, output: output.availableData, error: error.availableData)
210-
.get()
215+
let stdoutPublisher = args.context?.standardOutput
216+
let stderrPublisher = args.context?.standardError
217+
218+
do {
219+
let result = try SKProcessRunner.runSync(
220+
executableURL: exec,
221+
arguments: args.commands,
222+
stdinData: input,
223+
configuration: .init(
224+
cwd: args.context?.currentDirectory,
225+
environment: args.context?.environment ?? [:],
226+
timeoutMs: 5 * 60 * 1000,
227+
maxOutputBytes: 4 * 1024 * 1024
228+
),
229+
onStdout: { stdoutPublisher?.send($0) },
230+
onStderr: { stderrPublisher?.send($0) },
231+
throwOnNonZeroExit: true
232+
)
233+
return result.stdoutData
234+
} catch let error as SKProcessRunner.RunError {
235+
throw Shell.Error.processFailed(message: error.localizedDescription, code: -1)
236+
}
211237
}
212238

213239
@discardableResult
@@ -337,29 +363,33 @@
337363

338364
@discardableResult
339365
public func data(_ args: Shell.Arguments) async throws -> Data {
340-
try await withCheckedThrowingContinuation { continuation in
341-
do {
342-
var args = args
343-
changedArgsBeforeRun?(&args)
344-
let process = setupProcess(args.exec, args.commands, context: args.context)
345-
let output = Shell.Standard(publisher: args.context?.standardOutput).append(
346-
to: &process.standardOutput)
347-
let error = Shell.Standard(publisher: args.context?.standardError).append(
348-
to: &process.standardError)
349-
try process.run()
350-
process.terminationHandler = { [self] process in
351-
do {
352-
let data = try result(
353-
process, output: output.availableData, error: error.availableData
354-
).get()
355-
continuation.resume(returning: data)
356-
} catch {
357-
continuation.resume(throwing: error)
358-
}
359-
}
360-
} catch {
361-
continuation.resume(throwing: error)
362-
}
366+
var args = args
367+
changedArgsBeforeRun?(&args)
368+
guard let exec = args.exec else {
369+
throw Shell.Error.processFailed(message: "Missing executable.", code: -1)
370+
}
371+
372+
let stdoutPublisher = args.context?.standardOutput
373+
let stderrPublisher = args.context?.standardError
374+
375+
do {
376+
let result = try await SKProcessRunner.run(
377+
executableURL: exec,
378+
arguments: args.commands,
379+
stdinData: nil,
380+
configuration: .init(
381+
cwd: args.context?.currentDirectory,
382+
environment: args.context?.environment ?? [:],
383+
timeoutMs: 5 * 60 * 1000,
384+
maxOutputBytes: 4 * 1024 * 1024
385+
),
386+
onStdout: { stdoutPublisher?.send($0) },
387+
onStderr: { stderrPublisher?.send($0) },
388+
throwOnNonZeroExit: true
389+
)
390+
return result.stdoutData
391+
} catch let error as SKProcessRunner.RunError {
392+
throw Shell.Error.processFailed(message: error.localizedDescription, code: -1)
363393
}
364394
}
365395

0 commit comments

Comments
 (0)