summaryrefslogtreecommitdiffstats
path: root/lib/utils/git.js
diff options
context:
space:
mode:
authorSamy Pessé <samypesse@gmail.com>2015-01-24 18:04:03 +0100
committerSamy Pessé <samypesse@gmail.com>2015-01-24 18:04:03 +0100
commit796dd4c13ac55e8b6232cbf38d49d9cf8c6676d2 (patch)
treeebbb0853571aec61384188402f673b9834f32a88 /lib/utils/git.js
parente02f29e76392660b31be87063649abd4adb22826 (diff)
downloadgitbook-796dd4c13ac55e8b6232cbf38d49d9cf8c6676d2.zip
gitbook-796dd4c13ac55e8b6232cbf38d49d9cf8c6676d2.tar.gz
gitbook-796dd4c13ac55e8b6232cbf38d49d9cf8c6676d2.tar.bz2
Add base loader to resolve git dependencies
Diffstat (limited to 'lib/utils/git.js')
-rw-r--r--lib/utils/git.js110
1 files changed, 110 insertions, 0 deletions
diff --git a/lib/utils/git.js b/lib/utils/git.js
new file mode 100644
index 0000000..8b515ec
--- /dev/null
+++ b/lib/utils/git.js
@@ -0,0 +1,110 @@
+var Q = require("q");
+var _ = require("lodash");
+var url = require("url");
+var tmp = require("tmp");
+var path = require("path");
+var crc = require("crc");
+var exec = Q.denodeify(require("child_process").exec);
+
+var fs = require("./fs");
+
+var GIT_PREFIX = "git+";
+var GIT_TMP = null;
+
+
+// Check if an url is a git dependency url
+function checkGitUrl(giturl) {
+ return (giturl.indexOf(GIT_PREFIX) === 0);
+}
+
+// Validates a SHA in hexadecimal
+function validateSha(str) {
+ return (/[0-9a-f]{40}/).test(str);
+}
+
+// Parse and extract infos
+function parseGitUrl(giturl) {
+ if (!checkGitUrl(giturl)) return null;
+ giturl = giturl.slice(GIT_PREFIX.length);
+
+ var parts = url.parse(giturl);
+
+ var ref = parts.hash;
+
+ // Extract file inside the repo (after the .git)
+ var fileParts = parts.pathname.split(".git");
+ var filepath = fileParts.length > 1? fileParts.slice(1).join(".git") : "";
+ if (filepath[0] == "/") filepath = filepath.slice(1);
+
+ // Rebuild
+ parts.pathname = _.first(fileParts)+".git";
+ var githost = url.format(parts);
+
+ return {
+ host: githost,
+ ref: ref,
+ filepath: filepath
+ };
+}
+
+// Clone a git repo from a specific ref
+function cloneGitRepo(host, ref) {
+ var isBranch = false;
+
+ ref = ref || "master";
+ if (!validateSha(ref)) isBranch = true;
+
+ return Q()
+
+ // Create temporary folder to store git repos
+ .then(function() {
+ if (GIT_TMP) return;
+ return fs.tmp.dir().get(0)
+ .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);
+
+ // 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 exec("git clone "+host+" "+repoPath)
+ .then(function() {
+ return exec("git checkout "+ref, { cwd: repoPath });
+ })
+ })
+ .thenResolve(repoPath);
+ });
+}
+
+
+// Get file from a git repo
+function resolveFileFromGit(giturl) {
+ if (_.isString(giturl)) giturl = parseGitUrl(giturl);
+ if (!giturl) return Q(null);
+
+ // Clone or get from cache
+ return cloneGitRepo(giturl.host, giturl.ref)
+ .then(function(repo) {
+
+ // Resolve relative path
+ return path.resolve(repo, giturl.filepath);
+ });
+};
+
+
+module.exports = {
+ checkUrl: checkGitUrl,
+ parseUrl: parseGitUrl,
+ resolveFile: resolveFileFromGit
+};