summaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/pacote/lib/util/git.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/node_modules/pacote/lib/util/git.js')
-rw-r--r--deps/npm/node_modules/pacote/lib/util/git.js207
1 files changed, 207 insertions, 0 deletions
diff --git a/deps/npm/node_modules/pacote/lib/util/git.js b/deps/npm/node_modules/pacote/lib/util/git.js
new file mode 100644
index 0000000000..dc189b5418
--- /dev/null
+++ b/deps/npm/node_modules/pacote/lib/util/git.js
@@ -0,0 +1,207 @@
+'use strict'
+
+const BB = require('bluebird')
+
+const cp = require('child_process')
+const execFileAsync = BB.promisify(cp.execFile, {
+ multiArgs: true
+})
+const finished = BB.promisify(require('mississippi').finished)
+const LRU = require('lru-cache')
+const optCheck = require('./opt-check')
+const osenv = require('osenv')
+const path = require('path')
+const pinflight = require('promise-inflight')
+const uniqueFilename = require('unique-filename')
+const which = BB.promisify(require('which'))
+
+const GOOD_ENV_VARS = new Set([
+ 'GIT_ASKPASS',
+ 'GIT_EXEC_PATH',
+ 'GIT_PROXY_COMMAND',
+ 'GIT_SSH',
+ 'GIT_SSH_COMMAND',
+ 'GIT_SSL_CAINFO',
+ 'GIT_SSL_NO_VERIFY'
+])
+
+let GITENV
+function gitEnv () {
+ if (GITENV) { return GITENV }
+ const tmpDir = path.join(osenv.tmpdir(), 'pacote-git-template-tmp')
+ const tmpName = uniqueFilename(tmpDir, 'git-clone')
+ GITENV = {
+ GIT_ASKPASS: 'echo',
+ GIT_TEMPLATE_DIR: tmpName
+ }
+ Object.keys(process.env).forEach(k => {
+ if (GOOD_ENV_VARS.has(k) || !k.match(/^GIT_/)) {
+ GITENV[k] = process.env[k]
+ }
+ })
+ return GITENV
+}
+
+let GITPATH
+try {
+ GITPATH = which.sync('git')
+} catch (e) {}
+
+module.exports.clone = fullClone
+function fullClone (repo, committish, target, opts) {
+ opts = optCheck(opts)
+ const gitArgs = ['clone', '-q', repo, target]
+ if (process.platform === 'win32') {
+ gitArgs.push('--config', 'core.longpaths=true')
+ }
+ return execGit(gitArgs, {
+ cwd: path.dirname(target)
+ }, opts).then(() => {
+ return execGit(['checkout', committish], {
+ cwd: target
+ })
+ }).then(() => {
+ return updateSubmodules(target, opts)
+ }).then(() => headSha(target, opts))
+}
+
+module.exports.shallow = shallowClone
+function shallowClone (repo, branch, target, opts) {
+ opts = optCheck(opts)
+ const gitArgs = ['clone', '--depth=1', '-q', '-b', branch, repo, target]
+ if (process.platform === 'win32') {
+ gitArgs.push('--config', 'core.longpaths=true')
+ }
+ return execGit(gitArgs, {
+ cwd: target
+ }, opts).then(() => {
+ return updateSubmodules(target, opts)
+ }).then(() => headSha(target, opts))
+}
+
+function updateSubmodules (localRepo, opts) {
+ const gitArgs = ['submodule', 'update', '-q', '--init', '--recursive']
+ return execGit(gitArgs, {
+ cwd: localRepo
+ }, opts)
+}
+
+function headSha (repo, opts) {
+ opts = optCheck(opts)
+ return execGit(['rev-parse', '--revs-only', 'HEAD'], {cwd: repo}, opts).spread(stdout => {
+ return stdout.trim()
+ })
+}
+
+const REVS = new LRU({
+ max: 100,
+ maxAge: 5 * 60 * 1000
+})
+module.exports.revs = revs
+function revs (repo, opts) {
+ opts = optCheck(opts)
+ const cached = REVS.get(repo)
+ if (cached) {
+ return BB.resolve(cached)
+ }
+ return pinflight(`ls-remote:${repo}`, () => {
+ return spawnGit(['ls-remote', repo, '-t', '-h', '*'], {
+ env: gitEnv()
+ }, opts).then(child => {
+ let stdout = ''
+ child.stdout.on('data', d => { stdout += d })
+ return finished(child).then(() => {
+ return stdout.split('\n').reduce((revs, line) => {
+ const split = line.split(/\s+/, 2)
+ if (split.length < 2) { return revs }
+ const sha = split[0].trim()
+ const ref = split[1].trim().match(/(?:refs\/[^/]+\/)?(.*)/)[1]
+ if (!ref) { return revs } // ???
+ const type = refType(line)
+ const doc = {sha, ref, type}
+
+ revs.refs[ref] = doc
+ // We can check out shallow clones on specific SHAs if we have a ref
+ if (revs.shas[sha]) {
+ revs.shas[sha].push(ref)
+ } else {
+ revs.shas[sha] = [ref]
+ }
+
+ if (type === 'tag') {
+ const match = ref.match(/v?(\d+\.\d+\.\d+)$/)
+ if (match) {
+ revs.versions[match[1]] = doc
+ }
+ }
+
+ return revs
+ }, {versions: {}, 'dist-tags': {}, refs: {}, shas: {}})
+ }).then(revs => {
+ if (revs.refs.HEAD) {
+ const HEAD = revs.refs.HEAD
+ Object.keys(revs.versions).forEach(v => {
+ if (v.sha === HEAD.sha) {
+ revs['dist-tags'].HEAD = v
+ if (!revs.refs.latest) {
+ revs['dist-tags'].latest = revs.refs.HEAD
+ }
+ }
+ })
+ }
+ REVS.set(repo, revs)
+ return revs
+ })
+ })
+ })
+}
+
+module.exports._exec = execGit
+function execGit (gitArgs, gitOpts, opts) {
+ opts = optCheck(opts)
+ return checkGit().then(gitPath => {
+ return execFileAsync(gitPath, gitArgs, mkOpts(gitOpts, opts))
+ })
+}
+
+module.exports._spawn = spawnGit
+function spawnGit (gitArgs, gitOpts, opts) {
+ opts = optCheck(opts)
+ return checkGit().then(gitPath => {
+ return cp.spawn(gitPath, gitArgs, mkOpts(gitOpts, opts))
+ })
+}
+
+function mkOpts (_gitOpts, opts) {
+ const gitOpts = {
+ env: gitEnv()
+ }
+ if (+opts.uid && !isNaN(opts.uid)) {
+ gitOpts.uid = +opts.uid
+ }
+ if (+opts.gid && !isNaN(opts.gid)) {
+ gitOpts.gid = +opts.gid
+ }
+ Object.assign(gitOpts, _gitOpts)
+ return gitOpts
+}
+
+function checkGit () {
+ if (!GITPATH) {
+ const err = new Error('No git binary found in $PATH')
+ err.code = 'ENOGIT'
+ return BB.reject(err)
+ } else {
+ return BB.resolve(GITPATH)
+ }
+}
+
+function refType (ref) {
+ return ref.match(/refs\/tags\/.*$/)
+ ? 'tag'
+ : ref.match(/refs\/heads\/.*$/)
+ ? 'branch'
+ : ref.match(/HEAD$/)
+ ? 'head'
+ : 'other'
+}