mirror of https://github.com/lukechilds/node.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
213 lines
5.8 KiB
213 lines
5.8 KiB
10 years ago
|
var execFile = require('child_process').execFile
|
||
|
var path = require('path')
|
||
|
var zlib = require('zlib')
|
||
|
|
||
|
var asyncMap = require('slide').asyncMap
|
||
|
var deepEqual = require('deep-equal')
|
||
|
var fs = require('graceful-fs')
|
||
|
var mkdirp = require('mkdirp')
|
||
|
var once = require('once')
|
||
|
var requireInject = require('require-inject')
|
||
|
var rimraf = require('rimraf')
|
||
|
var tar = require('tar')
|
||
|
var test = require('tap').test
|
||
|
var tmpdir = require('osenv').tmpdir
|
||
|
var which = require('which')
|
||
|
|
||
|
var wd = path.resolve(tmpdir(), 'git-races')
|
||
|
var fixtures = path.resolve(__dirname, '../fixtures')
|
||
|
var testcase = 'github-com-BryanDonovan-npm-git-test'
|
||
|
var testcase_git = path.resolve(wd, testcase + '.git')
|
||
|
var testcase_path = path.resolve(wd, testcase)
|
||
|
var testcase_tgz = path.resolve(fixtures, testcase + '.git.tar.gz')
|
||
|
|
||
|
var testtarballs = []
|
||
|
var testrepos = {}
|
||
|
var testurls = {}
|
||
|
|
||
|
/*
|
||
|
This test is specifically for #7202, where the bug was if you tried installing multiple git urls that
|
||
|
pointed at the same repo but had different comittishes, you'd sometimes get the wrong version.
|
||
|
The test cases, provided by @BryanDonovan, have a dependency tree like this:
|
||
|
|
||
|
top
|
||
|
bar#4.0.0
|
||
|
buzz#3.0.0
|
||
|
foo#3.0.0
|
||
|
buzz#3.0.0
|
||
|
foo#4.0.0
|
||
|
buzz#2.0.0
|
||
|
|
||
|
But what would happen is that buzz#2.0.0 would end up installed under bar#4.0.0.
|
||
|
|
||
|
bar#4.0.0 shouldn't have gotten its own copy if buzz, and if it did, it shouldn've been buzz#3.0.0
|
||
|
*/
|
||
|
|
||
|
;['bar', 'foo', 'buzz'].forEach(function (name) {
|
||
|
var mockurl = 'ssh://git@github.com/BryanDonovan/dummy-npm-' + name + '.git'
|
||
|
var realrepo = path.resolve(wd, 'github-com-BryanDonovan-dummy-npm-' + name + '.git')
|
||
|
var tgz = path.resolve(fixtures, 'github-com-BryanDonovan-dummy-npm-' + name + '.git.tar.gz')
|
||
|
|
||
|
testrepos[mockurl] = realrepo
|
||
|
testtarballs.push(tgz)
|
||
|
})
|
||
|
|
||
|
function cleanup () {
|
||
|
process.chdir(tmpdir())
|
||
|
rimraf.sync(wd)
|
||
|
}
|
||
|
|
||
|
var npm = requireInject.installGlobally('../../lib/npm.js', {
|
||
|
'child_process': {
|
||
|
'execFile': function (cmd, args, options, cb) {
|
||
|
// If it's a clone we swap any requests for any of the urls we're mocking
|
||
|
// with the path to the bare repo
|
||
|
if (args[0] === 'clone') {
|
||
|
var m2 = args.length - 2
|
||
|
var m1 = args.length - 1
|
||
|
if (testrepos[args[m2]]) {
|
||
|
testurls[args[m1]] = args[m2]
|
||
|
args[m2] = testrepos[args[m2]]
|
||
|
}
|
||
|
execFile(cmd, args, options, cb)
|
||
|
// here, we intercept npm validating the remote origin url on one of the
|
||
|
// clones we've done previously and return the original url that was requested
|
||
|
} else if (args[0] === 'config' && args[1] === '--get' && args[2] === 'remote.origin.url') {
|
||
|
process.nextTick(function () {
|
||
|
cb(null, testurls[options.cwd], '')
|
||
|
})
|
||
|
} else {
|
||
|
execFile(cmd, args, options, cb)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
|
||
|
function extract (tarball, target, cb) {
|
||
|
cb = once(cb)
|
||
|
fs.createReadStream(tarball).on('error', function (er) { cb(er) })
|
||
|
.pipe(zlib.createGunzip()).on('error', function (er) { cb(er) })
|
||
|
.pipe(tar.Extract({path: target})).on('error', function (er) { cb(er) })
|
||
|
.on('end', function () {
|
||
|
cb()
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Copied from lib/utils/git, because we need to use
|
||
|
// it before calling npm.load and lib/utils/git uses npm.js
|
||
|
// which doesn't allow that. =( =(
|
||
|
|
||
|
function prefixGitArgs () {
|
||
|
return process.platform === 'win32' ? ['-c', 'core.longpaths=true'] : []
|
||
|
}
|
||
|
|
||
|
var gitcmd
|
||
|
|
||
|
function execGit (args, options, cb) {
|
||
|
var fullArgs = prefixGitArgs().concat(args || [])
|
||
|
return execFile(gitcmd, fullArgs, options, cb)
|
||
|
}
|
||
|
|
||
|
function gitWhichAndExec (args, options, cb) {
|
||
|
if (gitcmd) return execGit(args, options, cb)
|
||
|
|
||
|
which('git', function (err, pathtogit) {
|
||
|
if (err) {
|
||
|
err.code = 'ENOGIT'
|
||
|
return cb(err)
|
||
|
}
|
||
|
gitcmd = pathtogit
|
||
|
|
||
|
execGit(args, options, cb)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
function andClone (gitdir, repodir, cb) {
|
||
|
return function (er) {
|
||
|
if (er) return cb(er)
|
||
|
gitWhichAndExec(['clone', gitdir, repodir], {}, cb)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function setup (cb) {
|
||
|
cleanup()
|
||
|
mkdirp.sync(wd)
|
||
|
|
||
|
extract(testcase_tgz, wd, andClone(testcase_git, testcase_path, andExtractPackages))
|
||
|
|
||
|
function andExtractPackages (er) {
|
||
|
if (er) return cb(er)
|
||
|
asyncMap(testtarballs, function (tgz, done) {
|
||
|
extract(tgz, wd, done)
|
||
|
}, andChdir)
|
||
|
}
|
||
|
function andChdir (er) {
|
||
|
if (er) return cb(er)
|
||
|
process.chdir(testcase_path)
|
||
|
andLoadNpm()
|
||
|
}
|
||
|
function andLoadNpm () {
|
||
|
var opts = {
|
||
|
cache: path.resolve(wd, 'cache')
|
||
|
}
|
||
|
npm.load(opts, cb)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// there are two (sic) valid trees that can result we don't care which one we
|
||
|
// get in npm@2
|
||
|
var oneTree = [
|
||
|
'npm-git-test@1.0.0', [
|
||
|
['dummy-npm-bar@4.0.0', [
|
||
|
['dummy-npm-foo@3.0.0', []]
|
||
|
]],
|
||
|
['dummy-npm-buzz@3.0.0', []],
|
||
|
['dummy-npm-foo@4.0.0', [
|
||
|
['dummy-npm-buzz@2.0.0', []]
|
||
|
]]
|
||
|
]
|
||
|
]
|
||
|
var otherTree = [
|
||
|
'npm-git-test@1.0.0', [
|
||
|
['dummy-npm-bar@4.0.0', [
|
||
|
['dummy-npm-buzz@3.0.0', []],
|
||
|
['dummy-npm-foo@3.0.0', []]
|
||
|
]],
|
||
|
['dummy-npm-buzz@3.0.0', []],
|
||
|
['dummy-npm-foo@4.0.0', [
|
||
|
['dummy-npm-buzz@2.0.0', []]
|
||
|
]]
|
||
|
]
|
||
|
]
|
||
|
|
||
|
function toSimple (tree) {
|
||
|
var deps = []
|
||
|
Object.keys(tree.dependencies || {}).forEach(function (dep) {
|
||
|
deps.push(toSimple(tree.dependencies[dep]))
|
||
|
})
|
||
|
return [ tree['name'] + '@' + tree['version'], deps ]
|
||
|
}
|
||
|
|
||
|
test('setup', function (t) {
|
||
|
setup(function (er) {
|
||
|
t.ifError(er, 'setup ran OK')
|
||
|
t.end()
|
||
|
})
|
||
|
})
|
||
|
|
||
|
test('correct versions are installed for git dependency', function (t) {
|
||
|
t.plan(3)
|
||
|
t.comment('test for https://github.com/npm/npm/issues/7202')
|
||
|
npm.commands.install([], function (er) {
|
||
|
t.ifError(er, 'installed OK')
|
||
|
npm.commands.ls([], true, function (er, result) {
|
||
|
t.ifError(er, 'ls OK')
|
||
|
var simplified = toSimple(result)
|
||
|
t.ok(
|
||
|
deepEqual(simplified, oneTree) || deepEqual(simplified, otherTree),
|
||
|
'install tree is correct'
|
||
|
)
|
||
|
})
|
||
|
})
|
||
|
})
|