Skip to content

Commit fcb24a3

Browse files
authored
Merge pull request #108 from ignatremizov/fix/hooks-proxy-stdin-file-upstream
fix(hooks): materialize proxied hook stdin into a temp file
2 parents 1f274dc + 22ac81c commit fcb24a3

1 file changed

Lines changed: 34 additions & 3 deletions

File tree

app/src/lib/hooks/hooks-proxy.ts

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { spawn } from 'child_process'
2-
import { basename, resolve } from 'path'
2+
import { basename, resolve, join } from 'path'
33
import { ProcessProxyConnection as Connection } from 'process-proxy'
44
import type { HookCallbackOptions } from '../git'
55
import { resolveGitBinary } from 'dugite'
66
import { ShellEnvResult } from './get-shell-env'
77
import { shellFriendlyNames } from './config'
88
import { Writable } from 'stream'
9+
import { mkdtempSync, rmSync, writeFileSync } from 'fs'
10+
import { tmpdir } from 'os'
911

1012
const ignoredOnFailureHooks = [
1113
'post-applypatch',
@@ -64,6 +66,29 @@ const exitWithMessage = (conn: Connection, msg: string, exitCode = 0) =>
6466
const exitWithError = (conn: Connection, msg: string, exitCode = 1) =>
6567
exitWithMessage(conn, msg, exitCode)
6668

69+
const readStdin = (stream: NodeJS.ReadableStream) =>
70+
new Promise<Buffer>((resolve, reject) => {
71+
const chunks: Buffer[] = []
72+
73+
stream.on('data', chunk => {
74+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))
75+
})
76+
stream.on('end', () => resolve(Buffer.concat(chunks)))
77+
stream.on('error', reject)
78+
})
79+
80+
const createStdinFile = (content: Buffer) => {
81+
const dir = mkdtempSync(join(tmpdir(), 'github-desktop-hooks-'))
82+
const filePath = join(dir, 'stdin.txt')
83+
84+
writeFileSync(filePath, content)
85+
86+
return {
87+
filePath,
88+
cleanup: () => rmSync(dir, { recursive: true, force: true }),
89+
}
90+
}
91+
6792
export const createHooksProxy = (
6893
getShellEnv: (cwd: string) => Promise<ShellEnvResult>,
6994
onHookProgress?: HookCallbackOptions['onHookProgress'],
@@ -102,6 +127,10 @@ export const createHooksProxy = (
102127
return
103128
}
104129

130+
const stdinFile = hasStdin
131+
? createStdinFile(await readStdin(conn.stdin))
132+
: null
133+
105134
const args = [
106135
...['hook', 'run', hookName],
107136
// We always copy our pre-auto-gc hook in order to be able to tell the
@@ -110,7 +139,7 @@ export const createHooksProxy = (
110139
// pre-auto-gc hook configured themselves, so we tell Git to ignore
111140
// missing hooks here.
112141
...(hookName === 'pre-auto-gc' ? ['--ignore-missing'] : []),
113-
...(hasStdin ? ['--to-stdin=/dev/stdin'] : []),
142+
...(stdinFile ? [`--to-stdin=${stdinFile.filePath}`] : []),
114143
'--',
115144
...proxyArgs.slice(1),
116145
]
@@ -157,9 +186,11 @@ export const createHooksProxy = (
157186
// https://github.com/git/git/blob/4cf919bd7b946477798af5414a371b23fd68bf93/hook.c#L73C6-L73C22
158187
child.stderr.pipe(conn.stderr, { end: false }).on('error', reject)
159188
child.stderr.on('data', data => terminalOutput.push(data))
160-
conn.stdin.pipe(child.stdin).on('error', reject)
189+
child.stdin.end()
161190
})
162191

192+
stdinFile?.cleanup()
193+
163194
const dur = `after ${((Date.now() - startTime) / 1000).toFixed(2)}s`
164195
const prefix = `${hookName} hook`
165196
const terminationMessage = signal

0 commit comments

Comments
 (0)