Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New setting to control creation of Artifact Id folder #197

Merged
merged 5 commits into from
Feb 21, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@
"Open",
"Add to Workspace"
]
},
"spring.initializr.createArtifactIdFolder": {
brunovieira97 marked this conversation as resolved.
Show resolved Hide resolved
"default": true,
"type": "boolean",
"scope": "window",
"description": "Place the newly generated project inside a folder named after Artifact Id."
}
}
}
Expand Down
36 changes: 29 additions & 7 deletions src/handler/GenerateProjectHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ export class GenerateProjectHandler extends BaseHandler {
this.projectType = projectType;
this.metadata = {
pickSteps: [],
defaults: defaults || {}
defaults: defaults || {},
createArtifactIdFolder: vscode.workspace.getConfiguration("spring.initializr").get<boolean>("createArtifactIdFolder")
};
}

Expand All @@ -57,13 +58,20 @@ export class GenerateProjectHandler extends BaseHandler {

// Open project either is the same workspace or new workspace
const hasOpenFolder = vscode.workspace.workspaceFolders !== undefined || vscode.workspace.rootPath !== undefined;
const projectLocation = this.outputUri.fsPath;
const projectLocation = this.metadata.createArtifactIdFolder ? path.join(this.outputUri.fsPath, this.metadata.artifactId) : this.outputUri.fsPath;

// Don't prompt to open projectLocation if it's already a currently opened folder
if (hasOpenFolder && (vscode.workspace.workspaceFolders.some(folder => folder.uri.fsPath === projectLocation) || vscode.workspace.rootPath === projectLocation)) {
return;
}

const choice = await specifyOpenMethod(hasOpenFolder, this.outputUri.fsPath);

if (choice === OPEN_IN_NEW_WORKSPACE) {
vscode.commands.executeCommand("vscode.openFolder", vscode.Uri.file(path.join(projectLocation, this.metadata.artifactId)), hasOpenFolder);
vscode.commands.executeCommand("vscode.openFolder", vscode.Uri.file(projectLocation), hasOpenFolder);
} else if (choice === OPEN_IN_CURRENT_WORKSPACE) {
if (!vscode.workspace.workspaceFolders.find((workspaceFolder) => workspaceFolder.uri && this.outputUri.fsPath.startsWith(workspaceFolder.uri.fsPath))) {
vscode.workspace.updateWorkspaceFolders(vscode.workspace.workspaceFolders.length, null, { uri: vscode.Uri.file(path.join(projectLocation, this.metadata.artifactId)) });
vscode.workspace.updateWorkspaceFolders(vscode.workspace.workspaceFolders.length, null, { uri: vscode.Uri.file(projectLocation) });
}
}
}
Expand All @@ -78,9 +86,13 @@ export class GenerateProjectHandler extends BaseHandler {
`name=${this.metadata.artifactId}`,
`packaging=${this.metadata.packaging}`,
`bootVersion=${this.metadata.bootVersion}`,
`baseDir=${this.metadata.artifactId}`,
`dependencies=${this.metadata.dependencies.id}`,
];

if (this.metadata.createArtifactIdFolder) {
params.push(`baseDir=${ this.metadata.artifactId}`);
}

const targetUrl = new URL(this.metadata.serviceUrl);
targetUrl.pathname = "/starter.zip";
targetUrl.search = `?${params.join("&")}`;
Expand All @@ -93,10 +105,20 @@ async function specifyTargetFolder(metadata: IProjectMetadata): Promise<vscode.U
const OPTION_CHOOSE_ANOTHER_FOLDER: string = "Choose another folder";
const LABEL_CHOOSE_FOLDER: string = "Generate into this folder";
const MESSAGE_EXISTING_FOLDER: string = `A folder [${metadata.artifactId}] already exists in the selected folder. Continue to overwrite or Choose another folder?`;
const MESSAGE_FOLDER_NOT_EMPTY: string = "The selected folder is not empty. Existing files with same names will be overwritten. Continue to overwrite or Choose another folder?"

const MESSAGE: string = metadata.createArtifactIdFolder ? MESSAGE_EXISTING_FOLDER : MESSAGE_FOLDER_NOT_EMPTY;

let outputUri: vscode.Uri = metadata.defaults.targetFolder ? vscode.Uri.file(metadata.defaults.targetFolder) : await openDialogForFolder({ openLabel: LABEL_CHOOSE_FOLDER });
while (outputUri && await fse.pathExists(path.join(outputUri.fsPath, metadata.artifactId))) {
const overrideChoice: string = await vscode.window.showWarningMessage(MESSAGE_EXISTING_FOLDER, OPTION_CONTINUE, OPTION_CHOOSE_ANOTHER_FOLDER);
const projectLocation = metadata.createArtifactIdFolder ? path.join(outputUri.fsPath, metadata.artifactId) : outputUri.fsPath;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here when the user cancels the select folder dialog, outputUri will be undefined, directly accessing outputUri.fsPath would cause an error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that would happen in the previous code as well, right? Not very experienced in TS.

Anyway, do you have a more specific recommendation for this? Or simply checking if the value is not undefined right after line 112 seems fine?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that would happen in the previous code as well,

previous code is safe because it has a outputUri && before, so output.fsPath will not be executed if outputUri is undefined.

Another reason not to use fsPath is, for some virtual workspaces like Codespaces, there no filesystem and uri doesn's starts with scheme file:.

Here you create variable projectLocation only because you want to judge if it's an empty. I suggest to directly use vscode.workspace.fs.readDirectory(uri), which can also cover those virtual workspaces. And you don't need projectLocation then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe my changes now are more aligned with Virtual Workspaces compatibility. Instead of using vscode.Uri.file(), I've created them using .parse(), as the former adds the scheme to path as well, for some weird reason.

When showing the project path in specifyOpenMethod(), it'd be harder to read. Example:

{
    "path": "/file:https:///Users/johndoe/projects/folder",
    "scheme": "file"
}

By using vscode.Uri.parse("/Users/johndoe/projects/folder"), this is the result:

{
    "path": "/Users/johndoe/projects/folder",
    "scheme": "file"
}


// If not using Artifact Id as folder name, we assume any existing files with same names will be overwritten
// So we check if the folder is not empty, to avoid deleting files without user's consent
while (
(!metadata.createArtifactIdFolder && outputUri && ((await fse.readdir(projectLocation)).length > 0))
|| (metadata.createArtifactIdFolder && outputUri && await fse.pathExists(projectLocation))
) {
const overrideChoice: string = await vscode.window.showWarningMessage(MESSAGE, OPTION_CONTINUE, OPTION_CHOOSE_ANOTHER_FOLDER);
if (overrideChoice === OPTION_CHOOSE_ANOTHER_FOLDER) {
outputUri = await openDialogForFolder({ openLabel: LABEL_CHOOSE_FOLDER });
} else {
Expand Down
1 change: 1 addition & 0 deletions src/handler/HandlerInterfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface IProjectMetadata {
dependencies?: IDependenciesItem;
pickSteps: IStep[];
defaults: IDefaultProjectData;
createArtifactIdFolder?: boolean;
}

export interface IDefaultProjectData {
Expand Down