Skip to content

Commit de15b67

Browse files
committed
Address review comments
1 parent 77cc0b2 commit de15b67

34 files changed

+637
-694
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
name: Bug report
3+
about: Create a report to help us improve Subprocess
4+
title: ''
5+
labels: bug
6+
assignees: ''
7+
8+
---
9+
10+
**Describe the bug**
11+
A clear and concise description of what the bug is.
12+
13+
**To Reproduce**
14+
Steps to reproduce the behavior:
15+
1. What executable was running?
16+
2. What arguments are passed in?
17+
3. What environment values are used?
18+
19+
**Expected behavior**
20+
A clear and concise description of what you expected to happen.
21+
22+
**Environment (please complete the following information):**
23+
- OS [e.g. macOS 15]
24+
- Swift version (run `swift --version`) [e.g. swiftlang-6.2.0.1.23 clang-1700.3.1.3]
25+
26+
**Additional context**
27+
Add any other context about the problem here.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
name: Feature request
3+
about: Suggest an idea for Subprocess future directions
4+
title: "[Feature] Feature Request"
5+
labels: enhancement
6+
assignees: ''
7+
8+
---
9+
10+
**Is your feature request related to a problem? Please describe.**
11+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12+
13+
**Describe the solution you'd like**
14+
A clear and concise description of what you want to happen.
15+
16+
**Describe alternatives you've considered**
17+
A clear and concise description of any alternative solutions or features you've considered.
18+
19+
**Additional context**
20+
Add any other context or screenshots about the feature request here.

.spi.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
version: 1
2+
builder:
3+
configs:
4+
- documentation_targets: [Subprocess]

CODE_OF_CONDUCT.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
The code of conduct for this project can be found at https://swift.org/code-of-conduct.
44

5-
<!-- Copyright (c) 2024 Apple Inc and the Swift Project authors. All Rights Reserved. -->
5+
<!-- Copyright (c) 2025 Apple Inc and the Swift Project authors. All Rights Reserved. -->

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ defaultTraits.insert("SubprocessSpan")
3131

