Skip to content

Commit bd788be

Browse files
authored
Add swift.packageArguments setting (#1342)
* Add `swift.packageArguments` setting Adds a new setting to provide arguments to swift commands that can resolve packages. This applies to `swift package resolve`, `swift package update`, `swift build` and `swift test`. This lets users set package resolution specific flags that should be used whenever resolution is performed, such as `--replace-scm-with-registry`. Issue: #1340
1 parent ea293d6 commit bd788be

File tree

6 files changed

+97
-63
lines changed

6 files changed

+97
-63
lines changed

package.json

+9-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,15 @@
271271
"items": {
272272
"type": "string"
273273
},
274-
"markdownDescription": "Additional arguments to pass to `swift` commands such as `swift build`, `swift package`, `swift test`, etc... Keys and values should be provided as individual entries in the list. If you have created a copy of the build task in `tasks.json` then these build arguments will not be propagated to that task."
274+
"markdownDescription": "Additional arguments to pass to `swift build` and `swift test`. Keys and values should be provided as individual entries in the list. If you have created a copy of the build task in `tasks.json` then these build arguments will not be propagated to that task."
275+
},
276+
"swift.packageArguments": {
277+
"type": "array",
278+
"default": [],
279+
"items": {
280+
"type": "string"
281+
},
282+
"markdownDescription": "Additional arguments to pass to swift commands that do package resolution, such as `swift package resolve`, `swift package update`, `swift build` and `swift test`. Keys and values should be provided as individual entries in the list."
275283
},
276284
"swift.additionalTestArguments": {
277285
"type": "array",

src/configuration.ts

+4
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,10 @@ const configuration = {
239239
get buildArguments(): string[] {
240240
return vscode.workspace.getConfiguration("swift").get<string[]>("buildArguments", []);
241241
},
242+
/** swift package arguments */
243+
get packageArguments(): string[] {
244+
return vscode.workspace.getConfiguration("swift").get<string[]>("packageArguments", []);
245+
},
242246
/** thread/address sanitizer */
243247
get sanitizer(): string {
244248
return vscode.workspace.getConfiguration("swift").get<string>("sanitizer", "off");

src/tasks/SwiftTaskProvider.ts

+46-61
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,20 @@ function getBuildRevealOption(): vscode.TaskRevealKind {
103103

104104
const buildAllTaskCache = (() => {
105105
const cache = new Map<string, SwiftTask>();
106-
const key = (name: string, folderContext: FolderContext) => {
107-
return `${name}:${folderContext.folder}:${buildOptions(folderContext.workspaceContext.toolchain).join(",")}`;
106+
const key = (name: string, folderContext: FolderContext, task: SwiftTask) => {
107+
return `${name}:${folderContext.folder}:${buildOptions(folderContext.workspaceContext.toolchain).join(",")}:${task.definition.args.join(",")}`;
108108
};
109+
109110
return {
110-
get(name: string, folderContext: FolderContext): SwiftTask | undefined {
111-
return cache.get(key(name, folderContext));
111+
get(name: string, folderContext: FolderContext, task: SwiftTask): SwiftTask {
112+
const cached = cache.get(key(name, folderContext, task));
113+
if (!cached) {
114+
this.set(name, folderContext, task);
115+
}
116+
return cached ?? task;
112117
},
113118
set(name: string, folderContext: FolderContext, task: SwiftTask) {
114-
cache.set(key(name, folderContext), task);
119+
cache.set(key(name, folderContext, task), task);
115120
},
116121
};
117122
})();
@@ -135,15 +140,6 @@ export function createBuildAllTask(
135140
): SwiftTask {
136141
const args = BuildConfigurationFactory.buildAll(folderContext, false, release).args;
137142
const buildTaskName = buildAllTaskName(folderContext, release);
138-
139-
// Create one Build All task per folder context, since this can be called multiple
140-
// times and we want the same instance each time. Otherwise, VS Code may try and execute
141-
// one instance while our extension code tries to listen to events on an instance created earlier/later.
142-
const existingTask = buildAllTaskCache.get(buildTaskName, folderContext);
143-
if (existingTask) {
144-
return existingTask;
145-
}
146-
147143
const task = createSwiftTask(
148144
args,
149145
buildTaskName,
@@ -158,8 +154,11 @@ export function createBuildAllTask(
158154
},
159155
folderContext.workspaceContext.toolchain
160156
);
161-
buildAllTaskCache.set(buildTaskName, folderContext, task);
162-
return task;
157+
158+
// Ensures there is one Build All task per folder context, since this can be called multiple
159+
// times and we want the same instance each time. Otherwise, VS Code may try and execute
160+
// one instance while our extension code tries to listen to events on an instance created earlier/later.
161+
return buildAllTaskCache.get(buildTaskName, folderContext, task);
163162
}
164163

165164
/**
@@ -224,54 +223,40 @@ function createBuildTasks(product: Product, folderContext: FolderContext): vscod
224223
}
225224

226225
const buildDebugName = `Build Debug ${product.name}${buildTaskNameSuffix}`;
227-
let buildDebug = buildAllTaskCache.get(buildDebugName, folderContext);
228-
if (!buildDebug) {
229-
buildDebug = createSwiftTask(
230-
["build", "--product", product.name, ...buildOptions(toolchain)],
231-
buildDebugName,
232-
{
233-
group: vscode.TaskGroup.Build,
234-
cwd: folderContext.folder,
235-
scope: folderContext.workspaceFolder,
236-
presentationOptions: {
237-
reveal: getBuildRevealOption(),
238-
},
239-
disableTaskQueue: true,
240-
dontTriggerTestDiscovery: true,
226+
const buildDebugTask = createSwiftTask(
227+
["build", "--product", product.name, ...buildOptions(toolchain)],
228+
buildDebugName,
229+
{
230+
group: vscode.TaskGroup.Build,
231+
cwd: folderContext.folder,
232+
scope: folderContext.workspaceFolder,
233+
presentationOptions: {
234+
reveal: getBuildRevealOption(),
241235
},
242-
folderContext.workspaceContext.toolchain
243-
);
244-
buildAllTaskCache.set(buildDebugName, folderContext, buildDebug);
245-
}
236+
disableTaskQueue: true,
237+
dontTriggerTestDiscovery: true,
238+
},
239+
folderContext.workspaceContext.toolchain
240+
);
241+
const buildDebug = buildAllTaskCache.get(buildDebugName, folderContext, buildDebugTask);
246242

247243
const buildReleaseName = `Build Release ${product.name}${buildTaskNameSuffix}`;
248-
let buildRelease = buildAllTaskCache.get(buildReleaseName, folderContext);
249-
if (!buildRelease) {
250-
buildRelease = createSwiftTask(
251-
[
252-
"build",
253-
"-c",
254-
"release",
255-
"--product",
256-
product.name,
257-
...buildOptions(toolchain, false),
258-
],
259-
`Build Release ${product.name}${buildTaskNameSuffix}`,
260-
{
261-
group: vscode.TaskGroup.Build,
262-
cwd: folderContext.folder,
263-
scope: folderContext.workspaceFolder,
264-
presentationOptions: {
265-
reveal: getBuildRevealOption(),
266-
},
267-
disableTaskQueue: true,
268-
dontTriggerTestDiscovery: true,
244+
const buildReleaseTask = createSwiftTask(
245+
["build", "-c", "release", "--product", product.name, ...buildOptions(toolchain, false)],
246+
`Build Release ${product.name}${buildTaskNameSuffix}`,
247+
{
248+
group: vscode.TaskGroup.Build,
249+
cwd: folderContext.folder,
250+
scope: folderContext.workspaceFolder,
251+
presentationOptions: {
252+
reveal: getBuildRevealOption(),
269253
},
270-
folderContext.workspaceContext.toolchain
271-
);
272-
buildAllTaskCache.set(buildReleaseName, folderContext, buildRelease);
273-
}
274-
254+
disableTaskQueue: true,
255+
dontTriggerTestDiscovery: true,
256+
},
257+
folderContext.workspaceContext.toolchain
258+
);
259+
const buildRelease = buildAllTaskCache.get(buildReleaseName, folderContext, buildReleaseTask);
275260
return [buildDebug, buildRelease];
276261
}
277262

@@ -286,7 +271,7 @@ export function createSwiftTask(
286271
cmdEnv: { [key: string]: string } = {}
287272
): SwiftTask {
288273
const swift = toolchain.getToolchainExecutable("swift");
289-
args = toolchain.buildFlags.withSwiftSDKFlags(args);
274+
args = toolchain.buildFlags.withSwiftPackageFlags(toolchain.buildFlags.withSwiftSDKFlags(args));
290275

291276
// Add relative path current working directory
292277
const cwd = config.cwd.fsPath;

src/toolchain/BuildFlags.ts

+14
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@ export class BuildFlags {
6969
}
7070
}
7171

72+
withSwiftPackageFlags(args: string[]): string[] {
73+
switch (args[0]) {
74+
case "package":
75+
if (args[1] === "resolve" || args[1] === "update") {
76+
return [...args, ...configuration.packageArguments];
77+
}
78+
return args;
79+
case "build":
80+
return [...args, ...configuration.packageArguments];
81+
default:
82+
return args;
83+
}
84+
}
85+
7286
/**
7387
* Get SDK flags for SwiftPM
7488
*/

test/integration-tests/WorkspaceContext.test.ts

+14
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ suite("WorkspaceContext Test Suite", () => {
9696

9797
suiteTeardown(async () => {
9898
await swiftConfig.update("buildArguments", undefined);
99+
await swiftConfig.update("packageArguments", undefined);
99100
await swiftConfig.update("path", undefined);
100101
await swiftConfig.update("diagnosticsStyle", undefined);
101102
});
@@ -163,6 +164,19 @@ suite("WorkspaceContext Test Suite", () => {
163164
await swiftConfig.update("buildArguments", []);
164165
});
165166

167+
test("Package Arguments Settings", async () => {
168+
const folder = workspaceContext.folders.find(
169+
f => f.folder.fsPath === packageFolder.fsPath
170+
);
171+
assert(folder);
172+
await swiftConfig.update("diagnosticsStyle", undefined);
173+
await swiftConfig.update("packageArguments", ["--replace-scm-with-registry"]);
174+
const buildAllTask = createBuildAllTask(folder);
175+
const execution = buildAllTask.execution as SwiftExecution;
176+
assertContainsArg(execution, "--replace-scm-with-registry");
177+
await swiftConfig.update("packageArguments", []);
178+
});
179+
166180
test("Swift Path", async () => {
167181
/* Temporarily disabled (need swift path to update immediately for this to work)
168182
const folder = workspaceContext.folders.find(

test/unit-tests/tasks/SwiftTaskProvider.test.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ suite("SwiftTaskProvider Unit Test Suite", () => {
5050
setup(async () => {
5151
buildFlags = mockObject<BuildFlags>({
5252
withSwiftSDKFlags: mockFn(s => s.returns([])),
53+
withSwiftPackageFlags: mockFn(s => s.returns(s.args)),
5354
});
5455
toolchain = mockObject<SwiftToolchain>({
5556
swiftVersion: new Version(6, 0, 0),
@@ -186,14 +187,22 @@ suite("SwiftTaskProvider Unit Test Suite", () => {
186187
buildFlags.withSwiftSDKFlags
187188
.withArgs(match(["build"]))
188189
.returns(["build", "--sdk", "/path/to/sdk"]);
190+
buildFlags.withSwiftPackageFlags
191+
.withArgs(match(["build", "--sdk", "/path/to/sdk"]))
192+
.returns(["build", "--sdk", "/path/to/sdk", "--replace-scm-with-registry"]);
189193
const task = createSwiftTask(
190194
["build"],
191195
"build",
192196
{ cwd: workspaceFolder.uri, scope: vscode.TaskScope.Workspace },
193197
instance(toolchain)
194198
);
195199
const execution = task.execution as SwiftExecution;
196-
assert.deepEqual(execution.args, ["build", "--sdk", "/path/to/sdk"]);
200+
assert.deepEqual(execution.args, [
201+
"build",
202+
"--sdk",
203+
"/path/to/sdk",
204+
"--replace-scm-with-registry",
205+
]);
197206
});
198207

199208
test("include environment", () => {

0 commit comments

Comments
 (0)