@@ -28,9 +28,32 @@ import var TSCBasic.localFileSystem
28
28
/// ToolchainRegistry is usually initialized by performing a search of predetermined paths,
29
29
/// e.g. `ToolchainRegistry(searchPaths: ToolchainRegistry.defaultSearchPaths)`.
30
30
public final actor ToolchainRegistry {
31
+ /// The reason why a toolchain got added to the registry.
32
+ ///
33
+ /// Used to determine the default toolchain. For example, a toolchain discoverd by the `SOURCEKIT_TOOLCHAIN_PATH`
34
+ /// environment variable always takes precedence.
35
+ private enum ToolchainRegisterReason : Comparable {
36
+ /// The toolchain was found because of the `SOURCEKIT_TOOLCHAIN_PATH` environment variable (or equivalent if
37
+ /// overridden in `ToolchainRegistry.init`).
38
+ case sourcekitToolchainEnvironmentVariable
39
+
40
+ /// The toolchain was found relative to the location where sourcekit-lsp is installed.
41
+ case relativeToInstallPath
42
+
43
+ /// The toolchain was found in an Xcode installation
44
+ case xcode
45
+
46
+ /// The toolchain was found relative to the `SOURCEKIT_PATH` or `PATH` environment variables.
47
+ case pathEnvironmentVariable
48
+ }
49
+
50
+ /// The toolchains and the reasons why they were added to the registry.s
51
+ private let toolchainsAndReasons : [ ( toolchain: Toolchain , reason: ToolchainRegisterReason ) ]
31
52
32
53
/// The toolchains, in the order they were registered.
33
- public let toolchains : [ Toolchain ]
54
+ public var toolchains : [ Toolchain ] {
55
+ return toolchainsAndReasons. map ( \. toolchain)
56
+ }
34
57
35
58
/// The toolchains indexed by their identifier.
36
59
///
@@ -45,21 +68,31 @@ public final actor ToolchainRegistry {
45
68
/// The currently selected toolchain identifier on Darwin.
46
69
public let darwinToolchainOverride : String ?
47
70
71
+ /// Create a toolchain registry with a pre-defined list of toolchains.
72
+ ///
73
+ /// For testing purposes.
74
+ @_spi ( Testing)
75
+ public init ( toolchains: [ Toolchain ] ) {
76
+ self . init (
77
+ toolchainsAndReasons: toolchains. map { ( $0, . xcode) } ,
78
+ darwinToolchainOverride: nil
79
+ )
80
+ }
81
+
48
82
/// Creates a toolchain registry from a list of toolchains.
49
83
///
50
84
/// - Parameters:
51
- /// - toolchains : The toolchains that should be stored in the registry.
85
+ /// - toolchainsAndReasons : The toolchains that should be stored in the registry and why they should be added .
52
86
/// - darwinToolchainOverride: The contents of the `TOOLCHAINS` environment
53
87
/// variable, which picks the default toolchain.
54
- @_spi ( Testing)
55
- public init (
56
- toolchains toolchainsParam: [ Toolchain ] ,
88
+ private init (
89
+ toolchainsAndReasons toolchainsAndReasonsParam: [ ( toolchain: Toolchain , reason: ToolchainRegisterReason ) ] ,
57
90
darwinToolchainOverride: String ?
58
91
) {
59
- var toolchains : [ Toolchain ] = [ ]
92
+ var toolchainsAndReasons : [ ( toolchain : Toolchain , reason : ToolchainRegisterReason ) ] = [ ]
60
93
var toolchainsByIdentifier : [ String : [ Toolchain ] ] = [ : ]
61
94
var toolchainsByPath : [ AbsolutePath : Toolchain ] = [ : ]
62
- for toolchain in toolchainsParam {
95
+ for ( toolchain, reason ) in toolchainsAndReasonsParam {
63
96
// Non-XcodeDefault toolchain: disallow all duplicates.
64
97
if toolchain. identifier != ToolchainRegistry . darwinDefaultToolchainIdentifier {
65
98
guard toolchainsByIdentifier [ toolchain. identifier] == nil else {
@@ -76,10 +109,10 @@ public final actor ToolchainRegistry {
76
109
}
77
110
78
111
toolchainsByIdentifier [ toolchain. identifier, default: [ ] ] . append ( toolchain)
79
- toolchains . append ( toolchain)
112
+ toolchainsAndReasons . append ( ( toolchain, reason ) )
80
113
}
81
114
82
- self . toolchains = toolchains
115
+ self . toolchainsAndReasons = toolchainsAndReasons
83
116
self . toolchainsByIdentifier = toolchainsByIdentifier
84
117
self . toolchainsByPath = toolchainsByPath
85
118
@@ -115,18 +148,18 @@ public final actor ToolchainRegistry {
115
148
_ fileSystem: FileSystem = localFileSystem
116
149
) {
117
150
// The paths at which we have found toolchains
118
- var toolchainPaths : [ AbsolutePath ] = [ ]
151
+ var toolchainPaths : [ ( path : AbsolutePath , reason : ToolchainRegisterReason ) ] = [ ]
119
152
120
153
// Scan for toolchains in the paths given by `environmentVariables`.
121
154
for envVar in environmentVariables {
122
155
if let pathStr = ProcessEnv . block [ envVar] , let path = try ? AbsolutePath ( validating: pathStr) {
123
- toolchainPaths. append ( path)
156
+ toolchainPaths. append ( ( path, . sourcekitToolchainEnvironmentVariable ) )
124
157
}
125
158
}
126
159
127
160
// Search for toolchains relative to the path at which sourcekit-lsp is installed.
128
161
if let installPath = installPath {
129
- toolchainPaths. append ( installPath)
162
+ toolchainPaths. append ( ( installPath, . relativeToInstallPath ) )
130
163
}
131
164
132
165
// Search for toolchains in the Xcode developer directories and global toolchain install paths
@@ -149,22 +182,25 @@ public final actor ToolchainRegistry {
149
182
for name in direntries {
150
183
let path = xctoolchainSearchPath. appending ( component: name)
151
184
if path. extension == " xctoolchain " {
152
- toolchainPaths. append ( path)
185
+ toolchainPaths. append ( ( path, . xcode ) )
153
186
}
154
187
}
155
188
}
156
189
157
190
// Scan for toolchains by the given PATH-like environment variables.
158
191
for envVar : ProcessEnvironmentKey in [ " SOURCEKIT_PATH " , " PATH " , " Path " ] {
159
192
for path in getEnvSearchPaths ( pathString: ProcessEnv . block [ envVar] , currentWorkingDirectory: nil ) {
160
- toolchainPaths. append ( path)
193
+ toolchainPaths. append ( ( path, . pathEnvironmentVariable ) )
161
194
}
162
195
}
163
196
164
- self . init (
165
- toolchains: toolchainPaths. compactMap { Toolchain ( $0, fileSystem) } ,
166
- darwinToolchainOverride: darwinToolchainOverride
167
- )
197
+ let toolchainsAndReasons = toolchainPaths. compactMap {
198
+ if let toolchain = Toolchain ( $0. path, fileSystem) {
199
+ return ( toolchain, $0. reason)
200
+ }
201
+ return nil
202
+ }
203
+ self . init ( toolchainsAndReasons: toolchainsAndReasons, darwinToolchainOverride: darwinToolchainOverride)
168
204
}
169
205
170
206
/// The default toolchain.
@@ -176,11 +212,17 @@ public final actor ToolchainRegistry {
176
212
/// The default toolchain must be only of the registered toolchains.
177
213
public var `default` : Toolchain ? {
178
214
get {
215
+ // Toolchains discovered from the `SOURCEKIT_TOOLCHAIN_PATH` environment variable or relative to sourcekit-lsp's
216
+ // install path always take precedence over Xcode toolchains.
217
+ if let ( toolchain, reason) = toolchainsAndReasons. first, reason < . xcode {
218
+ return toolchain
219
+ }
220
+ // Try finding the Xcode default toolchain.
179
221
if let tc = toolchainsByIdentifier [ darwinToolchainIdentifier] ? . first {
180
222
return tc
181
- } else {
182
- return toolchains. first
183
223
}
224
+ // If neither of that worked, pick the first toolchain.
225
+ return toolchains. first
184
226
}
185
227
}
186
228
0 commit comments