1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | var Fs = require("fs-extra");
|
4 | var Minimist = require("minimist");
|
5 | var Path = require("path");
|
6 | var git_1 = require("./git");
|
7 | var local_storage_1 = require("./local-storage");
|
8 | var paths_1 = require("./paths");
|
9 | var utils_1 = require("./utils");
|
10 |
|
11 | function getRecentCommit(offset, format, grep) {
|
12 | if (typeof offset === 'string') {
|
13 | if (!grep) {
|
14 | grep = format;
|
15 | }
|
16 | format = offset;
|
17 | offset = 0;
|
18 | }
|
19 | var argv = [];
|
20 | if (format) {
|
21 | argv.push("--format=" + format);
|
22 | }
|
23 | if (grep) {
|
24 | argv.push("--grep=" + grep);
|
25 | }
|
26 | return git_1.Git.recentCommit(offset, argv);
|
27 | }
|
28 |
|
29 | function getRecentStepCommit(offset, format) {
|
30 | return getRecentCommit(offset, format, '^Step [0-9]\\+');
|
31 | }
|
32 |
|
33 | function getRecentSuperStepCommit(offset, format) {
|
34 | return getRecentCommit(offset, format, '^Step [0-9]\\+:');
|
35 | }
|
36 |
|
37 | function getRecentSubStepCommit(offset, format) {
|
38 | return getRecentCommit(offset, format, '^Step [0-9]\\+\\.[0-9]\\+:');
|
39 | }
|
40 |
|
41 | function getStepDescriptor(message) {
|
42 | if (message == null) {
|
43 | throw TypeError('A message must be provided');
|
44 | }
|
45 | var match = message.match(/^Step (\d+(?:\.\d+)?)\: ((?:.|\n)*)$/);
|
46 | return match && {
|
47 | number: match[1],
|
48 | message: match[2],
|
49 | type: match[1].split('.')[1] ? 'sub' : 'super',
|
50 | };
|
51 | }
|
52 |
|
53 | function getSuperStepDescriptor(message) {
|
54 | if (message == null) {
|
55 | throw TypeError('A message must be provided');
|
56 | }
|
57 | var match = message.match(/^Step (\d+)\: ((?:.|\n)*)$/);
|
58 | return match && {
|
59 | number: Number(match[1]),
|
60 | message: match[2],
|
61 | };
|
62 | }
|
63 |
|
64 | function getSubStepDescriptor(message) {
|
65 | if (message == null) {
|
66 | throw TypeError('A message must be provided');
|
67 | }
|
68 | var match = message.match(/^Step ((\d+)\.(\d+))\: ((?:.|\n)*)$/);
|
69 | return match && {
|
70 | number: match[1],
|
71 | superNumber: Number(match[2]),
|
72 | subNumber: Number(match[3]),
|
73 | message: match[4],
|
74 | };
|
75 | }
|
76 |
|
77 | function pushStep(message, options) {
|
78 | var step = getNextStep();
|
79 | commitStep(step, message, options);
|
80 |
|
81 | local_storage_1.localStorage.setItem('REBASE_NEW_STEP', step);
|
82 | }
|
83 |
|
84 | function popStep() {
|
85 | var headHash = git_1.Git(['rev-parse', 'HEAD']);
|
86 | var rootHash = git_1.Git.rootHash();
|
87 | if (headHash === rootHash) {
|
88 | throw Error("Can't remove root");
|
89 | }
|
90 | var removedCommitMessage = git_1.Git.recentCommit(['--format=%s']);
|
91 | var stepDescriptor = getStepDescriptor(removedCommitMessage);
|
92 | git_1.Git.print(['reset', '--hard', 'HEAD~1']);
|
93 |
|
94 | if (stepDescriptor) {
|
95 | local_storage_1.localStorage.setItem('REBASE_NEW_STEP', getCurrentStep());
|
96 |
|
97 | if (ensureStepMap()) {
|
98 | updateStepMap('remove', { step: stepDescriptor.number });
|
99 | }
|
100 |
|
101 |
|
102 | if (stepDescriptor.type === 'super' && !git_1.Git.rebasing()) {
|
103 | var branch = git_1.Git.activeBranchName();
|
104 | git_1.Git(['branch', '-D', branch + "-step" + stepDescriptor.number]);
|
105 | }
|
106 | }
|
107 | else {
|
108 | console.warn('Removed commit was not a step');
|
109 | return;
|
110 | }
|
111 | }
|
112 |
|
113 | function tagStep(message) {
|
114 | var step = getNextSuperStep();
|
115 | var tag = "step" + step;
|
116 | var manualFile = tag + ".tmpl";
|
117 | var manualTemplatePath = Path.resolve(paths_1.Paths.manuals.templates, manualFile);
|
118 | Fs.ensureDirSync(paths_1.Paths.manuals.templates);
|
119 | Fs.ensureDirSync(paths_1.Paths.manuals.views);
|
120 | Fs.writeFileSync(manualTemplatePath, '');
|
121 | git_1.Git(['add', manualTemplatePath]);
|
122 | commitStep(step, message);
|
123 |
|
124 | if (!git_1.Git.rebasing()) {
|
125 | var branch = git_1.Git.activeBranchName();
|
126 |
|
127 | git_1.Git(['branch', branch + "-step" + step]);
|
128 | }
|
129 |
|
130 | local_storage_1.localStorage.setItem('REBASE_NEW_STEP', step);
|
131 | }
|
132 |
|
133 | function getStepBase(step) {
|
134 | if (!step) {
|
135 | var message = getRecentStepCommit('%s');
|
136 | if (!message) {
|
137 | return '--root';
|
138 | }
|
139 | step = getStepDescriptor(message).number;
|
140 | }
|
141 | if (step === 'root') {
|
142 | return '--root';
|
143 | }
|
144 | var hash = git_1.Git.recentCommit([
|
145 | "--grep=^Step " + step + ":",
|
146 | '--format=%h',
|
147 | ]);
|
148 | if (!hash) {
|
149 | throw Error('Step not found');
|
150 | }
|
151 | return hash + "~1";
|
152 | }
|
153 |
|
154 | function editStep(steps, options) {
|
155 | if (options === void 0) { options = {}; }
|
156 | var rootSha1 = git_1.Git.rootHash();
|
157 |
|
158 | steps = [].concat(steps).filter(Boolean).map(function (step) {
|
159 |
|
160 | if (/^\d{1,5}(\.\d+)?$/.test(step) || step === 'root') {
|
161 | return step;
|
162 | }
|
163 | if (step === rootSha1) {
|
164 | return 'root';
|
165 | }
|
166 | var commitMessage = git_1.Git(['log', step, '-1', '--format=%s']);
|
167 | var descriptor = getStepDescriptor(commitMessage);
|
168 | return descriptor && descriptor.number;
|
169 | }).filter(Boolean);
|
170 | if (steps instanceof Array) {
|
171 | steps = steps.slice().sort(function (a, b) {
|
172 | var _a = a.split('.').concat('Infinity'), superA = _a[0], subA = _a[1];
|
173 | var _b = b.split('.').concat('Infinity'), superB = _b[0], subB = _b[1];
|
174 |
|
175 | if (a === 'root') {
|
176 | return -1;
|
177 | }
|
178 | if (b === 'root') {
|
179 | return 1;
|
180 | }
|
181 |
|
182 | return ((superA - superB) ||
|
183 | (subA - subB));
|
184 | });
|
185 | }
|
186 | else {
|
187 | steps = [steps];
|
188 | }
|
189 |
|
190 | var base = getStepBase(steps[0]);
|
191 |
|
192 |
|
193 | if (!steps.length && base === '--root') {
|
194 | steps[0] = 'root';
|
195 | }
|
196 | var argv = [paths_1.Paths.tortilla.editor, 'edit'].concat(steps);
|
197 |
|
198 | if (options.udiff != null) {
|
199 | argv.push('--udiff');
|
200 | }
|
201 |
|
202 | if (options.udiff) {
|
203 | argv.push(options.udiff.toString());
|
204 | }
|
205 |
|
206 |
|
207 | if (process.env.TORTILLA_SUBMODULE_CWD) {
|
208 | local_storage_1.localStorage.setItem('SUBMODULE_CWD', process.env.TORTILLA_SUBMODULE_CWD);
|
209 | }
|
210 | git_1.Git.print(['rebase', '-i', base, '--keep-empty'], {
|
211 | env: {
|
212 | GIT_SEQUENCE_EDITOR: "node " + argv.join(' '),
|
213 | },
|
214 | });
|
215 | }
|
216 |
|
217 | function sortStep(step) {
|
218 |
|
219 | if (!step) {
|
220 | step = getRecentStepCommit('%s');
|
221 | step = getStepDescriptor(step);
|
222 | step = step ? step.number : 'root';
|
223 | }
|
224 | var newStep;
|
225 | var oldStep;
|
226 | var base;
|
227 |
|
228 | if (step === 'root') {
|
229 | newStep = '1';
|
230 | oldStep = 'root';
|
231 | base = '--root';
|
232 | }
|
233 | else {
|
234 | newStep = step.split('.').map(Number)[0];
|
235 | oldStep = newStep - 1 || 'root';
|
236 | newStep = newStep + "." + 1;
|
237 | base = getStepBase(newStep);
|
238 | }
|
239 |
|
240 | local_storage_1.localStorage.setItem('REBASE_NEW_STEP', newStep);
|
241 | local_storage_1.localStorage.setItem('REBASE_OLD_STEP', oldStep);
|
242 | git_1.Git.print(['rebase', '-i', base, '--keep-empty'], {
|
243 | env: {
|
244 | GIT_SEQUENCE_EDITOR: "node " + paths_1.Paths.tortilla.editor + " sort",
|
245 | },
|
246 | });
|
247 | }
|
248 |
|
249 | function rewordStep(step, message) {
|
250 | var base = getStepBase(step);
|
251 | var argv = [paths_1.Paths.tortilla.editor, 'reword'];
|
252 | if (message) {
|
253 | argv.push('-m', "\"" + message + "\"");
|
254 | }
|
255 | git_1.Git.print(['rebase', '-i', base, '--keep-empty'], {
|
256 | env: {
|
257 | GIT_SEQUENCE_EDITOR: "node " + argv.join(' '),
|
258 | },
|
259 | });
|
260 | }
|
261 |
|
262 | function showStep(step) {
|
263 | var args = [];
|
264 | for (var _i = 1; _i < arguments.length; _i++) {
|
265 | args[_i - 1] = arguments[_i];
|
266 | }
|
267 | assertStep(step);
|
268 | step = step.split('.').join('\\.');
|
269 | var hash = git_1.Git(['log', "--grep=^Step " + step, '--format=%H']);
|
270 | if (!hash) {
|
271 | throw Error('Step not found');
|
272 | }
|
273 | git_1.Git.print(['show', hash].concat(args));
|
274 | }
|
275 |
|
276 | function assertStep(step, silent) {
|
277 | if (silent === void 0) { silent = false; }
|
278 | if (typeof step !== 'string' && typeof step !== 'number') {
|
279 | if (silent) {
|
280 | return false;
|
281 | }
|
282 | throw TypeError('Provided argument is not of type string or number');
|
283 | }
|
284 | step = step.toString();
|
285 | if (!/\d+/.test(step) && !/\d+\.\d+/.test(step)) {
|
286 | if (silent) {
|
287 | return false;
|
288 | }
|
289 | throw TypeError('Provided argument is not a step');
|
290 | }
|
291 | return true;
|
292 | }
|
293 |
|
294 | function commitStep(step, message, options) {
|
295 | if (options === void 0) { options = {}; }
|
296 | var argv = ['commit'];
|
297 | if (message) {
|
298 | argv.push('-m', message);
|
299 | }
|
300 | if (options.allowEmpty) {
|
301 | argv.push('--allow-empty');
|
302 | }
|
303 |
|
304 | local_storage_1.localStorage.setItem('HOOK_STEP', step);
|
305 | try {
|
306 |
|
307 | git_1.Git.print(argv);
|
308 | }
|
309 | catch (err) {
|
310 |
|
311 | local_storage_1.localStorage.removeItem('HOOK_STEP');
|
312 | throw err;
|
313 | }
|
314 | }
|
315 |
|
316 | function getCurrentStep() {
|
317 |
|
318 | var recentStepCommit = getRecentStepCommit('%s');
|
319 | if (!recentStepCommit) {
|
320 | return 'root';
|
321 | }
|
322 |
|
323 | var descriptor = getStepDescriptor(recentStepCommit);
|
324 | if (!descriptor) {
|
325 | return 'root';
|
326 | }
|
327 | return descriptor.number;
|
328 | }
|
329 |
|
330 | function getCurrentSuperStep() {
|
331 |
|
332 | var recentStepCommit = getRecentSuperStepCommit('%s');
|
333 | if (!recentStepCommit) {
|
334 | return 'root';
|
335 | }
|
336 |
|
337 | var descriptor = getSuperStepDescriptor(recentStepCommit);
|
338 | if (!descriptor) {
|
339 | return 'root';
|
340 | }
|
341 | return descriptor.number;
|
342 | }
|
343 |
|
344 | function getNextStep(offset) {
|
345 |
|
346 | var stepCommitMessage = getRecentStepCommit(offset, '%s');
|
347 | var followedByStep = !!stepCommitMessage;
|
348 |
|
349 | if (!followedByStep) {
|
350 | return '1.1';
|
351 | }
|
352 |
|
353 | var stepDescriptor = getStepDescriptor(stepCommitMessage);
|
354 | var stepNumbers = stepDescriptor.number.split('.');
|
355 | var superStepNumber = Number(stepNumbers[0]);
|
356 | var subStepNumber = Number(stepNumbers[1]);
|
357 | var isSuperStep = !subStepNumber;
|
358 | if (!offset) {
|
359 |
|
360 | if (isSuperStep) {
|
361 | return superStepNumber + 1 + "." + 1;
|
362 | }
|
363 |
|
364 | return superStepNumber + "." + (subStepNumber + 1);
|
365 | }
|
366 |
|
367 | var nextStepCommitMessage = getRecentStepCommit(offset - 1, '%s');
|
368 | var nextStepDescriptor = getStepDescriptor(nextStepCommitMessage);
|
369 | var nextStepNumbers = nextStepDescriptor.number.split('.');
|
370 | var nextSubStepNumber = Number(nextStepNumbers[1]);
|
371 | var isNextSuperStep = !nextSubStepNumber;
|
372 | if (isNextSuperStep) {
|
373 |
|
374 | if (isSuperStep) {
|
375 | return (superStepNumber + 1).toString();
|
376 | }
|
377 |
|
378 | return superStepNumber.toString();
|
379 | }
|
380 |
|
381 | if (isSuperStep) {
|
382 | return superStepNumber + 1 + "." + 1;
|
383 | }
|
384 |
|
385 | return superStepNumber + "." + (subStepNumber + 1);
|
386 | }
|
387 |
|
388 | function getNextSuperStep(offset) {
|
389 | return getNextStep(offset).split('.')[0];
|
390 | }
|
391 |
|
392 | function initializeStepMap(pending) {
|
393 | var map = git_1.Git([
|
394 | 'log', '--format=%s', '--grep=^Step [0-9]\\+',
|
395 | ])
|
396 | .split('\n')
|
397 | .filter(Boolean)
|
398 | .reduce(function (m, subject) {
|
399 | var num = getStepDescriptor(subject).number;
|
400 | m[num] = num;
|
401 | return m;
|
402 | }, {});
|
403 | local_storage_1.localStorage.setItem('STEP_MAP', JSON.stringify(map));
|
404 | if (pending) {
|
405 | local_storage_1.localStorage.setItem('STEP_MAP_PENDING', true);
|
406 | }
|
407 | else {
|
408 | local_storage_1.localStorage.removeItem('STEP_MAP_PENDING');
|
409 | }
|
410 | }
|
411 |
|
412 | function getStepMap(submoduleCwd, checkPending) {
|
413 | var localStorage;
|
414 |
|
415 | if (submoduleCwd) {
|
416 | localStorage = local_storage_1.localStorage.create(submoduleCwd);
|
417 | }
|
418 | else {
|
419 | localStorage = local_storage_1.localStorage;
|
420 | }
|
421 | if (ensureStepMap(submoduleCwd, checkPending)) {
|
422 | return JSON.parse(localStorage.getItem('STEP_MAP'));
|
423 | }
|
424 | }
|
425 |
|
426 |
|
427 | function ensureStepMap(submoduleCwd, checkPending) {
|
428 |
|
429 | if (checkPending && local_storage_1.localStorage.getItem('STEP_MAP_PENDING')) {
|
430 | return false;
|
431 | }
|
432 | var paths;
|
433 |
|
434 | if (submoduleCwd) {
|
435 | paths = paths_1.Paths.resolveProject(submoduleCwd);
|
436 | }
|
437 | else {
|
438 | paths = paths_1.Paths;
|
439 | }
|
440 | return utils_1.Utils.exists(Path.resolve(paths.storage, 'STEP_MAP'), 'file');
|
441 | }
|
442 | function disposeStepMap() {
|
443 | local_storage_1.localStorage.deleteItem('STEP_MAP');
|
444 | local_storage_1.localStorage.deleteItem('STEP_MAP_PENDING');
|
445 | }
|
446 | function updateStepMap(type, payload) {
|
447 | var map = getStepMap();
|
448 | switch (type) {
|
449 | case 'remove':
|
450 | delete map[payload.step];
|
451 | break;
|
452 | case 'reset':
|
453 | map[payload.oldStep] = payload.newStep;
|
454 | break;
|
455 | }
|
456 | local_storage_1.localStorage.setItem('STEP_MAP', JSON.stringify(map));
|
457 | }
|
458 |
|
459 |
|
460 |
|
461 | (function () {
|
462 | if (require.main !== module) {
|
463 | return;
|
464 | }
|
465 | var argv = Minimist(process.argv.slice(2), {
|
466 | string: ['_', 'message', 'm'],
|
467 | boolean: ['root', 'udiff', 'allow-empty'],
|
468 | });
|
469 | var method = argv._[0];
|
470 | var step = argv._[1];
|
471 | var message = argv.message || argv.m;
|
472 | var root = argv.root;
|
473 | var allowEmpty = argv['allow-empty'];
|
474 | var udiff = argv.udiff;
|
475 | if (!step && root) {
|
476 | step = 'root';
|
477 | }
|
478 | var options = {
|
479 | allowEmpty: allowEmpty,
|
480 | udiff: udiff,
|
481 | };
|
482 | switch (method) {
|
483 | case 'push':
|
484 | return pushStep(message, options);
|
485 | case 'pop':
|
486 | return popStep();
|
487 | case 'tag':
|
488 | return tagStep(message);
|
489 | case 'edit':
|
490 | return editStep(step, options);
|
491 | case 'sort':
|
492 | return sortStep(step);
|
493 | case 'reword':
|
494 | return rewordStep(step, message);
|
495 | }
|
496 | })();
|
497 | exports.Step = {
|
498 | push: pushStep,
|
499 | pop: popStep,
|
500 | tag: tagStep,
|
501 | edit: editStep,
|
502 | sort: sortStep,
|
503 | reword: rewordStep,
|
504 | show: showStep,
|
505 | assert: assertStep,
|
506 | commit: commitStep,
|
507 | current: getCurrentStep,
|
508 | currentSuper: getCurrentSuperStep,
|
509 | next: getNextStep,
|
510 | nextSuper: getNextSuperStep,
|
511 | base: getStepBase,
|
512 | recentCommit: getRecentStepCommit,
|
513 | recentSuperCommit: getRecentSuperStepCommit,
|
514 | recentSubCommit: getRecentSubStepCommit,
|
515 | descriptor: getStepDescriptor,
|
516 | superDescriptor: getSuperStepDescriptor,
|
517 | subDescriptor: getSubStepDescriptor,
|
518 | initializeStepMap: initializeStepMap,
|
519 | getStepMap: getStepMap,
|
520 | ensureStepMap: ensureStepMap,
|
521 | disposeStepMap: disposeStepMap,
|
522 | updateStepMap: updateStepMap,
|
523 | };
|
524 |
|
\ | No newline at end of file |