8
8
import shutil
9
9
import subprocess
10
10
import sys
11
- from typing import Dict , List , Optional
11
+ from typing import Dict , List
12
12
13
13
14
14
# -----------------------------------------------------------------------------
@@ -27,23 +27,45 @@ def escapeCmdArg(arg: str) -> str:
27
27
return arg
28
28
29
29
30
- def check_call (cmd : List [str ], env : Optional [Dict [str , str ]], cwd : Optional [str ] = None , verbose : bool = False ):
30
+ def print_cmd (cmd : List [str ], additional_env : Dict [str , str ]) -> None :
31
+ env_str = " " .join ([f"{ key } ={ escapeCmdArg (str (value ))} " for (key , value ) in additional_env .items ()])
32
+ command_str = " " .join ([escapeCmdArg (str (arg )) for arg in cmd ])
33
+ print (f"{ env_str } { command_str } " )
34
+
35
+
36
+ def env_with_additional_env (additional_env : Dict [str , str ]) -> Dict [str , str ]:
37
+ env = dict (os .environ )
38
+ for (key , value ) in additional_env .items ():
39
+ env [key ] = str (value )
40
+ return env
41
+
42
+
43
+ def check_call (cmd : List [str ], additional_env : Dict [str , str ] = {}, verbose : bool = False ) -> None :
31
44
if verbose :
32
- print (" " .join ([escapeCmdArg (arg ) for arg in cmd ]))
33
- return subprocess .check_call (cmd , cwd = cwd , env = env , stderr = subprocess .STDOUT )
45
+ print_cmd (cmd = cmd , additional_env = additional_env )
46
+
47
+ subprocess .check_call (cmd , env = env_with_additional_env (additional_env ), stderr = subprocess .STDOUT )
48
+
49
+
50
+ def check_output (cmd : List [str ], additional_env : Dict [str , str ] = {}, capture_stderr : bool = True , verbose : bool = False ) -> str :
51
+ if verbose :
52
+ print_cmd (cmd = cmd , additional_env = additional_env )
53
+ if capture_stderr :
54
+ stderr = subprocess .STDOUT
55
+ else :
56
+ stderr = subprocess .DEVNULL
57
+ return subprocess .check_output (cmd , env = env_with_additional_env (additional_env ), stderr = stderr , encoding = 'utf-8' )
34
58
35
59
# -----------------------------------------------------------------------------
36
60
# SwiftPM wrappers
37
61
38
62
39
- def swiftpm_bin_path (swift_exec : str , swiftpm_args : List [str ], env : Optional [ Dict [str , str ] ], verbose : bool = False ) -> str :
63
+ def swiftpm_bin_path (swift_exec : str , swiftpm_args : List [str ], additional_env : Dict [str , str ], verbose : bool = False ) -> str :
40
64
"""
41
65
Return the path of the directory that contains the binaries produced by this package.
42
66
"""
43
67
cmd = [swift_exec , 'build' , '--show-bin-path' ] + swiftpm_args
44
- if verbose :
45
- print (" " .join ([escapeCmdArg (arg ) for arg in cmd ]))
46
- return subprocess .check_output (cmd , env = env , universal_newlines = True ).strip ()
68
+ return check_output (cmd , additional_env = additional_env , capture_stderr = False , verbose = verbose ).strip ()
47
69
48
70
49
71
def get_build_target (swift_exec : str , args : argparse .Namespace ) -> str :
@@ -69,10 +91,13 @@ def get_build_target(swift_exec: str, args: argparse.Namespace) -> str:
69
91
def get_swiftpm_options (swift_exec : str , args : argparse .Namespace ) -> List [str ]:
70
92
swiftpm_args = [
71
93
'--package-path' , args .package_path ,
72
- '--build -path' , args .build_path ,
94
+ '--scratch -path' , args .build_path ,
73
95
'--configuration' , args .configuration ,
74
96
]
75
97
98
+ if args .multiroot_data_file :
99
+ swiftpm_args += ['--multiroot-data-file' , args .multiroot_data_file ]
100
+
76
101
if args .verbose :
77
102
swiftpm_args += ['--verbose' ]
78
103
@@ -129,10 +154,12 @@ def get_swiftpm_environment_variables(swift_exec: str, args: argparse.Namespace)
129
154
'swift test' invocation.
130
155
"""
131
156
132
- env = dict (os .environ )
133
- # Set the toolchain used in tests at runtime
134
- env ['SOURCEKIT_TOOLCHAIN_PATH' ] = args .toolchain
135
- env ['INDEXSTOREDB_TOOLCHAIN_BIN_PATH' ] = args .toolchain
157
+ env = {
158
+ # Set the toolchain used in tests at runtime
159
+ 'SOURCEKIT_TOOLCHAIN_PATH' : args .toolchain ,
160
+ 'INDEXSTOREDB_TOOLCHAIN_BIN_PATH' : args .toolchain ,
161
+ 'SWIFT_EXEC' : f'{ swift_exec } c'
162
+ }
136
163
# Use local dependencies (i.e. checked out next sourcekit-lsp).
137
164
if not args .no_local_deps :
138
165
env ['SWIFTCI_USE_LOCAL_DEPS' ] = "1"
@@ -152,29 +179,27 @@ def get_swiftpm_environment_variables(swift_exec: str, args: argparse.Namespace)
152
179
if args .action == 'test' and not args .skip_long_tests :
153
180
env ['SOURCEKIT_LSP_ENABLE_LONG_TESTS' ] = '1'
154
181
155
- env ['SWIFT_EXEC' ] = '%sc' % (swift_exec )
156
-
157
182
return env
158
183
159
184
160
- def build ( swift_exec : str , args : argparse .Namespace ) -> None :
185
+ def build_single_product ( product : str , swift_exec : str , args : argparse .Namespace ) -> None :
161
186
"""
162
187
Build one product in the package
163
188
"""
164
189
swiftpm_args = get_swiftpm_options (swift_exec , args )
165
- env = get_swiftpm_environment_variables (swift_exec , args )
166
- cmd = [swift_exec , 'build' ] + swiftpm_args
167
- check_call (cmd , env = env , verbose = args .verbose )
190
+ additional_env = get_swiftpm_environment_variables (swift_exec , args )
191
+ cmd = [swift_exec , 'build' , '--product' , product ] + swiftpm_args
192
+ check_call (cmd , additional_env = additional_env , verbose = args .verbose )
168
193
169
194
170
195
def run_tests (swift_exec : str , args : argparse .Namespace ) -> None :
171
196
"""
172
197
Run all tests in the package
173
198
"""
174
199
swiftpm_args = get_swiftpm_options (swift_exec , args )
175
- env = get_swiftpm_environment_variables (swift_exec , args )
200
+ additional_env = get_swiftpm_environment_variables (swift_exec , args )
176
201
177
- bin_path = swiftpm_bin_path (swift_exec , swiftpm_args , env )
202
+ bin_path = swiftpm_bin_path (swift_exec , swiftpm_args , additional_env = additional_env )
178
203
tests = os .path .join (bin_path , 'sk-tests' )
179
204
print ('Cleaning ' + tests )
180
205
shutil .rmtree (tests , ignore_errors = True )
@@ -185,27 +210,21 @@ def run_tests(swift_exec: str, args: argparse.Namespace) -> None:
185
210
'--disable-testable-imports' ,
186
211
'--test-product' , 'SourceKitLSPPackageTests'
187
212
] + swiftpm_args
188
- check_call (cmd , env = env , verbose = args .verbose )
213
+ check_call (cmd , additional_env = additional_env , verbose = args .verbose )
189
214
190
215
191
216
def install_binary (exe : str , source_dir : str , install_dir : str , verbose : bool ) -> None :
192
217
cmd = ['rsync' , '-a' , os .path .join (source_dir , exe ), install_dir ]
193
- check_call (cmd , env = None , verbose = verbose )
218
+ check_call (cmd , verbose = verbose )
194
219
195
220
196
221
def install (swift_exec : str , args : argparse .Namespace ) -> None :
197
- swiftpm_args = get_swiftpm_options (swift_exec , args )
198
- env = get_swiftpm_environment_variables (swift_exec , args )
199
-
200
- bin_path = swiftpm_bin_path (swift_exec , swiftpm_args , env )
201
- swiftpm_args += ['-Xswiftc' , '-no-toolchain-stdlib-rpath' ]
202
- check_call ([
203
- swift_exec , 'build'
204
- ] + swiftpm_args , env = env )
205
-
206
- if not args .install_prefixes :
207
- args .install_prefixes = [args .toolchain ]
222
+ build_single_product ('sourcekit-lsp' , swift_exec , args )
208
223
224
+ swiftpm_args = get_swiftpm_options (swift_exec , args )
225
+ additional_env = get_swiftpm_environment_variables (swift_exec , args )
226
+ bin_path = swiftpm_bin_path (swift_exec , swiftpm_args = swiftpm_args , additional_env = additional_env )
227
+
209
228
for prefix in args .install_prefixes :
210
229
install_binary ('sourcekit-lsp' , bin_path , os .path .join (prefix , 'bin' ), verbose = args .verbose )
211
230
@@ -214,12 +233,12 @@ def handle_invocation(swift_exec: str, args: argparse.Namespace) -> None:
214
233
"""
215
234
Depending on the action in 'args', build the package, installs the package or run tests.
216
235
"""
217
- if not args .no_clean :
218
- print ('Cleaning ' + args .build_path )
219
- shutil .rmtree (args .build_path , ignore_errors = True )
220
-
221
236
if args .action == 'build' :
222
- build (swift_exec , args )
237
+ # Build SourceKitLSPPackageTests to build all source code in sourcekit-lsp.
238
+ # Build _SourceKitLSP and sourcekit-lsp because they are products (dylib, executable) that can be used from the build.
239
+ products = ["SourceKitLSPPackageTests" , "_SourceKitLSP" , "sourcekit-lsp" ]
240
+ for product in products :
241
+ build_single_product (product , swift_exec , args )
223
242
elif args .action == 'test' :
224
243
run_tests (swift_exec , args )
225
244
elif args .action == 'install' :
@@ -247,6 +266,7 @@ def add_common_args(parser: argparse.ArgumentParser) -> None:
247
266
parser .add_argument ('--verbose' , '-v' , action = 'store_true' , help = 'enable verbose output' )
248
267
parser .add_argument ('--cross-compile-host' , help = 'cross-compile for another host instead' )
249
268
parser .add_argument ('--cross-compile-config' , help = 'an SPM JSON destination file containing Swift cross-compilation flags' )
269
+ parser .add_argument ('--multiroot-data-file' , help = 'path to an Xcode workspace to create a unified build of all of Swift\' s SwiftPM projects' )
250
270
251
271
if sys .version_info >= (3 , 7 , 0 ):
252
272
subparsers = parser .add_subparsers (title = 'subcommands' , dest = 'action' , required = True , metavar = 'action' )
@@ -274,6 +294,10 @@ def add_common_args(parser: argparse.ArgumentParser) -> None:
274
294
args .build_path = os .path .abspath (args .build_path )
275
295
args .toolchain = os .path .abspath (args .toolchain )
276
296
297
+ if args .action == 'install' :
298
+ if not args .install_prefixes :
299
+ args .install_prefixes = [args .toolchain ]
300
+
277
301
return args
278
302
279
303
0 commit comments