mirror of
https://github.com/S2-/minifyfromhtml.git
synced 2025-08-04 20:40:07 +02:00
update packages to latest version
This commit is contained in:
481
node_modules/npm/lib/cache/add-remote-git.js
generated
vendored
Normal file
481
node_modules/npm/lib/cache/add-remote-git.js
generated
vendored
Normal file
@@ -0,0 +1,481 @@
|
||||
var assert = require('assert')
|
||||
var crypto = require('crypto')
|
||||
var fs = require('graceful-fs')
|
||||
var path = require('path')
|
||||
var url = require('url')
|
||||
|
||||
var chownr = require('chownr')
|
||||
var dezalgo = require('dezalgo')
|
||||
var hostedFromURL = require('hosted-git-info').fromUrl
|
||||
var inflight = require('inflight')
|
||||
var log = require('npmlog')
|
||||
var mkdir = require('mkdirp')
|
||||
var normalizeGitUrl = require('normalize-git-url')
|
||||
var npa = require('npm-package-arg')
|
||||
var realizePackageSpecifier = require('realize-package-specifier')
|
||||
|
||||
var addLocal = require('./add-local.js')
|
||||
var correctMkdir = require('../utils/correct-mkdir.js')
|
||||
var git = require('../utils/git.js')
|
||||
var npm = require('../npm.js')
|
||||
var rm = require('../utils/gently-rm.js')
|
||||
|
||||
var remotes = path.resolve(npm.config.get('cache'), '_git-remotes')
|
||||
var templates = path.join(remotes, '_templates')
|
||||
|
||||
var VALID_VARIABLES = [
|
||||
'GIT_ASKPASS',
|
||||
'GIT_EXEC_PATH',
|
||||
'GIT_PROXY_COMMAND',
|
||||
'GIT_SSH',
|
||||
'GIT_SSH_COMMAND',
|
||||
'GIT_SSL_CAINFO',
|
||||
'GIT_SSL_NO_VERIFY'
|
||||
]
|
||||
|
||||
module.exports = addRemoteGit
|
||||
function addRemoteGit (uri, _cb) {
|
||||
assert(typeof uri === 'string', 'must have git URL')
|
||||
assert(typeof _cb === 'function', 'must have callback')
|
||||
var cb = dezalgo(_cb)
|
||||
|
||||
log.verbose('addRemoteGit', 'caching', uri)
|
||||
|
||||
// the URL comes in exactly as it was passed on the command line, or as
|
||||
// normalized by normalize-package-data / read-package-json / read-installed,
|
||||
// so figure out what to do with it using hosted-git-info
|
||||
var parsed = hostedFromURL(uri)
|
||||
if (parsed) {
|
||||
// normalize GitHub syntax to org/repo (for now)
|
||||
var from
|
||||
if (parsed.type === 'github' && parsed.default === 'shortcut') {
|
||||
from = parsed.path()
|
||||
} else {
|
||||
from = parsed.toString()
|
||||
}
|
||||
|
||||
log.verbose('addRemoteGit', from, 'is a repository hosted by', parsed.type)
|
||||
|
||||
// prefer explicit URLs to pushing everything through shortcuts
|
||||
if (parsed.default !== 'shortcut') {
|
||||
return tryClone(from, parsed.toString(), false, cb)
|
||||
}
|
||||
|
||||
// try git:, then git+ssh:, then git+https: before failing
|
||||
tryGitProto(from, parsed, cb)
|
||||
} else {
|
||||
// verify that this is a Git URL before continuing
|
||||
parsed = npa(uri)
|
||||
if (parsed.type !== 'git') {
|
||||
return cb(new Error(uri + 'is not a Git or GitHub URL'))
|
||||
}
|
||||
|
||||
tryClone(parsed.rawSpec, uri, false, cb)
|
||||
}
|
||||
}
|
||||
|
||||
function tryGitProto (from, hostedInfo, cb) {
|
||||
var gitURL = hostedInfo.git()
|
||||
if (!gitURL) return trySSH(from, hostedInfo, cb)
|
||||
|
||||
log.silly('tryGitProto', 'attempting to clone', gitURL)
|
||||
tryClone(from, gitURL, true, function (er) {
|
||||
if (er) return tryHTTPS(from, hostedInfo, cb)
|
||||
|
||||
cb.apply(this, arguments)
|
||||
})
|
||||
}
|
||||
|
||||
function tryHTTPS (from, hostedInfo, cb) {
|
||||
var httpsURL = hostedInfo.https()
|
||||
if (!httpsURL) {
|
||||
return cb(new Error(from + ' can not be cloned via Git, SSH, or HTTPS'))
|
||||
}
|
||||
|
||||
log.silly('tryHTTPS', 'attempting to clone', httpsURL)
|
||||
tryClone(from, httpsURL, true, function (er) {
|
||||
if (er) return trySSH(from, hostedInfo, cb)
|
||||
|
||||
cb.apply(this, arguments)
|
||||
})
|
||||
}
|
||||
|
||||
function trySSH (from, hostedInfo, cb) {
|
||||
var sshURL = hostedInfo.ssh()
|
||||
if (!sshURL) return tryHTTPS(from, hostedInfo, cb)
|
||||
|
||||
log.silly('trySSH', 'attempting to clone', sshURL)
|
||||
tryClone(from, sshURL, false, cb)
|
||||
}
|
||||
|
||||
function tryClone (from, combinedURL, silent, cb) {
|
||||
log.silly('tryClone', 'cloning', from, 'via', combinedURL)
|
||||
|
||||
var normalized = normalizeGitUrl(combinedURL)
|
||||
var cloneURL = normalized.url
|
||||
var treeish = normalized.branch
|
||||
|
||||
// ensure that similarly-named remotes don't collide
|
||||
var repoID = cloneURL.replace(/[^a-zA-Z0-9]+/g, '-') + '-' +
|
||||
crypto.createHash('sha1').update(combinedURL).digest('hex').slice(0, 8)
|
||||
var cachedRemote = path.join(remotes, repoID)
|
||||
|
||||
cb = inflight(repoID, cb)
|
||||
if (!cb) {
|
||||
return log.verbose('tryClone', repoID, 'already in flight; waiting')
|
||||
}
|
||||
log.verbose('tryClone', repoID, 'not in flight; caching')
|
||||
|
||||
// initialize the remotes cache with the correct perms
|
||||
getGitDir(function (er) {
|
||||
if (er) return cb(er)
|
||||
fs.stat(cachedRemote, function (er, s) {
|
||||
if (er) return mirrorRemote(from, cloneURL, treeish, cachedRemote, silent, finish)
|
||||
if (!s.isDirectory()) return resetRemote(from, cloneURL, treeish, cachedRemote, finish)
|
||||
|
||||
validateExistingRemote(from, cloneURL, treeish, cachedRemote, finish)
|
||||
})
|
||||
|
||||
// always set permissions on the cached remote
|
||||
function finish (er, data) {
|
||||
if (er) return cb(er, data)
|
||||
addModeRecursive(cachedRemote, npm.modes.file, function (er) {
|
||||
return cb(er, data)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// don't try too hard to hold on to a remote
|
||||
function resetRemote (from, cloneURL, treeish, cachedRemote, cb) {
|
||||
log.info('resetRemote', 'resetting', cachedRemote, 'for', from)
|
||||
rm(cachedRemote, function (er) {
|
||||
if (er) return cb(er)
|
||||
mirrorRemote(from, cloneURL, treeish, cachedRemote, false, cb)
|
||||
})
|
||||
}
|
||||
|
||||
// reuse a cached remote when possible, but nuke it if it's in an
|
||||
// inconsistent state
|
||||
function validateExistingRemote (from, cloneURL, treeish, cachedRemote, cb) {
|
||||
git.whichAndExec(
|
||||
['config', '--get', 'remote.origin.url'],
|
||||
{ cwd: cachedRemote, env: gitEnv() },
|
||||
function (er, stdout, stderr) {
|
||||
var originURL
|
||||
if (stdout) {
|
||||
originURL = stdout.trim()
|
||||
log.silly('validateExistingRemote', from, 'remote.origin.url:', originURL)
|
||||
}
|
||||
|
||||
if (stderr) stderr = stderr.trim()
|
||||
if (stderr || er) {
|
||||
log.warn('addRemoteGit', from, 'resetting remote', cachedRemote, 'because of error:', stderr || er)
|
||||
return resetRemote(from, cloneURL, treeish, cachedRemote, cb)
|
||||
} else if (cloneURL !== originURL) {
|
||||
log.warn(
|
||||
'addRemoteGit',
|
||||
from,
|
||||
'pre-existing cached repo', cachedRemote, 'points to', originURL, 'and not', cloneURL
|
||||
)
|
||||
return resetRemote(from, cloneURL, treeish, cachedRemote, cb)
|
||||
}
|
||||
|
||||
log.verbose('validateExistingRemote', from, 'is updating existing cached remote', cachedRemote)
|
||||
updateRemote(from, cloneURL, treeish, cachedRemote, cb)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// make a complete bare mirror of the remote repo
|
||||
// NOTE: npm uses a blank template directory to prevent weird inconsistencies
|
||||
// https://github.com/npm/npm/issues/5867
|
||||
function mirrorRemote (from, cloneURL, treeish, cachedRemote, silent, cb) {
|
||||
mkdir(cachedRemote, function (er) {
|
||||
if (er) return cb(er)
|
||||
|
||||
var args = [
|
||||
'clone',
|
||||
'--template=' + templates,
|
||||
'--mirror',
|
||||
cloneURL, cachedRemote
|
||||
]
|
||||
git.whichAndExec(
|
||||
['clone', '--template=' + templates, '--mirror', cloneURL, cachedRemote],
|
||||
{ cwd: cachedRemote, env: gitEnv() },
|
||||
function (er, stdout, stderr) {
|
||||
if (er) {
|
||||
var combined = (stdout + '\n' + stderr).trim()
|
||||
var command = 'git ' + args.join(' ') + ':'
|
||||
if (silent) {
|
||||
log.verbose(command, combined)
|
||||
} else {
|
||||
log.error(command, combined)
|
||||
}
|
||||
return cb(er)
|
||||
}
|
||||
log.verbose('mirrorRemote', from, 'git clone ' + cloneURL, stdout.trim())
|
||||
setPermissions(from, cloneURL, treeish, cachedRemote, cb)
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function setPermissions (from, cloneURL, treeish, cachedRemote, cb) {
|
||||
if (process.platform === 'win32') {
|
||||
log.verbose('setPermissions', from, 'skipping chownr on Windows')
|
||||
resolveHead(from, cloneURL, treeish, cachedRemote, cb)
|
||||
} else {
|
||||
getGitDir(function (er, cs) {
|
||||
if (er) {
|
||||
log.error('setPermissions', from, 'could not get cache stat')
|
||||
return cb(er)
|
||||
}
|
||||
|
||||
chownr(cachedRemote, cs.uid, cs.gid, function (er) {
|
||||
if (er) {
|
||||
log.error(
|
||||
'setPermissions',
|
||||
'Failed to change git repository ownership under npm cache for',
|
||||
cachedRemote
|
||||
)
|
||||
return cb(er)
|
||||
}
|
||||
|
||||
log.verbose('setPermissions', from, 'set permissions on', cachedRemote)
|
||||
resolveHead(from, cloneURL, treeish, cachedRemote, cb)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// always fetch the origin, even right after mirroring, because this way
|
||||
// permissions will get set correctly
|
||||
function updateRemote (from, cloneURL, treeish, cachedRemote, cb) {
|
||||
git.whichAndExec(
|
||||
['fetch', '-a', 'origin'],
|
||||
{ cwd: cachedRemote, env: gitEnv() },
|
||||
function (er, stdout, stderr) {
|
||||
if (er) {
|
||||
var combined = (stdout + '\n' + stderr).trim()
|
||||
log.error('git fetch -a origin (' + cloneURL + ')', combined)
|
||||
return cb(er)
|
||||
}
|
||||
log.verbose('updateRemote', 'git fetch -a origin (' + cloneURL + ')', stdout.trim())
|
||||
|
||||
setPermissions(from, cloneURL, treeish, cachedRemote, cb)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// branches and tags are both symbolic labels that can be attached to different
|
||||
// commits, so resolve the commit-ish to the current actual treeish the label
|
||||
// corresponds to
|
||||
//
|
||||
// important for shrinkwrap
|
||||
function resolveHead (from, cloneURL, treeish, cachedRemote, cb) {
|
||||
log.verbose('resolveHead', from, 'original treeish:', treeish)
|
||||
var args = ['rev-list', '-n1', treeish]
|
||||
git.whichAndExec(
|
||||
args,
|
||||
{ cwd: cachedRemote, env: gitEnv() },
|
||||
function (er, stdout, stderr) {
|
||||
if (er) {
|
||||
log.error('git ' + args.join(' ') + ':', stderr)
|
||||
return cb(er)
|
||||
}
|
||||
|
||||
var resolvedTreeish = stdout.trim()
|
||||
log.silly('resolveHead', from, 'resolved treeish:', resolvedTreeish)
|
||||
|
||||
var resolvedURL = getResolved(cloneURL, resolvedTreeish)
|
||||
if (!resolvedURL) {
|
||||
return cb(new Error(
|
||||
'unable to clone ' + from + ' because git clone string ' +
|
||||
cloneURL + ' is in a form npm can\'t handle'
|
||||
))
|
||||
}
|
||||
log.verbose('resolveHead', from, 'resolved Git URL:', resolvedURL)
|
||||
|
||||
// generate a unique filename
|
||||
var tmpdir = path.join(
|
||||
npm.tmp,
|
||||
'git-cache-' + crypto.pseudoRandomBytes(6).toString('hex'),
|
||||
resolvedTreeish
|
||||
)
|
||||
log.silly('resolveHead', 'Git working directory:', tmpdir)
|
||||
|
||||
mkdir(tmpdir, function (er) {
|
||||
if (er) return cb(er)
|
||||
|
||||
cloneResolved(from, resolvedURL, resolvedTreeish, cachedRemote, tmpdir, cb)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// make a clone from the mirrored cache so we have a temporary directory in
|
||||
// which we can check out the resolved treeish
|
||||
function cloneResolved (from, resolvedURL, resolvedTreeish, cachedRemote, tmpdir, cb) {
|
||||
var args = ['clone', cachedRemote, tmpdir]
|
||||
git.whichAndExec(
|
||||
args,
|
||||
{ cwd: cachedRemote, env: gitEnv() },
|
||||
function (er, stdout, stderr) {
|
||||
stdout = (stdout + '\n' + stderr).trim()
|
||||
if (er) {
|
||||
log.error('git ' + args.join(' ') + ':', stderr)
|
||||
return cb(er)
|
||||
}
|
||||
log.verbose('cloneResolved', from, 'clone', stdout)
|
||||
|
||||
checkoutTreeish(from, resolvedURL, resolvedTreeish, tmpdir, cb)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// there is no safe way to do a one-step clone to a treeish that isn't
|
||||
// guaranteed to be a branch, so explicitly check out the treeish once it's
|
||||
// cloned
|
||||
function checkoutTreeish (from, resolvedURL, resolvedTreeish, tmpdir, cb) {
|
||||
var args = ['checkout', resolvedTreeish]
|
||||
git.whichAndExec(
|
||||
args,
|
||||
{ cwd: tmpdir, env: gitEnv() },
|
||||
function (er, stdout, stderr) {
|
||||
stdout = (stdout + '\n' + stderr).trim()
|
||||
if (er) {
|
||||
log.error('git ' + args.join(' ') + ':', stderr)
|
||||
return cb(er)
|
||||
}
|
||||
log.verbose('checkoutTreeish', from, 'checkout', stdout)
|
||||
|
||||
// convince addLocal that the checkout is a local dependency
|
||||
realizePackageSpecifier(tmpdir, function (er, spec) {
|
||||
if (er) {
|
||||
log.error('addRemoteGit', 'Failed to map', tmpdir, 'to a package specifier')
|
||||
return cb(er)
|
||||
}
|
||||
|
||||
// ensure pack logic is applied
|
||||
// https://github.com/npm/npm/issues/6400
|
||||
addLocal(spec, null, function (er, data) {
|
||||
if (data) {
|
||||
if (npm.config.get('save-exact')) {
|
||||
log.verbose('addRemoteGit', 'data._from:', resolvedURL, '(save-exact)')
|
||||
data._from = resolvedURL
|
||||
} else {
|
||||
log.verbose('addRemoteGit', 'data._from:', from)
|
||||
data._from = from
|
||||
}
|
||||
|
||||
log.verbose('addRemoteGit', 'data._resolved:', resolvedURL)
|
||||
data._resolved = resolvedURL
|
||||
}
|
||||
|
||||
cb(er, data)
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function getGitDir (cb) {
|
||||
correctMkdir(remotes, function (er, stats) {
|
||||
if (er) return cb(er)
|
||||
|
||||
// We don't need global templates when cloning. Use an empty directory for
|
||||
// the templates, creating it (and setting its permissions) if necessary.
|
||||
mkdir(templates, function (er) {
|
||||
if (er) return cb(er)
|
||||
|
||||
// Ensure that both the template and remotes directories have the correct
|
||||
// permissions.
|
||||
fs.chown(templates, stats.uid, stats.gid, function (er) {
|
||||
cb(er, stats)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
var gitEnv_
|
||||
function gitEnv () {
|
||||
// git responds to env vars in some weird ways in post-receive hooks
|
||||
// so don't carry those along.
|
||||
if (gitEnv_) return gitEnv_
|
||||
|
||||
// allow users to override npm's insistence on not prompting for
|
||||
// passphrases, but default to just failing when credentials
|
||||
// aren't available
|
||||
gitEnv_ = { GIT_ASKPASS: 'echo' }
|
||||
|
||||
for (var k in process.env) {
|
||||
if (!~VALID_VARIABLES.indexOf(k) && k.match(/^GIT/)) continue
|
||||
gitEnv_[k] = process.env[k]
|
||||
}
|
||||
return gitEnv_
|
||||
}
|
||||
|
||||
addRemoteGit.getResolved = getResolved
|
||||
function getResolved (uri, treeish) {
|
||||
// normalize hosted-git-info clone URLs back into regular URLs
|
||||
// this will only work on URLs that hosted-git-info recognizes
|
||||
// https://github.com/npm/npm/issues/7961
|
||||
var rehydrated = hostedFromURL(uri)
|
||||
if (rehydrated) uri = rehydrated.toString()
|
||||
|
||||
var parsed = url.parse(uri)
|
||||
|
||||
// Checks for known protocols:
|
||||
// http:, https:, ssh:, and git:, with optional git+ prefix.
|
||||
if (!parsed.protocol ||
|
||||
!parsed.protocol.match(/^(((git\+)?(https?|ssh))|git|file):$/)) {
|
||||
uri = 'git+ssh://' + uri
|
||||
}
|
||||
|
||||
if (!/^git[+:]/.test(uri)) {
|
||||
uri = 'git+' + uri
|
||||
}
|
||||
|
||||
// Not all URIs are actually URIs, so use regex for the treeish.
|
||||
return uri.replace(/(?:#.*)?$/, '#' + treeish)
|
||||
}
|
||||
|
||||
// similar to chmodr except it add permissions rather than overwriting them
|
||||
// adapted from https://github.com/isaacs/chmodr/blob/master/chmodr.js
|
||||
function addModeRecursive (cachedRemote, mode, cb) {
|
||||
fs.readdir(cachedRemote, function (er, children) {
|
||||
// Any error other than ENOTDIR means it's not readable, or doesn't exist.
|
||||
// Give up.
|
||||
if (er && er.code !== 'ENOTDIR') return cb(er)
|
||||
if (er || !children.length) return addMode(cachedRemote, mode, cb)
|
||||
|
||||
var len = children.length
|
||||
var errState = null
|
||||
children.forEach(function (child) {
|
||||
addModeRecursive(path.resolve(cachedRemote, child), mode, then)
|
||||
})
|
||||
|
||||
function then (er) {
|
||||
if (errState) return undefined
|
||||
if (er) return cb(errState = er)
|
||||
if (--len === 0) return addMode(cachedRemote, dirMode(mode), cb)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function addMode (cachedRemote, mode, cb) {
|
||||
fs.stat(cachedRemote, function (er, stats) {
|
||||
if (er) return cb(er)
|
||||
mode = stats.mode | mode
|
||||
fs.chmod(cachedRemote, mode, cb)
|
||||
})
|
||||
}
|
||||
|
||||
// taken from https://github.com/isaacs/chmodr/blob/master/chmodr.js
|
||||
function dirMode (mode) {
|
||||
if (mode & parseInt('0400', 8)) mode |= parseInt('0100', 8)
|
||||
if (mode & parseInt('040', 8)) mode |= parseInt('010', 8)
|
||||
if (mode & parseInt('04', 8)) mode |= parseInt('01', 8)
|
||||
return mode
|
||||
}
|
Reference in New Issue
Block a user