mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-28 11:20:36 +00:00
Ignore broken console output in some situations.
This commit is contained in:
parent
55869de80a
commit
7274307af4
@ -1,5 +1,5 @@
|
||||
use cargo::core::features;
|
||||
use cargo::{self, CliResult, Config};
|
||||
use cargo::{self, drop_print, drop_println, CliResult, Config};
|
||||
use clap::{AppSettings, Arg, ArgMatches};
|
||||
|
||||
use super::commands;
|
||||
@ -25,7 +25,8 @@ pub fn main(config: &mut Config) -> CliResult {
|
||||
};
|
||||
|
||||
if args.value_of("unstable-features") == Some("help") {
|
||||
println!(
|
||||
drop_println!(
|
||||
config,
|
||||
"
|
||||
Available unstable (nightly-only) flags:
|
||||
|
||||
@ -40,7 +41,8 @@ Available unstable (nightly-only) flags:
|
||||
Run with 'cargo -Z [FLAG] [SUBCOMMAND]'"
|
||||
);
|
||||
if !features::nightly_features_allowed() {
|
||||
println!(
|
||||
drop_println!(
|
||||
config,
|
||||
"\nUnstable flags are only available on the nightly channel \
|
||||
of Cargo, but this is the `{}` channel.\n\
|
||||
{}",
|
||||
@ -48,7 +50,8 @@ Run with 'cargo -Z [FLAG] [SUBCOMMAND]'"
|
||||
features::SEE_CHANNELS
|
||||
);
|
||||
}
|
||||
println!(
|
||||
drop_println!(
|
||||
config,
|
||||
"\nSee https://doc.rust-lang.org/nightly/cargo/reference/unstable.html \
|
||||
for more information about these flags."
|
||||
);
|
||||
@ -58,7 +61,7 @@ Run with 'cargo -Z [FLAG] [SUBCOMMAND]'"
|
||||
let is_verbose = args.occurrences_of("verbose") > 0;
|
||||
if args.is_present("version") {
|
||||
let version = get_version_string(is_verbose);
|
||||
print!("{}", version);
|
||||
drop_print!(config, "{}", version);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -69,19 +72,19 @@ Run with 'cargo -Z [FLAG] [SUBCOMMAND]'"
|
||||
}
|
||||
|
||||
if args.is_present("list") {
|
||||
println!("Installed Commands:");
|
||||
drop_println!(config, "Installed Commands:");
|
||||
for command in list_commands(config) {
|
||||
match command {
|
||||
CommandInfo::BuiltIn { name, about } => {
|
||||
let summary = about.unwrap_or_default();
|
||||
let summary = summary.lines().next().unwrap_or(&summary); // display only the first line
|
||||
println!(" {:<20} {}", name, summary)
|
||||
drop_println!(config, " {:<20} {}", name, summary);
|
||||
}
|
||||
CommandInfo::External { name, path } => {
|
||||
if is_verbose {
|
||||
println!(" {:<20} {}", name, path.display())
|
||||
drop_println!(config, " {:<20} {}", name, path.display());
|
||||
} else {
|
||||
println!(" {}", name)
|
||||
drop_println!(config, " {}", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
use crate::command_prelude::*;
|
||||
|
||||
use cargo::print_json;
|
||||
use serde::Serialize;
|
||||
|
||||
pub fn cli() -> App {
|
||||
@ -30,6 +28,6 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
||||
|
||||
let location = ProjectLocation { root };
|
||||
|
||||
print_json(&location);
|
||||
config.shell().print_json(&location);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
use crate::command_prelude::*;
|
||||
|
||||
use cargo::ops::{self, OutputMetadataOptions};
|
||||
use cargo::print_json;
|
||||
|
||||
pub fn cli() -> App {
|
||||
subcommand("metadata")
|
||||
@ -54,6 +52,6 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
||||
};
|
||||
|
||||
let result = ops::output_metadata(&ws, &options)?;
|
||||
print_json(&result);
|
||||
config.shell().print_json(&result);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -37,6 +37,6 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
||||
let ws = args.workspace(config)?;
|
||||
let spec = args.value_of("spec").or_else(|| args.value_of("package"));
|
||||
let spec = ops::pkgid(&ws, spec)?;
|
||||
println!("{}", spec);
|
||||
cargo::drop_println!(config, "{}", spec);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
use crate::command_prelude::*;
|
||||
|
||||
use cargo::print_json;
|
||||
|
||||
pub fn cli() -> App {
|
||||
subcommand("read-manifest")
|
||||
.about(
|
||||
@ -17,6 +15,6 @@ Deprecated, use `cargo metadata --no-deps` instead.\
|
||||
|
||||
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
||||
let ws = args.workspace(config)?;
|
||||
print_json(&ws.current()?);
|
||||
config.shell().print_json(&ws.current()?);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
||||
if args.is_present("version") {
|
||||
let verbose = args.occurrences_of("verbose") > 0;
|
||||
let version = cli::get_version_string(verbose);
|
||||
print!("{}", version);
|
||||
cargo::drop_print!(config, "{}", version);
|
||||
return Ok(());
|
||||
}
|
||||
let prefix = if args.is_present("no-indent") {
|
||||
|
@ -3,8 +3,6 @@ use crate::command_prelude::*;
|
||||
use std::collections::HashMap;
|
||||
use std::process;
|
||||
|
||||
use cargo::print_json;
|
||||
|
||||
pub fn cli() -> App {
|
||||
subcommand("verify-project")
|
||||
.about("Check correctness of crate manifest")
|
||||
@ -13,19 +11,15 @@ pub fn cli() -> App {
|
||||
}
|
||||
|
||||
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
||||
fn fail(reason: &str, value: &str) -> ! {
|
||||
let mut h = HashMap::new();
|
||||
h.insert(reason.to_string(), value.to_string());
|
||||
print_json(&h);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
if let Err(e) = args.workspace(config) {
|
||||
fail("invalid", &e.to_string())
|
||||
let mut h = HashMap::new();
|
||||
h.insert("invalid".to_string(), e.to_string());
|
||||
config.shell().print_json(&h);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
let mut h = HashMap::new();
|
||||
h.insert("success".to_string(), "true".to_string());
|
||||
print_json(&h);
|
||||
config.shell().print_json(&h);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use crate::command_prelude::*;
|
||||
|
||||
use crate::cli;
|
||||
use crate::command_prelude::*;
|
||||
|
||||
pub fn cli() -> App {
|
||||
subcommand("version")
|
||||
@ -8,9 +7,9 @@ pub fn cli() -> App {
|
||||
.arg(opt("quiet", "No output printed to stdout").short("q"))
|
||||
}
|
||||
|
||||
pub fn exec(_config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
||||
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
||||
let verbose = args.occurrences_of("verbose") > 0;
|
||||
let version = cli::get_version_string(verbose);
|
||||
print!("{}", version);
|
||||
cargo::drop_print!(config, "{}", version);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -500,7 +500,7 @@ impl<'cfg> DrainState<'cfg> {
|
||||
plan.update(&module_name, &cmd, &filenames)?;
|
||||
}
|
||||
Message::Stdout(out) => {
|
||||
cx.bcx.config.shell().stdout_println(out);
|
||||
writeln!(cx.bcx.config.shell().out(), "{}", out)?;
|
||||
}
|
||||
Message::Stderr(err) => {
|
||||
let mut shell = cx.bcx.config.shell();
|
||||
@ -700,7 +700,7 @@ impl<'cfg> DrainState<'cfg> {
|
||||
success: error.is_none(),
|
||||
}
|
||||
.to_json_string();
|
||||
cx.bcx.config.shell().stdout_println(msg);
|
||||
writeln!(cx.bcx.config.shell().out(), "{}", msg)?;
|
||||
}
|
||||
|
||||
if let Some(e) = error {
|
||||
|
@ -146,7 +146,7 @@ fn compile<'cfg>(
|
||||
&unit.target,
|
||||
cx.files().message_cache_path(unit),
|
||||
cx.bcx.build_config.message_format,
|
||||
cx.bcx.config.shell().supports_color(),
|
||||
cx.bcx.config.shell().err_supports_color(),
|
||||
)
|
||||
} else {
|
||||
Work::noop()
|
||||
@ -1109,7 +1109,7 @@ struct OutputOptions {
|
||||
impl OutputOptions {
|
||||
fn new(cx: &Context<'_, '_>, unit: &Unit) -> OutputOptions {
|
||||
let look_for_metadata_directive = cx.rmeta_required(unit);
|
||||
let color = cx.bcx.config.shell().supports_color();
|
||||
let color = cx.bcx.config.shell().err_supports_color();
|
||||
let path = cx.files().message_cache_path(unit);
|
||||
// Remove old cache, ignore ENOENT, which is the common case.
|
||||
drop(fs::remove_file(&path));
|
||||
|
@ -245,7 +245,7 @@ impl<'cfg> Timings<'cfg> {
|
||||
rmeta_time: unit_time.rmeta_time,
|
||||
}
|
||||
.to_json_string();
|
||||
self.config.shell().stdout_println(msg);
|
||||
crate::drop_println!(self.config, "{}", msg);
|
||||
}
|
||||
self.unit_times.push(unit_time);
|
||||
}
|
||||
|
@ -113,6 +113,6 @@ pub fn emit_serialized_unit_graph(root_units: &[Unit], unit_graph: &UnitGraph) -
|
||||
let stdout = std::io::stdout();
|
||||
let mut lock = stdout.lock();
|
||||
serde_json::to_writer(&mut lock, &s)?;
|
||||
writeln!(lock)?;
|
||||
drop(writeln!(lock));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -500,7 +500,7 @@ impl Manifest {
|
||||
pub fn print_teapot(&self, config: &Config) {
|
||||
if let Some(teapot) = self.im_a_teapot {
|
||||
if config.cli_unstable().print_im_a_teapot {
|
||||
println!("im-a-teapot = {}", teapot);
|
||||
crate::drop_println!(config, "im-a-teapot = {}", teapot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -573,9 +573,13 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
||||
for ((pkg_id, dep_kind), features) in &self.activated_features {
|
||||
let r_features = self.resolve.features(*pkg_id);
|
||||
if !r_features.iter().eq(features.iter()) {
|
||||
eprintln!(
|
||||
crate::drop_eprintln!(
|
||||
self.ws.config(),
|
||||
"{}/{:?} features mismatch\nresolve: {:?}\nnew: {:?}\n",
|
||||
pkg_id, dep_kind, r_features, features
|
||||
pkg_id,
|
||||
dep_kind,
|
||||
r_features,
|
||||
features
|
||||
);
|
||||
found = true;
|
||||
}
|
||||
|
@ -14,13 +14,13 @@ pub enum Verbosity {
|
||||
Quiet,
|
||||
}
|
||||
|
||||
/// An abstraction around a `Write`able object that remembers preferences for output verbosity and
|
||||
/// color.
|
||||
/// An abstraction around console output that remembers preferences for output
|
||||
/// verbosity and color.
|
||||
pub struct Shell {
|
||||
/// the `Write`able object, either with or without color support (represented by different enum
|
||||
/// variants)
|
||||
err: ShellOut,
|
||||
/// How verbose messages should be
|
||||
/// Wrapper around stdout/stderr. This helps with supporting sending
|
||||
/// output to a memory buffer which is useful for tests.
|
||||
output: ShellOut,
|
||||
/// How verbose messages should be.
|
||||
verbosity: Verbosity,
|
||||
/// Flag that indicates the current line needs to be cleared before
|
||||
/// printing. Used when a progress bar is currently displayed.
|
||||
@ -29,7 +29,7 @@ pub struct Shell {
|
||||
|
||||
impl fmt::Debug for Shell {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.err {
|
||||
match self.output {
|
||||
ShellOut::Write(_) => f
|
||||
.debug_struct("Shell")
|
||||
.field("verbosity", &self.verbosity)
|
||||
@ -49,8 +49,9 @@ enum ShellOut {
|
||||
Write(Box<dyn Write>),
|
||||
/// Color-enabled stdio, with information on whether color should be used
|
||||
Stream {
|
||||
stream: StandardStream,
|
||||
tty: bool,
|
||||
stdout: StandardStream,
|
||||
stderr: StandardStream,
|
||||
stderr_tty: bool,
|
||||
color_choice: ColorChoice,
|
||||
},
|
||||
}
|
||||
@ -70,11 +71,13 @@ impl Shell {
|
||||
/// Creates a new shell (color choice and verbosity), defaulting to 'auto' color and verbose
|
||||
/// output.
|
||||
pub fn new() -> Shell {
|
||||
let auto = ColorChoice::CargoAuto.to_termcolor_color_choice();
|
||||
Shell {
|
||||
err: ShellOut::Stream {
|
||||
stream: StandardStream::stderr(ColorChoice::CargoAuto.to_termcolor_color_choice()),
|
||||
output: ShellOut::Stream {
|
||||
stdout: StandardStream::stdout(auto),
|
||||
stderr: StandardStream::stderr(auto),
|
||||
color_choice: ColorChoice::CargoAuto,
|
||||
tty: atty::is(atty::Stream::Stderr),
|
||||
stderr_tty: atty::is(atty::Stream::Stderr),
|
||||
},
|
||||
verbosity: Verbosity::Verbose,
|
||||
needs_clear: false,
|
||||
@ -84,7 +87,7 @@ impl Shell {
|
||||
/// Creates a shell from a plain writable object, with no color, and max verbosity.
|
||||
pub fn from_write(out: Box<dyn Write>) -> Shell {
|
||||
Shell {
|
||||
err: ShellOut::Write(out),
|
||||
output: ShellOut::Write(out),
|
||||
verbosity: Verbosity::Verbose,
|
||||
needs_clear: false,
|
||||
}
|
||||
@ -105,18 +108,12 @@ impl Shell {
|
||||
if self.needs_clear {
|
||||
self.err_erase_line();
|
||||
}
|
||||
self.err.print(status, message, color, justified)
|
||||
self.output
|
||||
.message_stderr(status, message, color, justified)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stdout_println(&mut self, message: impl fmt::Display) {
|
||||
if self.needs_clear {
|
||||
self.err_erase_line();
|
||||
}
|
||||
println!("{}", message);
|
||||
}
|
||||
|
||||
/// Sets whether the next print should clear the current line.
|
||||
pub fn set_needs_clear(&mut self, needs_clear: bool) {
|
||||
self.needs_clear = needs_clear;
|
||||
@ -129,31 +126,44 @@ impl Shell {
|
||||
|
||||
/// Returns the width of the terminal in spaces, if any.
|
||||
pub fn err_width(&self) -> Option<usize> {
|
||||
match self.err {
|
||||
ShellOut::Stream { tty: true, .. } => imp::stderr_width(),
|
||||
match self.output {
|
||||
ShellOut::Stream {
|
||||
stderr_tty: true, ..
|
||||
} => imp::stderr_width(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if stderr is a tty.
|
||||
pub fn is_err_tty(&self) -> bool {
|
||||
match self.err {
|
||||
ShellOut::Stream { tty, .. } => tty,
|
||||
match self.output {
|
||||
ShellOut::Stream { stderr_tty, .. } => stderr_tty,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a reference to the underlying writer.
|
||||
/// Gets a reference to the underlying stdout writer.
|
||||
pub fn out(&mut self) -> &mut dyn Write {
|
||||
if self.needs_clear {
|
||||
self.err_erase_line();
|
||||
}
|
||||
self.output.stdout()
|
||||
}
|
||||
|
||||
/// Gets a reference to the underlying stderr writer.
|
||||
pub fn err(&mut self) -> &mut dyn Write {
|
||||
if self.needs_clear {
|
||||
self.err_erase_line();
|
||||
}
|
||||
self.err.as_write()
|
||||
self.output.stderr()
|
||||
}
|
||||
|
||||
/// Erase from cursor to end of line.
|
||||
pub fn err_erase_line(&mut self) {
|
||||
if let ShellOut::Stream { tty: true, .. } = self.err {
|
||||
if let ShellOut::Stream {
|
||||
stderr_tty: true, ..
|
||||
} = self.output
|
||||
{
|
||||
imp::err_erase_line(self);
|
||||
self.needs_clear = false;
|
||||
}
|
||||
@ -216,7 +226,8 @@ impl Shell {
|
||||
if self.needs_clear {
|
||||
self.err_erase_line();
|
||||
}
|
||||
self.err.print(&"error", Some(&message), Red, false)
|
||||
self.output
|
||||
.message_stderr(&"error", Some(&message), Red, false)
|
||||
}
|
||||
|
||||
/// Prints an amber 'warning' message.
|
||||
@ -245,10 +256,11 @@ impl Shell {
|
||||
/// Updates the color choice (always, never, or auto) from a string..
|
||||
pub fn set_color_choice(&mut self, color: Option<&str>) -> CargoResult<()> {
|
||||
if let ShellOut::Stream {
|
||||
ref mut stream,
|
||||
ref mut stdout,
|
||||
ref mut stderr,
|
||||
ref mut color_choice,
|
||||
..
|
||||
} = self.err
|
||||
} = self.output
|
||||
{
|
||||
let cfg = match color {
|
||||
Some("always") => ColorChoice::Always,
|
||||
@ -263,7 +275,9 @@ impl Shell {
|
||||
),
|
||||
};
|
||||
*color_choice = cfg;
|
||||
*stream = StandardStream::stderr(cfg.to_termcolor_color_choice());
|
||||
let choice = cfg.to_termcolor_color_choice();
|
||||
*stdout = StandardStream::stdout(choice);
|
||||
*stderr = StandardStream::stderr(choice);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -273,17 +287,17 @@ impl Shell {
|
||||
/// If we are not using a color stream, this will always return `Never`, even if the color
|
||||
/// choice has been set to something else.
|
||||
pub fn color_choice(&self) -> ColorChoice {
|
||||
match self.err {
|
||||
match self.output {
|
||||
ShellOut::Stream { color_choice, .. } => color_choice,
|
||||
ShellOut::Write(_) => ColorChoice::Never,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the shell supports color.
|
||||
pub fn supports_color(&self) -> bool {
|
||||
match &self.err {
|
||||
pub fn err_supports_color(&self) -> bool {
|
||||
match &self.output {
|
||||
ShellOut::Write(_) => false,
|
||||
ShellOut::Stream { stream, .. } => stream.supports_color(),
|
||||
ShellOut::Stream { stderr, .. } => stderr.supports_color(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -302,6 +316,11 @@ impl Shell {
|
||||
self.err().write_all(message)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn print_json<T: serde::ser::Serialize>(&mut self, obj: &T) {
|
||||
let encoded = serde_json::to_string(&obj).unwrap();
|
||||
drop(writeln!(self.out(), "{}", encoded));
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Shell {
|
||||
@ -314,7 +333,7 @@ impl ShellOut {
|
||||
/// Prints out a message with a status. The status comes first, and is bold plus the given
|
||||
/// color. The status can be justified, in which case the max width that will right align is
|
||||
/// 12 chars.
|
||||
fn print(
|
||||
fn message_stderr(
|
||||
&mut self,
|
||||
status: &dyn fmt::Display,
|
||||
message: Option<&dyn fmt::Display>,
|
||||
@ -322,20 +341,20 @@ impl ShellOut {
|
||||
justified: bool,
|
||||
) -> CargoResult<()> {
|
||||
match *self {
|
||||
ShellOut::Stream { ref mut stream, .. } => {
|
||||
stream.reset()?;
|
||||
stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(color)))?;
|
||||
ShellOut::Stream { ref mut stderr, .. } => {
|
||||
stderr.reset()?;
|
||||
stderr.set_color(ColorSpec::new().set_bold(true).set_fg(Some(color)))?;
|
||||
if justified {
|
||||
write!(stream, "{:>12}", status)?;
|
||||
write!(stderr, "{:>12}", status)?;
|
||||
} else {
|
||||
write!(stream, "{}", status)?;
|
||||
stream.set_color(ColorSpec::new().set_bold(true))?;
|
||||
write!(stream, ":")?;
|
||||
write!(stderr, "{}", status)?;
|
||||
stderr.set_color(ColorSpec::new().set_bold(true))?;
|
||||
write!(stderr, ":")?;
|
||||
}
|
||||
stream.reset()?;
|
||||
stderr.reset()?;
|
||||
match message {
|
||||
Some(message) => writeln!(stream, " {}", message)?,
|
||||
None => write!(stream, " ")?,
|
||||
Some(message) => writeln!(stderr, " {}", message)?,
|
||||
None => write!(stderr, " ")?,
|
||||
}
|
||||
}
|
||||
ShellOut::Write(ref mut w) => {
|
||||
@ -353,10 +372,18 @@ impl ShellOut {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets this object as a `io::Write`.
|
||||
fn as_write(&mut self) -> &mut dyn Write {
|
||||
/// Gets stdout as a `io::Write`.
|
||||
fn stdout(&mut self) -> &mut dyn Write {
|
||||
match *self {
|
||||
ShellOut::Stream { ref mut stream, .. } => stream,
|
||||
ShellOut::Stream { ref mut stdout, .. } => stdout,
|
||||
ShellOut::Write(ref mut w) => w,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets stderr as a `io::Write`.
|
||||
fn stderr(&mut self) -> &mut dyn Write {
|
||||
match *self {
|
||||
ShellOut::Stream { ref mut stderr, .. } => stderr,
|
||||
ShellOut::Write(ref mut w) => w,
|
||||
}
|
||||
}
|
||||
@ -404,7 +431,7 @@ mod imp {
|
||||
// This is the "EL - Erase in Line" sequence. It clears from the cursor
|
||||
// to the end of line.
|
||||
// https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences
|
||||
let _ = shell.err.as_write().write_all(b"\x1B[K");
|
||||
let _ = shell.output.stderr().write_all(b"\x1B[K");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,6 @@ use crate::core::shell::Verbosity::Verbose;
|
||||
use crate::core::Shell;
|
||||
use anyhow::Error;
|
||||
use log::debug;
|
||||
use serde::ser;
|
||||
use std::fmt;
|
||||
|
||||
pub use crate::util::errors::{InternalError, VerboseError};
|
||||
@ -93,11 +92,6 @@ impl fmt::Display for VersionInfo {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_json<T: ser::Serialize>(obj: &T) {
|
||||
let encoded = serde_json::to_string(&obj).unwrap();
|
||||
println!("{}", encoded);
|
||||
}
|
||||
|
||||
pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! {
|
||||
debug!("exit_with_error; err={:?}", err);
|
||||
if let Some(ref err) = err.error {
|
||||
|
@ -9,11 +9,11 @@ use tempfile::Builder as TempFileBuilder;
|
||||
use crate::core::compiler::Freshness;
|
||||
use crate::core::compiler::{CompileKind, DefaultExecutor, Executor};
|
||||
use crate::core::{Edition, Package, PackageId, Source, SourceId, Workspace};
|
||||
use crate::ops;
|
||||
use crate::ops::common_for_install_and_uninstall::*;
|
||||
use crate::sources::{GitSource, SourceConfigMap};
|
||||
use crate::util::errors::{CargoResult, CargoResultExt};
|
||||
use crate::util::{paths, Config, Filesystem};
|
||||
use crate::{drop_println, ops};
|
||||
|
||||
struct Transaction {
|
||||
bins: Vec<PathBuf>,
|
||||
@ -531,9 +531,9 @@ pub fn install_list(dst: Option<&str>, config: &Config) -> CargoResult<()> {
|
||||
let root = resolve_root(dst, config)?;
|
||||
let tracker = InstallTracker::load(config, &root)?;
|
||||
for (k, v) in tracker.all_installed_bins() {
|
||||
println!("{}:", k);
|
||||
drop_println!(config, "{}:", k);
|
||||
for bin in v {
|
||||
println!(" {}", bin);
|
||||
drop_println!(config, " {}", bin);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -15,12 +15,12 @@ use tar::{Archive, Builder, EntryType, Header};
|
||||
use crate::core::compiler::{BuildConfig, CompileMode, DefaultExecutor, Executor};
|
||||
use crate::core::{Feature, Shell, Verbosity, Workspace};
|
||||
use crate::core::{Package, PackageId, PackageSet, Resolve, Source, SourceId};
|
||||
use crate::ops;
|
||||
use crate::sources::PathSource;
|
||||
use crate::util::errors::{CargoResult, CargoResultExt};
|
||||
use crate::util::paths;
|
||||
use crate::util::toml::TomlManifest;
|
||||
use crate::util::{self, restricted_names, Config, FileLock};
|
||||
use crate::{drop_println, ops};
|
||||
|
||||
pub struct PackageOpts<'cfg> {
|
||||
pub config: &'cfg Config,
|
||||
@ -102,7 +102,7 @@ pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult<Option
|
||||
|
||||
if opts.list {
|
||||
for ar_file in ar_files {
|
||||
println!("{}", ar_file.rel_str);
|
||||
drop_println!(config, "{}", ar_file.rel_str);
|
||||
}
|
||||
return Ok(None);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ use crate::util::errors::{CargoResult, CargoResultExt};
|
||||
use crate::util::important_paths::find_root_manifest_for_wd;
|
||||
use crate::util::IntoUrl;
|
||||
use crate::util::{paths, validate_package_name};
|
||||
use crate::version;
|
||||
use crate::{drop_print, drop_println, version};
|
||||
|
||||
/// Registry settings loaded from config files.
|
||||
///
|
||||
@ -660,7 +660,8 @@ pub fn registry_login(
|
||||
let token = match token {
|
||||
Some(token) => token,
|
||||
None => {
|
||||
println!(
|
||||
drop_println!(
|
||||
config,
|
||||
"please visit {}/me and paste the API Token below",
|
||||
registry.host()
|
||||
);
|
||||
@ -751,11 +752,11 @@ pub fn modify_owners(config: &Config, opts: &OwnersOptions) -> CargoResult<()> {
|
||||
.list_owners(&name)
|
||||
.chain_err(|| format!("failed to list owners of crate {}", name))?;
|
||||
for owner in owners.iter() {
|
||||
print!("{}", owner.login);
|
||||
drop_print!(config, "{}", owner.login);
|
||||
match (owner.name.as_ref(), owner.email.as_ref()) {
|
||||
(Some(name), Some(email)) => println!(" ({} <{}>)", name, email),
|
||||
(Some(s), None) | (None, Some(s)) => println!(" ({})", s),
|
||||
(None, None) => println!(),
|
||||
(Some(name), Some(email)) => drop_println!(config, " ({} <{}>)", name, email),
|
||||
(Some(s), None) | (None, Some(s)) => drop_println!(config, " ({})", s),
|
||||
(None, None) => drop_println!(config),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -876,12 +877,13 @@ pub fn search(
|
||||
}
|
||||
None => name,
|
||||
};
|
||||
println!("{}", line);
|
||||
drop_println!(config, "{}", line);
|
||||
}
|
||||
|
||||
let search_max_limit = 100;
|
||||
if total_crates > limit && limit < search_max_limit {
|
||||
println!(
|
||||
drop_println!(
|
||||
config,
|
||||
"... and {} crates more (use --limit N to see more)",
|
||||
total_crates - limit
|
||||
);
|
||||
@ -894,7 +896,12 @@ pub fn search(
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
println!("... and {} crates more{}", total_crates - limit, extra);
|
||||
drop_println!(
|
||||
config,
|
||||
"... and {} crates more{}",
|
||||
total_crates - limit,
|
||||
extra
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -6,7 +6,8 @@ use crate::core::dependency::DepKind;
|
||||
use crate::core::resolver::{HasDevUnits, ResolveOpts};
|
||||
use crate::core::{Package, PackageId, PackageIdSpec, Workspace};
|
||||
use crate::ops::{self, Packages};
|
||||
use crate::util::CargoResult;
|
||||
use crate::util::{CargoResult, Config};
|
||||
use crate::{drop_print, drop_println};
|
||||
use anyhow::{bail, Context};
|
||||
use graph::Graph;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
@ -200,12 +201,17 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()
|
||||
graph.invert();
|
||||
}
|
||||
|
||||
print(opts, root_indexes, &graph)?;
|
||||
print(ws.config(), opts, root_indexes, &graph)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Prints a tree for each given root.
|
||||
fn print(opts: &TreeOptions, roots: Vec<usize>, graph: &Graph<'_>) -> CargoResult<()> {
|
||||
fn print(
|
||||
config: &Config,
|
||||
opts: &TreeOptions,
|
||||
roots: Vec<usize>,
|
||||
graph: &Graph<'_>,
|
||||
) -> CargoResult<()> {
|
||||
let format = Pattern::new(&opts.format)
|
||||
.with_context(|| format!("tree format `{}` not valid", opts.format))?;
|
||||
|
||||
@ -220,7 +226,7 @@ fn print(opts: &TreeOptions, roots: Vec<usize>, graph: &Graph<'_>) -> CargoResul
|
||||
|
||||
for (i, root_index) in roots.into_iter().enumerate() {
|
||||
if i != 0 {
|
||||
println!();
|
||||
drop_println!(config);
|
||||
}
|
||||
|
||||
// A stack of bools used to determine where | symbols should appear
|
||||
@ -231,6 +237,7 @@ fn print(opts: &TreeOptions, roots: Vec<usize>, graph: &Graph<'_>) -> CargoResul
|
||||
let mut print_stack = vec![];
|
||||
|
||||
print_node(
|
||||
config,
|
||||
graph,
|
||||
root_index,
|
||||
&format,
|
||||
@ -248,6 +255,7 @@ fn print(opts: &TreeOptions, roots: Vec<usize>, graph: &Graph<'_>) -> CargoResul
|
||||
|
||||
/// Prints a package and all of its dependencies.
|
||||
fn print_node<'a>(
|
||||
config: &Config,
|
||||
graph: &'a Graph<'_>,
|
||||
node_index: usize,
|
||||
format: &Pattern,
|
||||
@ -261,12 +269,12 @@ fn print_node<'a>(
|
||||
let new = no_dedupe || visited_deps.insert(node_index);
|
||||
|
||||
match prefix {
|
||||
Prefix::Depth => print!("{}", levels_continue.len()),
|
||||
Prefix::Depth => drop_print!(config, "{}", levels_continue.len()),
|
||||
Prefix::Indent => {
|
||||
if let Some((last_continues, rest)) = levels_continue.split_last() {
|
||||
for continues in rest {
|
||||
let c = if *continues { symbols.down } else { " " };
|
||||
print!("{} ", c);
|
||||
drop_print!(config, "{} ", c);
|
||||
}
|
||||
|
||||
let c = if *last_continues {
|
||||
@ -274,7 +282,7 @@ fn print_node<'a>(
|
||||
} else {
|
||||
symbols.ell
|
||||
};
|
||||
print!("{0}{1}{1} ", c, symbols.right);
|
||||
drop_print!(config, "{0}{1}{1} ", c, symbols.right);
|
||||
}
|
||||
}
|
||||
Prefix::None => {}
|
||||
@ -290,7 +298,7 @@ fn print_node<'a>(
|
||||
} else {
|
||||
" (*)"
|
||||
};
|
||||
println!("{}{}", format.display(graph, node_index), star);
|
||||
drop_println!(config, "{}{}", format.display(graph, node_index), star);
|
||||
|
||||
if !new || in_cycle {
|
||||
return;
|
||||
@ -304,6 +312,7 @@ fn print_node<'a>(
|
||||
EdgeKind::Feature,
|
||||
] {
|
||||
print_dependencies(
|
||||
config,
|
||||
graph,
|
||||
node_index,
|
||||
format,
|
||||
@ -321,6 +330,7 @@ fn print_node<'a>(
|
||||
|
||||
/// Prints all the dependencies of a package for the given dependency kind.
|
||||
fn print_dependencies<'a>(
|
||||
config: &Config,
|
||||
graph: &'a Graph<'_>,
|
||||
node_index: usize,
|
||||
format: &Pattern,
|
||||
@ -348,10 +358,10 @@ fn print_dependencies<'a>(
|
||||
if let Some(name) = name {
|
||||
for continues in &**levels_continue {
|
||||
let c = if *continues { symbols.down } else { " " };
|
||||
print!("{} ", c);
|
||||
drop_print!(config, "{} ", c);
|
||||
}
|
||||
|
||||
println!("{}", name);
|
||||
drop_println!(config, "{}", name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -359,6 +369,7 @@ fn print_dependencies<'a>(
|
||||
while let Some(dependency) = it.next() {
|
||||
levels_continue.push(it.peek().is_some());
|
||||
print_node(
|
||||
config,
|
||||
graph,
|
||||
*dependency,
|
||||
format,
|
||||
|
@ -19,20 +19,23 @@ pub struct VendorOptions<'a> {
|
||||
}
|
||||
|
||||
pub fn vendor(ws: &Workspace<'_>, opts: &VendorOptions<'_>) -> CargoResult<()> {
|
||||
let config = ws.config();
|
||||
let mut extra_workspaces = Vec::new();
|
||||
for extra in opts.extra.iter() {
|
||||
let extra = ws.config().cwd().join(extra);
|
||||
let ws = Workspace::new(&extra, ws.config())?;
|
||||
let extra = config.cwd().join(extra);
|
||||
let ws = Workspace::new(&extra, config)?;
|
||||
extra_workspaces.push(ws);
|
||||
}
|
||||
let workspaces = extra_workspaces.iter().chain(Some(ws)).collect::<Vec<_>>();
|
||||
let vendor_config =
|
||||
sync(ws.config(), &workspaces, opts).chain_err(|| "failed to sync".to_string())?;
|
||||
sync(config, &workspaces, opts).chain_err(|| "failed to sync".to_string())?;
|
||||
|
||||
let shell = ws.config().shell();
|
||||
if shell.verbosity() != Verbosity::Quiet {
|
||||
eprint!("To use vendored sources, add this to your .cargo/config for this project:\n\n");
|
||||
print!("{}", &toml::to_string(&vendor_config).unwrap());
|
||||
if config.shell().verbosity() != Verbosity::Quiet {
|
||||
crate::drop_eprint!(
|
||||
config,
|
||||
"To use vendored sources, add this to your .cargo/config for this project:\n\n"
|
||||
);
|
||||
crate::drop_print!(config, "{}", &toml::to_string(&vendor_config).unwrap());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1744,3 +1744,45 @@ impl StringList {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! __shell_print {
|
||||
($config:expr, $which:ident, $newline:literal, $($arg:tt)*) => ({
|
||||
let mut shell = $config.shell();
|
||||
let out = shell.$which();
|
||||
drop(out.write_fmt(format_args!($($arg)*)));
|
||||
if $newline {
|
||||
drop(out.write_all(b"\n"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! drop_println {
|
||||
($config:expr) => ( $crate::drop_print!($config, "\n") );
|
||||
($config:expr, $($arg:tt)*) => (
|
||||
$crate::__shell_print!($config, out, true, $($arg)*)
|
||||
);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! drop_eprintln {
|
||||
($config:expr) => ( $crate::drop_eprint!($config, "\n") );
|
||||
($config:expr, $($arg:tt)*) => (
|
||||
$crate::__shell_print!($config, err, true, $($arg)*)
|
||||
);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! drop_print {
|
||||
($config:expr, $($arg:tt)*) => (
|
||||
$crate::__shell_print!($config, out, false, $($arg)*)
|
||||
);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! drop_eprint {
|
||||
($config:expr, $($arg:tt)*) => (
|
||||
$crate::__shell_print!($config, err, false, $($arg)*)
|
||||
);
|
||||
}
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Read;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Stdio;
|
||||
use std::str;
|
||||
|
||||
use cargo_test_support::cargo_process;
|
||||
@ -371,3 +373,24 @@ fn z_flags_help() {
|
||||
.with_stdout_contains(" -Z unstable-options -- Allow the usage of unstable options")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn closed_output_ok() {
|
||||
// Checks that closed output doesn't cause an error.
|
||||
let mut p = cargo_process("--list").build_command();
|
||||
p.stdout(Stdio::piped()).stderr(Stdio::piped());
|
||||
let mut child = p.spawn().unwrap();
|
||||
// Close stdout
|
||||
drop(child.stdout.take());
|
||||
// Read stderr
|
||||
let mut s = String::new();
|
||||
child
|
||||
.stderr
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.read_to_string(&mut s)
|
||||
.unwrap();
|
||||
let status = child.wait().unwrap();
|
||||
assert!(status.success());
|
||||
assert!(s.is_empty(), s);
|
||||
}
|
||||
|
@ -23,6 +23,10 @@ fn simple_list() {
|
||||
"id": 70,
|
||||
"login": "github:rust-lang:core",
|
||||
"name": "Core"
|
||||
},
|
||||
{
|
||||
"id": 123,
|
||||
"login": "octocat"
|
||||
}
|
||||
]
|
||||
}"#;
|
||||
@ -43,7 +47,14 @@ fn simple_list() {
|
||||
.file("src/main.rs", "fn main() {}")
|
||||
.build();
|
||||
|
||||
p.cargo("owner -l --token sekrit").run();
|
||||
p.cargo("owner -l --token sekrit")
|
||||
.with_stdout(
|
||||
"\
|
||||
github:rust-lang:core (Core)
|
||||
octocat
|
||||
",
|
||||
)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
|
@ -35,9 +35,45 @@ fn write_crates(dest: &Path) {
|
||||
"repository": "https://github.com/nick29581/libhoare",
|
||||
"updated_at": "2014-11-20T21:49:21Z",
|
||||
"versions": null
|
||||
}],
|
||||
},
|
||||
{
|
||||
"id": "postgres",
|
||||
"name": "postgres",
|
||||
"updated_at": "2020-05-01T23:17:54.335921+00:00",
|
||||
"versions": null,
|
||||
"keywords": null,
|
||||
"categories": null,
|
||||
"badges": [
|
||||
{
|
||||
"badge_type": "circle-ci",
|
||||
"attributes": {
|
||||
"repository": "sfackler/rust-postgres",
|
||||
"branch": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"created_at": "2014-11-24T02:34:44.756689+00:00",
|
||||
"downloads": 535491,
|
||||
"recent_downloads": 88321,
|
||||
"max_version": "0.17.3",
|
||||
"newest_version": "0.17.3",
|
||||
"description": "A native, synchronous PostgreSQL client",
|
||||
"homepage": null,
|
||||
"documentation": null,
|
||||
"repository": "https://github.com/sfackler/rust-postgres",
|
||||
"links": {
|
||||
"version_downloads": "/api/v1/crates/postgres/downloads",
|
||||
"versions": "/api/v1/crates/postgres/versions",
|
||||
"owners": "/api/v1/crates/postgres/owners",
|
||||
"owner_team": "/api/v1/crates/postgres/owner_team",
|
||||
"owner_user": "/api/v1/crates/postgres/owner_user",
|
||||
"reverse_dependencies": "/api/v1/crates/postgres/reverse_dependencies"
|
||||
},
|
||||
"exact_match": true
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"total": 1
|
||||
"total": 2
|
||||
}
|
||||
}"#;
|
||||
|
||||
@ -56,6 +92,11 @@ fn write_crates(dest: &Path) {
|
||||
}
|
||||
}
|
||||
|
||||
const SEARCH_RESULTS: &str = "\
|
||||
hoare = \"0.1.1\" # Design by contract style assertions for Rust
|
||||
postgres = \"0.17.3\" # A native, synchronous PostgreSQL client
|
||||
";
|
||||
|
||||
fn setup() {
|
||||
let cargo_home = paths::root().join(".cargo");
|
||||
fs::create_dir_all(cargo_home).unwrap();
|
||||
@ -114,7 +155,7 @@ fn not_update() {
|
||||
drop(lock);
|
||||
|
||||
cargo_process("search postgres")
|
||||
.with_stdout_contains("hoare = \"0.1.1\" # Design by contract style assertions for Rust")
|
||||
.with_stdout_contains(SEARCH_RESULTS)
|
||||
.with_stderr("") // without "Updating ... index"
|
||||
.run();
|
||||
}
|
||||
@ -125,7 +166,7 @@ fn replace_default() {
|
||||
set_cargo_config();
|
||||
|
||||
cargo_process("search postgres")
|
||||
.with_stdout_contains("hoare = \"0.1.1\" # Design by contract style assertions for Rust")
|
||||
.with_stdout_contains(SEARCH_RESULTS)
|
||||
.with_stderr_contains("[..]Updating [..] index")
|
||||
.run();
|
||||
}
|
||||
@ -136,7 +177,7 @@ fn simple() {
|
||||
|
||||
cargo_process("search postgres --index")
|
||||
.arg(registry_url().to_string())
|
||||
.with_stdout_contains("hoare = \"0.1.1\" # Design by contract style assertions for Rust")
|
||||
.with_stdout_contains(SEARCH_RESULTS)
|
||||
.run();
|
||||
}
|
||||
|
||||
@ -162,7 +203,7 @@ about this warning.
|
||||
[UPDATING] `[CWD]/registry` index
|
||||
",
|
||||
)
|
||||
.with_stdout_contains("hoare = \"0.1.1\" # Design by contract style assertions for Rust")
|
||||
.with_stdout_contains(SEARCH_RESULTS)
|
||||
.run();
|
||||
}
|
||||
|
||||
@ -190,7 +231,7 @@ about this warning.
|
||||
[UPDATING] `[CWD]/registry` index
|
||||
",
|
||||
)
|
||||
.with_stdout_contains("hoare = \"0.1.1\" # Design by contract style assertions for Rust")
|
||||
.with_stdout_contains(SEARCH_RESULTS)
|
||||
.run();
|
||||
}
|
||||
|
||||
@ -200,7 +241,7 @@ fn multiple_query_params() {
|
||||
|
||||
cargo_process("search postgres sql --index")
|
||||
.arg(registry_url().to_string())
|
||||
.with_stdout_contains("hoare = \"0.1.1\" # Design by contract style assertions for Rust")
|
||||
.with_stdout_contains(SEARCH_RESULTS)
|
||||
.run();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user