Skip to content

Commit ef76302

Browse files
fix: preserve file owner and permissions when rewriting file in generator (#4522)
1 parent 4aeaf1c commit ef76302

File tree

1 file changed

+41
-2
lines changed

1 file changed

+41
-2
lines changed

packages/router-generator/src/generator.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ import type { Logger } from './logger'
5858
import type { TransformPlugin } from './transform/types'
5959

6060
interface fs {
61-
stat: (filePath: string) => Promise<{ mtimeMs: bigint }>
61+
stat: (
62+
filePath: string,
63+
) => Promise<{ mtimeMs: bigint; mode: number; uid: number; gid: number }>
6264
mkdtempSync: (prefix: string) => string
6365
rename: (oldPath: string, newPath: string) => Promise<void>
6466
writeFile: (filePath: string, content: string) => Promise<void>
@@ -67,10 +69,20 @@ interface fs {
6769
) => Promise<
6870
{ stat: { mtimeMs: bigint }; fileContent: string } | 'file-not-existing'
6971
>
72+
chmod: (filePath: string, mode: number) => Promise<void>
73+
chown: (filePath: string, uid: number, gid: number) => Promise<void>
7074
}
7175

7276
const DefaultFileSystem: fs = {
73-
stat: (filePath) => fsp.stat(filePath, { bigint: true }),
77+
stat: async (filePath) => {
78+
const res = await fsp.stat(filePath, { bigint: true })
79+
return {
80+
mtimeMs: res.mtimeMs,
81+
mode: Number(res.mode),
82+
uid: Number(res.uid),
83+
gid: Number(res.gid),
84+
}
85+
},
7486
mkdtempSync: mkdtempSync,
7587
rename: (oldPath, newPath) => fsp.rename(oldPath, newPath),
7688
writeFile: (filePath, content) => fsp.writeFile(filePath, content),
@@ -90,6 +102,8 @@ const DefaultFileSystem: fs = {
90102
throw e
91103
}
92104
},
105+
chmod: (filePath, mode) => fsp.chmod(filePath, mode),
106+
chown: (filePath, uid, gid) => fsp.chown(filePath, uid, gid),
93107
}
94108

95109
interface Rerun {
@@ -1031,6 +1045,31 @@ ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${get
10311045
event: { type: 'update', path: opts.filePath },
10321046
})
10331047
}
1048+
const newFileState = await this.fs.stat(tmpPath)
1049+
if (newFileState.mode !== beforeStat.mode) {
1050+
await this.fs.chmod(tmpPath, beforeStat.mode)
1051+
}
1052+
if (
1053+
newFileState.uid !== beforeStat.uid ||
1054+
newFileState.gid !== beforeStat.gid
1055+
) {
1056+
try {
1057+
await this.fs.chown(tmpPath, beforeStat.uid, beforeStat.gid)
1058+
} catch (err) {
1059+
if (
1060+
typeof err === 'object' &&
1061+
err !== null &&
1062+
'code' in err &&
1063+
(err as any).code === 'EPERM'
1064+
) {
1065+
console.warn(
1066+
`[safeFileWrite] chown failed: ${(err as any).message}`,
1067+
)
1068+
} else {
1069+
throw err
1070+
}
1071+
}
1072+
}
10341073
} else {
10351074
if (await checkFileExists(opts.filePath)) {
10361075
throw rerun({

0 commit comments

Comments
 (0)