Skip to content

Commit

Permalink
Refactor commands
Browse files Browse the repository at this point in the history
  • Loading branch information
g-arjones committed May 11, 2024
1 parent e7a0d90 commit 56ba1a8
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 93 deletions.
101 changes: 45 additions & 56 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@ import * as wrappers from "./wrappers";
import * as path from "path";
import { ShimsWriter } from "./shimsWriter";

interface IWorkspaceItem {
description: string,
label: string,
workspace: autoproj.Workspace,
}

interface IFolderItem {
description: string,
label: string,
folder: {
name: string,
uri: Uri
}
}

export class Commands {
private _lastDebuggingSession: { ws: WorkspaceFolder | undefined, config: DebugConfiguration } | undefined;
constructor(private readonly _workspaces: autoproj.Workspaces,
Expand All @@ -25,28 +40,18 @@ export class Commands {
if (this._workspaces.workspaces.size === 0) {
throw new Error("No Autoproj workspace found");
}
const choices: Array<{ label, description, ws }> = [];
function addChoice(workspace: autoproj.Workspace) {
const choice = {
description: basename(dirname(workspace.root)),
label: `$(root-folder) ${workspace.name}`,
ws: workspace,
};
choices.push(choice);
}
if (this._workspaces.workspaces.size === 1) {
return this._workspaces.workspaces.values().next().value;
}
this._workspaces.forEachWorkspace((workspace: autoproj.Workspace) => {
addChoice(workspace);
const choices: IWorkspaceItem[] = [...this._workspaces.workspaces.values()].map((workspace) => {
return {
description: basename(dirname(workspace.root)),
label: `$(root-folder) ${workspace.name}`,
workspace: workspace,
}
});
const options: QuickPickOptions = {
placeHolder: "Select a workspace",
};
const ws = await this._vscode.showQuickPick(choices, options);
if (ws) {
return ws.ws;
}
const ws = await this._vscode.showQuickPick(choices, { placeHolder: "Select a workspace" });
return ws?.workspace;
}

public async updatePackageInfo() {
Expand All @@ -65,44 +70,36 @@ export class Commands {
}
}

public async packagePickerChoices(): Promise<Array<{ label, description, pkg }>> {
const choices: Array<{ label, description, pkg }> = [];
const fsPathsObj = {};
const wsInfos: Array<[autoproj.Workspace, Promise<autoproj.WorkspaceInfo>]> = [];

this._workspaces.forEachWorkspace((ws) => wsInfos.push([ws, ws.info()]));
if (this._vscode.workspaceFolders) {
for (const folder of this._vscode.workspaceFolders) {
fsPathsObj[folder.uri.fsPath] = true;
}
}
for (const [ws, wsInfoP] of wsInfos) {
public async packagePickerChoices(): Promise<IFolderItem[]> {
let choices: IFolderItem[] = [];
let currentFsPaths = this._vscode.workspaceFolders?.map((folder) => folder.uri.fsPath) || [];
for (const ws of this._workspaces.workspaces.values()) {
try {
const wsInfo = await wsInfoP;
const wsInfo = await ws.info();
const buildconfPath = pathjoin(ws.root, "autoproj");
if (!fsPathsObj.hasOwnProperty(buildconfPath)) {
if (!currentFsPaths.includes(buildconfPath)) {
const name = `autoproj`;
choices.push({
description: `${ws.name} (buildconf)`,
label: `$(root-folder) ${name}`,
pkg: { name: `autoproj (${ws.name})`, srcdir: buildconfPath },
folder: { name: `autoproj (${ws.name})`, uri: Uri.file(buildconfPath) },
});
}
for (const pkgSet of wsInfo.packageSets) {
if (!fsPathsObj.hasOwnProperty(pkgSet[1].user_local_dir)) {
for (const pkgSet of wsInfo.packageSets.values()) {
if (!currentFsPaths.includes(pkgSet.user_local_dir)) {
choices.push({
description: `${ws.name} (package set)`,
label: `$(folder-library) ${pkgSet[1].name}`,
pkg: { name: `${pkgSet[1].name} (package set)`, srcdir: pkgSet[1].user_local_dir },
label: `$(folder-library) ${pkgSet.name}`,
folder: { name: `${pkgSet.name} (package set)`, uri: Uri.file(pkgSet.user_local_dir) }
});
}
}
for (const aPkg of wsInfo.packages) {
if (!fsPathsObj.hasOwnProperty(aPkg[1].srcdir)) {
for (const pkg of wsInfo.packages.values()) {
if (!currentFsPaths.includes(pkg.srcdir)) {
choices.push({
description: ws.name,
label: `$(folder) ${aPkg[1].name}`,
pkg: aPkg[1],
label: `$(folder) ${pkg.name}`,
folder: { name: pkg.name, uri: Uri.file(pkg.srcdir) },
});
}
}
Expand All @@ -111,32 +108,24 @@ export class Commands {
}
}
choices.sort((a, b) =>
a.pkg.name < b.pkg.name ? -1 : a.pkg.name > b.pkg.name ? 1 : 0);
a.folder.name < b.folder.name ? -1 : a.folder.name > b.folder.name ? 1 : 0);

return choices;
}

public async addPackageToWorkspace() {
const tokenSource = new CancellationTokenSource();
const options: QuickPickOptions = {
matchOnDescription: true,
placeHolder: "Select a package to add to this workspace",
};
const choices = this.packagePickerChoices();
choices.catch((err) => {
this._vscode.showErrorMessage(err.message);
tokenSource.cancel();
});

const selectedOption = await this._vscode.showQuickPick(choices, options, tokenSource.token);
const choices = await this.packagePickerChoices();
const selectedOption = await this._vscode.showQuickPick(choices, options);

tokenSource.dispose();
if (selectedOption) {
const wsFolders = this._vscode.workspaceFolders;
let folders = wsFolders?.map((folder) => { return { name: folder.name, uri: folder.uri }; }) || [];
folders = folders.concat({
name: selectedOption.pkg.name,
uri: Uri.file(selectedOption.pkg.srcdir),
});
folders = folders.concat(selectedOption.folder);

const buildconfPaths = [...this._workspaces.workspaces.values()]
.map((folder) => path.join(folder.root, "autoproj"));
Expand All @@ -151,7 +140,7 @@ export class Commands {
});

if (!this._vscode.updateWorkspaceFolders(0, wsFolders?.length || null, ...buildconfs, ...pkgSets, ...pkgs)) {
this._vscode.showErrorMessage(`Could not add folder: ${selectedOption.pkg.srcdir}`);
throw (`Could not add folder: ${selectedOption.folder.uri.fsPath}`);
}
}
}
Expand Down Expand Up @@ -382,7 +371,7 @@ export class Commands {

public register() {
this._vscode.registerAndSubscribeCommand("autoproj.addPackageToWorkspace", () => {
this.addPackageToWorkspace();
this.handleError(() => this.addPackageToWorkspace());
});
this._vscode.registerAndSubscribeCommand("autoproj.updatePackageInfo", () => { this.updatePackageInfo(); });
this._vscode.registerAndSubscribeCommand("autoproj.setupRubyExtension", () => {
Expand Down
91 changes: 54 additions & 37 deletions test/commands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ describe("Commands", () => {
});
});
describe("showWorkspacePicker()", () => {
let choices: Array<{ label, description, ws }>;
let choices: { label, description, workspace }[];
function makeChoice(ws: autoproj.Workspace) {
return {
description: basename(dirname(ws.root)),
label: `$(root-folder) ${basename(ws.root)}`,
ws: ws,
workspace: ws,
};
}
beforeEach(() => {
Expand Down Expand Up @@ -105,7 +105,7 @@ describe("Commands", () => {
mockWrapper.setup((x) => x.showQuickPick(choices, It.isAny())).returns(() => Promise.resolve(choices[0]));
const ws = await subject.showWorkspacePicker();
mockWrapper.verify((x) => x.showQuickPick(choices, It.isAny()), Times.once());
assert.strictEqual(ws, choices[0].ws);
assert.strictEqual(ws, choices[0].workspace);
});
});
describe("packagePickerChoices()", () => {
Expand All @@ -126,21 +126,40 @@ describe("Commands", () => {
mockWrapper.setup((x) => x.workspaceFolders).returns(() => undefined);

const choices = await subject.packagePickerChoices();
assert.equal(choices.length, 4);
assert.deepStrictEqual(choices[0].pkg,
{ name: "autoproj (to)", srcdir: "/path/to/autoproj" });
assert.strictEqual(choices[0].label, "$(root-folder) autoproj");
assert.strictEqual(choices[0].description, "to (buildconf)");
assert.strictEqual(choices[1].pkg, packageOne);
assert.strictEqual(choices[1].label, "$(folder) one");
assert.strictEqual(choices[1].description, "to");
assert.deepStrictEqual(choices[2].pkg,
{ name: "set.one (package set)", srcdir: "/path/to/autoproj/remotes/set.one" });
assert.strictEqual(choices[2].label, "$(folder-library) set.one");
assert.strictEqual(choices[2].description, "to (package set)");
assert.strictEqual(choices[3].pkg, packageTwo);
assert.strictEqual(choices[3].label, "$(folder) two");
assert.strictEqual(choices[3].description, "to");
assert.deepStrictEqual(choices, [
{
description: "to (buildconf)",
label: "$(root-folder) autoproj",
folder: {
name: "autoproj (to)",
uri: vscode.Uri.file("/path/to/autoproj")
}
},
{
description: "to",
label: "$(folder) one",
folder: {
name: packageOne.name,
uri: vscode.Uri.file(packageOne.srcdir)
}
},
{
description: "to (package set)",
label: "$(folder-library) set.one",
folder: {
name: "set.one (package set)",
uri: vscode.Uri.file("/path/to/autoproj/remotes/set.one")
}
},
{
description: "to",
label: "$(folder) two",
folder: {
name: packageTwo.name,
uri: vscode.Uri.file(packageTwo.srcdir)
}
},
]);
});
it("returns packages that are not in the current workspace", async () => {
const folder1: vscode.WorkspaceFolder = {
Expand All @@ -161,17 +180,21 @@ describe("Commands", () => {
mockWrapper.setup((x) => x.workspaceFolders).returns(() => [folder1, folder2, folder3]);

const choices = await subject.packagePickerChoices();
assert.equal(choices.length, 1);
assert.strictEqual(choices[0].pkg, packageTwo);
assert.strictEqual(choices[0].label, "$(folder) two");
assert.strictEqual(choices[0].description, "to");
assert.deepStrictEqual(choices, [{
description: "to",
label: "$(folder) two",
folder: {
name: packageTwo.name,
uri: vscode.Uri.file(packageTwo.srcdir)
}
}]);
});
});
describe("addPackageToWorkspace()", () => {
let mockSubject: IMock<commands.Commands>;
let packageOne: autoproj.IPackage;
let packageTwo: autoproj.IPackage;
let choices: Array<{ label, description, pkg }> = [];
let choices: { label, description, folder }[] = [];
const options: vscode.QuickPickOptions = {
matchOnDescription: true,
placeHolder: "Select a package to add to this workspace",
Expand All @@ -182,28 +205,25 @@ describe("Commands", () => {
choices = [{
description: "to",
label: "$(folder) one",
pkg: packageOne,
folder: { name: packageOne.name, uri: vscode.Uri.file(packageOne.srcdir) }
},
{
description: "to",
label: "$(folder) two",
pkg: packageTwo,
folder: { name: packageTwo.name, uri: vscode.Uri.file(packageTwo.srcdir) }
}];
mockSubject = Mock.ofInstance(subject);
subject = mockSubject.target;
});
it("shows an error message if manifest loading fails", async () => {
it("throws if manifest loading fails", async () => {
mockSubject.setup((x) => x.packagePickerChoices()).returns(() => Promise.reject(new Error("test")));
await subject.addPackageToWorkspace();
mockWrapper.verify((x) => x.showErrorMessage("test"), Times.once());
await assert.rejects(subject.addPackageToWorkspace(), /test/);
});
it("shows a quick pick ui", async () => {
const promise = Promise.resolve(choices);
mockSubject.setup((x) => x.packagePickerChoices()).returns(() => promise);
await subject.addPackageToWorkspace();

mockWrapper.verify((x) => x.showErrorMessage(It.isAny()), Times.never());
mockWrapper.verify((x) => x.showQuickPick(promise, options, It.isAny()), Times.once());
mockWrapper.verify((x) => x.showQuickPick(choices, options), Times.once());
});
it("sorts the folder list", async () => {
mockWorkspaces.addPackageSetToWorkspace("/path/to/autoproj/remotes/set.foo", "/path/to");
Expand Down Expand Up @@ -237,22 +257,19 @@ describe("Commands", () => {
mockWrapper.setup((x) => x.workspaceFolders).returns(() => folders);
mockSubject.setup((x) => x.packagePickerChoices()). returns(() => promise);
mockWrapper.setup((x) => x.updateWorkspaceFolders(0, 3, ...sortedFolders)).returns(() => true);
mockWrapper.setup((x) => x.showQuickPick(promise,
options, It.isAny())).returns(() => Promise.resolve(choices[0]));
mockWrapper.setup((x) => x.showQuickPick(choices, options)).returns(() => Promise.resolve(choices[0]));
await subject.addPackageToWorkspace();
mockWrapper.verify((x) => x.updateWorkspaceFolders(0, 3, ...sortedFolders), Times.once());
});
it("shows an error if folder could not be added", async () => {
const promise = Promise.resolve(choices);
mockWrapper.setup((x) => x.workspaceFolders).returns(() => undefined);
mockSubject.setup((x) => x.packagePickerChoices()).returns(() => promise);
mockWrapper.setup((x) => x.showQuickPick(promise,
options, It.isAny())).returns(() => Promise.resolve(choices[1]));
mockWrapper.setup((x) => x.showQuickPick(choices, options)).returns(() => Promise.resolve(choices[1]));
mockWrapper.setup((x) => x.updateWorkspaceFolders(0, null,
{ uri: vscode.Uri.file("/path/to/tools/two") })).returns(() => false);

await subject.addPackageToWorkspace();
mockWrapper.verify((x) => x.showErrorMessage("Could not add folder: /path/to/tools/two"), Times.once());
await assert.rejects(subject.addPackageToWorkspace(), /Could not add folder: \/path\/to\/tools\/two/);
});
});
describe("setupPythonDefaultInterpreter()", () => {
Expand Down

0 comments on commit 56ba1a8

Please sign in to comment.