1 | module.exports = unbuild
|
2 | module.exports.rmStuff = rmStuff
|
3 | unbuild.usage = 'npm unbuild <folder>\n(this is plumbing)'
|
4 |
|
5 | const readJson = require('read-package-json')
|
6 | const gentlyRm = require('./utils/gently-rm.js')
|
7 | const npm = require('./npm.js')
|
8 | const path = require('path')
|
9 | const isInside = require('path-is-inside')
|
10 | const lifecycle = require('./utils/lifecycle.js')
|
11 | const asyncMap = require('slide').asyncMap
|
12 | const chain = require('slide').chain
|
13 | const log = require('npmlog')
|
14 | const build = require('./build.js')
|
15 | const output = require('./utils/output.js')
|
16 |
|
17 |
|
18 |
|
19 | function unbuild (args, silent, cb) {
|
20 | if (typeof silent === 'function') {
|
21 | cb = silent
|
22 | silent = false
|
23 | }
|
24 | asyncMap(args, unbuild_(silent), cb)
|
25 | }
|
26 |
|
27 | function 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 |
|
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 |
|
57 | function rmStuff (pkg, folder, cb) {
|
58 |
|
59 |
|
60 |
|
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 |
|
66 |
|
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 |
|
76 | function 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 |
|
94 | function 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 | }
|