Skip to content

Commit

Permalink
Merge pull request #2973 from neonichu/revert-122
Browse files Browse the repository at this point in the history
  • Loading branch information
shahmishal committed Oct 9, 2020
2 parents 2386d12 + 1cfe8a7 commit 5abb16c
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 82 deletions.
86 changes: 21 additions & 65 deletions swift-tools-support-core/Sources/TSCBasic/Process.swift
Expand Up @@ -331,11 +331,8 @@ public final class Process: ObjectIdentifierProtocol {
}
}

/// Launch the subprocess. Returns a WritableByteStream object that can be used to communicate to the process's
/// stdin. If needed, the stream can be closed using the close() API. Otherwise, the stream will be closed
/// automatically.
@discardableResult
public func launch() throws -> WritableByteStream {
/// Launch the subprocess.
public func launch() throws {
precondition(arguments.count > 0 && !arguments[0].isEmpty, "Need at least one argument to launch the process.")
precondition(!launched, "It is not allowed to launch the same process object again.")

Expand All @@ -354,15 +351,12 @@ public final class Process: ObjectIdentifierProtocol {
throw Process.Error.missingExecutableProgram(program: executable)
}

#if os(Windows)
#if os(Windows)
_process = Foundation.Process()
_process?.arguments = Array(arguments.dropFirst()) // Avoid including the executable URL twice.
_process?.executableURL = executablePath.asURL
_process?.environment = environment

let stdinPipe = Pipe()
_process?.standardInput = stdinPipe

if outputRedirection.redirectsOutput {
let stdoutPipe = Pipe()
let stderrPipe = Pipe()
Expand All @@ -385,8 +379,6 @@ public final class Process: ObjectIdentifierProtocol {
}

try _process?.run()

return stdinPipe.fileHandleForWriting
#else
// Initialize the spawn attributes.
#if canImport(Darwin) || os(Android)
Expand Down Expand Up @@ -461,17 +453,14 @@ public final class Process: ObjectIdentifierProtocol {
#endif
}

var stdinPipe: [Int32] = [-1, -1]
try open(pipe: &stdinPipe)

let stdinStream = try LocalFileOutputByteStream(filePointer: fdopen(stdinPipe[1], "wb"), closeOnDeinit: true)

// Dupe the read portion of the remote to 0.
posix_spawn_file_actions_adddup2(&fileActions, stdinPipe[0], 0)

// Close the other side's pipe since it was dupped to 0.
posix_spawn_file_actions_addclose(&fileActions, stdinPipe[0])
posix_spawn_file_actions_addclose(&fileActions, stdinPipe[1])
// Workaround for https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=89e435f3559c53084498e9baad22172b64429362
// Change allowing for newer version of glibc
guard let devNull = strdup("/dev/null") else {
throw SystemError.posix_spawn(0, arguments)
}
defer { free(devNull) }
// Open /dev/null as stdin.
posix_spawn_file_actions_addopen(&fileActions, 0, devNull, O_RDONLY, 0)

var outputPipe: [Int32] = [-1, -1]
var stderrPipe: [Int32] = [-1, -1]
Expand All @@ -482,7 +471,7 @@ public final class Process: ObjectIdentifierProtocol {
// Open the write end of the pipe.
posix_spawn_file_actions_adddup2(&fileActions, outputPipe[1], 1)

// Close the other ends of the pipe since they were dupped to 1.
// Close the other ends of the pipe.
posix_spawn_file_actions_addclose(&fileActions, outputPipe[0])
posix_spawn_file_actions_addclose(&fileActions, outputPipe[1])

Expand All @@ -494,7 +483,7 @@ public final class Process: ObjectIdentifierProtocol {
try open(pipe: &stderrPipe)
posix_spawn_file_actions_adddup2(&fileActions, stderrPipe[1], 2)

// Close the other ends of the pipe since they were dupped to 2.
// Close the other ends of the pipe.
posix_spawn_file_actions_addclose(&fileActions, stderrPipe[0])
posix_spawn_file_actions_addclose(&fileActions, stderrPipe[1])
}
Expand All @@ -511,14 +500,11 @@ public final class Process: ObjectIdentifierProtocol {
throw SystemError.posix_spawn(rv, arguments)
}

// Close the local read end of the input pipe.
try close(fd: stdinPipe[0])

if outputRedirection.redirectsOutput {
let outputClosures = outputRedirection.outputClosures

// Close the local write end of the output pipe.
try close(fd: outputPipe[1])
// Close the write end of the output pipe.
try close(fd: &outputPipe[1])

// Create a thread and start reading the output on it.
var thread = Thread { [weak self] in
Expand All @@ -531,8 +517,8 @@ public final class Process: ObjectIdentifierProtocol {

// Only schedule a thread for stderr if no redirect was requested.
if !outputRedirection.redirectStderr {
// Close the local write end of the stderr pipe.
try close(fd: stderrPipe[1])
// Close the write end of the stderr pipe.
try close(fd: &stderrPipe[1])

// Create a thread and start reading the stderr output on it.
thread = Thread { [weak self] in
Expand All @@ -544,8 +530,6 @@ public final class Process: ObjectIdentifierProtocol {
self.stderr.thread = thread
}
}

return stdinStream
#endif // POSIX implementation
}

Expand Down Expand Up @@ -747,15 +731,11 @@ private func open(pipe: inout [Int32]) throws {
}

/// Close the given fd.
private func close(fd: Int32) throws {
func innerClose(_ fd: inout Int32) throws {
let rv = TSCLibc.close(fd)
guard rv == 0 else {
throw SystemError.close(rv)
}
private func close(fd: inout Int32) throws {
let rv = TSCLibc.close(fd)
guard rv == 0 else {
throw SystemError.close(rv)
}
var innerFd = fd
try innerClose(&innerFd)
}

extension Process.Error: CustomStringConvertible {
Expand Down Expand Up @@ -808,27 +788,3 @@ extension ProcessResult.Error: CustomStringConvertible {
}
}
}

#if os(Windows)
extension FileHandle: WritableByteStream {
public var position: Int {
return Int(offsetInFile)
}

public func write(_ byte: UInt8) {
write(Data([byte]))
}

public func write<C: Collection>(_ bytes: C) where C.Element == UInt8 {
write(Data(bytes))
}

public func flush() {
synchronizeFile()
}

public func close() throws {
closeFile()
}
}
#endif
17 changes: 0 additions & 17 deletions swift-tools-support-core/Tests/TSCBasicTests/ProcessTests.swift
Expand Up @@ -188,23 +188,6 @@ class ProcessTests: XCTestCase {
XCTAssertEqual(result2, "hello\n")
}

func testStdin() throws {
var stdout = [UInt8]()
let process = Process(args: script("in-to-out"), outputRedirection: .stream(stdout: { stdoutBytes in
stdout += stdoutBytes
}, stderr: { _ in }))
let stdinStream = try process.launch()

stdinStream.write("hello\n")
stdinStream.flush()

try stdinStream.close()

try process.waitUntilExit()

XCTAssertEqual(String(decoding: stdout, as: UTF8.self), "hello\n")
}

func testStdoutStdErr() throws {
// A simple script to check that stdout and stderr are captured separatly.
do {
Expand Down

0 comments on commit 5abb16c

Please sign in to comment.