Skip to content

Commit 48c1b25

Browse files
committed
Rigorously check statuses and echo commands in build swiftly release script
1 parent 27ea36b commit 48c1b25

File tree

3 files changed

+63
-37
lines changed

3 files changed

+63
-37
lines changed

Sources/LinuxPlatform/Linux.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,6 @@ public struct Linux: Platform {
282282
try await fs.withTemporary(files: tmpFile) {
283283
try await ctx.httpClient.getGpgKeys().download(to: tmpFile)
284284
if let mockedHomeDir = ctx.mockedHomeDir {
285-
var env = ProcessInfo.processInfo.environment
286-
env["GNUPGHOME"] = (mockedHomeDir / ".gnupg").string
287285
try await sys.gpg()._import(key: tmpFile).run(environment: .inherit.updating(["GNUPGHOME": (mockedHomeDir / ".gnupg").string]), quiet: true)
288286
} else {
289287
try await sys.gpg()._import(key: tmpFile).run(quiet: true)

Sources/TestSwiftly/TestSwiftly.swift

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,9 @@ struct TestSwiftly: AsyncParsableCommand {
101101

102102
print("Extracting swiftly release")
103103
#if os(Linux)
104-
try await sys.tar().extract(.verbose, .compressed, .archive(swiftlyArchive)).run(quiet: false)
104+
try await sys.tar().extract(.verbose, .compressed, .archive(swiftlyArchive)).run()
105105
#elseif os(macOS)
106-
try await sys.installer(.verbose, .pkg(swiftlyArchive), .target("CurrentUserHomeDirectory")).run(quiet: false)
106+
try await sys.installer(.verbose, .pkg(swiftlyArchive), .target("CurrentUserHomeDirectory")).run()
107107
#endif
108108

109109
#if os(Linux)
@@ -127,8 +127,16 @@ struct TestSwiftly: AsyncParsableCommand {
127127
"SWIFTLY_TOOLCHAINS_DIR": (customLoc! / "toolchains").string,
128128
])
129129

130-
_ = try await Subprocess.run(.path(extractedSwiftly), arguments: ["init", "--assume-yes", "--no-modify-profile", "--skip-install"], environment: env, input: .standardInput, output: .standardOutput, error: .standardError)
131-
_ = try await sh(executable: .path(shell), .login, .command(". \"\(customLoc! / "env.sh")\" && swiftly install --assume-yes latest --post-install-file=./post-install.sh")).run(environment: env, output: .standardOutput, error: .standardError)
130+
let config = Configuration(
131+
.path(extractedSwiftly),
132+
arguments: ["init", "--assume-yes", "--no-modify-profile", "--skip-install"],
133+
environment: env
134+
)
135+
let result = try await Subprocess.run(config, output: .standardOutput, error: .standardError)
136+
if !result.terminationStatus.isSuccess {
137+
throw RunProgramError(terminationStatus: result.terminationStatus, config: config)
138+
}
139+
try await sh(executable: .path(shell), .login, .command(". \"\(customLoc! / "env.sh")\" && swiftly install --assume-yes latest --post-install-file=./post-install.sh")).run(environment: env, quiet: false)
132140
} else {
133141
print("Installing swiftly to the default location.")
134142
// Setting this environment helps to ensure that the profile gets sourced with bash, even if it is not in an interactive shell
@@ -140,8 +148,16 @@ struct TestSwiftly: AsyncParsableCommand {
140148
env = env.updating(["XDG_CONFIG_HOME": (fs.home / ".config").string])
141149
}
142150

143-
_ = try await Subprocess.run(.path(extractedSwiftly), arguments: ["init", "--assume-yes", "--skip-install"], environment: env, input: .standardInput, output: .standardOutput, error: .standardError)
144-
_ = try await sh(executable: .path(shell), .login, .command("swiftly install --assume-yes latest --post-install-file=./post-install.sh")).run(environment: env, output: .standardOutput, error: .standardError)
151+
let config = Configuration(
152+
.path(extractedSwiftly),
153+
arguments: ["init", "--assume-yes", "--skip-install"],
154+
environment: env
155+
)
156+
let result = try await Subprocess.run(config, output: .standardOutput, error: .standardError)
157+
if !result.terminationStatus.isSuccess {
158+
throw RunProgramError(terminationStatus: result.terminationStatus, config: config)
159+
}
160+
try await sh(executable: .path(shell), .login, .command("swiftly install --assume-yes latest --post-install-file=./post-install.sh")).run(environment: env)
145161
}
146162

147163
var swiftReady = false
@@ -158,9 +174,9 @@ struct TestSwiftly: AsyncParsableCommand {
158174
}
159175

160176
if let customLoc = customLoc, swiftReady {
161-
_ = try await sh(executable: .path(shell), .login, .command(". \"\(customLoc / "env.sh")\" && swift --version")).run(environment: env, output: .standardOutput, error: .standardError)
177+
try await sh(executable: .path(shell), .login, .command(". \"\(customLoc / "env.sh")\" && swift --version")).run(environment: env)
162178
} else if swiftReady {
163-
_ = try await sh(executable: .path(shell), .login, .command("swift --version")).run(environment: env, output: .standardOutput, error: .standardError)
179+
try await sh(executable: .path(shell), .login, .command("swift --version")).run(environment: env)
164180
}
165181

166182
// Test self-uninstall functionality
@@ -171,13 +187,13 @@ struct TestSwiftly: AsyncParsableCommand {
171187
private func testSelfUninstall(customLoc: SystemPackage.FilePath?, shell: SystemPackage.FilePath, env: Environment) async throws {
172188
if let customLoc = customLoc {
173189
// Test self-uninstall for custom location
174-
_ = try await sh(executable: .path(shell), .login, .command(". \"\(customLoc / "env.sh")\" && swiftly self-uninstall --assume-yes")).run(environment: env, output: .standardOutput, error: .standardError)
190+
try await sh(executable: .path(shell), .login, .command(". \"\(customLoc / "env.sh")\" && swiftly self-uninstall --assume-yes")).run(environment: env)
175191

176192
// Verify cleanup for custom location
177193
try await self.verifyCustomLocationCleanup(customLoc: customLoc)
178194
} else {
179195
// Test self-uninstall for default location
180-
_ = try await sh(executable: .path(shell), .login, .command("swiftly self-uninstall --assume-yes")).run(environment: env, output: .standardOutput, error: .standardError)
196+
try await sh(executable: .path(shell), .login, .command("swiftly self-uninstall --assume-yes")).run(environment: env)
181197

182198
// Verify cleanup for default location
183199
try await self.verifyDefaultLocationCleanup(shell: shell, env: env)
@@ -245,7 +261,7 @@ struct TestSwiftly: AsyncParsableCommand {
245261

246262
// Verify swiftly command is no longer available
247263
do {
248-
_ = try await sh(executable: .path(shell), .login, .command("which swiftly")).run(environment: env, output: .standardOutput, error: .standardError)
264+
try await sh(executable: .path(shell), .login, .command("which swiftly")).run(environment: env)
249265
throw TestError("swiftly command is still available in PATH after uninstall")
250266
} catch {
251267
// Expected - swiftly should not be found

Tools/build-swiftly-release/BuildSwiftlyRelease.swift

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import ArgumentParser
22
import AsyncHTTPClient
33
import Foundation
44
import NIOFileSystem
5+
import Subprocess
56
import SwiftlyCore
67
import SystemPackage
7-
import Subprocess
88

99
#if os(macOS)
1010
import MacOSPlatform
@@ -23,12 +23,10 @@ typealias sys = SystemCommand
2323

2424
extension Runnable {
2525
// Runs the command while echoing the full command-line to stdout for logging and reproduction
26-
func runEcho(quiet: Bool = false) async throws {
26+
func runEcho(environment: Environment = .inherit, quiet: Bool = false) async throws {
2727
let config = self.config()
28-
// if !quiet { print("\(args.joined(separator: " "))") }
2928
if !quiet { print("\(config)") }
30-
31-
try await self.run()
29+
try await self.run(environment: environment, quiet: quiet)
3230
}
3331
}
3432

@@ -117,7 +115,7 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
117115
}
118116

119117
do {
120-
try await sys.git().diffindex(.quiet, tree_ish: "HEAD").run()
118+
try await sys.git().diffindex(.quiet, tree_ish: "HEAD").runEcho()
121119
} catch {
122120
throw Error(message: "Git repo has local changes. First commit these changes, tag the commit with release \(self.version) and push the tag to GitHub.")
123121
}
@@ -136,7 +134,7 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
136134
try await self.checkGitRepoStatus()
137135

138136
// Start with a fresh SwiftPM package
139-
try await sys.swift().package().reset().run()
137+
try await sys.swift().package().reset().runEcho()
140138

141139
// Build a specific version of libarchive with a check on the tarball's SHA256
142140
let libArchiveVersion = "3.8.1"
@@ -172,14 +170,20 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
172170
let shaActual = libArchiveTarShaActual ?? "none"
173171
throw Error(message: "The libarchive tar.gz file sha256sum is \(shaActual), but expected \(libArchiveTarSha)")
174172
}
175-
try await sys.tar(.directory(buildCheckoutsDir)).extract(.compressed, .archive(buildCheckoutsDir / "libarchive-\(libArchiveVersion).tar.gz")).run()
173+
try await sys.tar(.directory(buildCheckoutsDir)).extract(.compressed, .archive(buildCheckoutsDir / "libarchive-\(libArchiveVersion).tar.gz")).runEcho()
176174

177175
let cwd = fs.cwd
178176
FileManager.default.changeCurrentDirectoryPath(libArchivePath.string)
179177

180178
let swiftVerRegex: Regex<(Substring, Substring)> = try! Regex("Swift version (\\d+\\.\\d+\\.?\\d*) ")
181179

182-
let swiftVerOutput = (try await Subprocess.run(.name("swift"), arguments: ["--version"], output: .string(limit: 1024))).standardOutput ?? ""
180+
let swiftVersionCmd = Configuration(
181+
.name("swift"),
182+
arguments: ["--version"]
183+
)
184+
print("\(swiftVersionCmd)")
185+
186+
let swiftVerOutput = (try await Subprocess.run(swiftVersionCmd, output: .string(limit: 1024))).standardOutput ?? ""
183187
guard let swiftVerMatch = try swiftVerRegex.firstMatch(in: swiftVerOutput) else {
184188
throw Error(message: "Unable to detect swift version")
185189
}
@@ -201,15 +205,15 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
201205
throw Error(message: "Swift release \(swiftVersion) has no Static SDK offering")
202206
}
203207

204-
_ = try await sys.swift().sdk().install(.checksum(sdkPlatform.checksum ?? "deadbeef"), bundle_path_or_url: "https://download.swift.org/swift-\(swiftVersion)-release/static-sdk/swift-\(swiftVersion)-RELEASE/swift-\(swiftVersion)-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz").run(output: .standardOutput, error: .standardError)
208+
try await sys.swift().sdk().install(.checksum(sdkPlatform.checksum ?? "deadbeef"), bundle_path_or_url: "https://download.swift.org/swift-\(swiftVersion)-release/static-sdk/swift-\(swiftVersion)-RELEASE/swift-\(swiftVersion)-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz").runEcho()
205209

206210
var customEnv: Environment = .inherit
207211
customEnv = customEnv.updating([
208212
"CC": "\(cwd)/Tools/build-swiftly-release/musl-clang",
209-
"MUSL_PREFIX": "\(fs.home / ".swiftpm/swift-sdks/\(sdkName).artifactbundle/\(sdkName)/swift-linux-musl/musl-1.2.5.sdk/\(arch)/usr")",
213+
"MUSL_PREFIX": "\(fs.home / ".swiftpm/swift-sdks/\(sdkName).artifactbundle/\(sdkName)/swift-linux-musl/musl-1.2.5.sdk/\(arch)/usr")",
210214
])
211215

212-
_ = try await Subprocess.run(
216+
let configCmd = Configuration(
213217
.path(FilePath("./configure")),
214218
arguments: [
215219
"--prefix=\(pkgConfigPath)",
@@ -231,23 +235,31 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
231235
"--disable-bsdcat",
232236
],
233237
environment: customEnv,
234-
input: .standardInput,
238+
)
239+
print("\(configCmd)")
240+
241+
let result = try await Subprocess.run(
242+
configCmd,
235243
output: .standardOutput,
236244
error: .standardError,
237245
)
238246

239-
_ = try await sys.make().run(environment: customEnv, output: .standardOutput, error: .standardError)
247+
if !result.terminationStatus.isSuccess {
248+
throw RunProgramError(terminationStatus: result.terminationStatus, config: configCmd)
249+
}
250+
251+
try await sys.make().runEcho(environment: customEnv)
240252

241-
try await sys.make().install().run()
253+
try await sys.make().install().runEcho()
242254

243255
FileManager.default.changeCurrentDirectoryPath(cwd.string)
244256

245-
try await sys.swift().build(.swift_sdk("\(arch)-swift-linux-musl"), .product("swiftly"), .pkg_config_path(pkgConfigPath / "lib/pkgconfig"), .static_swift_stdlib, .configuration("release")).run()
257+
try await sys.swift().build(.swift_sdk("\(arch)-swift-linux-musl"), .product("swiftly"), .pkg_config_path(pkgConfigPath / "lib/pkgconfig"), .static_swift_stdlib, .configuration("release")).runEcho()
246258

247259
let releaseDir = cwd / ".build/release"
248260

249261
// Strip the symbols from the binary to decrease its size
250-
try await sys.strip(name: releaseDir / "swiftly").run()
262+
try await sys.strip(name: releaseDir / "swiftly").runEcho()
251263

252264
try await self.collectLicenses(releaseDir)
253265

@@ -257,7 +269,7 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
257269
let releaseArchive = releaseDir / "swiftly-\(version)-x86_64.tar.gz"
258270
#endif
259271

260-
try await sys.tar(.directory(releaseDir)).create(.compressed, .archive(releaseArchive), files: ["swiftly", "LICENSE.txt"]).run()
272+
try await sys.tar(.directory(releaseDir)).create(.compressed, .archive(releaseArchive), files: ["swiftly", "LICENSE.txt"]).runEcho()
261273

262274
print(releaseArchive)
263275

@@ -270,8 +282,8 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
270282
let testArchive = debugDir / "test-swiftly-linux-x86_64.tar.gz"
271283
#endif
272284

273-
try await sys.swift().build(.swift_sdk("\(arch)-swift-linux-musl"), .product("test-swiftly"), .pkg_config_path(pkgConfigPath / "lib/pkgconfig"), .static_swift_stdlib, .configuration("debug")).run()
274-
try await sys.tar(.directory(debugDir)).create(.compressed, .archive(testArchive), files: ["test-swiftly"]).run()
285+
try await sys.swift().build(.swift_sdk("\(arch)-swift-linux-musl"), .product("test-swiftly"), .pkg_config_path(pkgConfigPath / "lib/pkgconfig"), .static_swift_stdlib, .configuration("debug")).runEcho()
286+
try await sys.tar(.directory(debugDir)).create(.compressed, .archive(testArchive), files: ["test-swiftly"]).runEcho()
275287

276288
print(testArchive)
277289
}
@@ -282,11 +294,11 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
282294
func buildMacOSRelease(cert: String?, identifier: String) async throws {
283295
try await self.checkGitRepoStatus()
284296

285-
try await sys.swift().package().clean().run()
297+
try await sys.swift().package().clean().runEcho()
286298

287299
for arch in ["x86_64", "arm64"] {
288-
try await sys.swift().build(.product("swiftly"), .configuration("release"), .arch("\(arch)")).run()
289-
try await sys.strip(name: FilePath(".build") / "\(arch)-apple-macosx/release/swiftly").run()
300+
try await sys.swift().build(.product("swiftly"), .configuration("release"), .arch("\(arch)")).runEcho()
301+
try await sys.strip(name: FilePath(".build") / "\(arch)-apple-macosx/release/swiftly").runEcho()
290302
}
291303

292304
let swiftlyBinDir = fs.cwd / ".build/release/.swiftly/bin"
@@ -362,7 +374,7 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
362374
.create(.output(swiftlyBinDir / "swiftly"))
363375
.runEcho()
364376

365-
try await sys.tar(.directory(".build/x86_64-apple-macosx/debug")).create(.compressed, .archive(testArchive), files: ["test-swiftly"]).run()
377+
try await sys.tar(.directory(".build/x86_64-apple-macosx/debug")).create(.compressed, .archive(testArchive), files: ["test-swiftly"]).runEcho()
366378

367379
print(testArchive)
368380
}

0 commit comments

Comments
 (0)