Skip to content
This repository has been archived by the owner on Aug 11, 2022. It is now read-only.

Commit

Permalink
factor out npm-install-checks
Browse files Browse the repository at this point in the history
This removes the following checks from install.js, which are run
during installation:

- checkEngine
- checkPlatform
- checkCycle
- checkGit
  • Loading branch information
robertkowalski authored and domenic committed Feb 7, 2014
1 parent a09ef2b commit 98c1716
Showing 1 changed file with 9 additions and 144 deletions.
153 changes: 9 additions & 144 deletions lib/install.js
Expand Up @@ -73,6 +73,7 @@ var npm = require("./npm.js")
, lifecycle = require("./utils/lifecycle.js")
, archy = require("archy")
, isGitUrl = require("./utils/is-git-url.js")
, npmInstallChecks = require("npm-install-checks")

function install (args, cb_) {
var hasArguments = !!args.length
Expand Down Expand Up @@ -842,12 +843,16 @@ function installOne_ (target, where, context, cb) {
}
installOnesInProgress[target.name].push(where)
var indexOfIOIP = installOnesInProgress[target.name].length - 1
, force = npm.config.get("force")
, nodeVersion = npm.config.get("node-version")
, strict = npm.config.get("engine-strict")
, c = npmInstallChecks

chain
( [ [checkEngine, target]
, [checkPlatform, target]
, [checkCycle, target, context.ancestors]
, [checkGit, targetFolder]
( [ [c.checkEngine, target, npm.version, nodeVersion, force, strict]
, [c.checkPlatform, target, force]
, [c.checkCycle, target, context.ancestors]
, [c.checkGit, targetFolder]
, [write, target, targetFolder, context] ]
, function (er, d) {
installOnesInProgress[target.name].splice(indexOfIOIP, 1)
Expand All @@ -860,146 +865,6 @@ function installOne_ (target, where, context, cb) {
)
}

function checkEngine (target, cb) {
var npmv = npm.version
, force = npm.config.get("force")
, nodev = force ? null : npm.config.get("node-version")
, strict = npm.config.get("engine-strict") || target.engineStrict
, eng = target.engines
if (!eng) return cb()
if (nodev && eng.node && !semver.satisfies(nodev, eng.node)
|| eng.npm && !semver.satisfies(npmv, eng.npm)) {
if (strict) {
var er = new Error("Unsupported")
er.code = "ENOTSUP"
er.required = eng
er.pkgid = target._id
return cb(er)
} else {
log.warn( "engine", "%s: wanted: %j (current: %j)"
, target._id, eng, {node: nodev, npm: npm.version} )
}
}
return cb()
}

function checkPlatform (target, cb) {
var platform = process.platform
, arch = process.arch
, osOk = true
, cpuOk = true
, force = npm.config.get("force")

if (force) {
return cb()
}

if (target.os) {
osOk = checkList(platform, target.os)
}
if (target.cpu) {
cpuOk = checkList(arch, target.cpu)
}
if (!osOk || !cpuOk) {
var er = new Error("Unsupported")
er.code = "EBADPLATFORM"
er.os = target.os || ['any']
er.cpu = target.cpu || ['any']
er.pkgid = target._id
return cb(er)
}
return cb()
}

function checkList (value, list) {
var tmp
, match = false
, blc = 0
if (typeof list === "string") {
list = [list]
}
if (list.length === 1 && list[0] === "any") {
return true
}
for (var i = 0; i < list.length; ++i) {
tmp = list[i]
if (tmp[0] === '!') {
tmp = tmp.slice(1)
if (tmp === value) {
return false
}
++blc
} else {
match = match || tmp === value
}
}
return match || blc === list.length
}

function checkCycle (target, ancestors, cb) {
// there are some very rare and pathological edge-cases where
// a cycle can cause npm to try to install a never-ending tree
// of stuff.
// Simplest:
//
// A -> B -> A' -> B' -> A -> B -> A' -> B' -> A -> ...
//
// Solution: Simply flat-out refuse to install any name@version
// that is already in the prototype tree of the ancestors object.
// A more correct, but more complex, solution would be to symlink
// the deeper thing into the new location.
// Will do that if anyone whines about this irl.
//
// Note: `npm install foo` inside of the `foo` package will abort
// earlier if `--force` is not set. However, if it IS set, then
// we need to still fail here, but just skip the first level. Of
// course, it'll still fail eventually if it's a true cycle, and
// leave things in an undefined state, but that's what is to be
// expected when `--force` is used. That is why getPrototypeOf
// is used *twice* here: to skip the first level of repetition.

var p = Object.getPrototypeOf(Object.getPrototypeOf(ancestors))
, name = target.name
, version = target.version
while (p && p !== Object.prototype && p[name] !== version) {
p = Object.getPrototypeOf(p)
}
if (p[name] !== version) return cb()

var er = new Error("Unresolvable cycle detected")
var tree = [target._id, JSON.parse(JSON.stringify(ancestors))]
, t = Object.getPrototypeOf(ancestors)
while (t && t !== Object.prototype) {
if (t === p) t.THIS_IS_P = true
tree.push(JSON.parse(JSON.stringify(t)))
t = Object.getPrototypeOf(t)
}
log.verbose("unresolvable dependency tree", tree)
er.pkgid = target._id
er.code = "ECYCLE"
return cb(er)
}

function checkGit (folder, cb) {
// if it's a git repo then don't touch it!
fs.lstat(folder, function (er, s) {
if (er || !s.isDirectory()) return cb()
else checkGit_(folder, cb)
})
}

function checkGit_ (folder, cb) {
fs.stat(path.resolve(folder, ".git"), function (er, s) {
if (!er && s.isDirectory()) {
var e = new Error("Appears to be a git repo or submodule.")
e.path = folder
e.code = "EISGIT"
return cb(e)
}
cb()
})
}

function write (target, targetFolder, context, cb_) {
var up = npm.config.get("unsafe-perm")
, user = up ? null : npm.config.get("user")
Expand Down

0 comments on commit 98c1716

Please sign in to comment.