Skip to content

Refine the command to create Java project #252

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

Merged
merged 2 commits into from
Apr 20, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion jdtls.ext/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<properties>
<base.name>Java Project Manager</base.name>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<tycho-version>1.0.0</tycho-version>
<tycho-version>1.5.0</tycho-version>
</properties>

<developers>
Expand Down
3,903 changes: 2,487 additions & 1,416 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 1 addition & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -274,14 +274,11 @@
"@types/mocha": "^5.2.5",
"@types/node": "^8.10.36",
"@types/vscode": "1.44.0",
"@types/xml2js": "^0.4.3",
"cross-env": "^5.2.0",
"glob": "^7.1.4",
"gulp": "^4.0.0",
"gulp-copy": "^4.0.1",
"gulp-tslint": "^8.1.3",
"mocha": "^7.1.1",
"shelljs": "^0.8.3",
"ts-loader": "^5.3.1",
"tslint": "^5.11.0",
"typescript": "^3.1.6",
Expand All @@ -290,11 +287,9 @@
"webpack-cli": "^3.3.11"
},
"dependencies": {
"find-java-home": "^0.2.0",
"fs-extra": "^7.0.1",
"lodash": "^4.17.15",
"minimatch": "^3.0.4",
"vscode-extension-telemetry-wrapper": "^0.4.0",
"xml2js": "^0.4.19"
"vscode-extension-telemetry-wrapper": "^0.4.0"
}
}
3 changes: 3 additions & 0 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export namespace Commands {

export const JAVA_MAVEN_PROJECT_ADD_DEPENDENCY = "java.project.maven.addDependency";

export const JAVA_MAVEN_CREATE_PROJECT = "maven.archetype.generate";

export const JAVA_PROJECT_LIST = "java.project.list";

export const JAVA_PROJECT_REFRESH_LIB_SERVER = "java.project.refreshLib";
Expand All @@ -48,4 +50,5 @@ export namespace Commands {

export const JAVA_RESOLVEPATH = "java.resolvePath";

export const VSCODE_OPEN_FOLDER = "vscode.openFolder";
}
7 changes: 7 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

export namespace Context {
export const MAVEN_ENABLED: string = "mavenEnabled";
export const EXTENSION_ACTIVATED: string = "extensionActivated";
}
33 changes: 33 additions & 0 deletions src/contextManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

import { commands, Disposable, ExtensionContext } from "vscode";

class ContextManager implements Disposable {
private _context: ExtensionContext;
private _contextValueMap: Map<string, any>;

public initialize(context: ExtensionContext) {
this._context = context;
this._contextValueMap = new Map<string, any>();
}

public get context(): ExtensionContext {
return this._context;
}

public async setContextValue(key: string, value: any): Promise<void> {
this._contextValueMap.set(key, value);
await commands.executeCommand("setContext", key, value);
}

public getContextValue<T>(key: string): T | undefined {
return <T> this._contextValueMap.get(key);
}

public dispose(): void {
this._contextValueMap.clear();
}
}

export const contextManager: ContextManager = new ContextManager();
102 changes: 48 additions & 54 deletions src/controllers/projectController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
import * as fse from "fs-extra";
import * as _ from "lodash";
import * as path from "path";
import { commands, Disposable, ExtensionContext, Uri, window, workspace } from "vscode";
import { commands, Disposable, ExtensionContext, QuickPickItem, Uri, window, workspace } from "vscode";
import { instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-wrapper";
import * as xml2js from "xml2js";
import { Commands } from "../commands";
import { Context } from "../constants";
import { contextManager } from "../contextManager";
import { Utility } from "../utility";

export class ProjectController implements Disposable {
Expand All @@ -25,10 +26,40 @@ export class ProjectController implements Disposable {
}

public async createJavaProject() {
const javaVersion: number = await this.getJavaVersion();
if (!javaVersion) {
const projectKinds: QuickPickItem[] = [{
label: BuildTool.None,
detail: "A project without any build tools",
}];
if (contextManager.getContextValue(Context.MAVEN_ENABLED)) {
projectKinds.push({
label: BuildTool.Maven,
detail: "Use Maven to manage your project",
});
}
const choice: QuickPickItem | undefined = projectKinds.length === 1 ? projectKinds[0] :
await window.showQuickPick(projectKinds, {
ignoreFocusOut: true,
placeHolder: "Select the project build tool",
},
);

if (!choice) {
return;
}

switch (choice.label) {
Copy link
Member

Choose a reason for hiding this comment

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

choice is possible to be undefined, if you have more than one project kinds.

case BuildTool.Maven:
await commands.executeCommand(Commands.JAVA_MAVEN_CREATE_PROJECT);
break;
case BuildTool.None:
await this.scaffoldSimpleProject();
break;
default:
break;
}
}

private async scaffoldSimpleProject(): Promise<void> {
const workspaceFolder = Utility.getDefaultWorkspaceFolder();
const location: Uri[] = await window.showOpenDialog({
defaultUri: workspaceFolder && workspaceFolder.uri,
Expand All @@ -39,73 +70,36 @@ export class ProjectController implements Disposable {
if (!location || !location.length) {
return;
}

const basePath: string = location[0].fsPath;
const projectName: string = await window.showInputBox({
prompt: "Input a java project name",
validateInput: (name: string): string => {
ignoreFocusOut: true,
validateInput: async (name: string): Promise<string> => {
if (name && !name.match(/^[^*~/\\]+$/)) {
return "Please input a valid project name";
}
if (name && fse.pathExistsSync(path.join(basePath, name))) {
if (name && await fse.pathExists(path.join(basePath, name))) {
return "A project with this name already exists.";
}
return null;
return "";
},
});
if (!projectName) {
return;
}
if (await this.scaffoldJavaProject(basePath, projectName, javaVersion)) {
const openInNewWindow = workspace && !_.isEmpty(workspace.workspaceFolders);
return commands.executeCommand("vscode.openFolder", Uri.file(path.join(basePath, projectName)), openInNewWindow);
}
}

private async scaffoldJavaProject(basePath: string, projectName: string, javaVersion: number): Promise<boolean> {
const projectRoot: string = path.join(basePath, projectName);
const templateRoot: string = path.join(this.context.extensionPath, "templates");
const projectFile: string = path.join(projectRoot, ".project");
const templateRoot: string = path.join(this.context.extensionPath, "templates", "invisible-project");
try {
let jdkSpecificTemplateRoot: string = path.join(templateRoot, `Java${javaVersion}`);
if (!await fse.pathExists(jdkSpecificTemplateRoot)) {
// fall back to 8
jdkSpecificTemplateRoot = path.join(templateRoot, `Java8`);
}
await fse.ensureDir(projectRoot);
await Promise.all([
fse.copy(path.join(templateRoot, "App.java.sample"), path.join(projectRoot, "src", "app", "App.java")),
fse.copy(jdkSpecificTemplateRoot, projectRoot),
fse.copy(path.join(templateRoot, ".project"), path.join(projectRoot, ".project")),
fse.ensureDir(path.join(projectRoot, "bin")),
]);

// replace the project name with user input project name
const xml: string = await fse.readFile(projectFile, "utf8");
const jsonObj: any = await Utility.parseXml(xml);
jsonObj.projectDescription.name = projectName;
const builder: xml2js.Builder = new xml2js.Builder();
const newXml: string = builder.buildObject(jsonObj);
await fse.writeFile(projectFile, newXml);
await fse.copy(templateRoot, projectRoot);
} catch (error) {
window.showErrorMessage(error.message);
return;
}
return true;
const openInNewWindow = workspace && !_.isEmpty(workspace.workspaceFolders);
await commands.executeCommand(Commands.VSCODE_OPEN_FOLDER, Uri.file(path.join(basePath, projectName)), openInNewWindow);
}
}

private async getJavaVersion(): Promise<number> {
let javaVersion: number;
try {
const javaHome: string = await Utility.checkJavaRuntime();
javaVersion = await Utility.checkJavaVersion(javaHome);
} catch (error) {
window.showErrorMessage(error.message, error.label).then((selection) => {
if (error.label && error.label === selection && error.openUrl) {
commands.executeCommand("vscode.open", error.openUrl);
}
});
return;
}
return javaVersion;
}
enum BuildTool {
Maven = "Maven",
None = "No build tools",
}
27 changes: 17 additions & 10 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

import { commands, Extension, ExtensionContext, extensions } from "vscode";
import { Extension, ExtensionContext, extensions } from "vscode";
import { dispose as disposeTelemetryWrapper, initializeFromJsonFile, instrumentOperation } from "vscode-extension-telemetry-wrapper";
import { Context } from "./constants";
import { contextManager } from "./contextManager";
import { LibraryController } from "./controllers/libraryController";
import { ProjectController } from "./controllers/projectController";
import { Settings } from "./settings";
Expand All @@ -13,23 +15,28 @@ export async function activate(context: ExtensionContext): Promise<any> {
return instrumentOperation("activation", activateExtension)(context);
}

function activateExtension(operationId: string, context: ExtensionContext) {
commands.executeCommand("setContext", "extensionActivated", true);

function activateExtension(_operationId: string, context: ExtensionContext) {
Settings.initialize(context);

setMavenEnabledContext();
contextManager.initialize(context);
setMavenExtensionState();

context.subscriptions.push(new ProjectController(context));
context.subscriptions.push(new LibraryController(context));
context.subscriptions.push(new DependencyExplorer(context));
context.subscriptions.push(contextManager);
contextManager.setContextValue(Context.EXTENSION_ACTIVATED, true);
}

// determine if the add dependency shortcut will show or not
function setMavenEnabledContext() {
const mavenExt: Extension<any> | undefined = extensions.getExtension("vscjava.vscode-maven");
if (mavenExt) {
commands.executeCommand("setContext", "mavenEnabled", true);
function setMavenExtensionState() {
setMavenEnabledContext();
extensions.onDidChange(() => {
setMavenEnabledContext();
});

function setMavenEnabledContext() {
const mavenExt: Extension<any> | undefined = extensions.getExtension("vscjava.vscode-maven");
contextManager.setContextValue(Context.MAVEN_ENABLED, !!mavenExt);
}
}

Expand Down
Loading