]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/lib/utils/gently-rm.js
Adding integrated tile server
[simantics/district.git] / org.simantics.maps.server / node / node-v4.8.0-win-x64 / node_modules / npm / lib / utils / gently-rm.js
1 // only remove the thing if it's a symlink into a specific folder.
2 // This is a very common use-case of npm's, but not so common elsewhere.
3
4 module.exports = gentlyRm
5
6 var npm = require('../npm.js')
7 var log = require('npmlog')
8 var resolve = require('path').resolve
9 var dirname = require('path').dirname
10 var lstat = require('graceful-fs').lstat
11 var readlink = require('graceful-fs').readlink
12 var isInside = require('path-is-inside')
13 var vacuum = require('fs-vacuum')
14 var some = require('async-some')
15 var asyncMap = require('slide').asyncMap
16 var normalize = require('path').normalize
17
18 function gentlyRm (target, gently, base, cb) {
19   if (!cb) {
20     cb = base
21     base = undefined
22   }
23
24   if (!cb) {
25     cb = gently
26     gently = false
27   }
28
29   log.silly(
30     'gentlyRm',
31     target,
32     'is being', gently ? 'gently removed' : 'purged',
33     base ? 'from base ' + base : ''
34   )
35
36   // never rm the root, prefix, or bin dirs
37   //
38   // globals included because of `npm link` -- as far as the package requesting
39   // the link is concerned, the linked package is always installed globally
40   var prefixes = [
41     npm.prefix,
42     npm.globalPrefix,
43     npm.dir,
44     npm.root,
45     npm.globalDir,
46     npm.bin,
47     npm.globalBin
48   ]
49
50   var resolved = normalize(resolve(npm.prefix, target))
51   if (prefixes.indexOf(resolved) !== -1) {
52     log.verbose('gentlyRm', resolved, "is part of npm and can't be removed")
53     return cb(new Error('May not delete: ' + resolved))
54   }
55
56   var options = { log: log.silly.bind(log, 'vacuum-fs') }
57   if (npm.config.get('force') || !gently) options.purge = true
58   if (base) options.base = normalize(resolve(npm.prefix, base))
59
60   if (!gently) {
61     log.verbose('gentlyRm', "don't care about contents; nuking", resolved)
62     return vacuum(resolved, options, cb)
63   }
64
65   var parent = options.base = normalize(base ? resolve(npm.prefix, base) : npm.prefix)
66
67   // is the parent directory managed by npm?
68   log.silly('gentlyRm', 'verifying', parent, 'is an npm working directory')
69   some(prefixes, isManaged(parent), function (er, matched) {
70     if (er) return cb(er)
71
72     if (!matched) {
73       log.error('gentlyRm', 'containing path', parent, "isn't under npm's control")
74       return clobberFail(resolved, parent, cb)
75     }
76     log.silly('gentlyRm', 'containing path', parent, "is under npm's control, in", matched)
77
78     // is the target directly contained within the (now known to be
79     // managed) parent?
80     if (isInside(resolved, parent)) {
81       log.silly('gentlyRm', 'deletion target', resolved, 'is under', parent)
82       log.verbose('gentlyRm', 'vacuuming from', resolved, 'up to', parent)
83       return vacuum(resolved, options, cb)
84     }
85     log.silly('gentlyRm', resolved, 'is not under', parent)
86
87     // the target isn't directly within the parent, but is it itself managed?
88     log.silly('gentlyRm', 'verifying', resolved, 'is an npm working directory')
89     some(prefixes, isManaged(resolved), function (er, matched) {
90       if (er) return cb(er)
91
92       if (matched) {
93         log.silly('gentlyRm', resolved, "is under npm's control, in", matched)
94         options.base = matched
95         log.verbose('gentlyRm', 'removing', resolved, 'with base', options.base)
96         return vacuum(resolved, options, cb)
97       }
98       log.verbose('gentlyRm', resolved, "is not under npm's control")
99
100       // the target isn't managed directly, but maybe it's a link...
101       log.silly('gentlyRm', 'checking to see if', resolved, 'is a link')
102       lstat(resolved, function (er, stat) {
103         if (er) {
104           // race conditions are common when unbuilding
105           if (er.code === 'ENOENT') return cb(null)
106           return cb(er)
107         }
108
109         if (!stat.isSymbolicLink()) {
110           log.error('gentlyRm', resolved, 'is outside', parent, 'and not a link')
111           return clobberFail(resolved, parent, cb)
112         }
113
114         // ...and maybe the link source, when read...
115         log.silly('gentlyRm', resolved, 'is a link')
116         readlink(resolved, function (er, link) {
117           if (er) {
118             // race conditions are common when unbuilding
119             if (er.code === 'ENOENT') return cb(null)
120             return cb(er)
121           }
122
123           // ...is inside the managed parent
124           var source = resolve(dirname(resolved), link)
125           if (isInside(source, parent)) {
126             log.silly('gentlyRm', source, 'symlink target', resolved, 'is inside', parent)
127             log.verbose('gentlyRm', 'vacuuming', resolved)
128             return vacuum(resolved, options, cb)
129           }
130
131           log.error('gentlyRm', source, 'symlink target', resolved, 'is not controlled by npm', parent)
132           return clobberFail(target, parent, cb)
133         })
134       })
135     })
136   })
137 }
138
139 var resolvedPaths = {}
140 function isManaged (target) {
141   return function predicate (path, cb) {
142     if (!path) {
143       log.verbose('isManaged', 'no path passed for target', target)
144       return cb(null, false)
145     }
146
147     asyncMap([path, target], resolveSymlink, function (er, results) {
148       if (er) {
149         if (er.code === 'ENOENT') return cb(null, false)
150
151         return cb(er)
152       }
153
154       var path = results[0]
155       var target = results[1]
156       var inside = isInside(target, path)
157       if (!inside) log.silly('isManaged', target, 'is not inside', path)
158
159       return cb(null, inside && path)
160     })
161   }
162
163   function resolveSymlink (toResolve, cb) {
164     var resolved = resolve(npm.prefix, toResolve)
165
166     // if the path has already been memoized, return immediately
167     var cached = resolvedPaths[resolved]
168     if (cached) return cb(null, cached)
169
170     // otherwise, check the path
171     lstat(resolved, function (er, stat) {
172       if (er) return cb(er)
173
174       // if it's not a link, cache & return the path itself
175       if (!stat.isSymbolicLink()) {
176         resolvedPaths[resolved] = resolved
177         return cb(null, resolved)
178       }
179
180       // otherwise, cache & return the link's source
181       readlink(resolved, function (er, source) {
182         if (er) return cb(er)
183
184         resolved = resolve(resolved, source)
185         resolvedPaths[resolved] = resolved
186         cb(null, resolved)
187       })
188     })
189   }
190 }
191
192 function clobberFail (target, root, cb) {
193   var er = new Error('Refusing to delete: ' + target + ' not in ' + root)
194   er.code = 'EEXIST'
195   er.path = target
196   return cb(er)
197 }