feat(core): forward stdin to commands started via rust (#21195)
Co-authored-by: Jonathan Cammisuli <jon@cammisuli.ca>
This commit is contained in:
parent
33e13910b1
commit
cb5eeb7475
@ -16,7 +16,7 @@ packages/jest/src/schematics/**/files/**/*.json
|
|||||||
packages/nx/src/plugins/js/lock-file/__fixtures__/**/*.*
|
packages/nx/src/plugins/js/lock-file/__fixtures__/**/*.*
|
||||||
packages/**/schematics/**/files/**/*.html
|
packages/**/schematics/**/files/**/*.html
|
||||||
packages/**/generators/**/files/**/*.html
|
packages/**/generators/**/files/**/*.html
|
||||||
packages/nx/src/native/
|
packages/nx/src/native/**/*.rs
|
||||||
nx-dev/nx-dev/.next/
|
nx-dev/nx-dev/.next/
|
||||||
nx-dev/nx-dev/public/documentation
|
nx-dev/nx-dev/public/documentation
|
||||||
graph/client/src/assets/environment.js
|
graph/client/src/assets/environment.js
|
||||||
|
|||||||
58
Cargo.lock
generated
58
Cargo.lock
generated
@ -346,6 +346,31 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossterm"
|
||||||
|
version = "0.27.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.1",
|
||||||
|
"crossterm_winapi",
|
||||||
|
"libc",
|
||||||
|
"mio",
|
||||||
|
"parking_lot",
|
||||||
|
"signal-hook",
|
||||||
|
"signal-hook-mio",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossterm_winapi"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ctor"
|
name = "ctor"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -1503,6 +1528,7 @@ dependencies = [
|
|||||||
"assert_fs",
|
"assert_fs",
|
||||||
"colored",
|
"colored",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
|
"crossterm",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
"dunce",
|
"dunce",
|
||||||
"fs_extra",
|
"fs_extra",
|
||||||
@ -1526,7 +1552,6 @@ dependencies = [
|
|||||||
"swc_ecma_dep_graph",
|
"swc_ecma_dep_graph",
|
||||||
"swc_ecma_parser",
|
"swc_ecma_parser",
|
||||||
"swc_ecma_visit",
|
"swc_ecma_visit",
|
||||||
"term_size",
|
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -2080,6 +2105,27 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
|
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook"
|
||||||
|
version = "0.3.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"signal-hook-registry",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook-mio"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"mio",
|
||||||
|
"signal-hook",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
@ -2383,16 +2429,6 @@ dependencies = [
|
|||||||
"windows-sys 0.45.0",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "term_size"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termios"
|
name = "termios"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
|||||||
@ -42,7 +42,7 @@ swc_common = "0.31.16"
|
|||||||
swc_ecma_parser = { version = "0.137.1", features = ["typescript"] }
|
swc_ecma_parser = { version = "0.137.1", features = ["typescript"] }
|
||||||
swc_ecma_visit = "0.93.0"
|
swc_ecma_visit = "0.93.0"
|
||||||
swc_ecma_ast = "0.107.0"
|
swc_ecma_ast = "0.107.0"
|
||||||
term_size = "0.3.2"
|
crossterm = "0.27.0"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ['cdylib']
|
crate-type = ['cdylib']
|
||||||
|
|||||||
@ -114,8 +114,6 @@ export async function affected(
|
|||||||
extraTargetDependencies,
|
extraTargetDependencies,
|
||||||
{ excludeTaskDependencies: false, loadDotEnvFiles: true }
|
{ excludeTaskDependencies: false, loadDotEnvFiles: true }
|
||||||
);
|
);
|
||||||
// fix for https://github.com/nrwl/nx/issues/1666
|
|
||||||
if (process.stdin['unref']) (process.stdin as any).unref();
|
|
||||||
process.exit(status);
|
process.exit(status);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -177,8 +177,6 @@ async function runPublishOnProjects(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (status !== 0) {
|
if (status !== 0) {
|
||||||
// fix for https://github.com/nrwl/nx/issues/1666
|
|
||||||
if (process.stdin['unref']) (process.stdin as any).unref();
|
|
||||||
process.exit(status);
|
process.exit(status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,8 +75,6 @@ export async function runMany(
|
|||||||
extraTargetDependencies,
|
extraTargetDependencies,
|
||||||
extraOptions
|
extraOptions
|
||||||
);
|
);
|
||||||
// fix for https://github.com/nrwl/nx/issues/1666
|
|
||||||
if (process.stdin['unref']) (process.stdin as any).unref();
|
|
||||||
process.exit(status);
|
process.exit(status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,8 +89,6 @@ export async function runOne(
|
|||||||
extraTargetDependencies,
|
extraTargetDependencies,
|
||||||
extraOptions
|
extraOptions
|
||||||
);
|
);
|
||||||
// fix for https://github.com/nrwl/nx/issues/1666
|
|
||||||
if (process.stdin['unref']) (process.stdin as any).unref();
|
|
||||||
process.exit(status);
|
process.exit(status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,8 @@ use std::{
|
|||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use crossbeam_channel::{bounded, unbounded, Receiver};
|
use crossbeam_channel::{bounded, unbounded, Receiver};
|
||||||
|
use crossterm::terminal::{self, disable_raw_mode, enable_raw_mode};
|
||||||
|
use crossterm::tty::IsTty;
|
||||||
use napi::threadsafe_function::ErrorStrategy::Fatal;
|
use napi::threadsafe_function::ErrorStrategy::Fatal;
|
||||||
use napi::threadsafe_function::ThreadsafeFunction;
|
use napi::threadsafe_function::ThreadsafeFunction;
|
||||||
use napi::threadsafe_function::ThreadsafeFunctionCallMode::NonBlocking;
|
use napi::threadsafe_function::ThreadsafeFunctionCallMode::NonBlocking;
|
||||||
@ -126,10 +128,10 @@ pub fn run_command(
|
|||||||
|
|
||||||
let pty_system = NativePtySystem::default();
|
let pty_system = NativePtySystem::default();
|
||||||
|
|
||||||
let (w, h) = term_size::dimensions().unwrap_or((80, 24));
|
let (w, h) = terminal::size().unwrap_or((80, 24));
|
||||||
let pair = pty_system.openpty(PtySize {
|
let pair = pty_system.openpty(PtySize {
|
||||||
rows: h as u16,
|
rows: h,
|
||||||
cols: w as u16,
|
cols: w,
|
||||||
pixel_width: 0,
|
pixel_width: 0,
|
||||||
pixel_height: 0,
|
pixel_height: 0,
|
||||||
})?;
|
})?;
|
||||||
@ -148,6 +150,8 @@ pub fn run_command(
|
|||||||
|
|
||||||
let reader = pair.master.try_clone_reader()?;
|
let reader = pair.master.try_clone_reader()?;
|
||||||
let mut stdout = std::io::stdout();
|
let mut stdout = std::io::stdout();
|
||||||
|
|
||||||
|
// Output -> stdout handling
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let mut reader = BufReader::new(reader);
|
let mut reader = BufReader::new(reader);
|
||||||
let mut buffer = [0; 8 * 1024];
|
let mut buffer = [0; 8 * 1024];
|
||||||
@ -182,10 +186,25 @@ pub fn run_command(
|
|||||||
|
|
||||||
let process_killer = child.clone_killer();
|
let process_killer = child.clone_killer();
|
||||||
let (exit_tx, exit_rx) = bounded(1);
|
let (exit_tx, exit_rx) = bounded(1);
|
||||||
|
|
||||||
|
let mut writer = pair.master.take_writer()?;
|
||||||
|
|
||||||
|
// Stdin -> pty stdin
|
||||||
|
if std::io::stdout().is_tty() {
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
enable_raw_mode().expect("Failed to enter raw terminal mode");
|
||||||
|
let mut stdin = std::io::stdin();
|
||||||
|
#[allow(clippy::redundant_pattern_matching)]
|
||||||
|
// ignore errors that come from copying the stream
|
||||||
|
if let Ok(_) = std::io::copy(&mut stdin, &mut writer) {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let exit = child.wait().unwrap();
|
let exit = child.wait().unwrap();
|
||||||
// make sure that master is only dropped after we wait on the child. Otherwise windows does not like it
|
// make sure that master is only dropped after we wait on the child. Otherwise windows does not like it
|
||||||
drop(pair.master);
|
drop(pair.master);
|
||||||
|
disable_raw_mode().expect("Failed to restore non-raw terminal");
|
||||||
exit_tx.send(exit.exit_code()).ok();
|
exit_tx.send(exit.exit_code()).ok();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -10,39 +10,40 @@ describe('runCommand', () => {
|
|||||||
});
|
});
|
||||||
it('should kill a running command', () => {
|
it('should kill a running command', () => {
|
||||||
const childProcess = new PseudoTtyProcess(
|
const childProcess = new PseudoTtyProcess(
|
||||||
runCommand(
|
runCommand('sleep 3 && echo "hello world" > file.txt', process.cwd())
|
||||||
'sleep 3 && echo "hello world" > file.txt',
|
|
||||||
process.cwd()
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
childProcess.onExit((exit_code) => {
|
childProcess.onExit((exit_code) => {
|
||||||
expect(exit_code).not.toEqual(0);
|
expect(exit_code).not.toEqual(0);
|
||||||
});
|
});
|
||||||
childProcess.kill();
|
childProcess.kill();
|
||||||
expect(childProcess.isAlive).toEqual(false);
|
expect(childProcess.isAlive).toEqual(false);
|
||||||
|
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
it('should subscribe to output', (done) => {
|
it('should subscribe to output', (done) => {
|
||||||
const childProcess = runCommand('echo "hello world"', process.cwd());
|
const childProcess = runCommand('echo "hello world"', process.cwd());
|
||||||
|
|
||||||
childProcess.onOutput((output) => {
|
let output = '';
|
||||||
expect(output.trim()).toEqual('hello world');
|
childProcess.onOutput((chunk) => {
|
||||||
|
output += chunk;
|
||||||
});
|
});
|
||||||
|
|
||||||
childProcess.onExit(() => {
|
childProcess.onExit(() => {
|
||||||
|
expect(output.trim()).toEqual('hello world');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be tty', (done) => {
|
it('should be tty', (done) => {
|
||||||
const childProcess = runCommand('node -p "process.stdout.isTTY"');
|
const childProcess = runCommand('node -p "process.stdout.isTTY"');
|
||||||
|
let output = '';
|
||||||
childProcess.onOutput((out) => {
|
childProcess.onOutput((out) => {
|
||||||
let output = JSON.stringify(out.trim());
|
output += out.trim();
|
||||||
// check to make sure that we have ansi sequence characters only available in tty terminals
|
// check to make sure that we have ansi sequence characters only available in tty terminals
|
||||||
expect(output).toMatchInlineSnapshot(`""\\u001b[33mtrue\\u001b[39m""`);
|
|
||||||
});
|
});
|
||||||
childProcess.onExit((_) => {
|
childProcess.onExit((_) => {
|
||||||
|
expect(JSON.stringify(output)).toMatchInlineSnapshot(
|
||||||
|
`""\\u001b[33mtrue\\u001b[39m""`
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user