-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
It works much like it does already for Linux with some notable differences: * The toolchains are installed using the pkg files and macOS installer * The toolchain directory is ~/Library/Developer/Toolchains instead of ~/.local/share/swiftly/toolchains * The swiftly shared directory is ~/Library/Application Support/swiftly as it this is a more typical place for macOS applications to store their supporting files Create a MacOS struct that implements the existing Platform protocol. Make a platform-specific target for this module. Bump the required swift toolchain version to resolve compiler errors and set the minimum macOS version to 13. Update the README.md with some macOS details and fix some of the details that were outdated, both there and in DESIGN.md. Since macOS configuration is very simple compared to Linux, the configuration can be auto-created from Swift directly if it is missing. Add some helpful notes regarding the need to rehash the zsh on macOS since even when the swiftly bin directory has higher precedence in the PATH it sometimes gets snagged on the /usr/bin/swift, which doesn't detect the user installed toolchains and sometimes tries to get the user to install Xcode. Make the shell script swiftly installer capable of operating in a standard macOS environment. First, detect that the environment is macOS, and then adjust the getopts for macOS's more limited implementation with the short opts. Also, remove any of the Linux specific steps to detect the distribution, check for gpg, and attempt to install Linux system packages.
- Loading branch information
1 parent
ab38db0
commit dfb441d
Showing
13 changed files
with
358 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,3 +6,4 @@ xcuserdata/ | |
DerivedData/ | ||
.swiftpm/ | ||
.vscode/ | ||
**/*.swp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
5.7 | ||
5.10 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
import Foundation | ||
import SwiftlyCore | ||
|
||
struct SwiftPkgInfo: Codable { | ||
var CFBundleIdentifier: String | ||
} | ||
|
||
/// `Platform` implementation for macOS systems. | ||
public struct MacOS: Platform { | ||
public init() {} | ||
|
||
public var appDataDirectory: URL { | ||
return FileManager.default.homeDirectoryForCurrentUser | ||
.appendingPathComponent("Library/Application Support", isDirectory: true) | ||
} | ||
|
||
public var swiftlyBinDir: URL { | ||
SwiftlyCore.mockedHomeDir.map { $0.appendingPathComponent("bin", isDirectory: true) } | ||
?? ProcessInfo.processInfo.environment["SWIFTLY_BIN_DIR"].map { URL(fileURLWithPath: $0) } | ||
?? FileManager.default.homeDirectoryForCurrentUser | ||
.appendingPathComponent("Library/Application Support/swiftly/bin", isDirectory: true) | ||
} | ||
|
||
public var swiftlyToolchainsDir: URL { | ||
SwiftlyCore.mockedHomeDir.map { $0.appendingPathComponent("Library/Developer/Toolchains", isDirectory: true) } | ||
?? FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent("Library/Developer/Toolchains", isDirectory: true) | ||
} | ||
|
||
public var toolchainFileExtension: String { | ||
"pkg" | ||
} | ||
|
||
public func isSystemDependencyPresent(_: SystemDependency) -> Bool { | ||
// All system dependencies on macOS should be present | ||
true | ||
} | ||
|
||
public func verifySystemPrerequisitesForInstall(requireSignatureValidation: Bool) throws { | ||
// All system prerequisites should be there for macOS | ||
} | ||
|
||
public func install(from tmpFile: URL, version: ToolchainVersion) throws { | ||
guard tmpFile.fileExists() else { | ||
throw Error(message: "\(tmpFile) doesn't exist") | ||
} | ||
|
||
if !self.swiftlyToolchainsDir.fileExists() { | ||
try FileManager.default.createDirectory(at: self.swiftlyToolchainsDir, withIntermediateDirectories: false) | ||
} | ||
|
||
SwiftlyCore.print("Installing package in user home directory...") | ||
try runProgram("installer", "-pkg", tmpFile.path, "-target", "CurrentUserHomeDirectory") | ||
} | ||
|
||
public func uninstall(_ toolchain: ToolchainVersion) throws { | ||
SwiftlyCore.print("Uninstalling package in user home directory...") | ||
|
||
let toolchainDir = self.swiftlyToolchainsDir.appendingPathComponent("\(toolchain.identifier).xctoolchain", isDirectory: true) | ||
|
||
let decoder = PropertyListDecoder() | ||
let infoPlist = toolchainDir.appendingPathComponent("Info.plist") | ||
guard let data = try? Data(contentsOf: infoPlist) else { | ||
throw Error(message: "could not open \(infoPlist)") | ||
} | ||
|
||
guard let pkgInfo = try? decoder.decode(SwiftPkgInfo.self, from: data) else { | ||
throw Error(message: "could not decode plist at \(infoPlist)") | ||
} | ||
|
||
try FileManager.default.removeItem(at: toolchainDir) | ||
|
||
let homedir = ProcessInfo.processInfo.environment["HOME"]! | ||
try runProgram("pkgutil", "--volume", homedir, "--forget", pkgInfo.CFBundleIdentifier) | ||
} | ||
|
||
public func use(_ toolchain: ToolchainVersion, currentToolchain: ToolchainVersion?) throws -> Bool { | ||
let toolchainBinURL = self.swiftlyToolchainsDir | ||
.appendingPathComponent(toolchain.identifier + ".xctoolchain", isDirectory: true) | ||
.appendingPathComponent("usr", isDirectory: true) | ||
.appendingPathComponent("bin", isDirectory: true) | ||
|
||
// Delete existing symlinks from previously in-use toolchain. | ||
if let currentToolchain { | ||
try self.unUse(currentToolchain: currentToolchain) | ||
} | ||
|
||
// Ensure swiftly doesn't overwrite any existing executables without getting confirmation first. | ||
let swiftlyBinDirContents = try FileManager.default.contentsOfDirectory(atPath: self.swiftlyBinDir.path) | ||
let toolchainBinDirContents = try FileManager.default.contentsOfDirectory(atPath: toolchainBinURL.path) | ||
let willBeOverwritten = Set(toolchainBinDirContents).intersection(swiftlyBinDirContents) | ||
if !willBeOverwritten.isEmpty { | ||
SwiftlyCore.print("The following existing executables will be overwritten:") | ||
|
||
for executable in willBeOverwritten { | ||
SwiftlyCore.print(" \(self.swiftlyBinDir.appendingPathComponent(executable).path)") | ||
} | ||
|
||
let proceed = SwiftlyCore.readLine(prompt: "Proceed? (y/n)") ?? "n" | ||
|
||
guard proceed == "y" else { | ||
SwiftlyCore.print("Aborting use") | ||
return false | ||
} | ||
} | ||
|
||
for executable in toolchainBinDirContents { | ||
let linkURL = self.swiftlyBinDir.appendingPathComponent(executable) | ||
let executableURL = toolchainBinURL.appendingPathComponent(executable) | ||
|
||
// Deletion confirmed with user above. | ||
try linkURL.deleteIfExists() | ||
|
||
try FileManager.default.createSymbolicLink( | ||
atPath: linkURL.path, | ||
withDestinationPath: executableURL.path | ||
) | ||
} | ||
|
||
SwiftlyCore.print(""" | ||
NOTE: On macOS it is possible that the shell will pick up the system Swift on the path | ||
instead of the one that swiftly has installed for you. You can run the 'hash -r' | ||
command to update the shell with the latest PATHs. | ||
hash -r | ||
""" | ||
) | ||
|
||
return true | ||
} | ||
|
||
public func unUse(currentToolchain: ToolchainVersion) throws { | ||
let currentToolchainBinURL = self.swiftlyToolchainsDir | ||
.appendingPathComponent(currentToolchain.identifier + ".xctoolchain", isDirectory: true) | ||
.appendingPathComponent("usr", isDirectory: true) | ||
.appendingPathComponent("bin", isDirectory: true) | ||
|
||
for existingExecutable in try FileManager.default.contentsOfDirectory(atPath: currentToolchainBinURL.path) { | ||
guard existingExecutable != "swiftly" else { | ||
continue | ||
} | ||
|
||
let url = self.swiftlyBinDir.appendingPathComponent(existingExecutable) | ||
let vals = try url.resourceValues(forKeys: [URLResourceKey.isSymbolicLinkKey]) | ||
|
||
guard let islink = vals.isSymbolicLink, islink else { | ||
throw Error(message: "Found executable not managed by swiftly in SWIFTLY_BIN_DIR: \(url.path)") | ||
} | ||
let symlinkDest = url.resolvingSymlinksInPath() | ||
guard symlinkDest.deletingLastPathComponent() == currentToolchainBinURL else { | ||
throw Error(message: "Found symlink that points to non-swiftly managed executable: \(symlinkDest.path)") | ||
} | ||
|
||
try self.swiftlyBinDir.appendingPathComponent(existingExecutable).deleteIfExists() | ||
} | ||
} | ||
|
||
public func listAvailableSnapshots(version _: String?) async -> [Snapshot] { | ||
[] | ||
} | ||
|
||
public func getExecutableName(forArch: String) -> String { | ||
"swiftly-\(forArch)-macos-osx" | ||
} | ||
|
||
public func currentToolchain() throws -> ToolchainVersion? { nil } | ||
|
||
public func getTempFilePath() -> URL { | ||
FileManager.default.temporaryDirectory.appendingPathComponent("swiftly-\(UUID()).pkg") | ||
} | ||
|
||
public func verifySignature(httpClient: SwiftlyHTTPClient, archiveDownloadURL: URL, archive: URL) async throws { | ||
// No signature verification is required on macOS since the pkg files have their own signing | ||
// mechanism and the swift.org downloadables are trusted by stock macOS installations. | ||
} | ||
|
||
public static let currentPlatform: any Platform = MacOS() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.