-
-
Notifications
You must be signed in to change notification settings - Fork 197
/
Copy pathcreate-plugin.ts
129 lines (108 loc) · 5.1 KB
/
create-plugin.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import * as path from "path";
import { isInteractive } from "../../common/helpers";
export class CreatePluginCommand implements ICommand {
public allowedParameters: ICommandParameter[] = [];
public userMessage = "What is your GitHub username?\n(will be used to update the Github URLs in the plugin's package.json)";
public nameMessage = "What will be the name of your plugin?\n(use lowercase characters and dashes only)";
public pathAlreadyExistsMessageTemplate = "Path already exists and is not empty %s";
constructor(private $options: IOptions,
private $errors: IErrors,
private $terminalSpinnerService: ITerminalSpinnerService,
private $logger: ILogger,
private $pacoteService: IPacoteService,
private $fs: IFileSystem,
private $childProcess: IChildProcess,
private $prompter: IPrompter,
private $packageManager: INodePackageManager) { }
public async execute(args: string[]): Promise<void> {
const pluginRepoName = args[0];
const pathToProject = this.$options.path;
const selectedTemplate = this.$options.template;
const selectedPath = path.resolve(pathToProject || ".");
const projectDir = path.join(selectedPath, pluginRepoName);
// Must be out of try catch block, because will throw error if folder alredy exists and we don't want to delete it.
this.ensurePackageDir(projectDir);
try {
await this.downloadPackage(selectedTemplate, projectDir);
await this.setupSeed(projectDir, pluginRepoName);
} catch (err) {
// The call to this.ensurePackageDir() above will throw error if folder alredy exists, so it is safe to delete here.
this.$fs.deleteDirectory(projectDir);
throw err;
}
this.$logger.printMarkdown("Solution for `%s` was successfully created.", pluginRepoName);
}
public async canExecute(args: string[]): Promise<boolean> {
if (!args[0]) {
this.$errors.fail("You must specify the plugin repository name.");
}
return true;
}
private async setupSeed(projectDir: string, pluginRepoName: string): Promise<void> {
this.$logger.printMarkdown("Executing initial plugin configuration script...");
const config = this.$options;
const spinner = this.$terminalSpinnerService.createSpinner();
const cwd = path.join(projectDir, "src");
try {
spinner.start();
const npmOptions: any = { silent: true };
await this.$packageManager.install(cwd, cwd, npmOptions);
} finally {
spinner.stop();
}
const gitHubUsername = await this.getGitHubUsername(config.username);
const pluginNameSource = await this.getPluginNameSource(config.pluginName, pluginRepoName);
if (!isInteractive() && (!config.username || !config.pluginName)) {
this.$logger.printMarkdown("Using default values for Github user and/or plugin name since your shell is not interactive.");
}
// run postclone script manually and kill it if it takes more than 10 sec
const pathToPostCloneScript = path.join("scripts", "postclone");
const params = [pathToPostCloneScript, `gitHubUsername=${gitHubUsername}`, `pluginName=${pluginNameSource}`, "initGit=y"];
const outputScript = (await this.$childProcess.spawnFromEvent(process.execPath, params, "close", { cwd, timeout: 10000 }));
if (outputScript && outputScript.stdout) {
this.$logger.printMarkdown(outputScript.stdout);
}
}
private ensurePackageDir(projectDir: string): void {
this.$fs.createDirectory(projectDir);
if (this.$fs.exists(projectDir) && !this.$fs.isEmptyDir(projectDir)) {
this.$errors.fail(this.pathAlreadyExistsMessageTemplate, projectDir);
}
}
private async downloadPackage(selectedTemplate: string, projectDir: string): Promise<void> {
if (selectedTemplate) {
this.$logger.printMarkdown("Make sure your custom template is compatible with the Plugin Seed at https://github.com/NativeScript/nativescript-plugin-seed/");
} else {
this.$logger.printMarkdown("Downloading the latest version of NativeScript Plugin Seed...");
}
const spinner = this.$terminalSpinnerService.createSpinner();
const packageToInstall = selectedTemplate || "https://github.com/NativeScript/nativescript-plugin-seed/archive/master.tar.gz";
try {
spinner.start();
await this.$pacoteService.extractPackage(packageToInstall, projectDir);
} finally {
spinner.stop();
}
}
private async getGitHubUsername(gitHubUsername: string) {
if (!gitHubUsername) {
gitHubUsername = "NativeScriptDeveloper";
if (isInteractive()) {
gitHubUsername = await this.$prompter.getString(this.userMessage, { allowEmpty: false, defaultAction: () => { return gitHubUsername; } });
}
}
return gitHubUsername;
}
private async getPluginNameSource(pluginNameSource: string, pluginRepoName: string) {
if (!pluginNameSource) {
// remove nativescript- prefix for naming plugin files
const prefix = 'nativescript-';
pluginNameSource = pluginRepoName.toLowerCase().startsWith(prefix) ? pluginRepoName.slice(prefix.length, pluginRepoName.length) : pluginRepoName;
if (isInteractive()) {
pluginNameSource = await this.$prompter.getString(this.nameMessage, { allowEmpty: false, defaultAction: () => { return pluginNameSource; } });
}
}
return pluginNameSource;
}
}
$injector.registerCommand(["plugin|create"], CreatePluginCommand);