• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1var fs = require('fs')
2var path = require('path')
3var util = require('util')
4var semver = require('semver')
5
6exports.checkEngine = checkEngine
7function checkEngine (target, npmVer, nodeVer, force, strict, cb) {
8  var nodev = force ? null : nodeVer
9  var eng = target.engines
10  var opt = { includePrerelease: true }
11  if (!eng) return cb()
12  if (nodev && eng.node && !semver.satisfies(nodev, eng.node, opt) ||
13      eng.npm && !semver.satisfies(npmVer, eng.npm, opt)) {
14    var er = new Error(util.format('Unsupported engine for %s: wanted: %j (current: %j)',
15      target._id, eng, {node: nodev, npm: npmVer}))
16    er.code = 'ENOTSUP'
17    er.required = eng
18    er.pkgid = target._id
19    if (strict) {
20      return cb(er)
21    } else {
22      return cb(null, er)
23    }
24  }
25  return cb()
26}
27
28exports.checkPlatform = checkPlatform
29function checkPlatform (target, force, cb) {
30  var platform = process.platform
31  var arch = process.arch
32  var osOk = true
33  var cpuOk = true
34
35  if (force) {
36    return cb()
37  }
38
39  if (target.os) {
40    osOk = checkList(platform, target.os)
41  }
42  if (target.cpu) {
43    cpuOk = checkList(arch, target.cpu)
44  }
45  if (!osOk || !cpuOk) {
46    var er = new Error(util.format('Unsupported platform for %s: wanted %j (current: %j)',
47      target._id, target, {os: platform, cpu: arch}))
48    er.code = 'EBADPLATFORM'
49    er.os = target.os || ['any']
50    er.cpu = target.cpu || ['any']
51    er.pkgid = target._id
52    return cb(er)
53  }
54  return cb()
55}
56
57function checkList (value, list) {
58  var tmp
59  var match = false
60  var blc = 0
61  if (typeof list === 'string') {
62    list = [list]
63  }
64  if (list.length === 1 && list[0] === 'any') {
65    return true
66  }
67  for (var i = 0; i < list.length; ++i) {
68    tmp = list[i]
69    if (tmp[0] === '!') {
70      tmp = tmp.slice(1)
71      if (tmp === value) {
72        return false
73      }
74      ++blc
75    } else {
76      match = match || tmp === value
77    }
78  }
79  return match || blc === list.length
80}
81
82exports.checkCycle = checkCycle
83function checkCycle (target, ancestors, cb) {
84  // there are some very rare and pathological edge-cases where
85  // a cycle can cause npm to try to install a never-ending tree
86  // of stuff.
87  // Simplest:
88  //
89  // A -> B -> A' -> B' -> A -> B -> A' -> B' -> A -> ...
90  //
91  // Solution: Simply flat-out refuse to install any name@version
92  // that is already in the prototype tree of the ancestors object.
93  // A more correct, but more complex, solution would be to symlink
94  // the deeper thing into the new location.
95  // Will do that if anyone whines about this irl.
96  //
97  // Note: `npm install foo` inside of the `foo` package will abort
98  // earlier if `--force` is not set.  However, if it IS set, then
99  // we need to still fail here, but just skip the first level. Of
100  // course, it'll still fail eventually if it's a true cycle, and
101  // leave things in an undefined state, but that's what is to be
102  // expected when `--force` is used.  That is why getPrototypeOf
103  // is used *twice* here: to skip the first level of repetition.
104
105  var p = Object.getPrototypeOf(Object.getPrototypeOf(ancestors))
106  var name = target.name
107  var version = target.version
108  while (p && p !== Object.prototype && p[name] !== version) {
109    p = Object.getPrototypeOf(p)
110  }
111  if (p[name] !== version) return cb()
112
113  var er = new Error(target._id + ': Unresolvable cycle detected')
114  var tree = [target._id, JSON.parse(JSON.stringify(ancestors))]
115  var t = Object.getPrototypeOf(ancestors)
116  while (t && t !== Object.prototype) {
117    if (t === p) t.THIS_IS_P = true
118    tree.push(JSON.parse(JSON.stringify(t)))
119    t = Object.getPrototypeOf(t)
120  }
121  er.pkgid = target._id
122  er.code = 'ECYCLE'
123  return cb(er)
124}
125
126exports.checkGit = checkGit
127function checkGit (folder, cb) {
128  // if it's a git repo then don't touch it!
129  fs.lstat(folder, function (er, s) {
130    if (er || !s.isDirectory()) return cb()
131    else checkGit_(folder, cb)
132  })
133}
134
135function checkGit_ (folder, cb) {
136  fs.stat(path.resolve(folder, '.git'), function (er, s) {
137    if (!er && s.isDirectory()) {
138      var e = new Error(folder + ': Appears to be a git repo or submodule.')
139      e.path = folder
140      e.code = 'EISGIT'
141      return cb(e)
142    }
143    cb()
144  })
145}
146