UNPKG

9.52 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3var Fs = require("fs-extra");
4var Handlebars = require("handlebars");
5var Minimist = require("minimist");
6var Path = require("path");
7var ReadlineSync = require("readline-sync");
8var Tmp = require("tmp");
9var ascii_1 = require("./ascii");
10var git_1 = require("./git");
11var local_storage_1 = require("./local-storage");
12var paths_1 = require("./paths");
13var submodule_1 = require("./submodule");
14var utils_1 = require("./utils");
15/**
16 Contains some essential utilities that should usually run once to create a project or
17 initialize a project.
18 */
19var exec = utils_1.Utils.exec;
20var tmpDir = Tmp.dirSync({ unsafeCleanup: true });
21var tmpPaths = paths_1.Paths.resolveProject(tmpDir.name);
22function init() {
23 if (require.main !== module) {
24 return;
25 }
26 var argv = Minimist(process.argv.slice(2), {
27 string: ['_', 'message', 'm', 'output', 'o'],
28 boolean: ['override'],
29 });
30 var method = argv._[0];
31 var arg1 = argv._[1];
32 var output = argv.output || argv.o;
33 var override = argv.override;
34 var options = {
35 output: output,
36 override: override,
37 };
38 switch (method) {
39 case 'create':
40 return createProject(arg1, options);
41 case 'ensure':
42 return ensureTortilla(arg1);
43 }
44}
45init();
46// Initialize tortilla project, it will use the skeleton as the template and it will fill
47// it up with the provided details. Usually should only run once
48function createProject(projectName, options) {
49 projectName = projectName || 'tortilla-project';
50 options = utils_1.Utils.extend({
51 output: Path.resolve(projectName),
52 }, options);
53 // In case dir already exists verify the user's decision
54 if (utils_1.Utils.exists(options.output)) {
55 options.override = options.override || ReadlineSync.keyInYN([
56 'Output path already exists.',
57 'Would you like to override it and continue?',
58 ].join('\n'));
59 if (!options.override) {
60 return;
61 }
62 }
63 Fs.emptyDirSync(tmpDir.name);
64 // Unpack skeleton
65 exec.print('tar', [
66 '--strip-components', 1, '-xf', paths_1.Paths.tortilla.skeleton, '-C', tmpDir.name
67 ]);
68 var packageName = utils_1.Utils.kebabCase(projectName);
69 var title = utils_1.Utils.startCase(projectName);
70 // Fill in template files
71 overwriteTemplateFile(tmpPaths.npm.package, {
72 name: packageName,
73 });
74 overwriteTemplateFile(tmpPaths.readme, {
75 title: title,
76 });
77 // Git chores
78 git_1.Git(['init'], { cwd: tmpDir.name });
79 git_1.Git(['add', '.'], { cwd: tmpDir.name });
80 git_1.Git(['commit', '-m', title], { cwd: tmpDir.name });
81 if (options.message) {
82 git_1.Git.print(['commit', '--amend', '-m', options.message], { cwd: tmpDir.name });
83 }
84 else {
85 git_1.Git.print(['commit', '--amend'], { cwd: tmpDir.name });
86 }
87 // Initializing
88 ensureTortilla(tmpPaths);
89 // Copy from temp to output
90 Fs.removeSync(options.output);
91 Fs.copySync(tmpDir.name, options.output);
92 tmpDir.removeCallback();
93}
94// Make sure that tortilla essentials are initialized on an existing project.
95// Used most commonly when cloning or creating a project
96function ensureTortilla(projectDir) {
97 projectDir = projectDir || utils_1.Utils.cwd();
98 var projectPaths = projectDir.resolve ? projectDir : paths_1.Paths.resolveProject(projectDir);
99 var localStorage = local_storage_1.localStorage.create(projectPaths);
100 var cwd = projectPaths.resolve();
101 // If tortilla is already initialized don't do anything
102 var isInitialized = localStorage.getItem('INIT');
103 if (isInitialized) {
104 return;
105 }
106 // Otherwise it might throw an error that dir doesn't exist
107 Fs.ensureDirSync(projectPaths.git.hooks);
108 var hookFiles = Fs.readdirSync(projectPaths.tortilla.hooks);
109 // For each hook file in the hooks directory
110 hookFiles.forEach(function (hookFile) {
111 var handlerPath = Path.resolve(projectPaths.tortilla.hooks, hookFile);
112 var hookName = Path.basename(hookFile, '.js');
113 var hookPath = Path.resolve(projectPaths.git.hooks, hookName);
114 // Place an executor in the project's git hooks
115 var hook = [
116 '',
117 '### TORTILLA ###',
118 'cd .',
119 "node " + handlerPath + " \"$@\"",
120 ].join('\n');
121 // If exists, append logic
122 if (utils_1.Utils.exists(hookPath, 'file')) {
123 var contents = Fs.readFileSync(hookPath).toString();
124 // Don't hook logic if already initialized
125 if (!/\n### TORTILLA ###\n/.test(contents)) {
126 contents += "\n" + hook;
127 Fs.writeFileSync(hookPath, contents);
128 }
129 }
130 else { // Else, create file
131 Fs.writeFileSync(hookPath, "#!/bin/sh" + hook);
132 }
133 // Give read permissions to hooks so git can execute properly
134 Fs.chmodSync(hookPath, '755');
135 });
136 // Create root branch reference for continues integration testing
137 var activeBranchName = git_1.Git(['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: cwd });
138 try {
139 git_1.Git(['rev-parse', activeBranchName + "-root"], { cwd: cwd });
140 }
141 catch (e) {
142 git_1.Git(['branch', activeBranchName + "-root", activeBranchName], { cwd: cwd });
143 }
144 // Ensure submodules are initialized
145 submodule_1.Submodule.list().forEach(function (submodule) {
146 submodule_1.Submodule.update(submodule);
147 // If hash not found
148 if (git_1.Git(['diff', '--name-only']).split('\n').filter(Boolean).includes(submodule)) {
149 submodule_1.Submodule.reset(submodule);
150 }
151 });
152 // Mark tortilla flag as initialized
153 localStorage.setItem('INIT', true);
154 localStorage.setItem('USE_STRICT', true);
155 // The art should be printed only if the operation finished for all submodules
156 if (!submodule_1.Submodule.isOne()) {
157 ascii_1.Ascii.print('ready');
158 }
159}
160// TODO: **Add tests**
161function cloneProject(url, out) {
162 if (!out) {
163 // git@github.com:srtucker22/chatty.git -> chatty
164 out = url.split('/').pop().split('.').shift();
165 }
166 out = Path.resolve(utils_1.Utils.cwd(), out);
167 git_1.Git.print(['clone', url, out]);
168 ensureTortilla(out);
169 // List all branches in origin
170 git_1.Git(['branch', '-a'], { cwd: out })
171 .split('\n')
172 .filter(Boolean)
173 .filter(function (remoteBranch) {
174 return /remotes\/origin\/[^\s]+$/.test(remoteBranch);
175 })
176 .map(function (remoteBranch) {
177 return remoteBranch.trim();
178 })
179 .map(function (remoteBranch) {
180 return remoteBranch.split('remotes/origin/').pop();
181 })
182 .forEach(function (remoteBranch) {
183 var branchName = remoteBranch.split('/').pop();
184 // Create all branches
185 try {
186 git_1.Git(['checkout', '-b', branchName], { cwd: out });
187 }
188 catch (e) {
189 // Branch already exists. I don't care
190 }
191 });
192 // Switch back to the original branch
193 git_1.Git(['checkout', 'master'], { cwd: out });
194}
195// Will reclone the current project. By doing so, we will sync the most recent changes
196function recloneProject(remote) {
197 if (remote === void 0) { remote = 'origin'; }
198 var proceed = ReadlineSync.keyInYN([
199 '⚠ Warning ⚠',
200 'Recloning will sync your project with the most recent changes but will discard',
201 'the current git-state completely. Are you sure you would like to proceed?',
202 ].join('\n'));
203 if (!proceed) {
204 return;
205 }
206 var url = git_1.Git(['remote', 'get-url', remote]);
207 Fs.removeSync(utils_1.Utils.cwd());
208 cloneProject(url, utils_1.Utils.cwd());
209}
210// Will force push our changes to the provided remote, including branches and tags
211function pushChanges(remote) {
212 if (remote === void 0) { remote = 'origin'; }
213 var proceed = ReadlineSync.keyInYN([
214 '⚠ Warning ⚠',
215 'Pushing your changes will override the entire hosted project.',
216 'Are you sure you would like to proceed?',
217 ].join('\n'));
218 if (!proceed) {
219 return;
220 }
221 git_1.Git.print(['push', remote, '--mirror']);
222}
223function disposeTortilla(cwd) {
224 if (cwd === void 0) { cwd = process.cwd(); }
225 cwd = Path.resolve(cwd, process.cwd());
226 var root = git_1.Git(['rev-parse', '--show-toplevel'], { cwd: cwd });
227 var paths = paths_1.Paths.resolveProject(root);
228 Fs.removeSync(paths.storage);
229 // If hooks dir doesn't exist there's nothing to remove
230 if (!Fs.existsSync(paths.git.hooks)) {
231 return;
232 }
233 // Remove tortilla logic from hooks
234 Fs.readdirSync(paths.git.hooks).forEach(function (hookFileName) {
235 var hookFilePath = paths.git.hooks + "/" + hookFileName;
236 var contents = Fs.readFileSync(hookFilePath).toString();
237 contents = contents.replace(/### TORTILLA ###\n[^\n]+\n[^\n]+\n?/, '');
238 Fs.writeFileSync(hookFilePath, contents);
239 });
240}
241function overwriteTemplateFile(path, scope) {
242 var templateContent = Fs.readFileSync(path, 'utf8');
243 var viewContent = Handlebars.compile(templateContent)(scope);
244 Fs.writeFileSync(path, viewContent);
245}
246exports.Essentials = {
247 clone: cloneProject,
248 reclone: recloneProject,
249 create: createProject,
250 ensure: ensureTortilla,
251 push: pushChanges,
252 dispose: disposeTortilla
253};
254//# sourceMappingURL=essentials.js.map
\No newline at end of file