Adapt the npmInstall script so that it works when packages are linked
This commit is contained in:
parent
c593f5cb97
commit
c423e4cacc
@ -125,7 +125,54 @@ if (testAppPaths.length === 0) {
|
|||||||
process.exit(-1);
|
process.exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
testAppPaths.forEach(testAppPath => execSync("yarn install", { cwd: testAppPath }));
|
testAppPaths.forEach(testAppPath => {
|
||||||
|
const packageJsonFilePath = pathJoin(testAppPath, "package.json");
|
||||||
|
|
||||||
|
const packageJsonContent = fs.readFileSync(packageJsonFilePath);
|
||||||
|
|
||||||
|
const parsedPackageJson = JSON.parse(packageJsonContent.toString("utf8")) as {
|
||||||
|
scripts?: Record<string, string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
let hasPostInstallOrPrepareScript = false;
|
||||||
|
|
||||||
|
if (parsedPackageJson.scripts !== undefined) {
|
||||||
|
for (const scriptName of ["postinstall", "prepare"]) {
|
||||||
|
if (parsedPackageJson.scripts[scriptName] === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasPostInstallOrPrepareScript = true;
|
||||||
|
|
||||||
|
delete parsedPackageJson.scripts[scriptName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasPostInstallOrPrepareScript) {
|
||||||
|
fs.writeFileSync(
|
||||||
|
packageJsonFilePath,
|
||||||
|
Buffer.from(JSON.stringify(parsedPackageJson, null, 2), "utf8")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const restorePackageJson = () => {
|
||||||
|
if (!hasPostInstallOrPrepareScript) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(packageJsonFilePath, packageJsonContent);
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
execSync("yarn install", { cwd: testAppPath });
|
||||||
|
} catch (error) {
|
||||||
|
restorePackageJson();
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
restorePackageJson();
|
||||||
|
});
|
||||||
|
|
||||||
console.log("=== Linking common dependencies ===");
|
console.log("=== Linking common dependencies ===");
|
||||||
|
|
||||||
@ -172,4 +219,20 @@ testAppPaths.forEach(testAppPath =>
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
testAppPaths.forEach(testAppPath => {
|
||||||
|
const { scripts = {} } = JSON.parse(
|
||||||
|
fs.readFileSync(pathJoin(testAppPath, "package.json")).toString("utf8")
|
||||||
|
) as {
|
||||||
|
scripts?: Record<string, string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const scriptName of ["postinstall", "prepare"]) {
|
||||||
|
if (scripts[scriptName] === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
execSync(`yarn run ${scriptName}`, { cwd: testAppPath });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export {};
|
export {};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { join as pathJoin, relative as pathRelative, dirname as pathDirname } from "path";
|
import { relative as pathRelative, dirname as pathDirname } from "path";
|
||||||
import type { BuildContext } from "../shared/buildContext";
|
import type { BuildContext } from "../shared/buildContext";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
@ -14,7 +14,6 @@ import { is } from "tsafe/is";
|
|||||||
import { id } from "tsafe/id";
|
import { id } from "tsafe/id";
|
||||||
import { npmInstall } from "../tools/npmInstall";
|
import { npmInstall } from "../tools/npmInstall";
|
||||||
import { copyBoilerplate } from "./copyBoilerplate";
|
import { copyBoilerplate } from "./copyBoilerplate";
|
||||||
import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath";
|
|
||||||
|
|
||||||
type BuildContextLike = BuildContextLike_getLatestsSemVersionedTag & {
|
type BuildContextLike = BuildContextLike_getLatestsSemVersionedTag & {
|
||||||
fetchOptions: BuildContext["fetchOptions"];
|
fetchOptions: BuildContext["fetchOptions"];
|
||||||
@ -121,20 +120,7 @@ export async function initializeAccountTheme_singlePage(params: {
|
|||||||
JSON.stringify(parsedPackageJson, undefined, 4)
|
JSON.stringify(parsedPackageJson, undefined, 4)
|
||||||
);
|
);
|
||||||
|
|
||||||
run_npm_install: {
|
|
||||||
if (
|
|
||||||
JSON.parse(
|
|
||||||
fs
|
|
||||||
.readFileSync(pathJoin(getThisCodebaseRootDirPath(), "package.json"))
|
|
||||||
.toString("utf8")
|
|
||||||
)["version"] === "0.0.0"
|
|
||||||
) {
|
|
||||||
//NOTE: Linked version
|
|
||||||
break run_npm_install;
|
|
||||||
}
|
|
||||||
|
|
||||||
npmInstall({ packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath) });
|
npmInstall({ packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath) });
|
||||||
}
|
|
||||||
|
|
||||||
copyBoilerplate({
|
copyBoilerplate({
|
||||||
accountThemeType: "Single-Page",
|
accountThemeType: "Single-Page",
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { join as pathJoin } from "path";
|
import { join as pathJoin, dirname as pathDirname } from "path";
|
||||||
import * as child_process from "child_process";
|
import * as child_process from "child_process";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { assert, type Equals } from "tsafe/assert";
|
||||||
|
import { id } from "tsafe/id";
|
||||||
|
import { is } from "tsafe/is";
|
||||||
|
import { objectKeys } from "tsafe/objectKeys";
|
||||||
|
import { getAbsoluteAndInOsFormatPath } from "./getAbsoluteAndInOsFormatPath";
|
||||||
|
import { exclude } from "tsafe/exclude";
|
||||||
|
|
||||||
export function npmInstall(params: { packageJsonDirPath: string }) {
|
export function npmInstall(params: { packageJsonDirPath: string }) {
|
||||||
const { packageJsonDirPath } = params;
|
const { packageJsonDirPath } = params;
|
||||||
@ -48,6 +55,27 @@ export function npmInstall(params: { packageJsonDirPath: string }) {
|
|||||||
|
|
||||||
console.log(`Installing the new dependencies...`);
|
console.log(`Installing the new dependencies...`);
|
||||||
|
|
||||||
|
install_without_breaking_links: {
|
||||||
|
if (packageManagerBinName !== "yarn") {
|
||||||
|
break install_without_breaking_links;
|
||||||
|
}
|
||||||
|
|
||||||
|
const garronejLinkInfos = getGarronejLinkInfos({ packageJsonDirPath });
|
||||||
|
|
||||||
|
if (garronejLinkInfos === undefined) {
|
||||||
|
break install_without_breaking_links;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(chalk.green("Installing in a way that won't break the links..."));
|
||||||
|
|
||||||
|
installWithoutBreakingLinks({
|
||||||
|
packageJsonDirPath,
|
||||||
|
garronejLinkInfos
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
child_process.execSync(`${packageManagerBinName} install`, {
|
child_process.execSync(`${packageManagerBinName} install`, {
|
||||||
cwd: packageJsonDirPath,
|
cwd: packageJsonDirPath,
|
||||||
@ -61,3 +89,362 @@ export function npmInstall(params: { packageJsonDirPath: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getGarronejLinkInfos(params: {
|
||||||
|
packageJsonDirPath: string;
|
||||||
|
}): { linkedModuleNames: string[]; yarnHomeDirPath: string } | undefined {
|
||||||
|
const { packageJsonDirPath } = params;
|
||||||
|
|
||||||
|
const nodeModuleDirPath = pathJoin(packageJsonDirPath, "node_modules");
|
||||||
|
|
||||||
|
if (!fs.existsSync(nodeModuleDirPath)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const linkedModuleNames: string[] = [];
|
||||||
|
|
||||||
|
let yarnHomeDirPath: string | undefined = undefined;
|
||||||
|
|
||||||
|
const getIsLinkedByGarronejScript = (path: string) => {
|
||||||
|
let realPath: string;
|
||||||
|
|
||||||
|
try {
|
||||||
|
realPath = fs.readlinkSync(path);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const doesIncludeYarnHome = realPath.includes(".yarn_home");
|
||||||
|
|
||||||
|
if (!doesIncludeYarnHome) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_yarnHomeDirPath: {
|
||||||
|
if (yarnHomeDirPath !== undefined) {
|
||||||
|
break set_yarnHomeDirPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [firstElement] = getAbsoluteAndInOsFormatPath({
|
||||||
|
pathIsh: realPath,
|
||||||
|
cwd: pathDirname(path)
|
||||||
|
}).split(".yarn_home");
|
||||||
|
|
||||||
|
yarnHomeDirPath = pathJoin(firstElement, ".yarn_home");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const basename of fs.readdirSync(nodeModuleDirPath)) {
|
||||||
|
const path = pathJoin(nodeModuleDirPath, basename);
|
||||||
|
|
||||||
|
if (fs.lstatSync(path).isSymbolicLink()) {
|
||||||
|
if (basename.startsWith("@")) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getIsLinkedByGarronejScript(path)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedModuleNames.push(basename);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.lstatSync(path).isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basename.startsWith("@")) {
|
||||||
|
for (const subBasename of fs.readdirSync(path)) {
|
||||||
|
const subPath = pathJoin(path, subBasename);
|
||||||
|
|
||||||
|
if (!fs.lstatSync(subPath).isSymbolicLink()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getIsLinkedByGarronejScript(subPath)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedModuleNames.push(`${basename}/${subBasename}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (yarnHomeDirPath === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { linkedModuleNames, yarnHomeDirPath };
|
||||||
|
}
|
||||||
|
|
||||||
|
function installWithoutBreakingLinks(params: {
|
||||||
|
packageJsonDirPath: string;
|
||||||
|
garronejLinkInfos: Exclude<ReturnType<typeof getGarronejLinkInfos>, undefined>;
|
||||||
|
}) {
|
||||||
|
const {
|
||||||
|
packageJsonDirPath,
|
||||||
|
garronejLinkInfos: { linkedModuleNames, yarnHomeDirPath }
|
||||||
|
} = params;
|
||||||
|
|
||||||
|
const parsedPackageJson = (() => {
|
||||||
|
const packageJsonFilePath = pathJoin(packageJsonDirPath, "package.json");
|
||||||
|
|
||||||
|
type ParsedPackageJson = {
|
||||||
|
scripts?: Record<string, string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const zParsedPackageJson = (() => {
|
||||||
|
type TargetType = ParsedPackageJson;
|
||||||
|
|
||||||
|
const zTargetType = z.object({
|
||||||
|
scripts: z.record(z.string()).optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
type InferredType = z.infer<typeof zTargetType>;
|
||||||
|
|
||||||
|
assert<Equals<TargetType, InferredType>>;
|
||||||
|
|
||||||
|
return id<z.ZodType<TargetType>>(zTargetType);
|
||||||
|
})();
|
||||||
|
|
||||||
|
const parsedPackageJson = JSON.parse(
|
||||||
|
fs.readFileSync(packageJsonFilePath).toString("utf8")
|
||||||
|
) as unknown;
|
||||||
|
|
||||||
|
zParsedPackageJson.parse(parsedPackageJson);
|
||||||
|
assert(is<ParsedPackageJson>(parsedPackageJson));
|
||||||
|
|
||||||
|
return parsedPackageJson;
|
||||||
|
})();
|
||||||
|
|
||||||
|
const isImplementedScriptByName = {
|
||||||
|
postinstall: false,
|
||||||
|
prepare: false
|
||||||
|
};
|
||||||
|
|
||||||
|
delete_postinstall_script: {
|
||||||
|
if (parsedPackageJson.scripts === undefined) {
|
||||||
|
break delete_postinstall_script;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const scriptName of objectKeys(isImplementedScriptByName)) {
|
||||||
|
if (parsedPackageJson.scripts[scriptName] === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
isImplementedScriptByName[scriptName] = true;
|
||||||
|
|
||||||
|
delete parsedPackageJson.scripts[scriptName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tmpProjectDirPath = pathJoin(yarnHomeDirPath, "tmpProject");
|
||||||
|
|
||||||
|
if (fs.existsSync(tmpProjectDirPath)) {
|
||||||
|
fs.rmdirSync(tmpProjectDirPath, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.mkdirSync(tmpProjectDirPath, { recursive: true });
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
pathJoin(tmpProjectDirPath, "package.json"),
|
||||||
|
JSON.stringify(parsedPackageJson, undefined, 4)
|
||||||
|
);
|
||||||
|
|
||||||
|
const YARN_LOCK = "yarn.lock";
|
||||||
|
|
||||||
|
fs.copyFileSync(
|
||||||
|
pathJoin(packageJsonDirPath, YARN_LOCK),
|
||||||
|
pathJoin(tmpProjectDirPath, YARN_LOCK)
|
||||||
|
);
|
||||||
|
|
||||||
|
child_process.execSync(`yarn install`, {
|
||||||
|
cwd: tmpProjectDirPath,
|
||||||
|
stdio: "inherit"
|
||||||
|
});
|
||||||
|
|
||||||
|
// NOTE: Moving the modules from the tmp project to the actual project
|
||||||
|
// without messing up the links.
|
||||||
|
{
|
||||||
|
const { getAreSameVersions } = (() => {
|
||||||
|
type ParsedPackageJson = {
|
||||||
|
version: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const zParsedPackageJson = (() => {
|
||||||
|
type TargetType = ParsedPackageJson;
|
||||||
|
|
||||||
|
const zTargetType = z.object({
|
||||||
|
version: z.string()
|
||||||
|
});
|
||||||
|
|
||||||
|
type InferredType = z.infer<typeof zTargetType>;
|
||||||
|
|
||||||
|
assert<Equals<TargetType, InferredType>>;
|
||||||
|
|
||||||
|
return id<z.ZodType<TargetType>>(zTargetType);
|
||||||
|
})();
|
||||||
|
|
||||||
|
function readVersion(params: { moduleDirPath: string }): string {
|
||||||
|
const { moduleDirPath } = params;
|
||||||
|
|
||||||
|
const packageJsonFilePath = pathJoin(moduleDirPath, "package.json");
|
||||||
|
|
||||||
|
const packageJson = JSON.parse(
|
||||||
|
fs.readFileSync(packageJsonFilePath).toString("utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
zParsedPackageJson.parse(packageJson);
|
||||||
|
assert(is<ParsedPackageJson>(packageJson));
|
||||||
|
|
||||||
|
return packageJson.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAreSameVersions(params: {
|
||||||
|
moduleDirPath_a: string;
|
||||||
|
moduleDirPath_b: string;
|
||||||
|
}): boolean {
|
||||||
|
const { moduleDirPath_a, moduleDirPath_b } = params;
|
||||||
|
|
||||||
|
return (
|
||||||
|
readVersion({ moduleDirPath: moduleDirPath_a }) ===
|
||||||
|
readVersion({ moduleDirPath: moduleDirPath_b })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { getAreSameVersions };
|
||||||
|
})();
|
||||||
|
|
||||||
|
const nodeModulesDirPath_tmpProject = pathJoin(tmpProjectDirPath, "node_modules");
|
||||||
|
const nodeModulesDirPath = pathJoin(packageJsonDirPath, "node_modules");
|
||||||
|
|
||||||
|
const modulePaths = fs
|
||||||
|
.readdirSync(nodeModulesDirPath_tmpProject)
|
||||||
|
.map(basename => {
|
||||||
|
if (basename.startsWith(".")) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const path = pathJoin(nodeModulesDirPath_tmpProject, basename);
|
||||||
|
|
||||||
|
if (basename.startsWith("@")) {
|
||||||
|
return fs
|
||||||
|
.readdirSync(path)
|
||||||
|
.map(subBasename => {
|
||||||
|
if (subBasename.startsWith(".")) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const subPath = pathJoin(path, subBasename);
|
||||||
|
|
||||||
|
if (!fs.lstatSync(subPath).isDirectory()) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
moduleName: `${basename}/${subBasename}`,
|
||||||
|
moduleDirPath_tmpProject: subPath,
|
||||||
|
moduleDirPath: pathJoin(
|
||||||
|
nodeModulesDirPath,
|
||||||
|
basename,
|
||||||
|
subBasename
|
||||||
|
)
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(exclude(undefined));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.lstatSync(path).isDirectory()) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
moduleName: basename,
|
||||||
|
moduleDirPath_tmpProject: path,
|
||||||
|
moduleDirPath: pathJoin(nodeModulesDirPath, basename)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
})
|
||||||
|
.filter(exclude(undefined))
|
||||||
|
.flat();
|
||||||
|
|
||||||
|
for (const {
|
||||||
|
moduleName,
|
||||||
|
moduleDirPath,
|
||||||
|
moduleDirPath_tmpProject
|
||||||
|
} of modulePaths) {
|
||||||
|
if (linkedModuleNames.includes(moduleName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let doesTargetModuleExist = false;
|
||||||
|
|
||||||
|
skip_condition: {
|
||||||
|
if (!fs.existsSync(moduleDirPath)) {
|
||||||
|
break skip_condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
doesTargetModuleExist = true;
|
||||||
|
|
||||||
|
const areSameVersions = getAreSameVersions({
|
||||||
|
moduleDirPath_a: moduleDirPath,
|
||||||
|
moduleDirPath_b: moduleDirPath_tmpProject
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!areSameVersions) {
|
||||||
|
break skip_condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doesTargetModuleExist) {
|
||||||
|
fs.rmdirSync(moduleDirPath, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.renameSync(moduleDirPath_tmpProject, moduleDirPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
move_bin: {
|
||||||
|
const binDirPath_tmpProject = pathJoin(nodeModulesDirPath_tmpProject, ".bin");
|
||||||
|
const binDirPath = pathJoin(nodeModulesDirPath, ".bin");
|
||||||
|
|
||||||
|
if (!fs.existsSync(binDirPath_tmpProject)) {
|
||||||
|
break move_bin;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const basename of fs.readdirSync(binDirPath_tmpProject)) {
|
||||||
|
const path_tmpProject = pathJoin(binDirPath_tmpProject, basename);
|
||||||
|
const path = pathJoin(binDirPath, basename);
|
||||||
|
|
||||||
|
if (fs.existsSync(path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.renameSync(path_tmpProject, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.cpSync(
|
||||||
|
pathJoin(tmpProjectDirPath, YARN_LOCK),
|
||||||
|
pathJoin(packageJsonDirPath, YARN_LOCK)
|
||||||
|
);
|
||||||
|
|
||||||
|
fs.rmdirSync(tmpProjectDirPath, { recursive: true });
|
||||||
|
|
||||||
|
for (const scriptName of objectKeys(isImplementedScriptByName)) {
|
||||||
|
if (!isImplementedScriptByName[scriptName]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
child_process.execSync(`yarn run ${scriptName}`, {
|
||||||
|
cwd: packageJsonDirPath,
|
||||||
|
stdio: "inherit"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user