Skip to content

Commit d0cbf9c

Browse files
authored
fix(cli): handle cross device link error on plugin init (#2465)
1 parent 65a3339 commit d0cbf9c

File tree

1 file changed

+22
-2
lines changed
  • cli/src/commands/router/commands/plugin/commands

1 file changed

+22
-2
lines changed

cli/src/commands/router/commands/plugin/commands/init.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable import/no-named-as-default-member */
2-
import { access, mkdir, rename, rm, writeFile } from 'node:fs/promises';
2+
import { access, mkdir, rename, rm, writeFile, cp } from 'node:fs/promises';
33
import { tmpdir } from 'node:os';
44
import { randomUUID } from 'node:crypto';
55
import { Command, program } from 'commander';
@@ -17,6 +17,26 @@ import TsTemplates from '../templates/typescript.js';
1717
import { renderResultTree } from '../helper.js';
1818
import { getGoModulePathProtoOption } from '../toolchain.js';
1919

20+
// The move function is a wrapper around the fs/promises rename operation.
21+
// This is necessary because the OS-level rename will fail with an EXDEV error
22+
// when trying to move a file or directory across different filesystems.
23+
// In such cases, move falls back to recursively copying the source to the destination
24+
// and then removing the original source directory or file.
25+
const move = async (src: string, dest: string) => {
26+
try {
27+
await rename(src, dest);
28+
} catch (error: unknown) {
29+
if (typeof error === 'object' && error !== null && 'code' in error && error.code === 'EXDEV') {
30+
// fallback for cross-device moves
31+
await cp(src, dest, { recursive: true });
32+
await rm(src, { recursive: true, force: true });
33+
return;
34+
}
35+
36+
throw error;
37+
}
38+
};
39+
2040
export default (opts: BaseCommandOptions) => {
2141
const command = new Command('init');
2242
command.description('Scaffold a new gRPC router plugin');
@@ -182,7 +202,7 @@ export default (opts: BaseCommandOptions) => {
182202
await mkdir(projectDir, { recursive: true });
183203
}
184204

185-
await rename(tempDir, pluginDir);
205+
await move(tempDir, pluginDir);
186206

187207
const endTime = performance.now();
188208
const elapsedTimeMs = endTime - startTime;

0 commit comments

Comments
 (0)