Ground work for Spring-CLI extension

This commit is contained in:
aboyko
2024-01-04 17:58:55 -05:00
parent 39bad4f173
commit 0b96f042ab
10 changed files with 2573 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
import * as path from "path";
import { CliNewProjectMetadata, CliProjectType } from "../cli/types";
import { CLI } from "../extension";
import { openDialogForFolder } from "../utils";
import vscode, { InputBox, QuickPickItem, QuickPickItemKind } from 'vscode';
const OPEN_IN_NEW_WORKSPACE = "Open";
const OPEN_IN_CURRENT_WORKSPACE = "Add to Workspace";
export async function handleCommand(metadata: CliNewProjectMetadata) {
if (!metadata.catalogType) {
const item = await vscode.window.showQuickPick(CLI.getProjectTypes().map(mapProjectTypetoQuickPick), { canPickMany: false });
if (item) {
metadata.catalogType = item.label;
}
}
await new Promise<void>((resolve, reject) => {
const inputBox: InputBox = vscode.window.createInputBox();
inputBox.title = 'Project Name';
inputBox.placeholder = metadata.name || metadata.catalogType;
inputBox.prompt = 'Enter project name';
inputBox.value = metadata.name;
inputBox.ignoreFocusOut = true;
inputBox.onDidAccept(() => {
metadata.name = inputBox.value;
inputBox.hide();
});
inputBox.onDidHide(() => resolve());
inputBox.show();
});
metadata.rootPackage = 'com.example.demo';
metadata.targetFolder = (await openDialogForFolder({})).fsPath;
if (metadata.name && metadata.catalogType && metadata.targetFolder) {
vscode.window.showInformationMessage(`Folder="${metadata.targetFolder}" Command="spring boot new ${metadata.name} ${metadata.catalogType}"`)
CLI.createProject(metadata);
// Open project either is the same workspace or new workspace
const hasOpenFolder = vscode.workspace.workspaceFolders !== undefined || vscode.workspace.rootPath !== undefined;
const pathToOpen = path.resolve(metadata.targetFolder, metadata.name);
// Don't prompt to open projectLocation if it's already a currently opened folder
if (hasOpenFolder && (vscode.workspace.workspaceFolders.some(folder => folder.uri.fsPath === pathToOpen) || vscode.workspace.rootPath === pathToOpen)) {
return;
}
const choice = await specifyOpenMethod(hasOpenFolder, vscode.Uri.file(pathToOpen))
if (choice === OPEN_IN_NEW_WORKSPACE) {
vscode.commands.executeCommand("vscode.openFolder", vscode.Uri.file(pathToOpen), hasOpenFolder);
} else if (choice === OPEN_IN_CURRENT_WORKSPACE) {
if (!vscode.workspace.workspaceFolders.find((workspaceFolder) => workspaceFolder.uri && pathToOpen.startsWith(workspaceFolder.uri.fsPath))) {
vscode.workspace.updateWorkspaceFolders(vscode.workspace.workspaceFolders.length, null, { uri: vscode.Uri.file(pathToOpen) });
}
}
}
}
function mapProjectTypetoQuickPick(metadata: CliProjectType): QuickPickItem {
return {
label: metadata.id,
kind: QuickPickItemKind.Default,
description: metadata.description,
detail: metadata.tags.toString()
};
}
async function specifyOpenMethod(hasOpenFolder: boolean, projectLocation: vscode.Uri): Promise<string> {
const candidates: string[] = [
OPEN_IN_NEW_WORKSPACE,
hasOpenFolder ? OPEN_IN_CURRENT_WORKSPACE : undefined,
].filter(Boolean);
return await vscode.window.showInformationMessage(`Successfully generated. Location: ${projectLocation.fsPath}`, ...candidates);
}

View File

@@ -0,0 +1,43 @@
import cp from 'child_process';
import { CliNewProjectMetadata, CliProjectType } from "./types";
export class Cli {
getProjectTypes() : CliProjectType[] {
return [
{
id: 'web',
description: 'Hello, World RESTful web service.',
url: 'https://github.com/rd-1-2022/rest-service',
catalogId: 'gs',
tags: ['java-17', 'boot-3.1.x', 'rest', 'web']
},
{
id: 'jpa',
description: 'Learn how to work with JPA data persistence using Spring Data JPA.',
url: 'https://github.com/rd-1-2022/rpt-spring-data-jpa',
catalogId: 'gs',
tags: ['java-17', 'boot-3.1.x', 'jpa', 'h2']
},
{
id: 'scheduling',
description: 'How to schedule tasks',
url: 'https://github.com/rd-1-2022/rpt-spring-scheduling-tasks',
catalogId: 'gs',
tags: ['scheduling']
}
];
}
createProject(metadata: CliNewProjectMetadata) {
this.exec(metadata.targetFolder, `spring boot new ${metadata.name} ${metadata.catalogType}`)
}
private exec(cwd: string, cmd: string) {
cp.execSync(cmd, {
cwd
});
}
}

View File

@@ -0,0 +1,14 @@
export interface CliProjectType {
id: string;
description?: string;
url?: string;
catalogId: string;
tags?: string[]
}
export interface CliNewProjectMetadata {
name?: string;
catalogType?: string;
rootPackage?: string;
targetFolder?: string;
}

View File

@@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
"use strict";
import * as vscode from "vscode";
import { Cli } from "./cli/core";
import { handleCommand } from "./boot-project/project-new";
export const CLI = new Cli();
export async function activate(context: vscode.ExtensionContext): Promise<void> {
vscode.commands.registerCommand('vscode-spring-cli.new-project', () => {
handleCommand({});
});
}
export async function deactivate(): Promise<void> {
}

View File

@@ -0,0 +1,17 @@
import { OpenDialogOptions, Uri, window, workspace } from "vscode";
export async function openDialogForFolder(customOptions: OpenDialogOptions): Promise<Uri> {
const options: OpenDialogOptions = {
canSelectFiles: false,
canSelectFolders: true,
canSelectMany: false,
// default to current workspace folder (pick 1st one in multi-root)
defaultUri: workspace.workspaceFolders && workspace.workspaceFolders.length > 0 ? workspace.workspaceFolders[0].uri : undefined
};
const result: Uri[] = await window.showOpenDialog(Object.assign(options, customOptions));
if (result && result.length) {
return Promise.resolve(result[0]);
} else {
return Promise.resolve(undefined);
}
}