clone-repo
Version:
使用node提取git仓库的下载工具,支持 GitHub,Gitee,GitLab,Bitbucket。
161 lines (143 loc) • 3.48 kB
JavaScript
const downloadUrl = require('download')
const gitclone = require('git-clone')
const rm = require('rimraf').sync
/**
* Download `repo` to `dest` and callback `fn(err)`.
*
* @param {String} repo
* @param {String} dest
* @param {Object} opts
*/
function download(repo, dest, opts = {}) {
return new Promise((resolve, reject) => {
let clone = opts.clone || false
delete opts.clone
repo = normalize(repo)
let url = repo.url || getUrl(repo, clone)
if (clone) {
const cloneOptions = {
checkout: repo.checkout,
shallow: repo.checkout === 'master',
...opts
}
gitclone(url, dest, cloneOptions, err => {
if (err === undefined) {
rm(dest + '/.git')
resolve()
} else {
reject(err)
}
})
} else {
const downloadOptions = {
extract: true,
strip: 1,
mode: '666',
...opts,
headers: {
accept: 'application/zip',
...(opts.headers || {})
}
}
downloadUrl(url, dest, downloadOptions).then(() => {
resolve()
}).catch(err => {
reject(err)
})
}
})
}
/**
* Normalize a repo string.
*
* @param {String} repo
* @return {Object}
*/
function normalize(repo) {
let regex = /^(?:(direct):([^#]+)(?:#(.+))?)$/
const match = regex.exec(repo)
if (match) {
const url = match[2]
let directCheckout = match[3] || 'master'
return {
type: 'direct',
url,
checkout: directCheckout
}
} else {
regex = /^(?:(github|gitlab|bitbucket|gitee):)?(?:(.+):)?([^/]+)\/([^#]+)(?:#(.+))?$/
match = regex.exec(repo)
let type = match[1] || 'github'
let origin = match[2] || null
const owner = match[3]
const name = match[4]
let checkout = match[5] || 'master'
if (origin == null) {
if (type === 'github') {
origin = 'github.com'
} else if (type === 'gitlab') {
origin = 'gitlab.com'
} else if (type === 'bitbucket') {
origin = 'bitbucket.org'
} else if (type === 'gitee') {
origin = 'gitee.com'
}
}
return {
type,
origin,
owner,
name,
checkout
}
}
}
/**
* Adds protocol to url in none specified
*
* @param {String} url
* @return {String}
*/
function addProtocol(origin, clone) {
if (!/^(f|ht)tps?:\/\//i.test(origin)) {
if (clone) {
origin = 'git@' + origin
} else {
origin = 'https://' + origin
}
}
return origin
}
/**
* Return a zip or git url for a given `repo`.
*
* @param {Object} repo
* @return {String}
*/
function getUrl(repo, clone) {
let url
// Get origin with protocol and add trailing slash or colon (for ssh)
let origin = addProtocol(repo.origin, clone)
if (/^git@/i.test(origin)) {
origin = origin + ':'
} else {
origin = origin + '/'
}
// Build url
if (clone) {
url = origin + repo.owner + '/' + repo.name + '.git'
} else {
if (repo.type === 'github') {
url = origin + repo.owner + '/' + repo.name + '/archive/' + repo.checkout + '.zip'
} else if (repo.type === 'gitlab') {
url = origin + repo.owner + '/' + repo.name + '/repository/archive.zip?ref=' + repo.checkout
} else if (repo.type === 'bitbucket') {
url = origin + repo.owner + '/' + repo.name + '/get/' + repo.checkout + '.zip'
}
}
return url
}
/**
* Expose `download`.
*/
module.exports = download