copy.js 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import arg from 'arg';
  2. import { globby as glob } from 'globby';
  3. import { promises as fs, readFileSync } from 'node:fs';
  4. import { posix } from 'node:path';
  5. import tar from 'tar';
  6. const { resolve, dirname, sep, join } = posix;
  7. /** @type {import('arg').Spec} */
  8. const spec = {
  9. '--tgz': Boolean,
  10. };
  11. export default async function copy() {
  12. let { _: patterns, ['--tgz']: isCompress } = arg(spec);
  13. patterns = patterns.slice(1);
  14. if (isCompress) {
  15. const files = await glob(patterns, { gitignore: true });
  16. const rootDir = resolveRootDir(files);
  17. const destDir = rootDir.replace(/^[^/]+/, 'dist');
  18. const templates = files.reduce((acc, curr) => {
  19. const name = curr.replace(rootDir, '').slice(1).split(sep)[0];
  20. if (acc[name]) {
  21. acc[name].push(resolve(curr));
  22. } else {
  23. acc[name] = [resolve(curr)];
  24. }
  25. return acc;
  26. }, {});
  27. let meta = {};
  28. return Promise.all(
  29. Object.entries(templates).map(([template, files]) => {
  30. const cwd = resolve(join(rootDir, template));
  31. const dest = join(destDir, `${template}.tgz`);
  32. const metafile = files.find((f) => f.endsWith('meta.json'));
  33. if (metafile) {
  34. files = files.filter((f) => f !== metafile);
  35. meta[template] = JSON.parse(readFileSync(metafile).toString());
  36. }
  37. return fs.mkdir(dirname(dest), { recursive: true }).then(() =>
  38. tar.create(
  39. {
  40. gzip: true,
  41. portable: true,
  42. file: dest,
  43. cwd,
  44. },
  45. files.map((f) => f.replace(cwd, '').slice(1))
  46. )
  47. );
  48. })
  49. ).then(() => {
  50. if (Object.keys(meta).length > 0) {
  51. return fs.writeFile(resolve(destDir, 'meta.json'), JSON.stringify(meta, null, 2));
  52. }
  53. });
  54. }
  55. const files = await glob(patterns);
  56. await Promise.all(
  57. files.map((file) => {
  58. const dest = resolve(file.replace(/^[^/]+/, 'dist'));
  59. return fs
  60. .mkdir(dirname(dest), { recursive: true })
  61. .then(() => fs.copyFile(resolve(file), dest, fs.constants.COPYFILE_FICLONE));
  62. })
  63. );
  64. }
  65. function resolveRootDir(files) {
  66. return files
  67. .reduce((acc, curr) => {
  68. const currParts = curr.split(sep);
  69. if (acc.length === 0) return currParts;
  70. const result = [];
  71. currParts.forEach((part, i) => {
  72. if (acc[i] === part) result.push(part);
  73. });
  74. return result;
  75. }, [])
  76. .join(sep);
  77. }