mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-04 23:44:41 +00:00
Keep in-flight Expo activity-result callbacks in the live AppContext until the picker returns, then release the detached registration. Run the lifecycle regression tests with the Android module suite.
125 lines
4.6 KiB
JavaScript
125 lines
4.6 KiB
JavaScript
import { copyFileSync, existsSync, mkdirSync, readdirSync, rmSync } from "node:fs";
|
|
import { spawnSync } from "node:child_process";
|
|
import { join, relative } from "node:path";
|
|
|
|
// In CI we often install a single workspace (e.g. server/relay/website). Only apply patches
|
|
// when the patched dependency is actually present.
|
|
// `cwd` is where patch-package must run from. Packages that npm does not hoist to the
|
|
// workspace root live in their workspace's own node_modules, and patch-package resolves
|
|
// the patch's node_modules/... paths relative to its working directory.
|
|
const patchedPackages = [
|
|
// Backport for expo-modules-core 57.0.23: https://github.com/expo/expo/pull/49634.
|
|
// Also retain in-flight picker callbacks across same-process Activity recreation (#7557).
|
|
// Remove when the installed Expo SDK includes both Activity recreation fixes.
|
|
{
|
|
nodeModulesPath: "node_modules/expo-modules-core",
|
|
patchPrefix: "expo-modules-core+",
|
|
},
|
|
{
|
|
nodeModulesPath: "packages/app/node_modules/react-native-enriched-markdown",
|
|
patchPrefix: "react-native-enriched-markdown+",
|
|
cwd: "packages/app",
|
|
},
|
|
// Remove after react-native-unistyles ships
|
|
// https://github.com/jpudysz/react-native-unistyles/pull/1203.
|
|
{
|
|
nodeModulesPath: "node_modules/react-native-unistyles",
|
|
patchPrefix: "react-native-unistyles+",
|
|
},
|
|
{
|
|
nodeModulesPath: "node_modules/react-native-draggable-flatlist",
|
|
patchPrefix: "react-native-draggable-flatlist+",
|
|
},
|
|
{
|
|
nodeModulesPath: "node_modules/react-native-gesture-handler",
|
|
patchPrefix: "react-native-gesture-handler+",
|
|
},
|
|
// Exports BottomSheetModalInternalProvider so a subtree can host its own sheets on the shared
|
|
// modal stack (see packages/app/src/components/ui/isolated-bottom-sheet-modal/host-scope.tsx), and
|
|
// keeps a dismissing modal's status through its final onChange(-1), so a modal with
|
|
// enableDismissOnClose=false that unmounts while presented still leaves the portal.
|
|
{
|
|
nodeModulesPath: "node_modules/@gorhom/bottom-sheet",
|
|
patchPrefix: "@gorhom+bottom-sheet+",
|
|
},
|
|
{
|
|
nodeModulesPath: "packages/app/node_modules/react-native-svg",
|
|
patchPrefix: "react-native-svg+",
|
|
cwd: "packages/app",
|
|
},
|
|
{
|
|
nodeModulesPath: "node_modules/@mattermost/react-native-paste-input",
|
|
patchPrefix: "@mattermost+react-native-paste-input+",
|
|
},
|
|
{
|
|
nodeModulesPath: "packages/server/node_modules/@opencode-ai/sdk",
|
|
patchPrefix: "@opencode-ai+sdk+",
|
|
cwd: "packages/server",
|
|
},
|
|
];
|
|
|
|
const installedPackages = patchedPackages.filter(({ nodeModulesPath }) =>
|
|
existsSync(nodeModulesPath),
|
|
);
|
|
|
|
if (!existsSync("patches") || installedPackages.length === 0) {
|
|
process.exit(0);
|
|
}
|
|
|
|
const patchFiles = readdirSync("patches").filter((file) => file.endsWith(".patch"));
|
|
|
|
const isWindows = process.platform === "win32";
|
|
const cmd = isWindows ? "patch-package.cmd" : "patch-package";
|
|
|
|
let failed = false;
|
|
for (const [index, { nodeModulesPath, patchPrefix, cwd = "." }] of installedPackages.entries()) {
|
|
const files = patchFiles.filter((file) => file.startsWith(patchPrefix));
|
|
if (files.length === 0) {
|
|
continue;
|
|
}
|
|
const outcome = applyPatches(cwd, files, index);
|
|
if (outcome === "applied") {
|
|
continue;
|
|
}
|
|
failed = true;
|
|
if (outcome === "unavailable") {
|
|
continue;
|
|
}
|
|
// patch-package cannot apply a patch that changed after an earlier version of it was
|
|
// applied. Without the package, the next install fetches it clean and applies the patch.
|
|
rmSync(nodeModulesPath, { recursive: true, force: true });
|
|
console.error(
|
|
`postinstall-patches: removed ${nodeModulesPath} because its patch did not apply. ` +
|
|
"Run npm install again to reinstall it with the current patch. " +
|
|
"If it fails again on the clean package, the patch is out of date and must be regenerated.",
|
|
);
|
|
}
|
|
|
|
process.exit(failed ? 1 : 0);
|
|
|
|
function applyPatches(cwd, files, index) {
|
|
const tempPatchDir = join(".tmp", `postinstall-patches-${process.pid}-${index}`);
|
|
mkdirSync(tempPatchDir, { recursive: true });
|
|
for (const patchFile of files) {
|
|
copyFileSync(join("patches", patchFile), join(tempPatchDir, patchFile));
|
|
}
|
|
|
|
let result;
|
|
try {
|
|
result = spawnSync(cmd, ["--patch-dir", relative(cwd, tempPatchDir), "--error-on-fail"], {
|
|
cwd,
|
|
shell: isWindows,
|
|
stdio: "inherit",
|
|
windowsHide: true,
|
|
});
|
|
} finally {
|
|
rmSync(tempPatchDir, { recursive: true, force: true });
|
|
}
|
|
|
|
if (result.error) {
|
|
console.error("postinstall-patches: patch-package failed to spawn:", result.error.message);
|
|
return "unavailable";
|
|
}
|
|
return result.status === 0 ? "applied" : "rejected";
|
|
}
|