Skip to content

Commit d4748bf

Browse files
committed
Dereference framework directories
1 parent 7b5b84e commit d4748bf

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
@@ -8,6 +8,7 @@ import {
88
AppleTriplet as Triplet,
99
createAppleFramework,
1010
createXCframework,
11+
dereferenceDirectory,
1112
} from "react-native-node-api";
1213

1314
import type { Platform } from "./types.js";
@@ -372,6 +373,18 @@ export const platform: Platform<Triplet[], AppleOpts> = {
372373
}
373374
}
374375

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

377390
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

@@ -502,3 +503,37 @@ describe("findNodeAddonForBindings()", () => {
502503
});
503504
}
504505
});
506+
507+
describe("dereferenceDirectory", () => {
508+
describe("when directory contains symlinks", () => {
509+
it("should dereference symlinks", async (context) => {
510+
// Create a temp directory with a symlink
511+
const tempDir = setupTempDirectory(context, {
512+
"original/file.txt": "Hello, world!",
513+
});
514+
const originalPath = path.join(tempDir, "original");
515+
const symlinkPath = path.join(tempDir, "link");
516+
// Create a link to the original directory
517+
fs.symlinkSync(originalPath, symlinkPath, "dir");
518+
// And an internal link
519+
fs.symlinkSync(
520+
path.join(originalPath, "file.txt"),
521+
path.join(originalPath, "linked-file.txt"),
522+
"file",
523+
);
524+
525+
await dereferenceDirectory(symlinkPath);
526+
527+
// Verify that outer link is no longer a link
528+
const symlinkStat = await fs.promises.lstat(symlinkPath);
529+
assert(!symlinkStat.isSymbolicLink());
530+
531+
// Verify that the internal link is still a link to a readable file
532+
const internalLinkPath = path.join(symlinkPath, "linked-file.txt");
533+
const internalLinkStat = await fs.promises.lstat(internalLinkPath);
534+
assert(internalLinkStat.isSymbolicLink());
535+
const content = await fs.promises.readFile(internalLinkPath, "utf8");
536+
assert.equal(content, "Hello, world!");
537+
});
538+
});
539+
});

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,3 +483,16 @@ export function findNodeAddonForBindings(id: string, fromDir: string) {
483483
}
484484
return undefined;
485485
}
486+
487+
export async function dereferenceDirectory(dirPath: string) {
488+
const tempPath = dirPath + ".tmp";
489+
// Move the existing framework out of the way
490+
await fs.promises.rename(dirPath, tempPath);
491+
// Only dereference the symlink at tempPath (not recursively)
492+
const realPath = await fs.promises.realpath(tempPath);
493+
await fs.promises.cp(realPath, dirPath, {
494+
recursive: true,
495+
verbatimSymlinks: true,
496+
});
497+
await fs.promises.unlink(tempPath);
498+
}

0 commit comments

Comments
 (0)