summaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/npm-install-checks/index.js
blob: 9ea7b875e4234b3e730aa96289ed7555a2a3c66b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
var fs = require('fs')
var path = require('path')
var util = require('util')
var semver = require('semver')

exports.checkEngine = checkEngine
function checkEngine (target, npmVer, nodeVer, force, strict, cb) {
  var nodev = force ? null : nodeVer
  var eng = target.engines
  if (!eng) return cb()
  if (nodev && eng.node && !semver.satisfies(nodev, eng.node) ||
      eng.npm && !semver.satisfies(npmVer, eng.npm)) {
    var er = new Error(util.format('Unsupported engine for %s: wanted: %j (current: %j)',
      target._id, eng, {node: nodev, npm: npmVer}))
    er.code = 'ENOTSUP'
    er.required = eng
    er.pkgid = target._id
    if (strict) {
      return cb(er)
    } else {
      return cb(null, er)
    }
  }
  return cb()
}

exports.checkPlatform = checkPlatform
function checkPlatform (target, force, cb) {
  var platform = process.platform
  var arch = process.arch
  var osOk = true
  var cpuOk = true

  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(util.format('Unsupported platform for %s: wanted %j (current: %j)',
      target._id, target, {os: platform, cpu: arch}))
    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
  var match = false
  var 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
}

exports.checkCycle = checkCycle
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))
  var name = target.name
  var 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(target._id + ': Unresolvable cycle detected')
  var tree = [target._id, JSON.parse(JSON.stringify(ancestors))]
  var 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)
  }
  er.pkgid = target._id
  er.code = 'ECYCLE'
  return cb(er)
}

exports.checkGit = checkGit
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(folder + ': Appears to be a git repo or submodule.')
      e.path = folder
      e.code = 'EISGIT'
      return cb(e)
    }
    cb()
  })
}