pack-directory.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. "use strict";
  2. const path = require("path");
  3. const packlist = require("npm-packlist");
  4. const log = require("npmlog");
  5. const tar = require("tar");
  6. const tempWrite = require("temp-write");
  7. const { getPacked } = require("@lerna/get-packed");
  8. const { Package } = require("@lerna/package");
  9. const { runLifecycle } = require("@lerna/run-lifecycle");
  10. module.exports.packDirectory = packDirectory;
  11. /**
  12. * @typedef {object} PackConfig
  13. * @property {typeof log} [log]
  14. * @property {string} [lernaCommand] If "publish", run "prepublishOnly" lifecycle
  15. * @property {boolean} [ignorePrepublish]
  16. */
  17. /**
  18. * Pack a directory suitable for publishing, writing tarball to a tempfile.
  19. * @param {Package|string} _pkg Package instance or path to manifest
  20. * @param {string} dir to pack
  21. * @param {PackConfig} options
  22. */
  23. function packDirectory(_pkg, dir, options) {
  24. const pkg = Package.lazy(_pkg, dir);
  25. const opts = {
  26. log,
  27. ...options,
  28. };
  29. opts.log.verbose("pack-directory", path.relative(".", pkg.contents));
  30. let chain = Promise.resolve();
  31. if (opts.ignorePrepublish !== true) {
  32. chain = chain.then(() => runLifecycle(pkg, "prepublish", opts));
  33. }
  34. chain = chain.then(() => runLifecycle(pkg, "prepare", opts));
  35. if (opts.lernaCommand === "publish") {
  36. chain = chain.then(() => pkg.refresh());
  37. chain = chain.then(() => runLifecycle(pkg, "prepublishOnly", opts));
  38. chain = chain.then(() => pkg.refresh());
  39. }
  40. chain = chain.then(() => runLifecycle(pkg, "prepack", opts));
  41. chain = chain.then(() => pkg.refresh());
  42. chain = chain.then(() => packlist({ path: pkg.contents }));
  43. chain = chain.then((files) =>
  44. tar.create(
  45. {
  46. cwd: pkg.contents,
  47. prefix: "package/",
  48. portable: true,
  49. // Provide a specific date in the 1980s for the benefit of zip,
  50. // which is confounded by files dated at the Unix epoch 0.
  51. mtime: new Date("1985-10-26T08:15:00.000Z"),
  52. gzip: true,
  53. },
  54. // NOTE: node-tar does some Magic Stuff depending on prefixes for files
  55. // specifically with @ signs, so we just neutralize that one
  56. // and any such future "features" by prepending `./`
  57. files.map((f) => `./${f}`)
  58. )
  59. );
  60. chain = chain.then((stream) => tempWrite(stream, getTarballName(pkg)));
  61. chain = chain.then((tarFilePath) =>
  62. getPacked(pkg, tarFilePath).then((packed) =>
  63. Promise.resolve()
  64. .then(() => runLifecycle(pkg, "postpack", opts))
  65. .then(() => packed)
  66. )
  67. );
  68. return chain;
  69. }
  70. function getTarballName(pkg) {
  71. const name =
  72. pkg.name[0] === "@"
  73. ? // scoped packages get special treatment
  74. pkg.name.substr(1).replace(/\//g, "-")
  75. : pkg.name;
  76. return `${name}-${pkg.version}.tgz`;
  77. }