diff options
author | Samy Pesse <samypesse@gmail.com> | 2016-02-11 17:10:59 +0100 |
---|---|---|
committer | Samy Pesse <samypesse@gmail.com> | 2016-02-11 17:10:59 +0100 |
commit | 7f9aa214a412f3d173ac52042bd7250aacda6143 (patch) | |
tree | 84a6d59d1c5baf185bb3357357bcfbdbf96bc80c | |
parent | 347a536a4e313dece2e12d0ba1ec6654ee729c85 (diff) | |
download | gitbook-7f9aa214a412f3d173ac52042bd7250aacda6143.zip gitbook-7f9aa214a412f3d173ac52042bd7250aacda6143.tar.gz gitbook-7f9aa214a412f3d173ac52042bd7250aacda6143.tar.bz2 |
Cleaner module for managing git refs
-rw-r--r-- | lib/utils/git.js | 142 | ||||
-rw-r--r-- | test/git.js | 31 |
2 files changed, 89 insertions, 84 deletions
diff --git a/lib/utils/git.js b/lib/utils/git.js index 6e37b14..9fca73f 100644 --- a/lib/utils/git.js +++ b/lib/utils/git.js @@ -2,118 +2,110 @@ var _ = require('lodash'); var path = require('path'); var crc = require('crc'); var URI = require('urijs'); -var pathUtil = require('./path'); +var pathUtil = require('./path'); var Promise = require('./promise'); var command = require('./command'); -var fs = require('./fs'); var GIT_PREFIX = 'git+'; -var GIT_TMP = null; - -// Check if an url is a git dependency url -function isGitUrl(giturl) { - return (giturl.indexOf(GIT_PREFIX) === 0); +function Git(tmpDir) { + this.tmpDir = tmpDir; + this.cloned = {}; } -// Parse and extract infos -function parseGitUrl(giturl) { - var ref, uri, fileParts, filepath; - - if (!isGitUrl(giturl)) return null; - giturl = giturl.slice(GIT_PREFIX.length); - - uri = new URI(giturl); - ref = uri.fragment() || 'master'; - uri.fragment(null); - - // Extract file inside the repo (after the .git) - fileParts =uri.path().split('.git'); - filepath = fileParts.length > 1? fileParts.slice(1).join('.git') : ''; - if (filepath[0] == '/') filepath = filepath.slice(1); - - // Recreate pathname without the real filename - uri.path(_.first(fileParts)+'.git'); - - return { - host: uri.toString(), - ref: ref || 'master', - filepath: filepath - }; -} +// Return an unique ID for a combinaison host/ref +Git.prototype.repoID = function(host, ref) { + return crc.crc32(host+'#'+(ref || '')).toString(16); +}; -// Clone a git repo from a specific ref -function cloneGitRepo(host, ref) { - ref = ref || 'master'; +// Clone a git repository if non existant +Git.prototype.clone = function(host, ref) { + var that = this; return Promise() - // Create temporary folder to store git repos - .then(function() { - if (GIT_TMP) return; - return fs.tmp.dir() - .then(function(_tmp) { - GIT_TMP = _tmp; - }); - }) - // Return or clone the git repo .then(function() { // Unique ID for repo/ref combinaison - var repoId = crc.crc32(host+'#'+ref).toString(16); + var repoId = that.repoID(host, ref); // Absolute path to the folder - var repoPath = path.resolve(GIT_TMP, repoId); - - return fs.exists(repoPath) - .then(function(doExists) { - if (doExists) return; - - // Clone repo - return command.exec('git clone '+host+' '+repoPath) - .then(function() { - return command.exec('git checkout '+ref, { cwd: repoPath }); - }); - }) - .thenResolve(repoPath); + var repoPath = path.join(that.tmpDir, repoId); + + if (that.cloned[repoId]) return repoPath; + + // Clone repo + return command.exec('git clone '+host+' '+repoPath) + + // Checkout reference if specified + .then(function() { + that.cloned[repoId] = true; + + if (!ref) return; + return command.exec('git checkout '+ref, { cwd: repoPath }); + }) + .thenResolve(repoPath); }); -} +}; // Get file from a git repo -function resolveFileFromGit(giturl) { - if (_.isString(giturl)) giturl = parseGitUrl(giturl); +Git.prototype.resolve = function(giturl) { + if (_.isString(giturl)) giturl = Git.parseUrl(giturl); if (!giturl) return Promise(null); // Clone or get from cache - return cloneGitRepo(giturl.host, giturl.ref) + return this.clone(giturl.host, giturl.ref) .then(function(repo) { - - // Resolve relative path return path.resolve(repo, giturl.filepath); }); -} +}; // Return root of git repo from a filepath -function resolveGitRoot(filepath) { +Git.prototype.resolveRoot = function(filepath) { var relativeToGit, repoId; // No git repo cloned, or file is not in a git repository - if (!GIT_TMP || !pathUtil.isInRoot(GIT_TMP, filepath)) return null; + if (!pathUtil.isInRoot(this.tmpDir, filepath)) return null; // Extract first directory (is the repo id) - relativeToGit = path.relative(GIT_TMP, filepath); + relativeToGit = path.relative(this.tmpDir, filepath); repoId = _.first(relativeToGit.split(path.sep)); if (!repoId) return; // Return an absolute file - return path.resolve(GIT_TMP, repoId); -} + return path.resolve(this.tmpDir, repoId); +}; +// Check if an url is a git dependency url +Git.isUrl = function(giturl) { + return (giturl.indexOf(GIT_PREFIX) === 0); +}; + +// Parse and extract infos +Git.parseUrl = function(giturl) { + var ref, uri, fileParts, filepath; + + if (!Git.isUrl(giturl)) return null; + giturl = giturl.slice(GIT_PREFIX.length); -module.exports = { - isUrl: isGitUrl, - parseUrl: parseGitUrl, - resolveFile: resolveFileFromGit, - resolveRoot: resolveGitRoot + uri = new URI(giturl); + ref = uri.fragment() || null; + uri.fragment(null); + + // Extract file inside the repo (after the .git) + fileParts = uri.path().split('.git'); + filepath = fileParts.length > 1? fileParts.slice(1).join('.git') : ''; + if (filepath[0] == '/') filepath = filepath.slice(1); + + // Recreate pathname without the real filename + uri.path(_.first(fileParts)+'.git'); + + return { + host: uri.toString(), + ref: ref, + filepath: filepath + }; }; + +module.exports = Git; diff --git a/test/git.js b/test/git.js index bad031b..8667b07 100644 --- a/test/git.js +++ b/test/git.js @@ -1,5 +1,8 @@ var should = require('should'); -var git = require('../lib/utils/git'); +var path = require('path'); +var os = require('os'); + +var Git = require('../lib/utils/git'); describe('Git', function() { @@ -7,27 +10,27 @@ describe('Git', function() { it('should correctly validate git urls', function() { // HTTPS - git.isUrl('git+https://github.com/Hello/world.git').should.be.ok; + Git.isUrl('git+https://github.com/Hello/world.git').should.be.ok; // SSH - git.isUrl('git+git@github.com:GitbookIO/gitbook.git/directory/README.md#e1594cde2c32e4ff48f6c4eff3d3d461743d74e1').should.be.ok; + Git.isUrl('git+git@github.com:GitbookIO/gitbook.git/directory/README.md#e1594cde2c32e4ff48f6c4eff3d3d461743d74e1').should.be.ok; // Non valid - git.isUrl('https://github.com/Hello/world.git').should.not.be.ok; - git.isUrl('README.md').should.not.be.ok; + Git.isUrl('https://github.com/Hello/world.git').should.not.be.ok; + Git.isUrl('README.md').should.not.be.ok; }); it('should parse HTTPS urls', function() { - var parts = git.parseUrl('git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md'); + var parts = Git.parseUrl('git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md'); should.exist(parts); parts.host.should.be.equal('https://gist.github.com/69ea4542e4c8967d2fa7.git'); - parts.ref.should.be.equal('master'); + should(parts.ref).be.equal(null); parts.filepath.should.be.equal('test.md'); }); it('should parse HTTPS urls with a reference', function() { - var parts = git.parseUrl('git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md#1.0.0'); + var parts = Git.parseUrl('git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md#1.0.0'); should.exist(parts); parts.host.should.be.equal('https://gist.github.com/69ea4542e4c8967d2fa7.git'); @@ -36,7 +39,7 @@ describe('Git', function() { }); it('should parse SSH urls', function() { - var parts = git.parseUrl('git+git@github.com:GitbookIO/gitbook.git/directory/README.md#e1594cde2c32e4ff48f6c4eff3d3d461743d74e1'); + var parts = Git.parseUrl('git+git@github.com:GitbookIO/gitbook.git/directory/README.md#e1594cde2c32e4ff48f6c4eff3d3d461743d74e1'); should.exist(parts); parts.host.should.be.equal('git@github.com:GitbookIO/gitbook.git'); @@ -45,4 +48,14 @@ describe('Git', function() { }); }); + describe('Cloning and resolving', function() { + it('should clone an HTTPS url', function() { + var git = new Git(path.join(os.tmpdir(), 'test-git-'+Date.now())); + return git.resolve('git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md') + .then(function(filename) { + path.extname(filename).should.equal('.md'); + }); + }); + }); + }); |