@@ -7,6 +7,17 @@ var swiftGPGKeysRefreshed = false
77/// This implementation can be reused for any supported Linux platform.
88/// TODO: replace dummy implementations
99public struct Linux: Platform {
10+ let linuxPlatforms = [
11+ PlatformDefinition . ubuntu2404,
12+ PlatformDefinition . ubuntu2204,
13+ PlatformDefinition . ubuntu2004,
14+ PlatformDefinition . ubuntu1804,
15+ PlatformDefinition . fedora39,
16+ PlatformDefinition . rhel9,
17+ PlatformDefinition . amazonlinux2,
18+ PlatformDefinition . debian12,
19+ ]
20+
1021 public init ( ) { }
1122
1223 public var appDataDirectory : URL {
@@ -125,6 +136,26 @@ public struct Linux: Platform {
125136 " tzdata " ,
126137 " zlib1g-dev " ,
127138 ]
139+ case " ubuntu2404 " :
140+ [
141+ " binutils " ,
142+ " git " ,
143+ " unzip " ,
144+ " gnupg2 " ,
145+ " libc6-dev " ,
146+ " libcurl4-openssl-dev " ,
147+ " libedit2 " ,
148+ " libgcc-13-dev " ,
149+ " libpython3-dev " ,
150+ " libsqlite3-0 " ,
151+ " libstdc++-13-dev " ,
152+ " libxml2-dev " ,
153+ " libncurses-dev " ,
154+ " libz3-dev " ,
155+ " pkg-config " ,
156+ " tzdata " ,
157+ " zlib1g-dev " ,
158+ ]
128159 case " amazonlinux2 " :
129160 [
130161 " binutils " ,
@@ -158,6 +189,39 @@ public struct Linux: Platform {
158189 " unzip " ,
159190 " zip " ,
160191 ]
192+ case " fedora39 " :
193+ [
194+ " binutils " ,
195+ " gcc " ,
196+ " git " ,
197+ " unzip " ,
198+ " libcurl-devel " ,
199+ " libedit-devel " ,
200+ " libicu-devel " ,
201+ " sqlite-devel " ,
202+ " libuuid-devel " ,
203+ " libxml2-devel " ,
204+ " python3-devel " ,
205+ " libstdc++-devel " ,
206+ " libstdc++-static " ,
207+ ]
208+ case " debian12 " :
209+ [
210+ " binutils-gold " ,
211+ " libicu-dev " ,
212+ " libcurl4-openssl-dev " ,
213+ " libedit-dev " ,
214+ " libsqlite3-dev " ,
215+ " libncurses-dev " ,
216+ " libpython3-dev " ,
217+ " libxml2-dev " ,
218+ " pkg-config " ,
219+ " uuid-dev " ,
220+ " tzdata " ,
221+ " git " ,
222+ " gcc " ,
223+ " libstdc++-12-dev " ,
224+ ]
161225 default :
162226 [ ]
163227 }
@@ -169,10 +233,16 @@ public struct Linux: Platform {
169233 " apt-get "
170234 case " ubuntu2204 " :
171235 " apt-get "
236+ case " ubuntu2404 " :
237+ " apt-get "
172238 case " amazonlinux2 " :
173239 " yum "
174240 case " ubi9 " :
175241 " yum "
242+ case " fedora39 " :
243+ " yum "
244+ case " debian12 " :
245+ " apt-get "
176246 default :
177247 nil
178248 }
@@ -196,7 +266,7 @@ public struct Linux: Platform {
196266 // Import the latest swift keys, but only once per session, which will help with the performance in tests
197267 if !swiftGPGKeysRefreshed {
198268 let tmpFile = self . getTempFilePath ( )
199- FileManager . default. createFile ( atPath: tmpFile. path, contents: nil , attributes: [ . posixPermissions: 0o600 ] )
269+ let _ = FileManager . default. createFile ( atPath: tmpFile. path, contents: nil , attributes: [ . posixPermissions: 0o600 ] )
200270 defer {
201271 try ? FileManager . default. removeItem ( at: tmpFile)
202272 }
@@ -407,7 +477,7 @@ public struct Linux: Platform {
407477 public func verifySignature( httpClient: SwiftlyHTTPClient , archiveDownloadURL: URL , archive: URL ) async throws {
408478 SwiftlyCore . print ( " Downloading toolchain signature... " )
409479 let sigFile = self . getTempFilePath ( )
410- FileManager . default. createFile ( atPath: sigFile. path, contents: nil )
480+ let _ = FileManager . default. createFile ( atPath: sigFile. path, contents: nil )
411481 defer {
412482 try ? FileManager . default. removeItem ( at: sigFile)
413483 }
@@ -425,59 +495,43 @@ public struct Linux: Platform {
425495 }
426496 }
427497
428- private func manualSelectPlatform( _ platformPretty: String ? ) -> PlatformDefinition {
498+ private func manualSelectPlatform( _ platformPretty: String ? ) async -> PlatformDefinition {
429499 if let platformPretty = platformPretty {
430500 print ( " \( platformPretty) is not an officially supported platform, but the toolchains for another platform may still work on it. " )
431501 } else {
432502 print ( " This platform could not be detected, but a toolchain for one of the supported platforms may work on it. " )
433503 }
434504
505+ let selections = self . linuxPlatforms. enumerated ( ) . map { " \( $0 + 1 ) ) \( $1. namePretty) " } . joined ( separator: " \n " )
506+
435507 print ( """
436508 Please select the platform to use for toolchain downloads:
437509
438510 0) Cancel
439- 1) Ubuntu 22.04
440- 2) Ubuntu 20.04
441- 3) Ubuntu 18.04
442- 4) RHEL 9
443- 5) Amazon Linux 2
511+ \( selections)
444512 """ )
445513
446- let choice = SwiftlyCore . readLine ( prompt: " > " ) ?? " 0 "
514+ let choice = SwiftlyCore . readLine ( prompt: " Pick one of the available selections [0- \( self . linuxPlatforms . count ) ] " ) ?? " 0 "
447515
448- switch choice {
449- case " 1 " :
450- return PlatformDefinition . ubuntu2204
451- case " 2 " :
452- return PlatformDefinition . ubuntu2004
453- case " 3 " :
454- return PlatformDefinition . ubuntu1804
455- case " 4 " :
456- return PlatformDefinition . rhel9
457- case " 5 " :
458- return PlatformDefinition . amazonlinux2
459- default :
516+ guard let choiceNum = Int ( choice) else {
517+ fatalError ( " Installation canceled " )
518+ }
519+
520+ guard choiceNum > 0 && choiceNum <= self . linuxPlatforms. count else {
460521 fatalError ( " Installation canceled " )
461522 }
523+
524+ return self . linuxPlatforms [ choiceNum - 1 ]
462525 }
463526
464527 public func detectPlatform( disableConfirmation: Bool , platform: String ? ) async throws -> PlatformDefinition {
465528 // We've been given a hint to use
466- if let platform = platform {
467- switch platform {
468- case " ubuntu22.04 " :
469- return PlatformDefinition . ubuntu2204
470- case " ubuntu20.04 " :
471- return PlatformDefinition . ubuntu2004
472- case " ubuntu18.04 " :
473- return PlatformDefinition . ubuntu1804
474- case " amazonlinux2 " :
475- return PlatformDefinition . amazonlinux2
476- case " rhel9 " :
477- return PlatformDefinition . rhel9
478- default :
479- fatalError ( " Unrecognized platform \( platform) " )
529+ if let platform {
530+ guard let pd = linuxPlatforms. first ( where: { $0. nameFull == platform } ) else {
531+ fatalError ( " Unrecognized platform \( platform) . Recognized values: \( self . linuxPlatforms. map ( \. nameFull) . joined ( separator: " , " ) ) . " )
480532 }
533+
534+ return pd
481535 }
482536
483537 let osReleaseFiles = [ " /etc/os-release " , " /usr/lib/os-release " ]
@@ -498,98 +552,62 @@ public struct Linux: Platform {
498552 } else {
499553 print ( message)
500554 }
501- return self . manualSelectPlatform ( platformPretty)
502- }
503-
504- let data = FileManager . default. contents ( atPath: releaseFile)
505- guard let data = data else {
506- let message = " Unable to read OS release information from file \( releaseFile) "
507- if disableConfirmation {
508- throw Error ( message: message)
509- } else {
510- print ( message)
511- }
512- return self . manualSelectPlatform ( platformPretty)
555+ return await self . manualSelectPlatform ( platformPretty)
513556 }
514557
515- guard let releaseInfo = String ( data: data, encoding: . utf8) else {
516- let message = " Unable to read OS release information from file \( releaseFile) "
517- if disableConfirmation {
518- throw Error ( message: message)
519- } else {
520- print ( message)
521- }
522- return self . manualSelectPlatform ( platformPretty)
523- }
558+ let releaseInfo = try String ( contentsOfFile: releaseFile, encoding: . utf8)
524559
525560 var id : String ?
526561 var idlike : String ?
527562 var versionID : String ?
528- var ubuntuCodeName : String ?
529563 for info in releaseInfo. split ( separator: " \n " ) . map ( String . init) {
530564 if info. hasPrefix ( " ID= " ) {
531565 id = String ( info. dropFirst ( " ID= " . count) ) . replacingOccurrences ( of: " \" " , with: " " )
532566 } else if info. hasPrefix ( " ID_LIKE= " ) {
533567 idlike = String ( info. dropFirst ( " ID_LIKE= " . count) ) . replacingOccurrences ( of: " \" " , with: " " )
534568 } else if info. hasPrefix ( " VERSION_ID= " ) {
535- versionID = String ( info. dropFirst ( " VERSION_ID= " . count) ) . replacingOccurrences ( of: " \" " , with: " " )
536- } else if info. hasPrefix ( " UBUNTU_CODENAME= " ) {
537- ubuntuCodeName = String ( info. dropFirst ( " UBUNTU_CODENAME= " . count) ) . replacingOccurrences ( of: " \" " , with: " " )
569+ versionID = String ( info. dropFirst ( " VERSION_ID= " . count) ) . replacingOccurrences ( of: " \" " , with: " " ) . replacingOccurrences ( of: " . " , with: " " )
538570 } else if info. hasPrefix ( " PRETTY_NAME= " ) {
539571 platformPretty = String ( info. dropFirst ( " PRETTY_NAME= " . count) ) . replacingOccurrences ( of: " \" " , with: " " )
540572 }
541573 }
542574
543- guard let id = id , let idlike = idlike else {
575+ guard let id, let versionID else {
544576 let message = " Unable to find release information from file \( releaseFile) "
545577 if disableConfirmation {
546578 throw Error ( message: message)
547579 } else {
548580 print ( message)
549581 }
550- return self . manualSelectPlatform ( platformPretty)
582+ return await self . manualSelectPlatform ( platformPretty)
551583 }
552584
553- if ( id + idlike) . contains ( " amzn " ) {
554- guard let versionID = versionID , versionID == " 2 " else {
585+ if ( id + ( idlike ?? " " ) ) . contains ( " amzn " ) {
586+ guard versionID == " 2 " else {
555587 let message = " Unsupported version of Amazon Linux "
556588 if disableConfirmation {
557589 throw Error ( message: message)
558590 } else {
559591 print ( message)
560592 }
561- return self . manualSelectPlatform ( platformPretty)
593+ return await self . manualSelectPlatform ( platformPretty)
562594 }
563595
564- return PlatformDefinition ( name: " amazonlinux2 " , nameFull: " amazonlinux2 " , namePretty: " Amazon Linux 2 " )
565- } else if ( id + idlike) . contains ( " ubuntu " ) {
566- if ubuntuCodeName == " jammy " {
567- return PlatformDefinition ( name: " ubuntu2204 " , nameFull: " ubuntu22.04 " , namePretty: " Ubuntu 22.04 " )
568- } else if ubuntuCodeName == " focal " {
569- return PlatformDefinition ( name: " ubuntu2004 " , nameFull: " ubuntu20.04 " , namePretty: " Ubuntu 20.04 " )
570- } else if ubuntuCodeName == " bionic " {
571- return PlatformDefinition ( name: " ubuntu1804 " , nameFull: " ubuntu18.04 " , namePretty: " Ubuntu 18.04 " )
572- } else {
573- let message = " Unsupported version of Ubuntu Linux "
574- if disableConfirmation {
575- throw Error ( message: message)
576- } else {
577- print ( message)
578- }
579- return self . manualSelectPlatform ( platformPretty)
580- }
581- } else if ( id + idlike) . contains ( " rhel " ) {
582- guard let versionID = versionID, versionID. hasPrefix ( " 9 " ) else {
596+ return PlatformDefinition . amazonlinux2
597+ } else if ( id + ( idlike ?? " " ) ) . contains ( " rhel " ) {
598+ guard versionID. hasPrefix ( " 9 " ) else {
583599 let message = " Unsupported version of RHEL "
584600 if disableConfirmation {
585601 throw Error ( message: message)
586602 } else {
587603 print ( message)
588604 }
589- return self . manualSelectPlatform ( platformPretty)
605+ return await self . manualSelectPlatform ( platformPretty)
590606 }
591607
592- return PlatformDefinition ( name: " ubi9 " , nameFull: " ubi9 " , namePretty: " RHEL 9 " )
608+ return PlatformDefinition . rhel9
609+ } else if let pd = [ PlatformDefinition . ubuntu1804, . ubuntu2004, . ubuntu2204, . ubuntu2404, . debian12, . fedora39] . first ( where: { $0. name == id + versionID } ) {
610+ return pd
593611 }
594612
595613 let message = " Unsupported Linux platform "
@@ -598,7 +616,7 @@ public struct Linux: Platform {
598616 } else {
599617 print ( message)
600618 }
601- return self . manualSelectPlatform ( platformPretty)
619+ return await self . manualSelectPlatform ( platformPretty)
602620 }
603621
604622 public func getShell( ) async throws -> String {
0 commit comments