summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamy Pesse <samypesse@gmail.com>2016-02-11 17:10:59 +0100
committerSamy Pesse <samypesse@gmail.com>2016-02-11 17:10:59 +0100
commit7f9aa214a412f3d173ac52042bd7250aacda6143 (patch)
tree84a6d59d1c5baf185bb3357357bcfbdbf96bc80c
parent347a536a4e313dece2e12d0ba1ec6654ee729c85 (diff)
downloadgitbook-7f9aa214a412f3d173ac52042bd7250aacda6143.zip
gitbook-7f9aa214a412f3d173ac52042bd7250aacda6143.tar.gz
gitbook-7f9aa214a412f3d173ac52042bd7250aacda6143.tar.bz2
Cleaner module for managing git refs
-rw-r--r--lib/utils/git.js142
-rw-r--r--test/git.js31
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');
+ });
+ });
+ });
+
});