-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathindex.js
110 lines (94 loc) · 2.9 KB
/
index.js
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
'use strict';
const fs = require('fs');
const tar = require('tar');
const path = require('path');
const https = require('https');
const mkdirp = require('mkdirp');
const parse = require('url').parse;
const lookup = require('dns').lookup;
const HOME = require('os').homedir();
const DIR = path.join(HOME, '.gittar');
const strip = (a, b, c) => a.replace(b, '').replace(c, '');
function download(uri, file) {
return new Promise((res, rej) => {
https.get(uri, r => {
const code = r.statusCode;
if (code >= 400) return rej({ code, message:r.statusMessage });
if (code > 300 && code < 400) return download(r.headers.location, file).then(res);
const write = writer(file).on('finish', _ => res(file));
r.pipe(write);
}).on('error', rej);
});
}
function writer(file) {
file = path.normalize(file);
mkdirp.sync(path.dirname(file));
return fs.createWriteStream(file);
}
function getHint(str) {
const arr = str.match(/^(git(hub|lab)|bitbucket):/i);
return arr && arr[1];
}
function getTarFile(obj) {
return path.join(DIR, obj.site, obj.repo, `${obj.type}.tar.gz`);
}
function getTarUrl(obj) {
switch (obj.site) {
case 'bitbucket':
return `https://bitbucket.org/${obj.repo}/get/${obj.type}.tar.gz`;
case 'gitlab':
return `https://gitlab.com/${obj.repo}/repository/archive.tar.gz?ref=${obj.type}`;
default:
return `https://github.com/${obj.repo}/archive/${obj.type}.tar.gz`;
}
}
function parser(uri, host) {
const info = parse(uri);
const site = getHint(uri) || host || 'github';
const repo = strip(uri, info.protocol, info.hash);
const type = (info.hash || '#master').substr(1);
return { site, repo, type };
}
function exists(file) {
// file is a `user/repo#tag`
if (!path.isAbsolute(file)) {
file = getTarFile( parser(file) );
}
return fs.existsSync(file) && file;
}
function run(arr) {
return new Promise((res, rej) => {
if (arr.length === 0) rej();
const next = () => run(arr.slice(1)).then(res);
return arr[0]().then(val => val ? res(val) : next()).catch(rej);
});
}
exports.fetch = function (repo, opts) {
opts = opts || {};
const info = parser(repo, opts.host);
const file = getTarFile(info);
const uri = getTarUrl(info);
const local = _ => Promise.resolve( exists(file) );
const remote = _ => download(uri, file);
return new Promise((res, rej) => {
lookup('google.com', err => {
const isOffline = !!err;
let order = [local, remote];
if (opts.useCache || isOffline) {
order = [local];
} else if (opts.force || info.type === 'master') {
order = [remote, local];
}
return run(order).then(res).catch(rej);
});
});
}
exports.extract = function (file, dest, opts) {
file = exists(file);
dest = path.resolve(dest || '.');
return new Promise((res, rej) => {
const ok = _ => res(dest);
opts = Object.assign({ strip:1 }, opts, { file, cwd:dest });
return file ? mkdirp(dest, err => err ? rej(err) : tar.extract(opts).then(ok).catch(rej)) : rej();
});
}