3232
let package = Package(
3333
name: "Subprocess",
34-
platforms: [.macOS("15.0"), .iOS("18.0"), .tvOS("18.0"), .watchOS("11.0")],
34+
platforms: [.macOS(.v13)],
3535
products: [
3636
.library(
3737
name: "Subprocess",

Package@swift-6.0.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ let availabilityMacro: SwiftSetting = .enableExperimentalFeature(
99

1010
let package = Package(
1111
name: "Subprocess",
12-
platforms: [.macOS("15.0"), .iOS("18.0"), .tvOS("18.0"), .watchOS("11.0")],
12+
platforms: [.macOS(.v13)],
1313
products: [
1414
.library(
1515
name: "Subprocess",

README.md

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,18 @@
44

55
Subprocess is a cross-platform package for spawning processes in Swift.
66

7-
It's like [Foundation.Process](https://developer.apple.com/documentation/foundation/process), but written for Swift and build on top of structural concurrency.
8-
97

108
## Getting Started
119

12-
Subprocess uses [SwiftPM](https://swift.org/package-manager/) as its build tool, so we recommend using that as well. If you want to depend on Subprocess in your own project, it's as simple as adding a `dependencies` clause to your `Package.swift`:
10+
To use `Subprocess` in a [SwiftPM](https://swift.org/package-manager/) project, add it as a package dependency to your `Package.swift`:
11+
1312

1413
```swift
1514
dependencies: [
16-
.package(url: "https://github.com/iCharlesHu/Subprocess.git", branch: "main")
15+
.package(url: "https://github.com/swiftlang/swift-subprocess.git", branch: "main")
1716
]
1817
```
19-
and then adding the `Subprocess` module to your target dependencies.
18+
Then, adding the `Subprocess` module to your target dependencies:
2019

2120
```swift
2221
.target(
@@ -124,7 +123,7 @@ let result = try await run(
124123

125124
`Subprocess` provides **platform-specific** configuration options, like setting `uid` and `gid` on Unix and adjusting window style on Windows, through the `PlatformOptions` struct. Check out the `PlatformOptions` documentation for a complete list of configurable parameters across different platforms.
126125

127-
Besides these platform-specific settings, `PlatformOptions` also includes an “escape hatch” via a closure. This closure allows you to have access to low level platform specific spawning constructs to perform customizations if `Subprocess` doesn’t have higher-level APIs.
126+
`PlatformOptions` also allows access to platform-specific spawning constructs and customizations via a closure.
128127

129128
```swift
130129
import Darwin
@@ -153,7 +152,7 @@ let result = try await run(.path("/bin/exe"), platformOptions: platformOptions)
153152

154153
By default, `Subprocess`:
155154
- Doesn’t send any input to the child process’s standard input
156-
- Captures the child process’s standard output as a `String`, up to 128kb
155+
- Captures the child process’s standard output as a `String`, up to 128kB
157156
- Ignores the child process’s standard error
158157

159158
You can tailor how `Subprocess` handles the standard input, standard output, and standard error by setting the `input`, `output`, and `error` parameters:
@@ -168,7 +167,7 @@ let result = try await run(.name("cat"), input: .string(content, using: UTF8.sel
168167
let result = try await run(.name("cat"), output: .data, error: .data)
169168
```
170169

171-
`Subprocess` ships with these input options:
170+
`Subprocess` supports these input options:
172171

173172
#### `NoInput`
174173

@@ -178,7 +177,7 @@ Use it by setting `.none` for `input`.
178177

179178
#### `FileDescriptorInput`
180179

181-
This option reads input from a specified `FileDescriptor` you provide. If `closeAfterSpawningProcess` is set to `true`, the subprocess will close the file descriptor after spawning. If `false`, you need to close it, even if the subprocess fails to spawn.
180+
This option reads input from a specified `FileDescriptor`. If `closeAfterSpawningProcess` is set to `true`, the subprocess will close the file descriptor after spawning. If `false`, you are responsible for closing it, even if the subprocess fails to spawn.
182181

183182
Use it by setting `.fileDescriptor(closeAfterSpawningProcess:)` for `input`.
184183

@@ -214,7 +213,7 @@ Use it by setting `.asyncSequence` for `input`.
214213

215214
---
216215

217-
`Subprocess` also ships these output options:
216+
`Subprocess` also supports these output options:
218217

219218
#### `DiscardedOutput`
220219

@@ -247,10 +246,9 @@ This option redirects the child output to the `.standardOutput` or `.standardErr
247246

248247
### Cross-platform support
249248

250-
`Subprocess` works on all major platforms supported by Swift, including macOS, Linux, and Windows, with feature parity on all platforms as well as platform-specific options for each.
249+
`Subprocess` works on macOS, Linux, and Windows, with feature parity on all platforms as well as platform-specific options for each.
251250

252-
The table below describes the current level of support that Subprocess has
253-
for various platforms:
251+
The table below describes the current level of support that Subprocess has for various platforms:
254252

255253
| **Platform** | **Support Status** |
256254
|---|---|
@@ -278,13 +276,11 @@ swift package --disable-sandbox preview-documentation --target Subprocess
278276

279277
## Contributing to Subprocess
280278

281-
Subprocess is part of the Foundation project. We have a dedicated [Foundation Forum][forum] where people can ask and answer questions on how to use or work on this package. It's also a great place to discuss its evolution.
282-
283-
[forum]: https://forums.swift.org/c/related-projects/foundation/
279+
Subprocess is part of the Foundation project. Discussion and evolution take place on [Swift Foundation Forum](https://forums.swift.org/c/related-projects/foundation/99).
284280

285281
If you find something that looks like a bug, please open a [Bug Report][bugreport]! Fill out as many details as you can.
286282

287-
[bugreport]: https://github.com/iCharlesHu/Subprocess/issues/new?assignees=&labels=bug&template=bug_report.md
283+
[bugreport]: https://github.com/swiftlang/swift-subprocess/issues/new?assignees=&labels=bug&template=bug_report.md
288284

289285
<p align="right">(<a href="#readme-top">back to top</a>)</p>
290286

@@ -298,8 +294,9 @@ Like all Swift.org projects, we would like the Subprocess project to foster a di
298294

299295
## Contact information
300296

301-
The current code owner of this package is Charles Hu ([@iCharlesHu](https://github.com/iCharlesHu)). You can contact him [on the Swift forums](https://forums.swift.org/u/icharleshu/summary).
297+
The Foundation Workgroup communicates with the broader Swift community using the [forum](https://forums.swift.org/c/related-projects/foundation/99) for general discussions.
298+
299+
The workgroup can also be contacted privately by messaging [@foundation-workgroup](https://forums.swift.org/new-message?groupname=foundation-workgroup) on the Swift Forums.
302300

303-
In case of moderation issues, you can also directly contact a member of the [Swift Core Team](https://swift.org/community/#community-structure).
304301

305302
<p align="right">(<a href="#readme-top">back to top</a>)</p>

Sources/Subprocess/API.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2024 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information

Sources/Subprocess/AsyncBufferSequence.swift

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2024 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -63,15 +63,40 @@ internal struct AsyncBufferSequence: AsyncSequence, Sendable {
6363
}
6464
}
6565

66-
extension RangeReplaceableCollection {
67-
/// Creates a new instance of a collection containing the elements of an asynchronous sequence.
68-
///
69-
/// - Parameter source: The asynchronous sequence of elements for the new collection.
70-
@inlinable
71-
internal init<Source: AsyncSequence>(_ source: Source) async rethrows where Source.Element == Element {
72-
self.init()
73-
for try await item in source {
74-
append(item)
75-
}
76-
}
66+
// MARK: - Page Size
67+
import _SubprocessCShims
68+
69+
#if canImport(Darwin)
70+
import Darwin
71+
internal import MachO.dyld
72+
73+
private let _pageSize: Int = {
74+
Int(_subprocess_vm_size())
75+
}()
76+
#elseif canImport(WinSDK)
77+
import WinSDK
78+
private let _pageSize: Int = {
79+
var sysInfo: SYSTEM_INFO = SYSTEM_INFO()
80+
GetSystemInfo(&sysInfo)
81+
return Int(sysInfo.dwPageSize)
82+
}()
83+
#elseif os(WASI)
84+
// WebAssembly defines a fixed page size
85+
private let _pageSize: Int = 65_536
86+
#elseif canImport(Android)
87+
@preconcurrency import Android
88+
private let _pageSize: Int = Int(getpagesize())
89+
#elseif canImport(Glibc)
90+
@preconcurrency import Glibc
91+
private let _pageSize: Int = Int(getpagesize())
92+
#elseif canImport(Musl)
93+
@preconcurrency import Musl
94+
private let _pageSize: Int = Int(getpagesize())
95+
#elseif canImport(C)
96+
private let _pageSize: Int = Int(getpagesize())
97+
#endif // canImport(Darwin)
98+
99+
@inline(__always)
100+
internal var readBufferSize: Int {
101+
return _pageSize
77102
}

Sources/Subprocess/Buffer.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2024 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -54,6 +54,7 @@ extension SequenceOutput.Buffer {
5454
@available(SubprocessSpan, *)
5555
#endif
5656
extension SequenceOutput.Buffer {
57+
#if !SubprocessSpan
5758
/// Access the raw bytes stored in this buffer
5859
/// - Parameter body: A closure with an `UnsafeRawBufferPointer` parameter that
5960
/// points to the contiguous storage for the type. If no such storage exists,
@@ -63,12 +64,20 @@ extension SequenceOutput.Buffer {
6364
/// - Returns: The return value, if any, of the body closure parameter.
6465
public func withUnsafeBytes<ResultType>(
6566
_ body: (UnsafeRawBufferPointer) throws -> ResultType
67+
) rethrows -> ResultType {
68+
return try self._withUnsafeBytes(body)
69+
}
70+
#endif // !SubprocessSpan
71+
72+
internal func _withUnsafeBytes<ResultType>(
73+
_ body: (UnsafeRawBufferPointer) throws -> ResultType
6674
) rethrows -> ResultType {
6775
#if os(Windows)
6876
return try self.data.withUnsafeBytes(body)
6977
#else
7078
// Although DispatchData was designed to be uncontiguous, in practice
71-
// we found that almost all DispatchData are contiguous.
79+
// we found that almost all DispatchData are contiguous. Therefore
80+
// we can access this body in O(1) most of the time.
7281
return try self.data.withUnsafeBytes { ptr in
7382
let bytes = UnsafeRawBufferPointer(start: ptr, count: self.data.count)
7483
return try body(bytes)

0 commit comments

Comments
 (0)