Skip to content

Commit bf792ff

Browse files
committed
Merge branch 'main' of https://github.com/swiftlang/swiftly into convert_filepath
2 parents ad705ae + 5583a8a commit bf792ff

File tree

13 files changed

+230
-88
lines changed

13 files changed

+230
-88
lines changed

.github/workflows/pull_request.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,26 @@ jobs:
9494
- name: Extract and Run Workflow Tests
9595
run: cp swiftly-*.tar.gz /root/swiftly.tar.gz && cp test-swiftly-*.tar.gz /root && cd /root && tar zxf test-swiftly-*.tar.gz && ./test-swiftly -y ./swiftly.tar.gz
9696

97+
release-custom-install-test:
98+
name: Test Release - Custom Install Location
99+
needs: releasebuildcheck
100+
runs-on: ubuntu-latest
101+
container:
102+
image: "ubuntu:24.04"
103+
steps:
104+
- name: Prepare System
105+
run: apt-get update && DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install ca-certificates gpg tzdata
106+
- name: Download Release
107+
uses: actions/download-artifact@v4
108+
with:
109+
name: swiftly-release-x86_64
110+
- name: Download Tests
111+
uses: actions/download-artifact@v4
112+
with:
113+
name: swiftly-tests-x86_64
114+
- name: Extract and Run Workflow Tests
115+
run: cp swiftly-*.tar.gz /root/swiftly.tar.gz && cp test-swiftly-*.tar.gz /root && cd /root && tar zxf test-swiftly-*.tar.gz && ./test-swiftly -y --custom-location ./swiftly.tar.gz
116+
97117
formatcheck:
98118
name: Format Check
99119
runs-on: ubuntu-latest

Package.swift

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
import PackageDescription
44

5+
let swiftSettings = [
6+
SwiftSetting.enableUpcomingFeature("MemberImportVisibility"),
7+
]
8+
59
let package = Package(
610
name: "swiftly",
711
platforms: [
@@ -40,7 +44,8 @@ let package = Package(
4044
.target(name: "MacOSPlatform", condition: .when(platforms: [.macOS])),
4145
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
4246
.product(name: "SystemPackage", package: "swift-system"),
43-
]
47+
],
48+
swiftSettings: swiftSettings
4449
),
4550
.executableTarget(
4651
name: "TestSwiftly",
@@ -49,7 +54,8 @@ let package = Package(
4954
.target(name: "SwiftlyCore"),
5055
.target(name: "LinuxPlatform", condition: .when(platforms: [.linux])),
5156
.target(name: "MacOSPlatform", condition: .when(platforms: [.macOS])),
52-
]
57+
],
58+
swiftSettings: swiftSettings
5359
),
5460
.target(
5561
name: "SwiftlyCore",
@@ -62,12 +68,14 @@ let package = Package(
6268
.product(name: "OpenAPIAsyncHTTPClient", package: "swift-openapi-async-http-client"),
6369
.product(name: "SystemPackage", package: "swift-system"),
6470
],
71+
swiftSettings: swiftSettings
6572
),
6673
.target(
6774
name: "SwiftlyDownloadAPI",
6875
dependencies: [
6976
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
7077
],
78+
swiftSettings: swiftSettings,
7179
plugins: [
7280
.plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator"),
7381
]
@@ -77,6 +85,7 @@ let package = Package(
7785
dependencies: [
7886
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
7987
],
88+
swiftSettings: swiftSettings,
8089
plugins: [
8190
.plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator"),
8291
]
@@ -119,6 +128,7 @@ let package = Package(
119128
"CLibArchive",
120129
.product(name: "SystemPackage", package: "swift-system"),
121130
],
131+
swiftSettings: swiftSettings,
122132
linkerSettings: [
123133
.linkedLibrary("z"),
124134
]
@@ -128,7 +138,8 @@ let package = Package(
128138
dependencies: [
129139
"SwiftlyCore",
130140
.product(name: "SystemPackage", package: "swift-system"),
131-
]
141+
],
142+
swiftSettings: swiftSettings
132143
),
133144
.systemLibrary(
134145
name: "CLibArchive",
@@ -145,7 +156,8 @@ let package = Package(
145156
],
146157
resources: [
147158
.embedInCode("mock-signing-key-private.pgp"),
148-
]
159+
],
160+
swiftSettings: swiftSettings
149161
),
150162
]
151163
)

