Coder Social home page Coder Social logo

atty's Introduction

atty

Build Status Build status Coverage Status crates.io Released API docs Master API docs

are you or are you not a tty?

install

Add the following to your Cargo.toml

[dependencies]
atty = "0.2"

usage

use atty::Stream;

fn main() {
  if atty::is(Stream::Stdout) {
    println!("I'm a terminal");
  } else {
    println!("I'm not");
  }
}

testing

This library has been unit tested on both unix and windows platforms (via appveyor).

A simple example program is provided in this repo to test various tty's. By default.

It prints

$ cargo run --example atty
stdout? true
stderr? true
stdin? true

To test std in, pipe some text to the program

$ echo "test" | cargo run --example atty
stdout? true
stderr? true
stdin? false

To test std out, pipe the program to something

$ cargo run --example atty | grep std
stdout? false
stderr? true
stdin? true

To test std err, pipe the program to something redirecting std err

$ cargo run --example atty 2>&1 | grep std
stdout? false
stderr? false
stdin? true

Doug Tangren (softprops) 2015-2019

atty's People

Contributors

adminxvii avatar alexbool avatar alexcrichton avatar burntsushi avatar busyjay avatar ehuss avatar ids1024 avatar ignatenkobrain avatar sburton84 avatar smarter avatar softprops avatar stlankes avatar yrashk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

atty's Issues

Consider MIT/Apache-2.0 license?

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!

Release 1.0

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?

Build failure because of 2018 edition

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.

Remove stdout assumption

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.

Allow faking a terminal for testing

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.

[0] https://github.com/casey/just

add integration tests for various platforms

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

is returns true on windows when stdout is piped

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.

Compilation failure using rust nightly webassembly target

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`.

Support no_std on windows

atty/src/lib.rs

Line 131 in 7b5df17

let mut name_info_bytes = vec![0u8; size + MAX_PATH * mem::size_of::<WCHAR>()];

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:

atty/src/lib.rs

Line 146 in 7b5df17

let name = String::from_utf16_lossy(s);

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

Pipes detected as a tty on MSYS

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 &&?

Fails to build for Mac OS

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

Maintenance status

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

cron atty::is(atty::Stream::Stdin)

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?

Possible soundness bug: alignment not checked

atty/src/lib.rs

Lines 131 to 141 in 7b5df17

let mut name_info_bytes = vec![0u8; size + MAX_PATH * mem::size_of::<WCHAR>()];
let res = GetFileInformationByHandleEx(
GetStdHandle(fd),
FileNameInfo,
&mut *name_info_bytes as *mut _ as *mut c_void,
name_info_bytes.len() as u32,
);
if res == 0 {
return false;
}
let name_info: &FILE_NAME_INFO = &*(name_info_bytes.as_ptr() as *const FILE_NAME_INFO);

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)

tty detection for mintty

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.

Fails tests in captive environments where stdin is closed

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.

Does not work correctly for wasm32-unknown-emscripten

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.