Skip to content

Commit df5ef35

Browse files
committed
fix a few things
1 parent 64cc995 commit df5ef35

File tree

2 files changed

+32
-12
lines changed

2 files changed

+32
-12
lines changed

packages/cli-v3/src/build/manifests.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { createHash } from "node:crypto";
44
import { existsSync } from "node:fs";
55
import { join } from "node:path";
66
import { logger } from "../utilities/logger.js";
7+
import { sanitizeHashForFilename } from "../utilities/fileSystem.js";
78

89
export async function copyManifestToDir(
910
manifest: BuildManifest,
@@ -47,14 +48,6 @@ export async function copyManifestToDir(
4748
return updatedManifest;
4849
}
4950

50-
/**
51-
* Sanitizes a hash to be safe for use as a filename.
52-
* esbuild's hashes are base64-encoded and may contain `/` and `+` characters.
53-
*/
54-
function sanitizeHashForFilename(hash: string): string {
55-
return hash.replace(/\//g, "_").replace(/\+/g, "-");
56-
}
57-
5851
/**
5952
* Computes a hash of file contents to use as content-addressable key.
6053
* This is a fallback for when outputHashes is not available.
@@ -99,7 +92,16 @@ async function copyDirWithStore(
9992

10093
if (existsSync(storePath)) {
10194
// Create hardlink to store file
102-
await link(storePath, destPath);
95+
// Fall back to copy if hardlink fails (e.g., on Windows or cross-device)
96+
try {
97+
await link(storePath, destPath);
98+
} catch (linkError) {
99+
try {
100+
await cp(storePath, destPath);
101+
} catch (copyError) {
102+
throw linkError; // Rethrow original error if copy also fails
103+
}
104+
}
103105
} else {
104106
// File wasn't in the store - copy normally
105107
await cp(sourcePath, destPath);

packages/cli-v3/src/utilities/fileSystem.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export async function createFile(
2020
* Sanitizes a hash to be safe for use as a filename.
2121
* esbuild's hashes are base64-encoded and may contain `/` and `+` characters.
2222
*/
23-
function sanitizeHashForFilename(hash: string): string {
23+
export function sanitizeHashForFilename(hash: string): string {
2424
return hash.replace(/\//g, "_").replace(/\+/g, "-");
2525
}
2626

@@ -57,14 +57,32 @@ export async function createFileWithStore(
5757
// Check if content already exists in store by hash
5858
if (fsSync.existsSync(storePath)) {
5959
// Create hardlink from build path to store path
60-
await fsModule.link(storePath, filePath);
60+
// Fall back to copy if hardlink fails (e.g., on Windows or cross-device)
61+
try {
62+
await fsModule.link(storePath, filePath);
63+
} catch (linkError) {
64+
try {
65+
await fsModule.copyFile(storePath, filePath);
66+
} catch (copyError) {
67+
throw linkError; // Rethrow original error if copy also fails
68+
}
69+
}
6170
return filePath;
6271
}
6372

6473
// Write to store first (using hash as filename)
6574
await fsModule.writeFile(storePath, contents);
6675
// Create hardlink in build directory (with original filename)
67-
await fsModule.link(storePath, filePath);
76+
// Fall back to copy if hardlink fails (e.g., on Windows or cross-device)
77+
try {
78+
await fsModule.link(storePath, filePath);
79+
} catch (linkError) {
80+
try {
81+
await fsModule.copyFile(storePath, filePath);
82+
} catch (copyError) {
83+
throw linkError; // Rethrow original error if copy also fails
84+
}
85+
}
6886

6987
return filePath;
7088
}

0 commit comments

Comments
 (0)