1
1
import Foundation
2
2
import PackagePlugin
3
+ import os
3
4
4
5
@main
5
6
struct InstallCLIPluginCommand : CommandPlugin {
6
7
8
+ enum Error : Swift . Error {
9
+ case CannotDetermineXcodeVersion
10
+ }
11
+
7
12
func performCommand( context: PackagePlugin . PluginContext , arguments: [ String ] ) async throws {
8
13
let dependencies = context. package . dependencies
9
14
try dependencies. forEach { dep in
@@ -27,14 +32,69 @@ extension InstallCLIPluginCommand: XcodeCommandPlugin {
27
32
28
33
/// 👇 This entry point is called when operating on an Xcode project.
29
34
func performCommand( context: XcodePluginContext , arguments: [ String ] ) throws {
30
- print ( " Installing Apollo CLI Plugin to Xcode project \( context. xcodeProject. displayName) " )
31
- let apolloPath = " \( context. pluginWorkDirectory) /../../checkouts/apollo-ios "
32
35
let process = Process ( )
33
- let path = try context. tool ( named: " sh " ) . path
34
- process. executableURL = URL ( fileURLWithPath: path. string)
35
- process. arguments = [ " \( apolloPath) /scripts/download-cli.sh " , context. xcodeProject. directory. string]
36
+ let toolPath = try context. tool ( named: " sh " ) . path
37
+ process. executableURL = URL ( fileURLWithPath: toolPath. string)
38
+
39
+ let downloadScriptPath = try downloadScriptPath ( context: context)
40
+ process. arguments = [ downloadScriptPath, context. xcodeProject. directory. string]
41
+
42
+ try process. run ( )
43
+ process. waitUntilExit ( )
44
+ }
45
+
46
+ /// Used to get the location of the CLI download script.
47
+ ///
48
+ /// - Parameter context: Contextual information based on the plugin's stated intent and requirements.
49
+ /// - Returns: The path to the download script used to fetch the CLI binary.
50
+ private func downloadScriptPath( context: XcodePluginContext ) throws -> String {
51
+ let xcodeVersion = try xcodeVersion ( context: context)
52
+ let relativeScriptPath = " SourcePackages/checkouts/apollo-ios/scripts/download-cli.sh "
53
+ let absoluteScriptPath : String
54
+
55
+ if xcodeVersion. lexicographicallyPrecedes ( " 16.3 " ) {
56
+ absoluteScriptPath = " \( context. pluginWorkDirectory) /../../../ \( relativeScriptPath) "
57
+ } else {
58
+ absoluteScriptPath = " \( context. pluginWorkDirectory) /../../../../ \( relativeScriptPath) "
59
+ }
60
+
61
+ return absoluteScriptPath
62
+ }
63
+
64
+ /// Used to get a string representation of Xcode in the current toolchain.
65
+ ///
66
+ /// - Parameter context: Contextual information based on the plugin's stated intent and requirements.
67
+ /// - Returns: A string representation of the Xcode version.
68
+ private func xcodeVersion( context: XcodePluginContext ) throws -> String {
69
+ let process = Process ( )
70
+ let toolPath = try context. tool ( named: " xcrun " ) . path
71
+ process. executableURL = URL ( fileURLWithPath: toolPath. string)
72
+ process. arguments = [ " xcodebuild " , " -version " ]
73
+
74
+ let outputPipe = Pipe ( )
75
+ process. standardOutput = outputPipe
76
+
36
77
try process. run ( )
37
78
process. waitUntilExit ( )
79
+
80
+ guard
81
+ let outputData = try outputPipe. fileHandleForReading. readToEnd ( ) ,
82
+ let output = String ( data: outputData, encoding: . utf8)
83
+ else {
84
+ throw Error . CannotDetermineXcodeVersion
85
+ }
86
+
87
+ let xcodeVersionString = output. components ( separatedBy: " \n " ) [ 0 ]
88
+ guard !xcodeVersionString. isEmpty else {
89
+ throw Error . CannotDetermineXcodeVersion
90
+ }
91
+
92
+ let versionString = xcodeVersionString
93
+ . components ( separatedBy: CharacterSet . decimalDigits. inverted)
94
+ . compactMap ( { $0. isEmpty ? nil : $0 } )
95
+ . joined ( separator: " . " )
96
+
97
+ return versionString
38
98
}
39
99
40
100
}
0 commit comments