atom-nuclide
Version:
A unified developer experience for web and mobile development, built as a suite of features on top of Atom to provide hackability and the support of an active community.
243 lines (195 loc) • 9.56 kB
JavaScript
Object.defineProperty(exports, '__esModule', {
value: true
});
/*
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the LICENSE file in
* the root directory of this source tree.
*/
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
exports.expressionForRevisionsBeforeHead = expressionForRevisionsBeforeHead;
exports.expressionForCommonAncestor = expressionForCommonAncestor;
/**
* @param revision The revision expression of a revision of interest.
* @param workingDirectory The working directory of the Hg repository.
* @return An expression for the common ancestor of the revision of interest and
* the current Hg head.
*/
var fetchCommonAncestorOfHeadAndRevision = _asyncToGenerator(function* (revision, workingDirectory) {
var ancestorExpression = expressionForCommonAncestor(revision);
// shell-escape does not wrap '{rev}' in quotes unless it is double-quoted.
var args = ['log', '--template', '{rev}', '--rev', ancestorExpression, '--limit', '1'];
var options = {
cwd: workingDirectory
};
try {
var _ref = yield (0, (_hgUtils2 || _hgUtils()).hgAsyncExecute)(args, options);
var ancestorRevisionNumber = _ref.stdout;
return ancestorRevisionNumber;
} catch (e) {
logger.warn('Failed to get hg common ancestor: ', e.stderr, e.command);
throw new Error('Could not fetch common ancestor of head and revision: ' + revision);
}
});
exports.fetchCommonAncestorOfHeadAndRevision = fetchCommonAncestorOfHeadAndRevision;
var fetchRevisions = _asyncToGenerator(function* (revisionExpression, workingDirectory) {
var revisionLogArgs = ['log', '--template', REVISION_INFO_TEMPLATE, '--rev', revisionExpression, '--limit', '20'];
var bookmarksArgs = ['bookmarks'];
var options = {
cwd: workingDirectory
};
try {
var _ref2 = yield Promise.all([(0, (_hgUtils2 || _hgUtils()).hgAsyncExecute)(revisionLogArgs, options), (0, (_hgUtils2 || _hgUtils()).hgAsyncExecute)(bookmarksArgs, options)]);
var _ref22 = _slicedToArray(_ref2, 2);
var revisionsResult = _ref22[0];
var bookmarksResult = _ref22[1];
var revisionsInfo = parseRevisionInfoOutput(revisionsResult.stdout);
var bookmarksInfo = parseBookmarksOutput(bookmarksResult.stdout);
for (var revisionInfo of revisionsInfo) {
revisionInfo.bookmarks = bookmarksInfo.get(revisionInfo.id) || [];
}
return revisionsInfo;
} catch (e) {
logger.warn('Failed to get revision info for revisions' + (' ' + revisionExpression + ': ' + (e.stderr || e) + ', ' + e.command));
throw new Error('Could not fetch revision info for revisions: ' + revisionExpression);
}
}
/**
* @param revisionFrom The revision expression of the "start" (older) revision.
* @param revisionTo The revision expression of the "end" (newer) revision.
* @param workingDirectory The working directory of the Hg repository.
* @return An array of revision info between revisionFrom and
* revisionTo, plus revisionFrom and revisionTo;
* "Between" means that revisionFrom is an ancestor of, and
* revisionTo is a descendant of.
* For each RevisionInfo, the `bookmarks` field will contain the list
* of bookmark names applied to that revision.
*/
);
var fetchRevisionInfoBetweenRevisions = _asyncToGenerator(function* (revisionFrom, revisionTo, workingDirectory) {
var revisionExpression = revisionFrom + '::' + revisionTo;
return yield fetchRevisions(revisionExpression, workingDirectory);
});
exports.fetchRevisionInfoBetweenRevisions = fetchRevisionInfoBetweenRevisions;
var fetchRevisionInfo = _asyncToGenerator(function* (revisionExpression, workingDirectory) {
var _ref3 = yield fetchRevisions(revisionExpression, workingDirectory);
var _ref32 = _slicedToArray(_ref3, 1);
var revisionInfo = _ref32[0];
return revisionInfo;
}
/**
* Helper function to `fetchRevisionInfoBetweenRevisions`.
*/
);
exports.fetchRevisionInfo = fetchRevisionInfo;
exports.parseRevisionInfoOutput = parseRevisionInfoOutput;
exports.parseBookmarksOutput = parseBookmarksOutput;
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { var callNext = step.bind(null, 'next'); var callThrow = step.bind(null, 'throw'); function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(callNext, callThrow); } } callNext(); }); }; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _hgUtils2;
function _hgUtils() {
return _hgUtils2 = require('./hg-utils');
}
var _assert2;
function _assert() {
return _assert2 = _interopRequireDefault(require('assert'));
}
var _nuclideLogging2;
function _nuclideLogging() {
return _nuclideLogging2 = require('../../nuclide-logging');
}
var logger = (0, (_nuclideLogging2 || _nuclideLogging()).getLogger)();
/**
* This file contains utilities for getting an expression to specify a certain
* revision in Hg (i.e. something that can be passed to the '--rev' option of
* an Hg command).
* Note: "Head" in this set of helper functions refers to the "current working
* directory parent" in Hg terms.
*/
// Section: Expression Formation
var HG_CURRENT_WORKING_DIRECTORY_PARENT = '.';
var INFO_ID_PREFIX = 'id:';
var INFO_HASH_PREFIX = 'hash:';
var INFO_TITLE_PREFIX = 'title:';
var INFO_AUTHOR_PREFIX = 'author:';
var INFO_DATE_PREFIX = 'date:';
// Exported for testing.
var INFO_REV_END_MARK = '<<NUCLIDE_REV_END_MARK>>';
exports.INFO_REV_END_MARK = INFO_REV_END_MARK;
var REVISION_INFO_TEMPLATE = INFO_ID_PREFIX + '{rev}\n' + INFO_TITLE_PREFIX + '{desc|firstline}\n' + INFO_AUTHOR_PREFIX + '{author}\n' + INFO_DATE_PREFIX + '{date|isodate}\n' + INFO_HASH_PREFIX + '{node|short}\n{desc}\n' + INFO_REV_END_MARK + '\n';
/**
* @param revisionExpression An expression that can be passed to hg as an argument
* to the '--rev' option.
* @param numberOfRevsBefore The number of revisions before the current revision
* that you want a revision expression for. Passing 0 here will simply return 'revisionExpression'.
* @return An expression for the 'numberOfRevsBefore'th revision before the given revision.
*/
function expressionForRevisionsBefore(revisionExpression, numberOfRevsBefore) {
if (numberOfRevsBefore === 0) {
return revisionExpression;
} else {
return revisionExpression + '~' + numberOfRevsBefore.toString();
}
}
function expressionForRevisionsBeforeHead(numberOfRevsBefore_) {
var numberOfRevsBefore = numberOfRevsBefore_;
if (numberOfRevsBefore < 0) {
numberOfRevsBefore = 0;
}
return expressionForRevisionsBefore(HG_CURRENT_WORKING_DIRECTORY_PARENT, numberOfRevsBefore);
}
// Section: Revision Sets
function expressionForCommonAncestor(revision) {
var commonAncestorExpression = 'ancestor(' + revision + ', ' + HG_CURRENT_WORKING_DIRECTORY_PARENT + ')';
// shell-escape does not wrap ancestorExpression in quotes without this toString conversion.
return commonAncestorExpression.toString();
}
function parseRevisionInfoOutput(revisionsInfoOutput) {
var revisions = revisionsInfoOutput.split(INFO_REV_END_MARK);
var revisionInfo = [];
for (var chunk of revisions) {
var revisionLines = chunk.trim().split('\n');
if (revisionLines.length < 6) {
continue;
}
revisionInfo.push({
id: parseInt(revisionLines[0].slice(INFO_ID_PREFIX.length), 10),
title: revisionLines[1].slice(INFO_TITLE_PREFIX.length),
author: revisionLines[2].slice(INFO_AUTHOR_PREFIX.length),
date: new Date(revisionLines[3].slice(INFO_DATE_PREFIX.length)),
hash: revisionLines[4].slice(INFO_HASH_PREFIX.length),
description: revisionLines.slice(5).join('\n'),
bookmarks: []
});
}
return revisionInfo;
}
// Capture the local commit id and bookmark name from the `hg bookmarks` output.
var BOOKMARK_MATCH_REGEX = /^ . ([^ ]+)\s+(\d+):([0-9a-f]+)$/;
/**
* Parse the result of `hg bookmarks` into a `Map` from
* revision id to a array of bookmark names applied to revision.
*/
function parseBookmarksOutput(bookmarksOutput) {
var bookmarksLines = bookmarksOutput.split('\n');
var commitsToBookmarks = new Map();
for (var bookmarkLine of bookmarksLines) {
var match = BOOKMARK_MATCH_REGEX.exec(bookmarkLine);
if (match == null) {
continue;
}
var _match = _slicedToArray(match, 3);
var bookmarkString = _match[1];
var commitIdString = _match[2];
var commitId = parseInt(commitIdString, 10);
if (!commitsToBookmarks.has(commitId)) {
commitsToBookmarks.set(commitId, []);
}
var bookmarks = commitsToBookmarks.get(commitId);
(0, (_assert2 || _assert()).default)(bookmarks != null);
bookmarks.push(bookmarkString);
}
return commitsToBookmarks;
}