11import { spawn } from 'child_process'
2- import { basename , resolve } from 'path'
2+ import { basename , resolve , join } from 'path'
33import { ProcessProxyConnection as Connection } from 'process-proxy'
44import type { HookCallbackOptions } from '../git'
55import { resolveGitBinary } from 'dugite'
66import { ShellEnvResult } from './get-shell-env'
77import { shellFriendlyNames } from './config'
88import { Writable } from 'stream'
9+ import { mkdtempSync , rmSync , writeFileSync } from 'fs'
10+ import { tmpdir } from 'os'
911
1012const ignoredOnFailureHooks = [
1113 'post-applypatch' ,
@@ -64,6 +66,29 @@ const exitWithMessage = (conn: Connection, msg: string, exitCode = 0) =>
6466const 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+
6792export 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