Closed daveyc123 closed 1 month ago
I can take this one.
I guess on macOS you can check the version of macOS installed, contents of /Library/Developer/Toolchains
and ~/Library/Developer/Toolchains
. There is already a command that allows you to choose Xcode installs Swift: Select Xcode Developer Dir...
.
On Linux this would be some interaction with Swiftly. This could become a much bigger task.
Ideally swiftly could be used for toolchain management on all platforms and the VSCode extension would use it. In a similar manner to how the rust-analyzer extension works with rustup.
There are currently two settings that control toolchain selection:
swift.path
- controls the path to the swift toolchain’s usr/bin
directoryswift.swiftEnvironmentVariables
- can set DEVELOPER_DIR
environment variableThe swift.path
setting is the primary method of setting the toolchain. The user must specify the full path to the usr/bin
directory within the toolchain that they’ve installed. Failing to do so will yield a cryptic error message (see the Existing UI
section below).
The DEVELOPER_DIR
environment only works on MacOS. There’s an existing command for selecting an Xcode developer directory (Swift: Select Xcode Developer Dir...
). This command is only shown in the command palette if the current platform is MacOS and will show the user a Quick Select to choose between different versions of Xcode installed on their machine. However, the swift toolchain path must be set manually.
On startup, the swift extension will check the swift.path setting. If the user has provided the path then it will use that, otherwise it uses one of the following platform specific methods to find the swift binary:
which swift
with a fallback to xcrun -find swift
if the first failstype swift
where swift
It then runs swift --version default
to find out which version of swift is being used. Additionally, on Windows where swiftCore.dll
is used to determine the path to the swift runtime. If either of these steps fails then the extension will fail to activate and show the following error messages:
In this state, none of the extension commands work. This includes the new project creation wizard which displays the following error when used:
The UI will have to vary based on platform much like the toolchain discovery. However, the entry point will be common between all of them: a Swift: Select Toolchain....
command that can be accessed via the command palette:
Another entry point to this workflow will be when the extension is unable to discover a swift toolchain on startup. The extension should successfully activate regardless of whether or not a swift binary is found, but should only allow a subset of functionality when doing so. We also should provide a better error message informing the user how to install swift:
Selecting the Download
option will open the user’s browser to https://swift.org/install/ where they can download and install a swift toolchain. As it stands right now, the swift extension must be reloaded in order for toolchain auto-discovery to happen again. A new warning message will appear asking them to reload the extension in this case:
Selecting the Select Toolchain Folder
option shows the open folder dialog for your platform. Selecting a folder in this way will update the swift.path
setting.
macOS has a built-in way of discovering toolchains by finding Xcode installations. We can perform auto discovery in the following order on extension activation:
PATH
Xcode-select -p
/Library/Developer/Toolchains
and ~/Library/Developer/Toolchains
mdfind "kMDItemCFBundleIdentifier == 'com.apple.dt.Xcode'"
When a user attempts to change the toolchain via the swift extension, we should show them the list of available Xcode installations or let them choose a path on their machine.
The user can also opt to download a toolchain from Swift.org or to manually select a toolchain directory. The latter option will configure swift.path
to the directory that the user selects.
Linux doesn’t really have a built-in way to find swift toolchains other than by looking at PATH. For this platform the plan is to auto-detect Swiftly installations since this is the only other way to install toolchains aside from swift.org/install.
Toolchain discovery would be performed in the following order on extension activation:
PATH
Swiftly has a configuration file ($SWIFTLY_HOME_DIR/config.json
) that can be used to determine available toolchains:
{
"installedToolchains" : [
"5.10.0"
],
"platform" : {
"namePretty" : "Ubuntu 22.04.4 LTS",
"name" : "ubuntu2204",
"architecture" : "aarch64",
"nameFull" : "ubuntu22.04"
},
"inUse" : "5.10.0"
}
Toolchains are stored in separate directories under $SWIFTLY_HOME_DIR/toolchains/
named as the corresponding version number in the config.json
:
❯ ls "$SWIFTLY_HOME_DIR/toolchains"
5.10.0
We will show these options in the toolchain selection dialog. However, selecting the toolchain will only update the swift.path
setting and not invoke swiftly
at all:
The user can also opt to download a toolchain from Swift.org or to manually select a toolchain directory. The latter option will configure swift.path
to the directory that the user selects.
Right now on windows we can only offer the option to download swift from https://www.swift.org/install/ and have them switch toolchains by selecting the directory where swift is installed. Auto-detection will only involve looking for swift in PATH
on extension activation. We will only offer two options for now:
The first option opens the user’s browser to https://swift.org/install/ where they can download an install a swift version.
Opting to select the toolchain directory will open up the file explorer where the user can select a folder that will be populated into the swift.path
setting.
After the user selects the toolchain they would like to use, we have to decide where to save this in the Visual Studio Code configuration. There are three possibilities:
Global
- usually the user settings in VSCode, but could also be remote settings if working in a remote workspaceWorkspace
- the active workspace’s configuration fileWorkspace Folder
- one of the active workspace folders’ configuration fileIf no Workspace is opened, then we can safely default to Global. However, in all other cases we must ask the user which configuration they would like to update. The example UI below shows the case where the user has a workspace open with two workspace folders named swift-executable
and swift-library
:
@adam-fowler I would love to get some feedback on this before I get around to implementing it.
In the way rust-analyzer extensions uses rustup to manage rust toolchains, the swift extension should use swiftly to manage swift toolchains.
So the target is to get swiftly
to be the standard swift install tool across all platforms. In a way I'd prefer that swiftly for macOS was implemented first. Then we wouldn't be wasting time setting up a macOS solution which we'd dump once swiftly became available.
Select Toolchain ...
should do is check for the existence of swiftly and if it is not installed then post a dialog saying to select a toolchain install it. There isn't really any other method to select toolchains on Linux, outside of a file finder, so the command is relatively useless without swiftly. swift.path
. I'd rather we actually used swiftly: swiftly use <version>
. That would mean the version of swift I use in the VSCode terminal is the same as the one being used by VSCode tasks.swiftly list
.Err yeah Windows. Not really got a solution here. You could use the file finder at the moment, but I'd prefer we are sure multiple toolchains on one machine works ok before even considering providing this. Also the recommended way to install on Windows is via a package manager eg Windows Package Manager or Scoop.
Thanks for the feedback! My main issues with prompting users to install swiftly right now are:
sudo curl | bash
an install script from a security standpointI'd love to get swiftly to the point where it can be used as the recommended installation method, but I think a decent compromise in the meantime is to detect installed swiftly toolchains and allow the user to point the swift extension at a specific one. Using swiftly to download/install toolchains requires a separate discussion about what users expect the swift extension to do. E.g. right now swiftly use
globally changes the swift version which would be problematic if the user wants to have multiple different toolchains to use on a per-project basis.
I'd rather read the swiftly configuration file's JSON format and make that API than have to parse the output from swiftly list
. Though if the plan is to modify swiftly itself to support this then we could add a --json
option or similar.
Yes, users are expected to download the toolchain themselves either via swift.org/install or swiftly if they choose to go that route. I can raise a separate follow up issue to discuss having the extension install toolchains via swiftly.
Currently the extension provides a mechanism to discover installed toolchains and automatically sets a toolchain (via the vscode configuration settings).
Users should have the ability to run a command and select from the list of installed toolchains. When a toolchain isn't installed, they should be guided on how to install one.