UNPKG

7.5 kBJavaScriptView Raw
1const path = require('path');
2const fs = require('fs');
3// const glob = require('fast-glob');
4const { getPackageJson, writePackageJson, shell, copyFile, end, getArg } = require('./utils');
5const { logInfo } = require('./log');
6
7const root = process.cwd();
8
9function sortDependencies(target, depsName) {
10 if (!target[depsName]) { return; }
11 const deps = target[depsName];
12 target[depsName] = Object.keys(deps)
13 .map(name => ({ name, version: deps[name] }))
14 .sort((a, b) => a.name > b.name ? 1 : a.name < b.name ? -1 : 0)
15 .reduce((newDeps, { name, version }) => ({
16 ...newDeps,
17 [name]: version,
18 }), {});
19}
20
21function sortAllDependencies(targetPackageJson) {
22 sortDependencies(targetPackageJson, 'dependencies');
23 sortDependencies(targetPackageJson, 'devDependencies');
24 sortDependencies(targetPackageJson, 'peerDependencies');
25}
26
27async function createTarballOf(packagePath, packageJson) {
28 const tarballFileName = path.resolve(packagePath, 'package.tgz');
29 const packageJsonFileName = path.resolve(packagePath, 'package.json');
30 if (!fs.existsSync(packageJsonFileName)) { throw new Error(`Unable to find the package json file at this location: "${packagePath}`); }
31 // const lastModifiedDateOfTarball = getLastModifiedDateOf(tarballFileName);
32 // const lastModifiedDateOfPackageJson = getLastModifiedDateOf(packageJsonFileName);
33 // if (lastModifiedDateOfTarball > lastModifiedDateOfPackageJson) { return tarballFileName; }
34 const { name } = packageJson || getPackageJson({ packagePath });
35 logInfo(`Creating tarball of ${name}...`);
36 const result = await shell('npm pack --loglevel error', { cwd: packagePath, stdout: false });
37 const sourceTarballFileName = path.resolve(packagePath, result.stdout.trim());
38 copyFile(sourceTarballFileName, tarballFileName);
39 fs.unlinkSync(sourceTarballFileName);
40 return tarballFileName;
41}
42
43async function loopThroughLinksFrom(packageJson, delegate) {
44 const links = packageJson['links'] || packageJson['link'] || {};
45 for (const name of Object.keys(links)) {
46 const linkPath = links[name];
47 await delegate(name, linkPath);
48 }
49}
50
51async function makeTarballsOfLinks(tarballPackages) {
52 await Promise.all(tarballPackages.map(({ packagePath }) => createTarballOf(packagePath)));
53}
54
55async function getTarballsOfLinks(packagePath, packageJson) {
56 const tarballPackages = [];
57 packageJson = packageJson || getPackageJson({ packagePath });
58 await loopThroughLinksFrom(packageJson, async (name, linkPath) => {
59 const resolvedLinkPath = path.resolve(packagePath, linkPath);
60 if (!fs.existsSync(resolvedLinkPath)) { throw new Error(`Unable to install as the link for ${name} was invalid: ${linkPath} (resolves to: ${resolvedLinkPath})`); }
61 const tarballFileName = path.join(resolvedLinkPath, './package.tgz');
62 tarballPackages.push(...(await getTarballsOfLinks(resolvedLinkPath)));
63 tarballPackages.push({ packagePath: resolvedLinkPath.toLowerCase(), tarballFileName, name, parentPackages: [packagePath.toLowerCase()] });
64 });
65 return tarballPackages;
66}
67
68/**
69 *
70 * @param {any[]} tarballPackages
71 */
72function removeDuplicatesFromTarballPackages(tarballPackages) {
73 for (let index = tarballPackages.length - 1; index >= 0; index--) {
74 const package = tarballPackages[index];
75 const foundIndex = tarballPackages.findIndex(item => item.packagePath === package.packagePath);
76 if (foundIndex === index) continue;
77 const { parentPackages } = tarballPackages[foundIndex];
78 tarballPackages.splice(index, 1);
79 package.parentPackages.forEach(parentPackage => {
80 if (parentPackages.includes(parentPackage)) return;
81 parentPackages.push(parentPackage);
82 });
83 }
84}
85
86/**
87 *
88 * @param {any[]} tarballPackages
89 */
90function updatePackagesWithTarballLinks(tarballPackages) {
91 const updates = {};
92 tarballPackages.forEach(({ name, tarballFileName, parentPackages }) => parentPackages.forEach(parentPackage => {
93 updates[parentPackage] = (updates[parentPackage] || []);
94 updates[parentPackage].push({ name, tarballFileName });
95 }));
96 Object.entries(updates).forEach(([packagePath, details]) => {
97 const packageJson = getPackageJson({ packagePath, throwErrorIfNotFound: true });
98 sortAllDependencies(packageJson);
99 details.forEach(({ name, tarballFileName }) => {
100 ['dependencies', 'devDependencies'].forEach(location => {
101 if (packageJson[location][name]) packageJson[location][name] = `file:${tarballFileName}`;
102 });
103 });
104 writePackageJson(packageJson, packagePath);
105 });
106}
107
108async function doInstall() {
109 logInfo('Installing dependencies...');
110 return shell('npm install --loglevel=error --color always');
111}
112
113async function removeLinksFromNodeModules(packagePath, packageJson) {
114 packageJson = packageJson || getPackageJson({ packagePath });
115 await loopThroughLinksFrom(packageJson, async name => {
116 const nodeModulesLinkPath = path.resolve(packagePath, 'node_modules', name);
117 if (!fs.existsSync(nodeModulesLinkPath)) { return; }
118 await shell(`rm -rf ${nodeModulesLinkPath}`);
119 });
120}
121
122// async function createSymlinksForLinks(packageJson) {
123// const mandatoryFiles = [
124// 'package.json',
125// ];
126// const globRoot = path.resolve(root, 'node_modules');
127// return loopThroughLinksFrom(packageJson, async (name, linkPath) => {
128// logInfo(`Linking ${name} package...`);
129// linkPath = path.resolve(root, linkPath);
130// const linkPackageJson = require(path.resolve(linkPath, 'package.json'));
131// const rootFiles = linkPackageJson.files || ['dist'];
132// const allFiles = rootFiles.concat(mandatoryFiles);
133// const globPattern = `./**/${name}`;
134// const linkLocations = await glob(globPattern, { cwd: globRoot, onlyDirectories: true, absolute: true });
135// await Promise.all(linkLocations.map(linkLocation => Promise.all(allFiles.map(async fileOrPath => {
136// const localFileOrPath = path.resolve(linkLocation, fileOrPath);
137// const linkFileOrPath = path.resolve(linkPath, fileOrPath);
138// if (fs.existsSync(localFileOrPath)) {
139// if (fs.realpathSync(localFileOrPath) !== localFileOrPath) { return; }
140// await shell(`rm -rf ${localFileOrPath}`, { stdout: false });
141// }
142// if (fs.statSync(linkFileOrPath).isDirectory()) {
143// fs.symlinkSync(linkFileOrPath, localFileOrPath, 'junction');
144// } else {
145// fs.symlinkSync(linkFileOrPath, localFileOrPath, 'file');
146// }
147// }))));
148// });
149// }
150
151module.exports = async function anuxInstall() {
152 const packOnlyInstall = getArg(process.argv, '--pack-only', false, false)
153 logInfo(`Installing...${packOnlyInstall ? ' (pack only)' : ''}`);
154 const packageJson = getPackageJson();
155 sortAllDependencies(packageJson);
156 const tarballPackages = await getTarballsOfLinks(root, packageJson);
157 removeDuplicatesFromTarballPackages(tarballPackages);
158 makeTarballsOfLinks(tarballPackages);
159 updatePackagesWithTarballLinks(tarballPackages);
160 await removeLinksFromNodeModules(root, packageJson);
161 writePackageJson(packageJson);
162 if (packOnlyInstall === true) { return; }
163 try {
164 await doInstall();
165 } catch ({ exitCode, stderr }) {
166 // eslint-disable-next-line no-console
167 console.error(stderr);
168 end(1);
169 }
170 // await createSymlinksForLinks(packageJson);
171 logInfo('Finished installing.');
172};