| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 | module.exports = unbuildmodule.exports.rmStuff = rmStuffunbuild.usage = 'npm unbuild <folder>\n(this is plumbing)'const readJson = require('read-package-json')const gentlyRm = require('./utils/gently-rm.js')const npm = require('./npm.js')const path = require('path')const isInside = require('path-is-inside')const lifecycle = require('./utils/lifecycle.js')const asyncMap = require('slide').asyncMapconst chain = require('slide').chainconst log = require('npmlog')const build = require('./build.js')const output = require('./utils/output.js')// args is a list of folders.// remove any bins/etc, and then delete the folder.function unbuild (args, silent, cb) {  if (typeof silent === 'function') {    cb = silent    silent = false  }  asyncMap(args, unbuild_(silent), cb)}function unbuild_ (silent) {  return function (folder, cb_) {    function cb (er) {      cb_(er, path.relative(npm.root, folder))    }    folder = path.resolve(folder)    const base = isInside(folder, npm.prefix) ? npm.prefix : folder    delete build._didBuild[folder]    log.verbose('unbuild', folder.substr(npm.prefix.length + 1))    readJson(path.resolve(folder, 'package.json'), function (er, pkg) {      // if no json, then just trash it, but no scripts or whatever.      if (er) return gentlyRm(folder, false, base, cb)      chain(        [          [lifecycle, pkg, 'preuninstall', folder, { failOk: true }],          [lifecycle, pkg, 'uninstall', folder, { failOk: true }],          !silent && function (cb) {            output('unbuild ' + pkg._id)            cb()          },          [rmStuff, pkg, folder],          [lifecycle, pkg, 'postuninstall', folder, { failOk: true }],          [gentlyRm, folder, false, base]        ],        cb      )    })  }}function rmStuff (pkg, folder, cb) {  // if it's global, and folder is in {prefix}/node_modules,  // then bins are in {prefix}/bin  // otherwise, then bins are in folder/../.bin  const dir = path.dirname(folder)  const scope = path.basename(dir)  const parent = scope.charAt(0) === '@' ? path.dirname(dir) : dir  const gnm = npm.dir  // gnm might be an absolute path, parent might be relative  // this checks they're the same directory regardless  const top = path.relative(gnm, parent) === ''  log.verbose('unbuild rmStuff', pkg._id, 'from', gnm)  if (!top) log.verbose('unbuild rmStuff', 'in', parent)  asyncMap([rmBins, rmMans], function (fn, cb) {    fn(pkg, folder, parent, top, cb)  }, cb)}function rmBins (pkg, folder, parent, top, cb) {  if (!pkg.bin) return cb()  const binRoot = top ? npm.bin : path.resolve(parent, '.bin')  asyncMap(Object.keys(pkg.bin), function (b, cb) {    if (process.platform === 'win32') {      chain([        [gentlyRm, path.resolve(binRoot, b) + '.ps1', true, folder],        [gentlyRm, path.resolve(binRoot, b) + '.cmd', true, folder],        [gentlyRm, path.resolve(binRoot, b), true, folder]      ], cb)    } else {      gentlyRm(path.resolve(binRoot, b), true, folder, cb)    }  }, gentlyRmBinRoot)  function gentlyRmBinRoot (err) {    if (err || top) return cb(err)    return gentlyRm(binRoot, true, parent, cb)  }}function rmMans (pkg, folder, parent, top, cb) {  if (!pkg.man ||      !top ||      process.platform === 'win32' ||      !npm.config.get('global')) {    return cb()  }  const manRoot = path.resolve(npm.config.get('prefix'), 'share', 'man')  log.verbose('rmMans', 'man files are', pkg.man, 'in', manRoot)  asyncMap(pkg.man, function (man, cb) {    if (Array.isArray(man)) {      man.forEach(rmMan)    } else {      rmMan(man)    }    function rmMan (man) {      log.silly('rmMan', 'preparing to remove', man)      const parseMan = man.match(/(.*\.([0-9]+)(\.gz)?)$/)      if (!parseMan) {        log.error(          'rmMan', man, 'is not a valid name for a man file.',          'Man files must end with a number, ' +          'and optionally a .gz suffix if they are compressed.'        )        return cb()      }      const stem = parseMan[1]      const sxn = parseMan[2]      const gz = parseMan[3] || ''      const bn = path.basename(stem)      const manDest = path.join(        manRoot,        'man' + sxn,        (bn.indexOf(pkg.name) === 0 ? bn : pkg.name + '-' + bn) + '.' + sxn + gz      )      gentlyRm(manDest, true, cb)    }  }, cb)}
 |