Skip to content

Fix installations going out of sync - #607

Merged
cmcgee1024 merged 3 commits into
swiftlang:mainfrom
MahdiBM:mmbm-fix-unsync
Oct 19, 2026
Merged

cmcgee1024 merged 3 commits into
swiftlang:mainfrom
MahdiBM:mmbm-fix-unsync

Conversation

@MahdiBM

@MahdiBM MahdiBM commented Oct 2, 2026

Copy link
Copy Markdown
Member

Fixes #439.

The issue manifests like so: https://github.com/swift-dns/swift-idna/actions/runs/36990986233/job/110786900189?pr=53 (similar to the linked issue above).

Claude's report

Swiftly considers a toolchain installed as soon as it is listed in installedToolchains of config.json:

guard !config.installedToolchains.contains(version) else {

If the toolchain's files are gone while config.json still lists it (removed by hand, a different SWIFTLY_TOOLCHAINS_DIR, or a CI cache that restored ~/.swiftly but not the toolchains directory), swiftly install reports it as already installed. swiftly use then fails while listing the toolchain's usr/bin to set up the proxies:

let toolchainBinDir = try await Swiftly.currentPlatform.findToolchainBinDir(ctx, version)
let toolchainBinDirContents = try await fs.ls(atPath: toolchainBinDir)

$ swiftly install 6.3
Fetching the latest stable Swift 6.3 release...
Swift 6.3.3 is already installed
$ swiftly use 6.3
Error: The folder “bin” doesn’t exist.

This patch makes swiftly install install such a toolchain again instead of reporting it as already installed:

$ swiftly install 6.3
Fetching the latest stable Swift 6.3 release...
Toolchain Swift 6.3.3 could not be located in /Users/runner/Library/Developer/Toolchains/swift-6.3.3-RELEASE.xctoolchain/usr/bin.
Installing Swift 6.3.3
...
Swift 6.3.3 is installed successfully!

It also makes the proxy setup of swiftly use and swiftly link report the missing toolchain, the way proxyEnvironment already does, instead of surfacing the Foundation error.

Both cases are covered by new tests.

Comment thread Sources/Swiftly/Install.swift Outdated

try await ctx.output(installInfo)
return (nil, pathChanged)
await ctx.message("Toolchain \(version) could not be located in \(toolchainBinDir).")

@cmcgee1024 cmcgee1024 Oct 15, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

suggestion (non-blocking): This can give a more actionable error message indicating that swiftly uninstall <version> followed by swiftly install <version> could get everything back in order for this toolchain version.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done

#expect(before == after)
}

/// Tests that a toolchain that is installed according to the config, but missing from disk, is installed again.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

praise: It's always good to see another test for edge cases, especially ones that have a direct user impact.

Comment thread Sources/Swiftly/Install.swift Outdated

try await ctx.output(installInfo)
return (nil, pathChanged)
await ctx.message("Toolchain \(version) could not be located in \(toolchainBinDir).")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Does this compile? This function is supposed to return a tuple but I don't see this returning anything?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Hmm there is only 1 func message in the whole repo, it's this one, and it doesn't return anything. You must be thinking about some other function I guess?
Should I change this func message's behavior?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No, execute returns the (String?, Bool). I was thinking that this was at the bottom of the function since I misread the indentation level.

try await Use.execute(ctx, version, globalDefault: false, verbose: verbose, &config)
} else {
false
if config.installedToolchains.contains(version) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Once we have the return value, I think that a guard here is easier to read.
e.g:

guard config.installedToolchains.contains(version) else {
  await ctx.message("Toolchain \(version) could not be located in \(toolchainBinDir)")
  <return (nil, false)>
}

// everything else ...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I mean the suggested code wouldn't really match the logic there 🤔.

@etcwilde etcwilde Oct 15, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

doh, I misread the indentation level.

@MahdiBM

MahdiBM commented Oct 16, 2026

Copy link
Copy Markdown
Member Author

Looks like some auto-formatting changes sneaked into the last commit (presumably due to my VSCode auto-formatting the file, as I've set it to, using swift-format). I've amended those formatting changes.

Comment thread Sources/Swiftly/Install.swift Outdated
guard try await fs.exists(atPath: toolchainBinDir) else {
throw SwiftlyError(
message:
"Toolchain \(version) could not be located in \(toolchainBinDir). You can try `swiftly install \(version.name)` to install it again."

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

issue: this is a bit misleading now because you'd have to uninstall the toolchain to clear it out of config.json first, and then install it again to download and sync up the config.json with the toolchain directory in the fs.

@MahdiBM
MahdiBM requested a review from cmcgee1024 October 17, 2026 14:05

@cmcgee1024 cmcgee1024 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good. Thank you.

@cmcgee1024
cmcgee1024 merged commit 5822305 into swiftlang:main Oct 19, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error: The folder "bin" doesn't exist

3 participants