• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict'
2var fs = require('graceful-fs')
3var path = require('path')
4var chain = require('slide').chain
5var iferr = require('iferr')
6var rimraf = require('rimraf')
7var mkdirp = require('gentle-fs').mkdir
8var rmStuff = require('../../unbuild.js').rmStuff
9var lifecycle = require('../../utils/lifecycle.js')
10var move = require('../../utils/move.js')
11
12/*
13  Move a module from one point in the node_modules tree to another.
14  Do not disturb either the source or target location's node_modules
15  folders.
16*/
17
18module.exports = function (staging, pkg, log, next) {
19  log.silly('move', pkg.fromPath, pkg.path)
20  chain([
21    [lifecycle, pkg.package, 'preuninstall', pkg.fromPath, { failOk: true }],
22    [lifecycle, pkg.package, 'uninstall', pkg.fromPath, { failOk: true }],
23    [rmStuff, pkg.package, pkg.fromPath],
24    [lifecycle, pkg.package, 'postuninstall', pkg.fromPath, { failOk: true }],
25    [moveModuleOnly, pkg.fromPath, pkg.path, log],
26    [lifecycle, pkg.package, 'preinstall', pkg.path, { failOk: true }],
27    [removeEmptyParents, path.resolve(pkg.fromPath, '..')]
28  ], next)
29}
30
31function removeEmptyParents (pkgdir, next) {
32  fs.rmdir(pkgdir, function (er) {
33    // FIXME: Make sure windows does what we want here
34    if (er && er.code !== 'ENOENT') return next()
35    removeEmptyParents(path.resolve(pkgdir, '..'), next)
36  })
37}
38
39function moveModuleOnly (from, to, log, done) {
40  var fromModules = path.join(from, 'node_modules')
41  var tempFromModules = from + '.node_modules'
42  var toModules = path.join(to, 'node_modules')
43  var tempToModules = to + '.node_modules'
44
45  log.silly('move', 'move existing destination node_modules away', toModules)
46
47  move(toModules, tempToModules).then(removeDestination(done), removeDestination(done))
48
49  function removeDestination (next) {
50    return function (er) {
51      log.silly('move', 'remove existing destination', to)
52      if (er) {
53        rimraf(to, iferr(next, makeDestination(next)))
54      } else {
55        rimraf(to, iferr(next, makeDestination(iferr(next, moveToModulesBack(next)))))
56      }
57    }
58  }
59
60  function moveToModulesBack (next) {
61    return function () {
62      log.silly('move', 'move existing destination node_modules back', toModules)
63      move(tempToModules, toModules).then(next, done)
64    }
65  }
66
67  function makeDestination (next) {
68    return function () {
69      log.silly('move', 'make sure destination parent exists', path.resolve(to, '..'))
70      mkdirp(path.resolve(to, '..'), iferr(done, moveNodeModules(next)))
71    }
72  }
73
74  function moveNodeModules (next) {
75    return function () {
76      log.silly('move', 'move source node_modules away', fromModules)
77      move(fromModules, tempFromModules).then(doMove(moveNodeModulesBack(next)), doMove(next))
78    }
79  }
80
81  function doMove (next) {
82    return function () {
83      log.silly('move', 'move module dir to final dest', from, to)
84      move(from, to).then(next, done)
85    }
86  }
87
88  function moveNodeModulesBack (next) {
89    return function () {
90      mkdirp(from, iferr(done, function () {
91        log.silly('move', 'put source node_modules back', fromModules)
92        move(tempFromModules, fromModules).then(next, done)
93      }))
94    }
95  }
96}
97