1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
var _ = require('lodash');
var path = require('path');
var crc = require('crc');
var URI = require('urijs');
var pathUtil = require('./path');
var Promise = require('./promise');
var command = require('./command');
var GIT_PREFIX = 'git+';
function Git(tmpDir) {
this.tmpDir = tmpDir;
this.cloned = {};
}
// 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 repository if non existant
Git.prototype.clone = function(host, ref) {
var that = this;
return Promise()
// Return or clone the git repo
.then(function() {
// Unique ID for repo/ref combinaison
var repoId = that.repoID(host, ref);
// Absolute path to the folder
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
Git.prototype.resolve = function(giturl) {
if (_.isString(giturl)) giturl = Git.parseUrl(giturl);
if (!giturl) return Promise(null);
// Clone or get from cache
return this.clone(giturl.host, giturl.ref)
.then(function(repo) {
return path.resolve(repo, giturl.filepath);
});
};
// Return root of git repo from a filepath
Git.prototype.resolveRoot = function(filepath) {
var relativeToGit, repoId;
// No git repo cloned, or file is not in a git repository
if (!pathUtil.isInRoot(this.tmpDir, filepath)) return null;
// Extract first directory (is the repo id)
relativeToGit = path.relative(this.tmpDir, filepath);
repoId = _.first(relativeToGit.split(path.sep));
if (!repoId) return;
// Return an absolute file
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);
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;
|