Sources/LinuxPlatform/Linux.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ public struct Linux: Platform {
3434
}
3535

3636
public func swiftlyToolchainsDir(_ ctx: SwiftlyCoreContext) -> FilePath {
37-
self.swiftlyHomeDir(ctx) / "toolchains"
37+
ctx.mockedHomeDir.map { $0 / "toolchains" }
38+
?? ProcessInfo.processInfo.environment["SWIFTLY_TOOLCHAINS_DIR"].map { FilePath($0) }
39+
?? homeDir / ".local/share/swiftly/toolchains"
3840
}
3941

4042
public var toolchainFileExtension: String {

Sources/MacOSPlatform/MacOS.swift

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,21 @@ public struct MacOS: Platform {
1818
homeDir / ".swiftly"
1919
}
2020

21+
public var defaultToolchainsDirectory: FilePath {
22+
homeDir / "Library/Developer/Toolchains"
23+
}
24+
2125
public func swiftlyBinDir(_ ctx: SwiftlyCoreContext) -> FilePath {
2226
ctx.mockedHomeDir.map { $0 / "bin" }
2327
?? ProcessInfo.processInfo.environment["SWIFTLY_BIN_DIR"].map { FilePath($0) }
24-
?? (homeDir / ".swiftly/bin")
28+
?? homeDir / ".swiftly/bin"
2529
}
2630

2731
public func swiftlyToolchainsDir(_ ctx: SwiftlyCoreContext) -> FilePath {
2832
ctx.mockedHomeDir.map { $0 / "Toolchains" }
29-
// The toolchains are always installed here by the installer. We bypass the installer in the case of test mocks
30-
?? homeDir / "Library/Developer/Toolchains"
33+
?? ProcessInfo.processInfo.environment["SWIFTLY_TOOLCHAINS_DIR"].map { FilePath($0) }
34+
// This is where the installer will put the toolchains, and where Xcode can find them
35+
?? self.defaultToolchainsDirectory
3136
}
3237

3338
public var toolchainFileExtension: String {
@@ -53,26 +58,43 @@ public struct MacOS: Platform {
5358
throw SwiftlyError(message: "\(tmpFile) doesn't exist")
5459
}
5560

56-
if !(try await fileExists(atPath: self.swiftlyToolchainsDir(ctx))) {
57-
try await mkdir(atPath: self.swiftlyToolchainsDir(ctx))
61+
let toolchainsDir = self.swiftlyToolchainsDir(ctx)
62+
63+
if !(try await fileExists(atPath: toolchainsDir)) {
64+
try await mkdir(atPath: self.swiftlyToolchainsDir(ctx), parents: true)
5865
}
5966

60-
if ctx.mockedHomeDir == nil {
67+
if toolchainsDir == self.defaultToolchainsDirectory {
68+
// If the toolchains go into the default user location then we use the installer to install them
6169
await ctx.print("Installing package in user home directory...")
6270
try runProgram(
6371
"installer", "-verbose", "-pkg", "\(tmpFile)", "-target", "CurrentUserHomeDirectory",
6472
quiet: !verbose
6573
)
6674
} else {
67-
// In the case of a mock for testing purposes we won't use the installer, perferring a manual process because
68-
// the installer will not install to an arbitrary path, only a volume or user home directory.
75+
// Otherwise, we extract the pkg into the requested toolchains directory.
6976
await ctx.print("Expanding pkg...")
7077
let tmpDir = mktemp()
71-
let toolchainDir = self.swiftlyToolchainsDir(ctx) / "\(version.identifier).xctoolchain"
78+
let toolchainDir = toolchainsDir / "\(version.identifier).xctoolchain"
79+
7280
if !(try await fileExists(atPath: toolchainDir)) {
7381
try await mkdir(atPath: toolchainDir)
7482
}
83+
84+
await ctx.print("Checking package signature...")
85+
do {
86+
try runProgram("pkgutil", "--check-signature", "\(tmpFile)", quiet: !verbose)
87+
} catch {
88+
// If this is not a test that uses mocked toolchains then we must throw this error and abort installation
89+
guard ctx.mockedHomeDir != nil else {
90+
throw error
91+
}
92+
93+
// We permit the signature verification to fail during testing
94+
await ctx.print("Signature verification failed, which is allowable during testing with mocked toolchains")
95+
}
7596
try runProgram("pkgutil", "--verbose", "--expand", "\(tmpFile)", "\(tmpDir)", quiet: !verbose)
97+
7698
// There's a slight difference in the location of the special Payload file between official swift packages
7799
// and the ones that are mocked here in the test framework.
78100
var payload = tmpDir / "Payload"

Sources/Swiftly/Init.swift

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ struct Init: SwiftlyCommand {
7171

7272
// Give the user the prompt and the choice to abort at this point.
7373
if !assumeYes {
74+
let toolchainsDir = Swiftly.currentPlatform.swiftlyToolchainsDir(ctx)
75+
7476
var msg = """
7577
Welcome to swiftly, the Swift toolchain manager for Linux and macOS!
7678
@@ -82,12 +84,20 @@ struct Init: SwiftlyCommand {
8284
8385
\(Swiftly.currentPlatform.swiftlyHomeDir(ctx)) - Directory for configuration files
8486
\(Swiftly.currentPlatform.swiftlyBinDir(ctx)) - Links to the binaries of the active toolchain
85-
\(Swiftly.currentPlatform.swiftlyToolchainsDir(ctx)) - Directory hosting installed toolchains
87+
\(toolchainsDir) - Directory hosting installed toolchains
8688
8789
These locations can be changed by setting the environment variables
88-
SWIFTLY_HOME_DIR and SWIFTLY_BIN_DIR before running 'swiftly init' again.
90+
SWIFTLY_HOME_DIR, SWIFTLY_BIN_DIR, and SWIFTLY_TOOLCHAINS_DIR before running 'swiftly init' again.
8991
9092
"""
93+
#if os(macOS)
94+
if toolchainsDir != homeDir / "Library/Developer/Toolchains" {
95+
msg += """
96+
97+
NOTE: The toolchains are not being installed in a standard macOS location, so Xcode may not be able to find them.
98+
"""
99+
}
100+
#endif
91101
if !skipInstall {
92102
msg += """
93103
@@ -189,6 +199,7 @@ struct Init: SwiftlyCommand {
189199
env = """
190200
set -x SWIFTLY_HOME_DIR "\(Swiftly.currentPlatform.swiftlyHomeDir(ctx))"
191201
set -x SWIFTLY_BIN_DIR "\(Swiftly.currentPlatform.swiftlyBinDir(ctx))"
202+
set -x SWIFTLY_TOOLCHAINS_DIR "\(Swiftly.currentPlatform.swiftlyToolchainsDir(ctx))"
192203
if not contains "$SWIFTLY_BIN_DIR" $PATH
193204
set -x PATH "$SWIFTLY_BIN_DIR" $PATH
194205
end
@@ -198,6 +209,7 @@ struct Init: SwiftlyCommand {
198209
env = """
199210
export SWIFTLY_HOME_DIR="\(Swiftly.currentPlatform.swiftlyHomeDir(ctx))"
200211
export SWIFTLY_BIN_DIR="\(Swiftly.currentPlatform.swiftlyBinDir(ctx))"
212+
export SWIFTLY_TOOLCHAINS_DIR="\(Swiftly.currentPlatform.swiftlyToolchainsDir(ctx))"
201213
if [[ ":$PATH:" != *":$SWIFTLY_BIN_DIR:"* ]]; then
202214
export PATH="$SWIFTLY_BIN_DIR:$PATH"
203215
fi
@@ -249,50 +261,50 @@ struct Init: SwiftlyCommand {
249261
addEnvToProfile = true
250262
}
251263

252-
var postInstall: String?
253-
var pathChanged = false
254-
255-
if !skipInstall {
256-
let latestVersion = try await Install.resolve(ctx, config: config, selector: ToolchainSelector.latest)
257-
(postInstall, pathChanged) = try await Install.execute(ctx, version: latestVersion, &config, useInstalledToolchain: true, verifySignature: true, verbose: verbose, assumeYes: assumeYes)
258-
}
259-
260264
if addEnvToProfile {
261265
try Data(sourceLine.utf8).append(to: profileHome)
266+
}
267+
}
262268

263-
if !quietShellFollowup {
264-
await ctx.print("""
265-
To begin using installed swiftly from your current shell, first run the following command:
266-
\(sourceLine)
269+
var postInstall: String?
270+
var pathChanged = false
267271

268-
""")
269-
}
270-
}
272+
if !skipInstall {
273+
let latestVersion = try await Install.resolve(ctx, config: config, selector: ToolchainSelector.latest)
274+
(postInstall, pathChanged) = try await Install.execute(ctx, version: latestVersion, &config, useInstalledToolchain: true, verifySignature: true, verbose: verbose, assumeYes: assumeYes)
275+
}
276+
277+
if !quietShellFollowup {
278+
await ctx.print("""
279+
To begin using installed swiftly from your current shell, first run the following command:
280+
\(sourceLine)
271281
272-
// Fish doesn't have path caching, so this might only be needed for bash/zsh
273-
if pathChanged && !quietShellFollowup && !shell.hasSuffix("fish") {
274-
await ctx.print("""
275-
Your shell caches items on your path for better performance. Swiftly has added
276-
items to your path that may not get picked up right away. You can update your
277-
shell's environment by running
282+
""")
283+
}
278284

279-
hash -r
285+
// Fish doesn't have path caching, so this might only be needed for bash/zsh
286+
if pathChanged && !quietShellFollowup && !shell.hasSuffix("fish") {
287+
await ctx.print("""
288+
Your shell caches items on your path for better performance. Swiftly has added
289+
items to your path that may not get picked up right away. You can update your
290+
shell's environment by running
280291
281-
or restarting your shell.
292+
hash -r
282293
283-
""")
284-
}
294+
or restarting your shell.
285295
286-
if let postInstall {
287-
await ctx.print("""
288-
There are some dependencies that should be installed before using this toolchain.
289-
You can run the following script as the system administrator (e.g. root) to prepare
290-
your system:
296+
""")
297+
}
291298

292-
\(postInstall)
299+
if let postInstall {
300+
await ctx.print("""
301+
There are some dependencies that should be installed before using this toolchain.
302+
You can run the following script as the system administrator (e.g. root) to prepare
303+
your system:
293304
294-
""")
295-
}
305+
\(postInstall)
306+
307+
""")
296308
}
297309
}
298310
}

Sources/Swiftly/Proxy.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import ArgumentParser
12
import Foundation
23
import SwiftlyCore
34

Sources/Swiftly/Run.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ struct Run: SwiftlyCommand {
105105

106106
try await Swiftly.currentPlatform.proxy(ctx, toolchain, command[0], [String](command[1...]))
107107
} catch let terminated as RunProgramError {
108+
if ctx.mockedHomeDir != nil {
109+
throw terminated
110+
}
108111
Foundation.exit(terminated.exitCode)
109112
} catch {
110113
throw error

Sources/Swiftly/SelfUpdate.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import ArgumentParser
22
import Foundation
33
import SwiftlyCore
4+
import SwiftlyWebsiteAPI
45
@preconcurrency import TSCBasic
56
import TSCUtility
67

0 commit comments

Comments
 (0)