@@ -12,9 +12,7 @@ import class Foundation.ProcessInfo
12
12
import protocol Foundation. CustomNSError
13
13
import var Foundation. NSLocalizedDescriptionKey
14
14
15
- #if os(Windows)
16
15
import Foundation
17
- #endif
18
16
19
17
@_implementationOnly import TSCclibc
20
18
import TSCLibc
@@ -210,14 +208,10 @@ public final class Process: ObjectIdentifierProtocol {
210
208
public let workingDirectory : AbsolutePath ?
211
209
212
210
/// The process id of the spawned process, available after the process is launched.
213
- #if os(Windows)
214
211
private var _process : Foundation . Process ?
215
212
public var processID : ProcessID {
216
- return DWORD ( _process? . processIdentifier ?? 0 )
213
+ return ProcessID ( _process? . processIdentifier ?? 0 )
217
214
}
218
- #else
219
- public private( set) var processID = ProcessID ( )
220
- #endif
221
215
222
216
/// If the subprocess has launched.
223
217
/// Note: This property is not protected by the serial queue because it is only mutated in `launch()`, which will be
@@ -384,7 +378,6 @@ public final class Process: ObjectIdentifierProtocol {
384
378
throw Process . Error. missingExecutableProgram ( program: executable)
385
379
}
386
380
387
- #if os(Windows)
388
381
_process = Foundation . Process ( )
389
382
_process? . arguments = Array ( arguments. dropFirst ( ) ) // Avoid including the executable URL twice.
390
383
_process? . executableURL = executablePath. asURL
@@ -416,175 +409,11 @@ public final class Process: ObjectIdentifierProtocol {
416
409
417
410
try _process? . run ( )
418
411
return stdinPipe. fileHandleForWriting
419
- #else
420
- // Initialize the spawn attributes.
421
- #if canImport(Darwin) || os(Android)
422
- var attributes : posix_spawnattr_t ? = nil
423
- #else
424
- var attributes = posix_spawnattr_t ( )
425
- #endif
426
- posix_spawnattr_init ( & attributes)
427
- defer { posix_spawnattr_destroy ( & attributes) }
428
-
429
- // Unmask all signals.
430
- var noSignals = sigset_t ( )
431
- sigemptyset ( & noSignals)
432
- posix_spawnattr_setsigmask ( & attributes, & noSignals)
433
-
434
- // Reset all signals to default behavior.
435
- #if os(macOS)
436
- var mostSignals = sigset_t ( )
437
- sigfillset ( & mostSignals)
438
- sigdelset ( & mostSignals, SIGKILL)
439
- sigdelset ( & mostSignals, SIGSTOP)
440
- posix_spawnattr_setsigdefault ( & attributes, & mostSignals)
441
- #else
442
- // On Linux, this can only be used to reset signals that are legal to
443
- // modify, so we have to take care about the set we use.
444
- var mostSignals = sigset_t ( )
445
- sigemptyset ( & mostSignals)
446
- for i in 1 ..< SIGSYS {
447
- if i == SIGKILL || i == SIGSTOP {
448
- continue
449
- }
450
- sigaddset ( & mostSignals, i)
451
- }
452
- posix_spawnattr_setsigdefault ( & attributes, & mostSignals)
453
- #endif
454
-
455
- // Set the attribute flags.
456
- var flags = POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
457
- if startNewProcessGroup {
458
- // Establish a separate process group.
459
- flags |= POSIX_SPAWN_SETPGROUP
460
- posix_spawnattr_setpgroup ( & attributes, 0 )
461
- }
462
-
463
- posix_spawnattr_setflags ( & attributes, Int16 ( flags) )
464
-
465
- // Setup the file actions.
466
- #if canImport(Darwin) || os(Android)
467
- var fileActions : posix_spawn_file_actions_t ? = nil
468
- #else
469
- var fileActions = posix_spawn_file_actions_t ( )
470
- #endif
471
- posix_spawn_file_actions_init ( & fileActions)
472
- defer { posix_spawn_file_actions_destroy ( & fileActions) }
473
-
474
- if let workingDirectory = workingDirectory? . pathString {
475
- #if os(macOS)
476
- // The only way to set a workingDirectory is using an availability-gated initializer, so we don't need
477
- // to handle the case where the posix_spawn_file_actions_addchdir_np method is unavailable. This check only
478
- // exists here to make the compiler happy.
479
- if #available( macOS 10 . 15 , * ) {
480
- posix_spawn_file_actions_addchdir_np ( & fileActions, workingDirectory)
481
- }
482
- #elseif os(Linux)
483
- guard SPM_posix_spawn_file_actions_addchdir_np_supported ( ) else {
484
- throw Process . Error. workingDirectoryNotSupported
485
- }
486
-
487
- SPM_posix_spawn_file_actions_addchdir_np ( & fileActions, workingDirectory)
488
- #else
489
- throw Process . Error. workingDirectoryNotSupported
490
- #endif
491
- }
492
-
493
- var stdinPipe : [ Int32 ] = [ - 1 , - 1 ]
494
- try open ( pipe: & stdinPipe)
495
-
496
- let stdinStream = try LocalFileOutputByteStream ( filePointer: fdopen ( stdinPipe [ 1 ] , " wb " ) , closeOnDeinit: true )
497
-
498
- // Dupe the read portion of the remote to 0.
499
- posix_spawn_file_actions_adddup2 ( & fileActions, stdinPipe [ 0 ] , 0 )
500
-
501
- // Close the other side's pipe since it was dupped to 0.
502
- posix_spawn_file_actions_addclose ( & fileActions, stdinPipe [ 0 ] )
503
- posix_spawn_file_actions_addclose ( & fileActions, stdinPipe [ 1 ] )
504
-
505
- var outputPipe : [ Int32 ] = [ - 1 , - 1 ]
506
- var stderrPipe : [ Int32 ] = [ - 1 , - 1 ]
507
- if outputRedirection. redirectsOutput {
508
- // Open the pipe.
509
- try open ( pipe: & outputPipe)
510
-
511
- // Open the write end of the pipe.
512
- posix_spawn_file_actions_adddup2 ( & fileActions, outputPipe [ 1 ] , 1 )
513
-
514
- // Close the other ends of the pipe since they were dupped to 1.
515
- posix_spawn_file_actions_addclose ( & fileActions, outputPipe [ 0 ] )
516
- posix_spawn_file_actions_addclose ( & fileActions, outputPipe [ 1 ] )
517
-
518
- if outputRedirection. redirectStderr {
519
- // If merged was requested, send stderr to stdout.
520
- posix_spawn_file_actions_adddup2 ( & fileActions, 1 , 2 )
521
- } else {
522
- // If no redirect was requested, open the pipe for stderr.
523
- try open ( pipe: & stderrPipe)
524
- posix_spawn_file_actions_adddup2 ( & fileActions, stderrPipe [ 1 ] , 2 )
525
-
526
- // Close the other ends of the pipe since they were dupped to 2.
527
- posix_spawn_file_actions_addclose ( & fileActions, stderrPipe [ 0 ] )
528
- posix_spawn_file_actions_addclose ( & fileActions, stderrPipe [ 1 ] )
529
- }
530
- } else {
531
- posix_spawn_file_actions_adddup2 ( & fileActions, 1 , 1 )
532
- posix_spawn_file_actions_adddup2 ( & fileActions, 2 , 2 )
533
- }
534
-
535
- var resolvedArgs = arguments
536
- if workingDirectory != nil {
537
- resolvedArgs [ 0 ] = executablePath. pathString
538
- }
539
- let argv = CStringArray ( resolvedArgs)
540
- let env = CStringArray ( environment. map ( { " \( $0. 0 ) = \( $0. 1 ) " } ) )
541
- let rv = posix_spawnp ( & processID, argv. cArray [ 0 ] !, & fileActions, & attributes, argv. cArray, env. cArray)
542
-
543
- guard rv == 0 else {
544
- throw SystemError . posix_spawn ( rv, arguments)
545
- }
546
-
547
- // Close the local read end of the input pipe.
548
- try close ( fd: stdinPipe [ 0 ] )
549
-
550
- if outputRedirection. redirectsOutput {
551
- let outputClosures = outputRedirection. outputClosures
552
-
553
- // Close the local write end of the output pipe.
554
- try close ( fd: outputPipe [ 1 ] )
555
-
556
- // Create a thread and start reading the output on it.
557
- var thread = Thread { [ weak self] in
558
- if let readResult = self ? . readOutput ( onFD: outputPipe [ 0 ] , outputClosure: outputClosures? . stdoutClosure) {
559
- self ? . stdout. result = readResult
560
- }
561
- }
562
- thread. start ( )
563
- self . stdout. thread = thread
564
-
565
- // Only schedule a thread for stderr if no redirect was requested.
566
- if !outputRedirection. redirectStderr {
567
- // Close the local write end of the stderr pipe.
568
- try close ( fd: stderrPipe [ 1 ] )
569
-
570
- // Create a thread and start reading the stderr output on it.
571
- thread = Thread { [ weak self] in
572
- if let readResult = self ? . readOutput ( onFD: stderrPipe [ 0 ] , outputClosure: outputClosures? . stderrClosure) {
573
- self ? . stderr. result = readResult
574
- }
575
- }
576
- thread. start ( )
577
- self . stderr. thread = thread
578
- }
579
- }
580
- return stdinStream
581
- #endif // POSIX implementation
582
412
}
583
413
584
414
/// Blocks the calling process until the subprocess finishes execution.
585
415
@discardableResult
586
416
public func waitUntilExit( ) throws -> ProcessResult {
587
- #if os(Windows)
588
417
precondition ( _process != nil , " The process is not yet launched. " )
589
418
let p = _process!
590
419
p. waitUntilExit ( )
@@ -599,88 +428,8 @@ public final class Process: ObjectIdentifierProtocol {
599
428
stderrOutput: stderr. result
600
429
)
601
430
return executionResult
602
- #else
603
- return try serialQueue. sync {
604
- precondition ( launched, " The process is not yet launched. " )
605
-
606
- // If the process has already finsihed, return it.
607
- if let existingResult = _result {
608
- return existingResult
609
- }
610
-
611
- // If we're reading output, make sure that is finished.
612
- stdout. thread? . join ( )
613
- stderr. thread? . join ( )
614
-
615
- // Wait until process finishes execution.
616
- var exitStatusCode : Int32 = 0
617
- var result = waitpid ( processID, & exitStatusCode, 0 )
618
- while result == - 1 && errno == EINTR {
619
- result = waitpid ( processID, & exitStatusCode, 0 )
620
- }
621
- if result == - 1 {
622
- throw SystemError . waitpid ( errno)
623
- }
624
-
625
- // Construct the result.
626
- let executionResult = ProcessResult (
627
- arguments: arguments,
628
- environment: environment,
629
- exitStatusCode: exitStatusCode,
630
- output: stdout. result,
631
- stderrOutput: stderr. result
632
- )
633
- self . _result = executionResult
634
- return executionResult
635
- }
636
- #endif
637
431
}
638
432
639
- #if !os(Windows)
640
- /// Reads the given fd and returns its result.
641
- ///
642
- /// Closes the fd before returning.
643
- private func readOutput( onFD fd: Int32 , outputClosure: OutputClosure ? ) -> Result < [ UInt8 ] , Swift . Error > {
644
- // Read all of the data from the output pipe.
645
- let N = 4096
646
- var buf = [ UInt8] ( repeating: 0 , count: N + 1 )
647
-
648
- var out = [ UInt8] ( )
649
- var error : Swift . Error ? = nil
650
- loop: while true {
651
- let n = read ( fd, & buf, N)
652
- switch n {
653
- case - 1 :
654
- if errno == EINTR {
655
- continue
656
- } else {
657
- error = SystemError . read ( errno)
658
- break loop
659
- }
660
- case 0 :
661
- // Close the read end of the output pipe.
662
- // We should avoid closing the read end of the pipe in case
663
- // -1 because the child process may still have content to be
664
- // flushed into the write end of the pipe. If the read end of the
665
- // pipe is closed, then a write will cause a SIGPIPE signal to
666
- // be generated for the calling process. If the calling process is
667
- // ignoring this signal, then write fails with the error EPIPE.
668
- close ( fd)
669
- break loop
670
- default :
671
- let data = buf [ 0 ..< n]
672
- if let outputClosure = outputClosure {
673
- outputClosure ( Array ( data) )
674
- } else {
675
- out += data
676
- }
677
- }
678
- }
679
- // Construct the output result.
680
- return error. map ( Result . failure) ?? . success( out)
681
- }
682
- #endif
683
-
684
433
/// Send a signal to the process.
685
434
///
686
435
/// Note: This will signal all processes in the process group.
@@ -750,12 +499,6 @@ extension Process {
750
499
// MARK: - Private helpers
751
500
752
501
#if !os(Windows)
753
- #if os(macOS)
754
- private typealias swiftpm_posix_spawn_file_actions_t = posix_spawn_file_actions_t ?
755
- #else
756
- private typealias swiftpm_posix_spawn_file_actions_t = posix_spawn_file_actions_t
757
- #endif
758
-
759
502
private func WIFEXITED( _ status: Int32 ) -> Bool {
760
503
return _WSTATUS ( status) == 0
761
504
}
@@ -776,26 +519,6 @@ private func WTERMSIG(_ status: Int32) -> Int32 {
776
519
return status & 0x7f
777
520
}
778
521
779
- /// Open the given pipe.
780
- private func open( pipe: inout [ Int32 ] ) throws {
781
- let rv = TSCLibc . pipe ( & pipe)
782
- guard rv == 0 else {
783
- throw SystemError . pipe ( rv)
784
- }
785
- }
786
-
787
- /// Close the given fd.
788
- private func close( fd: Int32 ) throws {
789
- func innerClose( _ fd: inout Int32 ) throws {
790
- let rv = TSCLibc . close ( fd)
791
- guard rv == 0 else {
792
- throw SystemError . close ( rv)
793
- }
794
- }
795
- var innerFd = fd
796
- try innerClose ( & innerFd)
797
- }
798
-
799
522
extension Process . Error : CustomStringConvertible {
800
523
public var description : String {
801
524
switch self {
0 commit comments