Skip to content

Add an option to self-update to provide the swiftly version to update #370

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Documentation/SwiftlyDocs.docc/swiftly-cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ swiftly init [--no-modify-profile] [--overwrite] [--platform=<platform>] [--skip
Update the version of swiftly itself.

```
swiftly self-update [--assume-yes] [--verbose] [--version] [--help]
swiftly self-update [--assume-yes] [--verbose] [--version] [--help]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space added here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, the documentation generator is homegrown, and naive. This seems minor enough that I wanted to keep the change to another PR, or possibly adopt the revision of it that's now available in the swift argument parser project.

```

**--assume-yes:**
Expand Down
92 changes: 65 additions & 27 deletions Sources/Swiftly/SelfUpdate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,23 @@ import SwiftlyWebsiteAPI
@preconcurrency import TSCBasic
import TSCUtility

extension SwiftlyVersion: ExpressibleByArgument {
public init?(argument: String) {
try? self.init(parsing: argument)
}
}

struct SelfUpdate: SwiftlyCommand {
public static let configuration = CommandConfiguration(
abstract: "Update the version of swiftly itself."
)

@OptionGroup var root: GlobalOptions

@Option(help: .hidden) var toVersion: SwiftlyVersion

private enum CodingKeys: String, CodingKey {
case root
case root, toVersion
}

mutating func run() async throws {
Expand All @@ -31,50 +39,80 @@ struct SelfUpdate: SwiftlyCommand {
)
}

let _ = try await Self.execute(ctx, verbose: self.root.verbose)
let _ = try await Self.execute(ctx, verbose: self.root.verbose, version: self.toVersion)
}

public static func execute(_ ctx: SwiftlyCoreContext, verbose: Bool) async throws
public static func execute(_ ctx: SwiftlyCoreContext, verbose: Bool, version swiftlyVersion: SwiftlyVersion?) async throws
-> SwiftlyVersion
{
await ctx.print("Checking for swiftly updates...")
var downloadURL: Foundation.URL?
var version: SwiftlyVersion? = swiftlyVersion

let swiftlyRelease = try await ctx.httpClient.getCurrentSwiftlyRelease()
if let version {
#if os(macOS)
downloadURL = URL(string: "https://download.swift.org/swiftly/darwin/swiftly-\(version).pkg")
#endif

guard try swiftlyRelease.swiftlyVersion > SwiftlyCore.version else {
await ctx.print("Already up to date.")
return SwiftlyCore.version
#if os(Linux)
#if arch(x86_64)
downloadURL = URL(string: "https://download.swift.org/swiftly/linux/swiftly-\(version)-x86_64.tar.gz")
#elseif arch(arm64)
downloadURL = URL(string: "https://download.swift.org/swiftly/linux/swiftly-\(version)-aarch64.tar.gz")
#else
fatalError("Unsupported architecture")
#endif
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this throw an error if we somehow get here and don't know what we're downloading?
As it stands, I think this will end up running the update based on getCurrentSwiftlyRelease() since downloadURL won't get set, even though a version was specified.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added fatal errors in the unsupported cases.

#else
fatalError("Unsupported OS")
#endif

guard version > SwiftlyCore.version else {
await ctx.print("Self-update does not support downgrading to an older version or re-installing the current version. Current version is \(SwiftlyCore.version) and requested version is \(version).")
return SwiftlyCore.version
}

await ctx.print("Self-update requested to swiftly version \(version)")
}

var downloadURL: Foundation.URL?
for platform in swiftlyRelease.platforms {
#if os(macOS)
guard platform.isDarwin else {
continue
if downloadURL == nil {
await ctx.print("Checking for swiftly updates...")

let swiftlyRelease = try await ctx.httpClient.getCurrentSwiftlyRelease()

guard try swiftlyRelease.swiftlyVersion > SwiftlyCore.version else {
await ctx.print("Already up to date.")
return SwiftlyCore.version
}
for platform in swiftlyRelease.platforms {
#if os(macOS)
guard platform.isDarwin else {
continue
}
#elseif os(Linux)
guard platform.isLinux else {
continue
}
guard platform.isLinux else {
continue
}
#endif

#if arch(x86_64)
downloadURL = try platform.x86_64URL
downloadURL = try platform.x86_64URL
#elseif arch(arm64)
downloadURL = try platform.arm64URL
downloadURL = try platform.arm64URL
#endif
}
}

guard let downloadURL else {
throw SwiftlyError(
message:
"The newest release of swiftly is incompatible with your current OS and/or processor architecture."
)
}
guard let downloadURL else {
throw SwiftlyError(
message:
"The newest release of swiftly is incompatible with your current OS and/or processor architecture."
)
}

version = try swiftlyRelease.swiftlyVersion

let version = try swiftlyRelease.swiftlyVersion
await ctx.print("A new version of swiftly is available: \(version!)")
}

await ctx.print("A new version is available: \(version)")
guard let version, let downloadURL else { fatalError() }

let tmpFile = fs.mktemp()
try await fs.create(file: tmpFile, contents: nil)
Expand Down
2 changes: 1 addition & 1 deletion Tests/SwiftlyTests/SelfUpdateTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import Testing
func runSelfUpdateTest(latestVersion: SwiftlyVersion) async throws {
try await SwiftlyTests.withTestHome {
try await SwiftlyTests.withMockedSwiftlyVersion(latestSwiftlyVersion: latestVersion) {
let updatedVersion = try await SelfUpdate.execute(SwiftlyTests.ctx, verbose: true)
let updatedVersion = try await SelfUpdate.execute(SwiftlyTests.ctx, verbose: true, version: nil)
#expect(latestVersion == updatedVersion)
}
}
Expand Down