softprops / atty Goto Github PK
View Code? Open in Web Editor NEWare you or are you not a tty?
License: MIT License
are you or are you not a tty?
License: MIT License
Our vendor tooling builds and tests cargo stuff in its own private space, where direct stdin is not available.
But a simple way to emulate the situations that causes this failure is redirecting /dev/null
into stdin.
A simple way to replicate this behaviour is:
RUST_BACKTRACE=full cargo test </dev/null
Finished dev [unoptimized + debuginfo] target(s) in 0.07s
Running target/debug/deps/atty-a5c6cbcdd7f2e95c
running 3 tests
test tests::is_err ... ok
test tests::is_out ... ok
test tests::is_in ... FAILED
failures:
---- tests::is_in stdout ----
thread 'tests::is_in' panicked at 'assertion failed: is(Stream::Stdin)', src/lib.rs:195:9
stack backtrace:
0: 0x555ad16db314 - backtrace::backtrace::libunwind::trace::h4dc2f373699fbe93
at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.37/src/backtrace/libunwind.rs:88
1: 0x555ad16db314 - backtrace::backtrace::trace_unsynchronized::h7b04f002610ccc35
at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.37/src/backtrace/mod.rs:66
2: 0x555ad16db314 - std::sys_common::backtrace::_print_fmt::h0238c0a72ffc5be3
at src/libstd/sys_common/backtrace.rs:76
3: 0x555ad16db314 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h40ab018276d013f4
at src/libstd/sys_common/backtrace.rs:60
4: 0x555ad16f613c - core::fmt::write::h029a8d927db7b721
at src/libcore/fmt/mod.rs:1030
5: 0x555ad1696895 - std::io::Write::write_fmt::h188f2aadaaf2e907
at /rustc/66bf391c3aabfc77f5f7139fc9e6944f995d574e/src/libstd/io/mod.rs:1412
6: 0x555ad16d6f71 - std::io::impls::<impl std::io::Write for alloc::boxed::Box<W>>::write_fmt::h4d5381185853a108
at src/libstd/io/impls.rs:141
7: 0x555ad16dd7a5 - std::sys_common::backtrace::_print::he925af2d0a3180ad
at src/libstd/sys_common/backtrace.rs:64
8: 0x555ad16dd7a5 - std::sys_common::backtrace::print::ha41b6194bcf8f6ce
at src/libstd/sys_common/backtrace.rs:49
9: 0x555ad16dd7a5 - std::panicking::default_hook::{{closure}}::h659784bc3ca43626
at src/libstd/panicking.rs:196
10: 0x555ad16dd42c - std::panicking::default_hook::h2f638ec54806c9d8
at src/libstd/panicking.rs:207
11: 0x555ad16ddea5 - std::panicking::rust_panic_with_hook::h12d7650e86d2fcb0
at src/libstd/panicking.rs:473
12: 0x555ad16dda42 - std::panicking::continue_panic_fmt::h70eeb0d1820fa233
at src/libstd/panicking.rs:380
13: 0x555ad16dd936 - rust_begin_unwind
at src/libstd/panicking.rs:307
14: 0x555ad16f382a - core::panicking::panic_fmt::hbbf14b8c86c6fc9d
at src/libcore/panicking.rs:85
15: 0x555ad16f3769 - core::panicking::panic::h55ac7fee752f83d1
at src/libcore/panicking.rs:49
16: 0x555ad16958a0 - atty::tests::is_in::h44535dbfe2769274
at src/lib.rs:195
17: 0x555ad169533a - atty::tests::is_in::{{closure}}::hf66be9b54f1cebe2
at src/lib.rs:194
18: 0x555ad169563e - core::ops::function::FnOnce::call_once::ha5f31d1376a1d459
at /rustc/66bf391c3aabfc77f5f7139fc9e6944f995d574e/src/libcore/ops/function.rs:227
19: 0x555ad16a078f - <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once::hc4223621e68f84c1
at /rustc/66bf391c3aabfc77f5f7139fc9e6944f995d574e/src/liballoc/boxed.rs:922
20: 0x555ad16e05aa - __rust_maybe_catch_panic
at src/libpanic_unwind/lib.rs:80
21: 0x555ad16baf9e - std::panicking::try::hc81bdd9007d9c5da
at /rustc/66bf391c3aabfc77f5f7139fc9e6944f995d574e/src/libstd/panicking.rs:271
22: 0x555ad16baf9e - std::panic::catch_unwind::hf7e7956e7e4c2bce
at /rustc/66bf391c3aabfc77f5f7139fc9e6944f995d574e/src/libstd/panic.rs:394
23: 0x555ad16baf9e - test::run_test::run_test_inner::{{closure}}::hc786e5a908160c30
at src/libtest/lib.rs:1413
24: 0x555ad1696005 - std::sys_common::backtrace::__rust_begin_short_backtrace::h95b152913f9dfacb
at /rustc/66bf391c3aabfc77f5f7139fc9e6944f995d574e/src/libstd/sys_common/backtrace.rs:126
25: 0x555ad169a1b5 - std::thread::Builder::spawn_unchecked::{{closure}}::{{closure}}::he45de012a497b092
at /rustc/66bf391c3aabfc77f5f7139fc9e6944f995d574e/src/libstd/thread/mod.rs:470
26: 0x555ad169a1b5 - <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once::hf68db3f5a78ee690
at /rustc/66bf391c3aabfc77f5f7139fc9e6944f995d574e/src/libstd/panic.rs:315
27: 0x555ad169a1b5 - std::panicking::try::do_call::hf5c86a524ef68531
at /rustc/66bf391c3aabfc77f5f7139fc9e6944f995d574e/src/libstd/panicking.rs:292
28: 0x555ad16e05aa - __rust_maybe_catch_panic
at src/libpanic_unwind/lib.rs:80
29: 0x555ad169a832 - std::panicking::try::ha8e33b8d02e42b94
at /rustc/66bf391c3aabfc77f5f7139fc9e6944f995d574e/src/libstd/panicking.rs:271
30: 0x555ad169a832 - std::panic::catch_unwind::he00df3131fcbf67d
at /rustc/66bf391c3aabfc77f5f7139fc9e6944f995d574e/src/libstd/panic.rs:394
31: 0x555ad169a832 - std::thread::Builder::spawn_unchecked::{{closure}}::h677216b4f657bbdb
at /rustc/66bf391c3aabfc77f5f7139fc9e6944f995d574e/src/libstd/thread/mod.rs:469
32: 0x555ad169a832 - core::ops::function::FnOnce::call_once{{vtable.shim}}::hf34a76822ad504a1
at /rustc/66bf391c3aabfc77f5f7139fc9e6944f995d574e/src/libcore/ops/function.rs:227
33: 0x555ad16d39cf - <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once::h1d0ecaf281abdf71
at /rustc/66bf391c3aabfc77f5f7139fc9e6944f995d574e/src/liballoc/boxed.rs:922
34: 0x555ad16dfd00 - <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once::hfc866af69ec8f7e1
at /rustc/66bf391c3aabfc77f5f7139fc9e6944f995d574e/src/liballoc/boxed.rs:922
35: 0x555ad16dfd00 - std::sys_common::thread::start_thread::h884843b1b0377783
at src/libstd/sys_common/thread.rs:13
36: 0x555ad16dfd00 - std::sys::unix::thread::Thread::new::thread_start::hf370570edee1b7e3
at src/libstd/sys/unix/thread.rs:79
37: 0x7f0722f1a3a7 - start_thread
at /var/tmp/portage/sys-libs/glibc-2.29-r5/work/glibc-2.29/nptl/pthread_create.c:486
38: 0x7f0722e2f0ff - __clone
39: 0x0 - <unknown>
failures:
tests::is_in
test result: FAILED. 2 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
error: test failed, to rerun pass '--lib'
the stdout test can also be made to fail by redirecting the test output via:
RUST_BACKTRACE=full cargo test | cat
And the stderr test can also be made to fail by redirecting the test output via:
RUST_BACKTRACE=full cargo test 2>/dev/null
I understand that this is the problem domain atty is targeted at solving, so its a bit tricky, but I suspect the "right" thing to do here is have the tests in question exec a common binary internally, where, supposedly, you can control the availability and state of the various IO handles, that way, you're testing the logic, not testing whether or not the user is consuming the tests in an approved way.
I have a program that reads from stdin
only when isatty returns false
let input_stdin = !atty::is(atty::Stream::Stdin);
When running this from a cron it always returns true
like if there were something in stdin but there is nothing.
use atty::Stream;
fn main() {
if atty::is(Stream::Stdout) {
println!("I'm a terminal");
} else {
println!("I'm not");
}
let input_stdin = !atty::is(atty::Stream::Stdin); // isatty returns false if there's something in stdin.
if input_stdin {
println!("stdin"); // how to prevent this to happen when calling it from a cron
}
}
Any idea how to prevent this so that I could call my app from a cron
job and distinguish when there is something in stdin and not?
Hiya @softprops wonder if you would be happy for people be using this crate still or whether it is deprecated ?
I know the API is very stable and people really love to use this where people looking for the magical 1.0.0 release :)
Also just wondering if any potentially - not saying there is - but any soundness issues if these arise would be still looked up ?
e.g. there is some community push to address some possible outstanding issue with PR:
It would be nice if you could spare a moment to look into the above ❤️
Cheers
On Mac OS, using the latest Rust nightly version, cloning and building this crate fails:
$ cargo run --example atty
Updating registry `https://github.com/rust-lang/crates.io-index`
Compiling libc v0.2.40
Compiling atty v0.2.9 (file:///Users/stephen/drive/hexops/hexi/display/tmp/atty)
error[E0428]: the name `is` is defined multiple times
--> src/lib.rs:164:1
|
40 | pub fn is(stream: Stream) -> bool {
| --------------------------------- previous definition of the value `is` here
...
164 | pub fn is(_stream: Stream) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `is` redefined here
|
= note: `is` must be defined only once in the value namespace of this module
error: aborting due to previous error
For more information about this error, try `rustc --explain E0428`.
error: Could not compile `atty`.
To learn more, run the command again with --verbose.
This may be the same regression as #21
All other crates are migrated already
What is atty all about?
Thanks for this! I'm using it a command runner[0] to figure out when to produce colored error messages and it works great.
It would be great if I could somehow fool atty into thinking that a stream is a terminal for testing, so that I can make sure that error messages are being formatted correctly when a terminal is attached.
It would be good for this crate to appear in https://crates.io/search?q=isatty.
Over time, ripgrep has grown its own tty detection code which includes a hack for (seemingly reliably) detecting the presence of a tty on Windows inside mintty. Would you be interested in a PR that brings it to this crate?
There isn't much code, but you can see it all here: https://github.com/BurntSushi/ripgrep/blob/master/src/atty.rs
There is a pretty long issue on the topic of mintty detection here, which includes the provenance of the hack: BurntSushi/ripgrep#94 --- Spoiler alert: it's what git
does.
The value of the handles returned by GetStdHandle are not 0, 1, and 2, so the standard predefined stream constants in Stdio.h (STDIN, STDOUT, and STDERR) cannot be used in functions that require a console handle.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682075(v=vs.85).aspx
The tests for std out/err are failing with a last err or 6 meaning invalid handle. Need to rethink windows again
it would be nice to skip travis commits when just working on windows. [ci skip] also skips appveyor builds. this seems to be customizable though
The is()
function gets defined twice, because you have one cfg
statement that tests for OS (unix) and one that tests for architecture (wasm32). Emscripten pretends to be unix, so is()
gets defined twice.
Proposed fix: turn the wasm32
architecture into an OS test for unknown
.
Line 118 in c92ca03
Windows 10 supports longer paths than MAXPATH. When stdout is attached to such a file, the above code panics because it tries to index beyond MAXPATH + 8.
I think this code should be modified to allocate up to 32,767 plus some buffer (see the Note at https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file).
My crate uom
has dev-dependencies
on quickcheck = "0.7"
. quickcheck
has a dependency on evn_logger = "0.5"
. evn_logger
has a dependency on atty = "0.2.5"
. I support older versions of rustc
in uom
and currently have a minimum of 1.28.0. The recent release of atty
v0.2.12 ended up breaking my build. The way env_logger
's dependency on atty
is written any patch version in the v0.2 series can be used and rustc
1.28.0 doesn't support the 2018 edition.
Would you consider yanking v0.2.12 or releasing a v0.2.13 which doesn't require the 2018 edition and re-releasing the 2018 edition changes as v0.3?
I've worked around issues like this in the past by only running my full test suite on a newer version of rustc
while ensuring the crate itself compiles with the older version. However it would be great if I could continue to run tests on the older version as well.
unit testing has proven unreliable because it ultimately depends on ci runtime internals and how they run tests. instead it would be better to use scripted integrations tests
Line 131 in 7b5df17
By replacing this vector with an array, we can remove the std dependency. The allocation is only 524 bytes long, and it wouldn't be unreasonable to allocate it on the stack (Rust's default stack size is 2MiB, giving us plenty of room).
We'd also need to remove the utf16 conversion that allocates to a string here:
Line 146 in 7b5df17
One solution would simply be to write s.contains(&[b'-' as u16, 'p' as _, 't' as _, 'y' as _])
, but there's also https://docs.rs/utf16_lit which makes this more readable
I'm afraid I didn't create a test case, but tried this crate and found it not to work on windows. I was calling is
from a program whose output was being piped, while running under the msys shell.
I did notice your code is significantly different from rustc's.
I was personally a little confused recently when I discovered the isatty
crate as we'd previously been using this crate for things like rustc and Cargo. Upon opening an issue seeking clarification it seems like the main difference is licensing. Would you be open to relicensing with Rust's same dual license? We may then be able to hopefully consolidate crates!
This interface assumes you are always asking if stdout its a tty. In other case you may want to ask if stderr is a tty.
Hi! It looks like this crate has been doing a good job of doing its thing for a while. What do you think about a 1.0
stable release? Are there any blocking design questions or issues lurking that need to be solved before that can happen?
It is very useful for testing.
Lines 131 to 141 in 7b5df17
As far as I can tell, the pointer deference on line 141 in unsound, as there is no guarantee the vector will be properly aligned for FILE_NAME_INFO
(which has an alignment of 4 due to FileNameLength
being a u32
)
I've initially attempted to integrate atty/termcolor into rustc at rust-lang/rust#48588 but unfortunately it looks like there may be a misdiagnosis of terminal colors! It looks like in the MSYS terminal/shell pipes are classified as ttys, for example this program:
extern crate atty;
fn main() {
println!("stdin: {}", atty::is(atty::Stream::Stdin));
println!("stdout: {}", atty::is(atty::Stream::Stdout));
println!("stderr: {}", atty::is(atty::Stream::Stderr));
}
Will print:
$ echo a | cargo run 2>&1 | cat
stdin: true
stdout: true
stderr: true
when run in MSYS.
The same program for Unix, however, prints:
$ echo a | cargo run 2>&1 | cat
stdin: false
stdout: false
stderr: false
With some debugging it looks like the filename reported for the MSYS pipes are along the lines of:
"\\msys-dd50a72ab4668b33-2996-pipe-0x5A"
"\\msys-dd50a72ab4668b33-2996-pipe-0x5C"
which looks to trigger this logic. Was the ||
there supposed to be &&
?
Rust now has a webassembly target, trying to use it in a project that depends on atty
results in a build failure:
% cargo +nightly build --target wasm32-unknown-unknown --release --verbose
Compiling atty v0.2.3
Running `rustc --crate-name atty /home/smarter/.cargo/registry/src/github.com-1ecc6299db9ec823/atty-0.2.3/src/lib.rs --crate-type lib --emit=dep-info,link -C opt-level=3 -C metadata=0a084c269a4ac4bc -C extra-filename=-0a084c269a4ac4bc --out-dir /home/smarter/hello/target/wasm32-unknown-unknown/release/deps --target wasm32-unknown-unknown -L dependency=/home/smarter/hello/target/wasm32-unknown-unknown/release/deps -L dependency=/home/smarter/hello/target/release/deps --cap-lints allow`
error[E0425]: cannot find function `is` in this scope
--> /home/smarter/.cargo/registry/src/github.com-1ecc6299db9ec823/atty-0.2.3/src/lib.rs:85:6
|
85 | !is(stream)
| ^^ not found in this scope
error: aborting due to previous error
error: Could not compile `atty`.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.