@@ -267,27 +267,61 @@ extension Platform {
267267 }
268268 }
269269
270- public func systemManagedBinary( _ cmd: String ) throws -> String ? {
271- let userHome = FileManager . default. homeDirectoryForCurrentUser
272- let binLocs = [ cmd] + ProcessInfo. processInfo. environment [ " PATH " ] !. components ( separatedBy: " : " ) . map { $0 + " / " + cmd }
273- var bin : String ?
274- for binLoc in binLocs {
275- if FileManager . default. fileExists ( atPath: binLoc) {
276- bin = binLoc
277- break
278- }
270+ // Find the resting place for the swiftly binary, installing ourselves there if possible.
271+ public func findSwiftlyBin( installSwiftly: Bool ) throws -> String ? {
272+ let swiftlyHomeBin = self . swiftlyBinDir. appendingPathComponent ( " swiftly " , isDirectory: false ) . path
273+
274+ // First, let's find out where we are.
275+ let cmd = CommandLine . arguments [ 0 ]
276+ let cmdAbsolute = if cmd. hasPrefix ( " / " ) {
277+ cmd
278+ } else {
279+ ( [ FileManager . default. currentDirectoryPath] + ( ProcessInfo . processInfo. environment [ " PATH " ] ? . components ( separatedBy: " : " ) ?? [ ] ) ) . map {
280+ $0 + " / " + cmd
281+ } . filter {
282+ FileManager . default. fileExists ( atPath: $0)
283+ } . first
284+ }
285+
286+ // We couldn't find outselves in the usual places, so if we're not going to be installing
287+ // swiftly then we can assume that we are running from the final location.
288+ if cmdAbsolute == nil && !installSwiftly && FileManager . default. fileExists ( atPath: swiftlyHomeBin) {
289+ return swiftlyHomeBin
279290 }
280- guard let bin = bin else {
281- throw Error ( message: " Could not locate source of \( cmd) binary in either the PATH, relative, or absolute path " )
291+
292+ // If we are system managed then we know where swiftly should be, no installation necessary.
293+ let userHome = FileManager . default. homeDirectoryForCurrentUser
294+ if let cmdAbsolute, !cmdAbsolute. hasPrefix ( userHome. path + " / " ) && ( cmdAbsolute. hasPrefix ( " /usr/ " ) || cmdAbsolute. hasPrefix ( " /opt/ " ) || cmdAbsolute. hasPrefix ( " /bin/ " ) ) {
295+ return cmdAbsolute
282296 }
283297
284- // If the binary is in the user's home directory, or is not in system locations ("/usr", "/opt", "/bin")
285- // then it is expected to be outside of a system package location and we manage the binary ourselves .
286- if bin . hasPrefix ( userHome . path + " / " ) || ( !bin . hasPrefix ( " /usr " ) && !bin . hasPrefix ( " /opt " ) && !bin . hasPrefix ( " /bin " ) ) {
298+ // If we're running inside an xctest or we couldn't determine our absolute path then
299+ // we don't install nor do we have a swiftly location for the proxies .
300+ guard let cmdAbsolute , !cmdAbsolute . hasSuffix ( " xctest " ) else {
287301 return nil
288302 }
289303
290- return bin
304+ // We're installed and running in our bin directory, return our location
305+ if cmdAbsolute == swiftlyHomeBin {
306+ return swiftlyHomeBin
307+ }
308+
309+ if installSwiftly {
310+ SwiftlyCore . print ( " Installing swiftly in \( swiftlyHomeBin) ... " )
311+
312+ if FileManager . default. fileExists ( atPath: swiftlyHomeBin) {
313+ try FileManager . default. removeItem ( atPath: swiftlyHomeBin)
314+ }
315+
316+ do {
317+ try FileManager . default. moveItem ( atPath: cmdAbsolute, toPath: swiftlyHomeBin)
318+ } catch {
319+ try FileManager . default. copyItem ( atPath: cmdAbsolute, toPath: swiftlyHomeBin)
320+ SwiftlyCore . print ( " Swiftly has been copied into the installation directory. You can remove ' \( cmd) '. It is no longer needed. " )
321+ }
322+ }
323+
324+ return FileManager . default. fileExists ( atPath: swiftlyHomeBin) ? swiftlyHomeBin : nil
291325 }
292326
293327 public func findToolchainBinDir( _ toolchain: ToolchainVersion ) -> URL {
0 commit comments