UNPKG

4.29 kBJavaScriptView Raw
1module.exports = unbuild
2module.exports.rmStuff = rmStuff
3unbuild.usage = 'npm unbuild <folder>\n(this is plumbing)'
4
5const readJson = require('read-package-json')
6const gentlyRm = require('./utils/gently-rm.js')
7const npm = require('./npm.js')
8const path = require('path')
9const isInside = require('path-is-inside')
10const lifecycle = require('./utils/lifecycle.js')
11const asyncMap = require('slide').asyncMap
12const chain = require('slide').chain
13const log = require('npmlog')
14const build = require('./build.js')
15const output = require('./utils/output.js')
16
17// args is a list of folders.
18// remove any bins/etc, and then delete the folder.
19function unbuild (args, silent, cb) {
20 if (typeof silent === 'function') {
21 cb = silent
22 silent = false
23 }
24 asyncMap(args, unbuild_(silent), cb)
25}
26
27function unbuild_ (silent) {
28 return function (folder, cb_) {
29 function cb (er) {
30 cb_(er, path.relative(npm.root, folder))
31 }
32 folder = path.resolve(folder)
33 const base = isInside(folder, npm.prefix) ? npm.prefix : folder
34 delete build._didBuild[folder]
35 log.verbose('unbuild', folder.substr(npm.prefix.length + 1))
36 readJson(path.resolve(folder, 'package.json'), function (er, pkg) {
37 // if no json, then just trash it, but no scripts or whatever.
38 if (er) return gentlyRm(folder, false, base, cb)
39 chain(
40 [
41 [lifecycle, pkg, 'preuninstall', folder, { failOk: true }],
42 [lifecycle, pkg, 'uninstall', folder, { failOk: true }],
43 !silent && function (cb) {
44 output('unbuild ' + pkg._id)
45 cb()
46 },
47 [rmStuff, pkg, folder],
48 [lifecycle, pkg, 'postuninstall', folder, { failOk: true }],
49 [gentlyRm, folder, false, base]
50 ],
51 cb
52 )
53 })
54 }
55}
56
57function rmStuff (pkg, folder, cb) {
58 // if it's global, and folder is in {prefix}/node_modules,
59 // then bins are in {prefix}/bin
60 // otherwise, then bins are in folder/../.bin
61 const dir = path.dirname(folder)
62 const scope = path.basename(dir)
63 const parent = scope.charAt(0) === '@' ? path.dirname(dir) : dir
64 const gnm = npm.dir
65 // gnm might be an absolute path, parent might be relative
66 // this checks they're the same directory regardless
67 const top = path.relative(gnm, parent) === ''
68
69 log.verbose('unbuild rmStuff', pkg._id, 'from', gnm)
70 if (!top) log.verbose('unbuild rmStuff', 'in', parent)
71 asyncMap([rmBins, rmMans], function (fn, cb) {
72 fn(pkg, folder, parent, top, cb)
73 }, cb)
74}
75
76function rmBins (pkg, folder, parent, top, cb) {
77 if (!pkg.bin) return cb()
78 const binRoot = top ? npm.bin : path.resolve(parent, '.bin')
79 asyncMap(Object.keys(pkg.bin), function (b, cb) {
80 if (process.platform === 'win32') {
81 chain([ [gentlyRm, path.resolve(binRoot, b) + '.cmd', true, folder],
82 [gentlyRm, path.resolve(binRoot, b), true, folder] ], cb)
83 } else {
84 gentlyRm(path.resolve(binRoot, b), true, folder, cb)
85 }
86 }, gentlyRmBinRoot)
87
88 function gentlyRmBinRoot (err) {
89 if (err || top) return cb(err)
90 return gentlyRm(binRoot, true, parent, cb)
91 }
92}
93
94function rmMans (pkg, folder, parent, top, cb) {
95 if (!pkg.man ||
96 !top ||
97 process.platform === 'win32' ||
98 !npm.config.get('global')) {
99 return cb()
100 }
101 const manRoot = path.resolve(npm.config.get('prefix'), 'share', 'man')
102 log.verbose('rmMans', 'man files are', pkg.man, 'in', manRoot)
103 asyncMap(pkg.man, function (man, cb) {
104 if (Array.isArray(man)) {
105 man.forEach(rmMan)
106 } else {
107 rmMan(man)
108 }
109
110 function rmMan (man) {
111 log.silly('rmMan', 'preparing to remove', man)
112 const parseMan = man.match(/(.*\.([0-9]+)(\.gz)?)$/)
113 if (!parseMan) {
114 log.error(
115 'rmMan', man, 'is not a valid name for a man file.',
116 'Man files must end with a number, ' +
117 'and optionally a .gz suffix if they are compressed.'
118 )
119 return cb()
120 }
121
122 const stem = parseMan[1]
123 const sxn = parseMan[2]
124 const gz = parseMan[3] || ''
125 const bn = path.basename(stem)
126 const manDest = path.join(
127 manRoot,
128 'man' + sxn,
129 (bn.indexOf(pkg.name) === 0 ? bn : pkg.name + '-' + bn) + '.' + sxn + gz
130 )
131 gentlyRm(manDest, true, cb)
132 }
133 }, cb)
134}