scripts.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. var mout = require('mout');
  2. var cmd = require('../util/cmd');
  3. var Q = require('q');
  4. var shellquote = require('shell-quote');
  5. var orderByDependencies = function (packages, installed, json) {
  6. var ordered = [];
  7. installed = mout.object.keys(installed);
  8. var depsSatisfied = function (packageName) {
  9. return mout.array.difference(mout.object.keys(packages[packageName].dependencies), installed, ordered).length === 0;
  10. };
  11. var depsFromBowerJson = json && json.dependencies ? mout.object.keys(json.dependencies) : [];
  12. var packageNames = mout.object.keys(packages);
  13. //get the list of the packages that are specified in bower.json in that order
  14. //its nice to maintain that order for users
  15. var desiredOrder = mout.array.intersection(depsFromBowerJson, packageNames);
  16. //then add to the end any remaining packages that werent in bower.json
  17. desiredOrder = desiredOrder.concat(mout.array.difference(packageNames, desiredOrder));
  18. //the desired order isn't necessarily a correct dependency specific order
  19. //so we ensure that below
  20. var resolvedOne = true;
  21. while (resolvedOne) {
  22. resolvedOne = false;
  23. for (var i = 0; i < desiredOrder.length; i++) {
  24. var packageName = desiredOrder[i];
  25. if (depsSatisfied(packageName)) {
  26. ordered.push(packageName);
  27. mout.array.remove(desiredOrder, packageName);
  28. //as soon as we resolve a package start the loop again
  29. resolvedOne = true;
  30. break;
  31. }
  32. }
  33. if (!resolvedOne && desiredOrder.length > 0) {
  34. //if we're here then some package(s) doesn't have all its deps satisified
  35. //so lets just jam those names on the end
  36. ordered = ordered.concat(desiredOrder);
  37. }
  38. }
  39. return ordered;
  40. };
  41. var run = function (cmdString, action, logger, config) {
  42. logger.action(action, cmdString);
  43. //pass env + BOWER_PID so callees can identify a preinstall+postinstall from the same bower instance
  44. var env = mout.object.mixIn({ 'BOWER_PID': process.pid }, process.env);
  45. var args = shellquote.parse(cmdString, env);
  46. var cmdName = args[0];
  47. mout.array.remove(args, cmdName); //no rest() in mout
  48. var options = {
  49. cwd: config.cwd,
  50. env: env
  51. };
  52. var promise = cmd(cmdName, args, options);
  53. promise.progress(function (progress) {
  54. progress.split('\n').forEach(function (line) {
  55. if (line) {
  56. logger.action(action, line);
  57. }
  58. });
  59. });
  60. return promise;
  61. };
  62. var hook = function (action, ordered, config, logger, packages, installed, json) {
  63. if (mout.object.keys(packages).length === 0 || !config.scripts || !config.scripts[action]) {
  64. /*jshint newcap: false */
  65. return Q();
  66. }
  67. var orderedPackages = ordered ? orderByDependencies(packages, installed, json) : mout.object.keys(packages);
  68. var cmdString = mout.string.replace(config.scripts[action], '%', orderedPackages.join(' '));
  69. return run(cmdString, action, logger, config);
  70. };
  71. module.exports = {
  72. preuninstall: mout.function.partial(hook, 'preuninstall', false),
  73. preinstall: mout.function.partial(hook, 'preinstall', true),
  74. postinstall: mout.function.partial(hook, 'postinstall', true),
  75. //only exposed for test
  76. _orderByDependencies: orderByDependencies
  77. };