| // Copyright 2024 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import { ChildProcessWithoutNullStreams } from 'child_process'; |
| // @ts-ignore: no @types/jsonparse available. |
| import JsonParser from 'jsonparse'; |
| |
| /** |
| * A stream of Data coming from a process. |
| */ |
| export class DataStreamProcess { |
| constructor( |
| private process: ChildProcessWithoutNullStreams, |
| onData: (data: Buffer) => void, |
| onError: (data: Buffer) => void, |
| ) { |
| this.process.stdout.on('data', onData); |
| this.process.stderr.on('data', onError); |
| } |
| |
| /** |
| * A future that resolves when the process exits. |
| */ |
| public get exitCode(): Promise<number | null> { |
| return new Promise(resolve => { |
| this.process.on('exit', resolve); |
| }); |
| } |
| |
| /** |
| * Kills the underlying process and all its children. |
| */ |
| public stop() { |
| const pid = this.process?.pid; |
| if (pid) { |
| try { |
| // This handles the in-tree use case where `ffx` launches a subprocess `fx ffx`. |
| process.kill(-pid); |
| } catch { |
| // If the process with the given `pid` didn't exist, this error will rise, which we can |
| // just swallow. |
| } |
| } |
| } |
| } |
| |
| /** |
| * A stream of JSON Data coming from a process. |
| */ |
| export class JsonStreamProcess { |
| private process: DataStreamProcess | undefined; |
| private parser: JsonParser; |
| |
| constructor( |
| process: ChildProcessWithoutNullStreams | undefined, |
| private onData: (data: Object) => void, |
| onError: (data: Buffer) => void, |
| ) { |
| this.parser = new JsonParser(); |
| if (process) { |
| this.process = new DataStreamProcess(process, (chunk) => { |
| this.parser.write(chunk); |
| }, onError); |
| |
| } |
| let self = this; |
| this.parser.onValue = function (value: Object) { |
| if (this.stack.length === 0) { |
| self.onData(value); |
| } |
| }; |
| } |
| |
| /** |
| * Kills the underlying process and all its children. |
| */ |
| public stop() { |
| this.process?.stop(); |
| } |
| } |