@@ -19,7 +19,6 @@ import {
1919 ExecOptions ,
2020 ReadFileContents ,
2121 GetTempDir ,
22- KillProcess ,
2322} from './utilities' ;
2423import {
2524 UnityReleasesClient ,
@@ -100,27 +99,27 @@ export class UnityHub {
10099
101100 try {
102101 exitCode = await new Promise < number > ( ( resolve , reject ) => {
103- let tasksComplete : boolean = false ;
102+ let isSettled : boolean = false ; // Has the promise been settled (resolved or rejected)?
103+ let isHubTaskComplete : boolean = false ; // Has the Unity Hub tasks completed successfully?
104+ let lineBuffer = '' ; // Buffer for incomplete lines
104105 const tasksCompleteMessage = 'All Tasks Completed Successfully.' ;
105106 const child = spawn ( executable , execArgs , {
106- stdio : [ 'ignore' , 'pipe' , 'pipe' ] ,
107- detached : process . platform !== 'win32'
107+ stdio : [ 'ignore' , 'pipe' , 'pipe' ]
108108 } ) ;
109109 const sigintHandler = ( ) => child . kill ( 'SIGINT' ) ;
110110 const sigtermHandler = ( ) => child . kill ( 'SIGTERM' ) ;
111111 process . once ( 'SIGINT' , sigintHandler ) ;
112112 process . once ( 'SIGTERM' , sigtermHandler ) ;
113113
114114 let hasCleanedUpListeners = false ;
115- function removeListeners ( ) {
115+ function removeListeners ( ) : void {
116116 if ( hasCleanedUpListeners ) { return ; }
117117 hasCleanedUpListeners = true ;
118118 process . removeListener ( 'SIGINT' , sigintHandler ) ;
119119 process . removeListener ( 'SIGTERM' , sigtermHandler ) ;
120120 }
121121
122- let lineBuffer = '' ; // Buffer for incomplete lines
123- function processOutput ( data : Buffer ) {
122+ function processOutput ( data : Buffer ) : void {
124123 try {
125124 const chunk = data . toString ( ) ;
126125 const fullChunk = lineBuffer + chunk ;
@@ -137,10 +136,26 @@ export class UnityHub {
137136 const outputLines = lines . filter ( line => ! ignoredLines . some ( ignored => line . includes ( ignored ) ) ) ;
138137
139138 if ( outputLines . includes ( tasksCompleteMessage ) ) {
140- tasksComplete = true ;
139+ isHubTaskComplete = true ;
141140
142141 if ( child ?. pid ) {
143- void KillProcess ( { pid : child . pid , name : child . spawnfile , ppid : process . pid } ) ;
142+ try {
143+ child . kill ( 'SIGTERM' ) ;
144+
145+ setTimeout ( ( ) => {
146+ try {
147+ if ( child ?. pid && ! child . killed ) {
148+ child . kill ( 'SIGKILL' ) ;
149+ }
150+ } catch {
151+ // Ignore, process may have already exited
152+ }
153+ } , 1000 ) ;
154+ } catch {
155+ // Ignore, process may have already exited
156+ } finally {
157+ settle ( 0 ) ;
158+ }
144159 }
145160 }
146161
@@ -157,41 +172,57 @@ export class UnityHub {
157172 }
158173 }
159174 }
160- child . stdout . on ( 'data' , processOutput ) ;
161- child . stderr . on ( 'data' , processOutput ) ;
162- child . on ( 'error' , ( error ) => {
163- removeListeners ( ) ;
164- reject ( error ) ;
165- } ) ;
166- child . on ( 'close' , ( code ) => {
167- removeListeners ( ) ;
168175
169- // Flush any remaining buffered content
170- if ( lineBuffer . length > 0 ) {
171- const lines = lineBuffer . split ( '\n' ) // split by newline
172- . map ( line => line . replace ( / \r $ / , '' ) ) // remove trailing carriage return
173- . filter ( line => line . length > 0 ) ; // filter out empty lines
174- const outputLines = lines . filter ( line => ! ignoredLines . some ( ignored => line . includes ( ignored ) ) ) ;
176+ function flushOutput ( ) : void {
177+ try {
178+ if ( lineBuffer . length > 0 ) {
179+ const lines = lineBuffer . split ( '\n' ) // split by newline
180+ . map ( line => line . replace ( / \r $ / , '' ) ) // remove trailing carriage return
181+ . filter ( line => line . length > 0 ) ; // filter out empty lines
182+ lineBuffer = '' ;
183+ const outputLines = lines . filter ( line => ! ignoredLines . some ( ignored => line . includes ( ignored ) ) ) ;
175184
176- if ( outputLines . includes ( tasksCompleteMessage ) ) {
177- tasksComplete = true ;
178- }
185+ if ( outputLines . includes ( tasksCompleteMessage ) ) {
186+ isHubTaskComplete = true ;
187+ }
179188
180- for ( const line of outputLines ) {
181- output += `${ line } \n` ;
189+ for ( const line of outputLines ) {
190+ output += `${ line } \n` ;
182191
183- if ( ! options . silent ) {
184- process . stdout . write ( `${ line } \n` ) ;
192+ if ( ! options . silent ) {
193+ process . stdout . write ( `${ line } \n` ) ;
194+ }
185195 }
186196 }
197+ } catch ( error : any ) {
198+ if ( error . code !== 'EPIPE' ) {
199+ Logger . instance . error ( `Failed to process buffered output: ${ error } ` ) ;
200+ }
187201 }
202+ }
188203
189- if ( tasksComplete ) {
204+ function settle ( code : number | null ) : void {
205+ if ( isSettled ) { return ; }
206+ isSettled = true ;
207+ removeListeners ( ) ;
208+ flushOutput ( ) ;
209+
210+ if ( isHubTaskComplete ) {
190211 resolve ( 0 ) ;
191212 } else {
192213 resolve ( code === null ? 0 : code ) ;
193214 }
215+ }
216+
217+ child . stdout . on ( 'data' , processOutput ) ;
218+ child . stderr . on ( 'data' , processOutput ) ;
219+ child . on ( 'error' , ( error ) => {
220+ isSettled = true ;
221+ removeListeners ( ) ;
222+ flushOutput ( ) ;
223+ reject ( error ) ;
194224 } ) ;
225+ child . on ( 'close' , settle ) ;
195226 } ) ;
196227 } finally {
197228 this . logger . endGroup ( ) ;
0 commit comments