123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- var fs = require('fs');
- var waterfall = require('async/waterfall');
- var exec = require('child_process').exec;
- var ini = require('ini');
- var path = require('path');
- var helper = require('../helper.js');
- var cliCommand = require('../cliCommand.js');
- var jsGitService = require('./js-git-service.js');
- var git = {};
- var TIMEOUT = 5000;
- var MAXBUFFER = 1024 * 64; // 16KB
- git.parseGitConfig = function (folder, cb) {
- fs.readFile(path.join(folder, '.git/config'), 'utf-8', function (err, data) {
- if (err) {
- return cb(err);
- }
- var config = ini.parse(data);
- cb(null, config);
- });
- };
- git.getUrl = function (folder, cb) {
- git.parseGitConfig(folder, function (err, config) {
- if (err) {
- return cb(err);
- }
- var data = {};
- data.type = 'git';
- data.url = helper.get(config, 'remote "origin".url');
- cb(null, data);
- });
- };
- git.getCommitInfo = function (folder, data, cb) {
- jsGitService.getHeadCommit(folder, function (err, commit) {
- if (err) {
- return cb(err);
- }
- data.revision = helper.get(commit, 'hash');
- data.comment = helper.get(commit, 'message');
- cb(null, data);
- });
- };
- git.getStaged = function (folder, data, cb) {
- exec(cliCommand(folder, 'git status -s'), {timeout: TIMEOUT, maxBuffer: MAXBUFFER},
- function (err, stdout, stderr) {
- if (err) {
- return cb(err);
- }
- data.unstaged = (stdout === '') ? false : true;
- return cb(null, data);
- });
- };
- git.getBranch = function (folder, data, cb) {
- fs.readFile(path.join(folder, '.git/HEAD'), 'utf-8', function (err, content) {
- if (err) {
- return cb(err);
- }
- var regex = /ref: refs\/heads\/(.*)/;
- var match = regex.exec(content);
- data.branch = match ? match[1] : 'HEAD';
- return cb(null, data);
- });
- };
- git.getRemote = function (folder, data, cb) {
- git.parseGitConfig(folder, function (err, config) {
- if (err) {
- return cb(err);
- }
- data.remotes = [];
- Object.keys(config).map(function (key) {
- var regex = /remote "(.*)"/;
- var match = regex.exec(key);
- if (match) {
- data.remotes.push(match[1]);
- }
- });
- data.remote = (data.remotes.indexOf('origin') === -1) ? data.remotes[0] : 'origin';
- cb(null, data);
- });
- };
- git.isCurrentBranchOnRemote = function (folder, data, cb) {
- jsGitService.getRefHash(folder, data.branch, data.remote, function (err, hash) {
- if (err) {
- return cb(err);
- }
- data.branch_exists_on_remote = !!hash;
- return cb(null, data);
- });
- };
- git.getPrevNext = function (folder, data, cb) {
- var remote = data.branch_exists_on_remote ? data.remote : null;
- jsGitService.getCommitHistory(folder, 100, data.branch, remote, function (err, commitHistory) {
- if (err) {
- return cb(err);
- }
- var currentCommitIndex = commitHistory.findIndex(({ hash }) => hash === data.revision);
- if (currentCommitIndex === -1) {
- data.ahead = true;
- data.next_rev = null;
- data.prev_rev = null;
- }
- else {
- data.ahead = false;
- data.next_rev = (currentCommitIndex === 0) ? null : commitHistory[currentCommitIndex - 1].hash;
- data.prev_rev = (currentCommitIndex === (commitHistory.length - 1)) ? null : commitHistory[currentCommitIndex + 1].hash;
- }
- cb(null, data);
- });
- };
- git.getUpdateTime = function (folder, data, cb) {
- fs.stat(folder + ".git", function (err, stats) {
- if (err) {
- return cb(err);
- }
- data.update_time = helper.trimNewLine(stats.mtime);
- return cb(null, data);
- });
- };
- git.getTags = function (folder, data, cb) {
- exec(cliCommand(folder, 'git tag'), {timeout: TIMEOUT, maxBuffer: MAXBUFFER},
- function (err, stdout, stderr) {
- if (err) {
- return cb(err);
- }
- if (stdout.length) {
- data.tags = stdout.split('\n');
- data.tags.pop();
- data.tags = data.tags.slice(0, 10);
- }
- return cb(null, data);
- });
- };
- git.parse = function (folder, cb) {
- waterfall([
- git.getUrl.bind(null, folder),
- git.getCommitInfo.bind(null, folder),
- git.getStaged.bind(null, folder),
- git.getBranch.bind(null, folder),
- git.getRemote.bind(null, folder),
- git.isCurrentBranchOnRemote.bind(null, folder),
- git.getPrevNext.bind(null, folder),
- git.getUpdateTime.bind(null, folder),
- git.getTags.bind(null, folder)],
- function (err, data) {
- if (err) {
- return cb(err);
- }
- return cb(null, data);
- });
- };
- git.isUpdated = function (folder, cb) {
- waterfall([
- git.getCommitInfo.bind(null, folder, {}),
- git.getBranch.bind(null, folder),
- git.getRemote.bind(null, folder),
- git.isCurrentBranchOnRemote.bind(null, folder),
- ],
- function (err, data) {
- if (err) {
- return cb(err);
- }
- exec(cliCommand(folder, 'git remote update'), {timeout: 60000, maxBuffer: MAXBUFFER},
- function (err, stdout, stderr) {
- if (err) {
- return cb(err);
- }
- var remote = data.branch_exists_on_remote ? data.remote : null;
- jsGitService.getLastCommit(folder, data.branch, remote, function (err, commit) {
- if (err) {
- return cb(err);
- }
- var res = {
- new_revision: commit.hash,
- current_revision: data.revision,
- is_up_to_date: (commit.hash === data.revision)
- };
- return cb(null, res);
- });
- });
- });
- };
- git.revert = function (args, cb) {
- var ret = {};
- var command = cliCommand(args.folder, "git reset --hard " + args.revision);
- ret.output = '';
- ret.output += command + '\n';
- ret.success = true;
- exec(command, {timeout: TIMEOUT, maxBuffer: MAXBUFFER},
- function (err, stdout, stderr) {
- ret.output += stdout;
- if (err !== null || stderr.substring(0, 6) === 'fatal:')
- ret.success = false;
- return cb(null, ret);
- });
- };
- git.update = function (folder, cb) {
- git.isUpdated(folder, function (err, data) {
- if (err) {
- return cb(err);
- }
- var res = {};
- if (data.is_up_to_date === true) {
- res.success = false;
- res.current_revision = data.new_revision;
- return cb(null, res);
- }
- else {
- git.revert({folder: folder, revision: data.new_revision},
- function (err, dt) {
- if (err) {
- return cb(err);
- }
- res.output = dt.output;
- res.success = dt.success;
- res.current_revision = (dt.success) ? data.new_revision : data.current_revision;
- return cb(null, res);
- });
- }
- });
- };
- git.prev = function (folder, cb) {
- waterfall([
- git.getCommitInfo.bind(null, folder, {}),
- git.getBranch.bind(null, folder),
- git.getRemote.bind(null, folder),
- git.isCurrentBranchOnRemote.bind(null, folder),
- git.getPrevNext.bind(null, folder),
- ], function (err, data) {
- if (err) {
- return cb(err);
- }
- var res = {};
- if (data.prev_rev !== null) {
- git.revert({folder: folder, revision: data.prev_rev}, function (err, meta) {
- if (err) {
- return cb(err);
- }
- res.output = meta.output;
- res.success = meta.success;
- res.current_revision = (res.success) ? data.prev_rev : data.revision;
- return cb(null, res);
- });
- }
- else {
- res.success = false;
- res.current_revision = data.revision;
- return cb(null, res);
- }
- });
- };
- git.next = function (folder, cb) {
- waterfall([
- git.getCommitInfo.bind(null, folder, {}),
- git.getBranch.bind(null, folder),
- git.getRemote.bind(null, folder),
- git.isCurrentBranchOnRemote.bind(null, folder),
- git.getPrevNext.bind(null, folder),
- ], function (err, data) {
- if (err) {
- return cb(err);
- }
- var res = {};
- if (data.next_rev !== null) {
- git.revert({folder: folder, revision: data.next_rev}, function (err, meta) {
- if (err) {
- return cb(err);
- }
- res.output = meta.output;
- res.success = meta.success;
- res.current_revision = (res.success) ? data.next_rev : data.revision;
- return cb(null, res);
- });
- }
- else {
- res.success = false;
- res.current_revision = data.revision;
- return cb(null, res);
- }
- });
- };
- module.exports = git;
|