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