mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-21 01:53:26 +00:00
Add git urls parsing and tests
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
var childProcess = require('child_process');
|
||||
var Promise = require('./promise');
|
||||
|
||||
// On borwser, command execution is not possible
|
||||
var isAvailable = childProcess && childProcess.exec;
|
||||
|
||||
// Execute a command
|
||||
function exec(command, options) {
|
||||
if (!isAvailable) {
|
||||
return Promise.reject(new Error('Command execution is not possible on this platform'));
|
||||
}
|
||||
|
||||
return Promise.nfcall(childProcess.exec, command, options);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isAvailable: isAvailable,
|
||||
exec: exec
|
||||
};
|
||||
@@ -0,0 +1,119 @@
|
||||
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 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);
|
||||
}
|
||||
|
||||
// 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
|
||||
};
|
||||
}
|
||||
|
||||
// Clone a git repo from a specific ref
|
||||
function cloneGitRepo(host, ref) {
|
||||
ref = ref || 'master';
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
});
|
||||
}
|
||||
|
||||
// Get file from a git repo
|
||||
function resolveFileFromGit(giturl) {
|
||||
if (_.isString(giturl)) giturl = parseGitUrl(giturl);
|
||||
if (!giturl) return Promise(null);
|
||||
|
||||
// Clone or get from cache
|
||||
return cloneGitRepo(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) {
|
||||
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;
|
||||
|
||||
// Extract first directory (is the repo id)
|
||||
relativeToGit = path.relative(GIT_TMP, filepath);
|
||||
repoId = _.first(relativeToGit.split(path.sep));
|
||||
if (!repoId) return;
|
||||
|
||||
// Return an absolute file
|
||||
return path.resolve(GIT_TMP, repoId);
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
isUrl: isGitUrl,
|
||||
parseUrl: parseGitUrl,
|
||||
resolveFile: resolveFileFromGit,
|
||||
resolveRoot: resolveGitRoot
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>The HTML5 Herald</title>
|
||||
<meta name="description" content="The HTML5 Herald">
|
||||
<meta name="author" content="SitePoint">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="test-browser.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -8,6 +8,7 @@ require('./langs');
|
||||
require('./parse');
|
||||
|
||||
require('./template');
|
||||
require('./git');
|
||||
|
||||
// Output
|
||||
require('./output-json');
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
var should = require('should');
|
||||
var git = require('../lib/utils/git');
|
||||
|
||||
describe('Git', function() {
|
||||
|
||||
describe('URL parsing', function() {
|
||||
|
||||
it('should correctly validate git urls', function() {
|
||||
// HTTPS
|
||||
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;
|
||||
|
||||
// Non valid
|
||||
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');
|
||||
|
||||
should.exist(parts);
|
||||
parts.host.should.be.equal('https://gist.github.com/69ea4542e4c8967d2fa7.git');
|
||||
parts.ref.should.be.equal('master');
|
||||
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');
|
||||
|
||||
should.exist(parts);
|
||||
parts.host.should.be.equal('https://gist.github.com/69ea4542e4c8967d2fa7.git');
|
||||
parts.ref.should.be.equal('1.0.0');
|
||||
parts.filepath.should.be.equal('test.md');
|
||||
});
|
||||
|
||||
it('should parse SSH urls', function() {
|
||||
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');
|
||||
parts.ref.should.be.equal('e1594cde2c32e4ff48f6c4eff3d3d461743d74e1');
|
||||
parts.filepath.should.be.equal('directory/README.md');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user