Skip to content

Commit 06057de

Browse files
committed
Dereference framework directories
1 parent 2577ae4 commit 06057de

File tree

4 files changed

+65
-1
lines changed

4 files changed

+65
-1
lines changed

packages/cmake-rn/src/platforms/apple.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
AppleTriplet as Triplet,
1313
createAppleFramework,
1414
createXCframework,
15+
dereferenceDirectory,
1516
} from "react-native-node-api";
1617

1718
import type { Platform } from "./types.js";
@@ -376,6 +377,18 @@ export const platform: Platform<Triplet[], AppleOpts> = {
376377
}
377378
}
378379

380+
// Make sure none of the frameworks are symlinks
381+
// We do this before creating an xcframework to avoid symlink paths being invalidated
382+
// as the xcframework might be moved to a different location
383+
await Promise.all(
384+
frameworkPaths.map(async (frameworkPath) => {
385+
const stat = await fs.promises.lstat(frameworkPath);
386+
if (stat.isSymbolicLink()) {
387+
await dereferenceDirectory(frameworkPath);
388+
}
389+
}),
390+
);
391+
379392
const extension = xcframeworkExtension ? ".xcframework" : ".apple.node";
380393

381394
assert(

packages/host/src/node/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ export {
2222
determineXCFrameworkFilename,
2323
} from "./prebuilds/apple.js";
2424

25-
export { determineLibraryBasename } from "./path-utils.js";
25+
export {
26+
determineLibraryBasename,
27+
dereferenceDirectory,
28+
} from "./path-utils.js";
2629

2730
export { weakNodeApiPath } from "./weak-node-api.js";

packages/host/src/node/path-utils.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
isNodeApiModule,
1414
stripExtension,
1515
findNodeApiModulePathsByDependency,
16+
dereferenceDirectory,
1617
} from "./path-utils.js";
1718
import { setupTempDirectory } from "./test-utils.js";
1819

@@ -550,3 +551,37 @@ describe("findNodeAddonForBindings()", () => {
550551
});
551552
}
552553
});
554+
555+
describe("dereferenceDirectory", () => {
556+
describe("when directory contains symlinks", () => {
557+
it("should dereference symlinks", async (context) => {
558+
// Create a temp directory with a symlink
559+
const tempDir = setupTempDirectory(context, {
560+
"original/file.txt": "Hello, world!",
561+
});
562+
const originalPath = path.join(tempDir, "original");
563+
const symlinkPath = path.join(tempDir, "link");
564+
// Create a link to the original directory
565+
fs.symlinkSync(originalPath, symlinkPath, "dir");
566+
// And an internal link
567+
fs.symlinkSync(
568+
path.join(originalPath, "file.txt"),
569+
path.join(originalPath, "linked-file.txt"),
570+
"file",
571+
);
572+
573+
await dereferenceDirectory(symlinkPath);
574+
575+
// Verify that outer link is no longer a link
576+
const symlinkStat = await fs.promises.lstat(symlinkPath);
577+
assert(!symlinkStat.isSymbolicLink());
578+
579+
// Verify that the internal link is still a link to a readable file
580+
const internalLinkPath = path.join(symlinkPath, "linked-file.txt");
581+
const internalLinkStat = await fs.promises.lstat(internalLinkPath);
582+
assert(internalLinkStat.isSymbolicLink());
583+
const content = await fs.promises.readFile(internalLinkPath, "utf8");
584+
assert.equal(content, "Hello, world!");
585+
});
586+
});
587+
});

packages/host/src/node/path-utils.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,3 +543,16 @@ export function findNodeAddonForBindings(id: string, fromDir: string) {
543543
}
544544
return undefined;
545545
}
546+
547+
export async function dereferenceDirectory(dirPath: string) {
548+
const tempPath = dirPath + ".tmp";
549+
// Move the existing framework out of the way
550+
await fs.promises.rename(dirPath, tempPath);
551+
// Only dereference the symlink at tempPath (not recursively)
552+
const realPath = await fs.promises.realpath(tempPath);
553+
await fs.promises.cp(realPath, dirPath, {
554+
recursive: true,
555+
verbatimSymlinks: true,
556+
});
557+
await fs.promises.unlink(tempPath);
558+
}

0 commit comments

Comments
 (0)