diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 249faea5c71..3f68682cf5a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -267,4 +267,4 @@ jobs: steps: - uses: actions/checkout@v4 - uses: taiki-e/install-action@cargo-hack - - run: cargo hack check --all-targets --rust-version --workspace --ignore-private + - run: cargo hack check --all-targets --rust-version --workspace --ignore-private --locked diff --git a/Cargo.lock b/Cargo.lock index 634a796eb62..b14e0ae6ba1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -342,6 +342,7 @@ dependencies = [ "toml", "toml_edit", "tracing", + "tracing-chrome", "tracing-subscriber", "unicase", "unicode-width", @@ -2702,15 +2703,22 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.9.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" +checksum = "dce76ce678ffc8e5675b22aa1405de0b7037e2fdf8913fea40d1926c6fe1e6e7" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "memchr", + "pulldown-cmark-escape", "unicase", ] +[[package]] +name = "pulldown-cmark-escape" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d8f9aa0e3cbcfaf8bf00300004ee3b72f74770f9cbac93f6928771f613276b" + [[package]] name = "quick-error" version = "1.2.3" @@ -3443,6 +3451,17 @@ dependencies = [ "syn 2.0.46", ] +[[package]] +name = "tracing-chrome" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496b3cd5447f7ff527bbbf19b071ad542a000adf297d4127078b4dfdb931f41a" +dependencies = [ + "serde_json", + "tracing-core", + "tracing-subscriber", +] + [[package]] name = "tracing-core" version = "0.1.32" diff --git a/Cargo.toml b/Cargo.toml index 502f30ffa3c..277c72b80f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,7 +74,7 @@ pathdiff = "0.2" percent-encoding = "2.3" pkg-config = "0.3.30" proptest = "1.4.0" -pulldown-cmark = { version = "0.9.3", default-features = false } +pulldown-cmark = { version = "0.10.0", default-features = false, features = ["html"] } rand = "0.8.5" regex = "1.10.3" rusqlite = { version = "0.31.0", features = ["bundled"] } @@ -99,6 +99,7 @@ time = { version = "0.3", features = ["parsing", "formatting", "serde"] } toml = "0.8.10" toml_edit = { version = "0.22.6", features = ["serde"] } tracing = "0.1.40" # be compatible with rustc_log: https://github.com/rust-lang/rust/blob/e51e98dde6a/compiler/rustc_log/Cargo.toml#L9 +tracing-chrome = "0.7.1" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } unicase = "2.7.0" unicode-width = "0.1.11" @@ -198,6 +199,7 @@ time.workspace = true toml.workspace = true toml_edit.workspace = true tracing.workspace = true +tracing-chrome.workspace = true tracing-subscriber.workspace = true unicase.workspace = true unicode-width.workspace = true @@ -229,6 +231,7 @@ features = [ ] [dev-dependencies] +annotate-snippets = { workspace = true, features = ["testing-colors"] } cargo-test-macro.workspace = true cargo-test-support.workspace = true same-file.workspace = true diff --git a/crates/mdman/src/format/man.rs b/crates/mdman/src/format/man.rs index 9767fdd5186..edb5c05e34b 100644 --- a/crates/mdman/src/format/man.rs +++ b/crates/mdman/src/format/man.rs @@ -3,7 +3,7 @@ use crate::util::{header_text, parse_name_and_section}; use crate::EventIter; use anyhow::{bail, Error}; -use pulldown_cmark::{Alignment, Event, HeadingLevel, LinkType, Tag}; +use pulldown_cmark::{Alignment, Event, HeadingLevel, LinkType, Tag, TagEnd}; use std::fmt::Write; use url::Url; @@ -110,6 +110,7 @@ impl<'e> ManRenderer<'e> { let mut suppress_paragraph = false; let mut table_cell_index = 0; + let mut last_seen_link_data = None; while let Some((event, range)) = self.parser.next() { let this_suppress_paragraph = suppress_paragraph; suppress_paragraph = false; @@ -122,7 +123,7 @@ impl<'e> ManRenderer<'e> { self.output.push_str(".sp\n"); } } - Tag::Heading(level, ..) => { + Tag::Heading { level, .. } => { if level == HeadingLevel::H1 { self.push_top_header()?; } else if level == HeadingLevel::H2 { @@ -212,7 +213,12 @@ impl<'e> ManRenderer<'e> { Tag::Strong => self.push_font(Font::Bold), // Strikethrough isn't usually supported for TTY. Tag::Strikethrough => self.output.push_str("~~"), - Tag::Link(link_type, dest_url, _title) => { + Tag::Link { + link_type, + dest_url, + .. + } => { + last_seen_link_data = Some((link_type.clone(), dest_url.to_owned())); if dest_url.starts_with('#') { // In a man page, page-relative anchors don't // have much meaning. @@ -247,68 +253,71 @@ impl<'e> ManRenderer<'e> { } } } - Tag::Image(_link_type, _dest_url, _title) => { + Tag::Image { .. } => { bail!("images are not currently supported") } + Tag::HtmlBlock { .. } | Tag::MetadataBlock { .. } => {} } } - Event::End(tag) => { - match &tag { - Tag::Paragraph => self.flush(), - Tag::Heading(..) => {} - Tag::BlockQuote => { + Event::End(tag_end) => { + match &tag_end { + TagEnd::Paragraph => self.flush(), + TagEnd::Heading(..) => {} + TagEnd::BlockQuote => { self.flush(); // restore left margin, restore line length self.output.push_str(".br\n.RE\n.ll\n"); } - Tag::CodeBlock(_kind) => { + TagEnd::CodeBlock => { self.flush(); // Restore fill mode, move margin back one level. self.output.push_str(".fi\n.RE\n"); } - Tag::List(_) => { + TagEnd::List(_) => { list.pop(); } - Tag::Item => { + TagEnd::Item => { self.flush(); // Move margin back one level. self.output.push_str(".RE\n"); } - Tag::FootnoteDefinition(_label) => {} - Tag::Table(_) => { + TagEnd::FootnoteDefinition => {} + TagEnd::Table => { // Table end // I don't know why, but the .sp is needed to provide // space with the following content. self.output.push_str("\n.TE\n.sp\n"); } - Tag::TableHead => {} - Tag::TableRow => {} - Tag::TableCell => { + TagEnd::TableHead => {} + TagEnd::TableRow => {} + TagEnd::TableCell => { // End text block. self.output.push_str("\nT}"); } - Tag::Emphasis | Tag::Strong => self.pop_font(), - Tag::Strikethrough => self.output.push_str("~~"), - Tag::Link(link_type, dest_url, _title) => { - if dest_url.starts_with('#') { - continue; - } - match link_type { - LinkType::Autolink | LinkType::Email => {} - LinkType::Inline - | LinkType::Reference - | LinkType::Collapsed - | LinkType::Shortcut => { - self.pop_font(); - self.output.push(' '); + TagEnd::Emphasis | TagEnd::Strong => self.pop_font(), + TagEnd::Strikethrough => self.output.push_str("~~"), + TagEnd::Link => { + if let Some((link_type, ref dest_url)) = last_seen_link_data { + if dest_url.starts_with('#') { + continue; } - _ => { - panic!("unexpected tag {:?}", tag); + match link_type { + LinkType::Autolink | LinkType::Email => {} + LinkType::Inline + | LinkType::Reference + | LinkType::Collapsed + | LinkType::Shortcut => { + self.pop_font(); + self.output.push(' '); + } + _ => { + panic!("unexpected tag {:?}", tag_end); + } } + write!(self.output, "<{}>", escape(&dest_url)?)?; } - write!(self.output, "<{}>", escape(&dest_url)?)?; } - Tag::Image(_link_type, _dest_url, _title) => {} + TagEnd::Image | TagEnd::HtmlBlock | TagEnd::MetadataBlock(..) => {} } } Event::Text(t) => { @@ -346,6 +355,7 @@ impl<'e> ManRenderer<'e> { self.output.push_str("\\l'\\n(.lu'\n"); } Event::TaskListMarker(_b) => unimplemented!(), + Event::InlineHtml(..) => unimplemented!(), } } Ok(()) diff --git a/crates/mdman/src/format/text.rs b/crates/mdman/src/format/text.rs index 5d6398e7974..5a858fcc792 100644 --- a/crates/mdman/src/format/text.rs +++ b/crates/mdman/src/format/text.rs @@ -3,7 +3,7 @@ use crate::util::{header_text, unwrap}; use crate::EventIter; use anyhow::{bail, Error}; -use pulldown_cmark::{Alignment, Event, HeadingLevel, LinkType, Tag}; +use pulldown_cmark::{Alignment, Event, HeadingLevel, LinkType, Tag, TagEnd}; use std::fmt::Write; use std::mem; use url::Url; @@ -102,6 +102,7 @@ impl<'e> TextRenderer<'e> { // Whether or not word-wrapping is enabled. let mut wrap_text = true; + let mut last_seen_link_data = None; while let Some((event, range)) = self.parser.next() { let this_suppress_paragraph = suppress_paragraph; // Always reset suppression, even if the next event isn't a @@ -116,7 +117,7 @@ impl<'e> TextRenderer<'e> { self.flush(); } } - Tag::Heading(level, ..) => { + Tag::Heading { level, .. } => { self.flush(); if level == HeadingLevel::H1 { let text = header_text(&mut self.parser)?; @@ -180,7 +181,12 @@ impl<'e> TextRenderer<'e> { Tag::Strong => {} // Strikethrough isn't usually supported for TTY. Tag::Strikethrough => self.word.push_str("~~"), - Tag::Link(link_type, dest_url, _title) => { + Tag::Link { + link_type, + dest_url, + .. + } => { + last_seen_link_data = Some((link_type.clone(), dest_url.to_owned())); if dest_url.starts_with('#') { // In a man page, page-relative anchors don't // have much meaning. @@ -213,59 +219,62 @@ impl<'e> TextRenderer<'e> { } } } - Tag::Image(_link_type, _dest_url, _title) => { + Tag::Image { .. } => { bail!("images are not currently supported") } + Tag::HtmlBlock { .. } | Tag::MetadataBlock { .. } => {} } } - Event::End(tag) => match &tag { - Tag::Paragraph => { + Event::End(tag_end) => match &tag_end { + TagEnd::Paragraph => { self.flush(); self.hard_break(); } - Tag::Heading(..) => {} - Tag::BlockQuote => { + TagEnd::Heading(..) => {} + TagEnd::BlockQuote => { self.indent -= 3; } - Tag::CodeBlock(_kind) => { + TagEnd::CodeBlock => { self.hard_break(); wrap_text = true; self.indent -= 4; } - Tag::List(_) => { + TagEnd::List(..) => { list.pop(); } - Tag::Item => { + TagEnd::Item => { self.flush(); self.indent -= 3; self.hard_break(); } - Tag::FootnoteDefinition(_label) => {} - Tag::Table(_) => {} - Tag::TableHead => {} - Tag::TableRow => {} - Tag::TableCell => {} - Tag::Emphasis => {} - Tag::Strong => {} - Tag::Strikethrough => self.word.push_str("~~"), - Tag::Link(link_type, dest_url, _title) => { - if dest_url.starts_with('#') { - continue; - } - match link_type { - LinkType::Autolink | LinkType::Email => {} - LinkType::Inline - | LinkType::Reference - | LinkType::Collapsed - | LinkType::Shortcut => self.flush_word(), - _ => { - panic!("unexpected tag {:?}", tag); + TagEnd::FootnoteDefinition => {} + TagEnd::Table => {} + TagEnd::TableHead => {} + TagEnd::TableRow => {} + TagEnd::TableCell => {} + TagEnd::Emphasis => {} + TagEnd::Strong => {} + TagEnd::Strikethrough => self.word.push_str("~~"), + TagEnd::Link => { + if let Some((link_type, ref dest_url)) = last_seen_link_data { + if dest_url.starts_with('#') { + continue; + } + match link_type { + LinkType::Autolink | LinkType::Email => {} + LinkType::Inline + | LinkType::Reference + | LinkType::Collapsed + | LinkType::Shortcut => self.flush_word(), + _ => { + panic!("unexpected tag {:?}", tag_end); + } } + self.flush_word(); + write!(self.word, "<{}>", dest_url)?; } - self.flush_word(); - write!(self.word, "<{}>", dest_url)?; } - Tag::Image(_link_type, _dest_url, _title) => {} + TagEnd::Image | TagEnd::HtmlBlock | TagEnd::MetadataBlock(..) => {} }, Event::Text(t) | Event::Code(t) => { if wrap_text { @@ -337,6 +346,7 @@ impl<'e> TextRenderer<'e> { self.flush(); } Event::TaskListMarker(_b) => unimplemented!(), + Event::InlineHtml(..) => unimplemented!(), } } Ok(()) @@ -451,20 +461,20 @@ impl Table { | Tag::Strong => {} Tag::Strikethrough => self.cell.push_str("~~"), // Links not yet supported, they usually won't fit. - Tag::Link(_, _, _) => {} + Tag::Link { .. } => {} _ => bail!("unexpected tag in table: {:?}", tag), }, - Event::End(tag) => match tag { - Tag::Table(_) => return self.render(indent), - Tag::TableCell => { + Event::End(tag_end) => match tag_end { + TagEnd::Table => return self.render(indent), + TagEnd::TableCell => { let cell = mem::replace(&mut self.cell, String::new()); self.row.push(cell); } - Tag::TableHead | Tag::TableRow => { + TagEnd::TableHead | TagEnd::TableRow => { let row = mem::replace(&mut self.row, Vec::new()); self.rows.push(row); } - Tag::Strikethrough => self.cell.push_str("~~"), + TagEnd::Strikethrough => self.cell.push_str("~~"), _ => {} }, Event::Text(t) | Event::Code(t) => { diff --git a/crates/mdman/src/lib.rs b/crates/mdman/src/lib.rs index 5cfb3f4cac9..f0b5167e80c 100644 --- a/crates/mdman/src/lib.rs +++ b/crates/mdman/src/lib.rs @@ -1,7 +1,7 @@ //! mdman markdown to man converter. use anyhow::{bail, Context, Error}; -use pulldown_cmark::{CowStr, Event, LinkType, Options, Parser, Tag}; +use pulldown_cmark::{CowStr, Event, LinkType, Options, Parser, Tag, TagEnd}; use std::collections::HashMap; use std::fs; use std::io::{self, BufRead}; @@ -74,14 +74,21 @@ pub(crate) fn md_parser(input: &str, url: Option) -> EventIter<'_> { let parser = parser.into_offset_iter(); // Translate all links to include the base url. let parser = parser.map(move |(event, range)| match event { - Event::Start(Tag::Link(lt, dest_url, title)) if !matches!(lt, LinkType::Email) => ( - Event::Start(Tag::Link(lt, join_url(url.as_ref(), dest_url), title)), - range, - ), - Event::End(Tag::Link(lt, dest_url, title)) if !matches!(lt, LinkType::Email) => ( - Event::End(Tag::Link(lt, join_url(url.as_ref(), dest_url), title)), + Event::Start(Tag::Link { + link_type, + dest_url, + title, + id, + }) if !matches!(link_type, LinkType::Email) => ( + Event::Start(Tag::Link { + link_type, + dest_url: join_url(url.as_ref(), dest_url), + title, + id, + }), range, ), + Event::End(TagEnd::Link) => (Event::End(TagEnd::Link), range), _ => (event, range), }); Box::new(parser) diff --git a/crates/mdman/src/util.rs b/crates/mdman/src/util.rs index a4c71ad38af..ed4b61c4b58 100644 --- a/crates/mdman/src/util.rs +++ b/crates/mdman/src/util.rs @@ -1,7 +1,7 @@ ///! General utilities. use crate::EventIter; use anyhow::{bail, format_err, Context, Error}; -use pulldown_cmark::{CowStr, Event, Tag}; +use pulldown_cmark::{CowStr, Event, TagEnd}; /// Splits the text `foo(1)` into "foo" and `1`. pub fn parse_name_and_section(text: &str) -> Result<(&str, u8), Error> { @@ -31,7 +31,7 @@ pub fn header_text<'e>(parser: &mut EventIter<'e>) -> Result, Error> e => bail!("expected plain text in man header, got {:?}", e), }; match parser.next() { - Some((Event::End(Tag::Heading(..)), _range)) => { + Some((Event::End(TagEnd::Heading(..)), _range)) => { return Ok(text); } e => bail!("expected plain text in man header, got {:?}", e), diff --git a/crates/mdman/tests/compare/expected/tables.md b/crates/mdman/tests/compare/expected/tables.md index 831132c44ec..fb4acf63656 100644 --- a/crates/mdman/tests/compare/expected/tables.md +++ b/crates/mdman/tests/compare/expected/tables.md @@ -5,7 +5,7 @@ Testing tables. | Single col | --------------- +|------------| | Hi! :) | @@ -27,7 +27,7 @@ Extra long text 123456789012 with mixed widths. | Extra long text 123456789012 w | Link check | --------------- +|------------| | [foo] | | | diff --git a/crates/mdman/tests/compare/tables.md b/crates/mdman/tests/compare/tables.md index 831132c44ec..fb4acf63656 100644 --- a/crates/mdman/tests/compare/tables.md +++ b/crates/mdman/tests/compare/tables.md @@ -5,7 +5,7 @@ Testing tables. | Single col | --------------- +|------------| | Hi! :) | @@ -27,7 +27,7 @@ Extra long text 123456789012 with mixed widths. | Extra long text 123456789012 w | Link check | --------------- +|------------| | [foo] | | | diff --git a/src/bin/cargo/cli.rs b/src/bin/cargo/cli.rs index 74d3ddf76ac..fc589606560 100644 --- a/src/bin/cargo/cli.rs +++ b/src/bin/cargo/cli.rs @@ -16,6 +16,7 @@ use crate::util::is_rustup; use cargo::core::shell::ColorChoice; use cargo::util::style; +#[tracing::instrument(skip_all)] pub fn main(gctx: &mut GlobalContext) -> CliResult { // CAUTION: Be careful with using `config` until it is configured below. // In general, try to avoid loading config values unless necessary (like @@ -272,6 +273,7 @@ fn add_ssl(version_string: &mut String) { /// [`GlobalArgs`] need to be extracted before expanding aliases because the /// clap code for extracting a subcommand discards global options /// (appearing before the subcommand). +#[tracing::instrument(skip_all)] fn expand_aliases( gctx: &mut GlobalContext, args: ArgMatches, @@ -377,6 +379,7 @@ For more information, see issue #12207 CliResult { match self { Self::Builtin(exec) => exec(gctx, subcommand_args), @@ -530,6 +534,7 @@ impl GlobalArgs { } } +#[tracing::instrument(skip_all)] pub fn cli(gctx: &GlobalContext) -> Command { // Don't let config errors get in the way of parsing arguments let term = gctx.get::("term").unwrap_or_default(); diff --git a/src/bin/cargo/main.rs b/src/bin/cargo/main.rs index a84d300c498..a2147b4d037 100644 --- a/src/bin/cargo/main.rs +++ b/src/bin/cargo/main.rs @@ -18,7 +18,7 @@ mod commands; use crate::command_prelude::*; fn main() { - setup_logger(); + let _guard = setup_logger(); let mut gctx = match GlobalContext::default() { Ok(gctx) => gctx, @@ -41,16 +41,43 @@ fn main() { } } -fn setup_logger() { - let env = tracing_subscriber::EnvFilter::from_env("CARGO_LOG"); +fn setup_logger() -> Option { + #![allow(clippy::disallowed_methods)] + + use tracing_subscriber::prelude::*; - tracing_subscriber::fmt() + let env = tracing_subscriber::EnvFilter::from_env("CARGO_LOG"); + let fmt_layer = tracing_subscriber::fmt::layer() .with_timer(tracing_subscriber::fmt::time::Uptime::default()) .with_ansi(std::io::IsTerminal::is_terminal(&std::io::stderr())) .with_writer(std::io::stderr) - .with_env_filter(env) - .init(); + .with_filter(env); + + let (profile_layer, profile_guard) = + if env_to_bool(std::env::var_os("CARGO_LOG_PROFILE").as_deref()) { + let capture_args = + env_to_bool(std::env::var_os("CARGO_LOG_PROFILE_CAPTURE_ARGS").as_deref()); + let (layer, guard) = tracing_chrome::ChromeLayerBuilder::new() + .include_args(capture_args) + .build(); + (Some(layer), Some(guard)) + } else { + (None, None) + }; + + let registry = tracing_subscriber::registry() + .with(fmt_layer) + .with(profile_layer); + registry.init(); tracing::trace!(start = humantime::format_rfc3339(std::time::SystemTime::now()).to_string()); + profile_guard +} + +fn env_to_bool(os: Option<&OsStr>) -> bool { + match os.and_then(|os| os.to_str()) { + Some("1") | Some("true") => true, + _ => false, + } } /// Table for defining the aliases which come builtin in `Cargo`. @@ -287,6 +314,7 @@ fn search_directories(gctx: &GlobalContext) -> Vec { } /// Initialize libgit2. +#[tracing::instrument(skip_all)] fn init_git(gctx: &GlobalContext) { // Disabling the owner validation in git can, in theory, lead to code execution // vulnerabilities. However, libgit2 does not launch executables, which is the foundation of @@ -318,6 +346,7 @@ fn init_git(gctx: &GlobalContext) { /// If the user has a non-default network configuration, then libgit2 will be /// configured to use libcurl instead of the built-in networking support so /// that those configuration settings can be used. +#[tracing::instrument(skip_all)] fn init_git_transports(gctx: &GlobalContext) { match needs_custom_http_transport(gctx) { Ok(true) => {} diff --git a/src/cargo/core/compiler/build_runner/mod.rs b/src/cargo/core/compiler/build_runner/mod.rs index 1be9769ac29..ac99b734c8d 100644 --- a/src/cargo/core/compiler/build_runner/mod.rs +++ b/src/cargo/core/compiler/build_runner/mod.rs @@ -9,7 +9,6 @@ use crate::core::compiler::{self, artifact, Unit}; use crate::core::PackageId; use crate::util::cache_lock::CacheLockMode; use crate::util::errors::CargoResult; -use crate::util::profile; use anyhow::{bail, Context as _}; use filetime::FileTime; use itertools::Itertools; @@ -133,6 +132,7 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> { /// See [`ops::cargo_compile`] for a higher-level view of the compile process. /// /// [`ops::cargo_compile`]: ../../../ops/cargo_compile/index.html + #[tracing::instrument(skip_all)] pub fn compile(mut self, exec: &Arc) -> CargoResult> { // A shared lock is held during the duration of the build since rustc // needs to read from the `src` cache, and we don't want other @@ -324,6 +324,7 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> { .map(|output| output.bin_dst().clone())) } + #[tracing::instrument(skip_all)] pub fn prepare_units(&mut self) -> CargoResult<()> { let dest = self.bcx.profiles.get_dir_name(); let host_layout = Layout::new(self.bcx.ws, None, &dest)?; @@ -349,9 +350,8 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> { /// Prepare this context, ensuring that all filesystem directories are in /// place. + #[tracing::instrument(skip_all)] pub fn prepare(&mut self) -> CargoResult<()> { - let _p = profile::start("preparing layout"); - self.files .as_mut() .unwrap() @@ -451,6 +451,7 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> { /// Check if any output file name collision happens. /// See for more. + #[tracing::instrument(skip_all)] fn check_collisions(&self) -> CargoResult<()> { let mut output_collisions = HashMap::new(); let describe_collision = |unit: &Unit, other_unit: &Unit, path: &PathBuf| -> String { @@ -633,6 +634,7 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> { /// If the current crate has reverse-dependencies, such a Check unit should exist, and so /// we use that crate's metadata. If not, we use the crate's Doc unit so at least examples /// scraped from the current crate can be used when documenting the current crate. + #[tracing::instrument(skip_all)] pub fn compute_metadata_for_doc_units(&mut self) { for unit in self.bcx.unit_graph.keys() { if !unit.mode.is_doc() && !unit.mode.is_doc_scrape() { diff --git a/src/cargo/core/compiler/custom_build.rs b/src/cargo/core/compiler/custom_build.rs index 153ef3aa666..426d8f128c2 100644 --- a/src/cargo/core/compiler/custom_build.rs +++ b/src/cargo/core/compiler/custom_build.rs @@ -38,8 +38,8 @@ use crate::core::compiler::fingerprint::DirtyReason; use crate::core::compiler::job_queue::JobState; use crate::core::{profiles::ProfileRoot, PackageId, Target}; use crate::util::errors::CargoResult; +use crate::util::internal; use crate::util::machine_message::{self, Message}; -use crate::util::{internal, profile}; use anyhow::{bail, Context as _}; use cargo_platform::Cfg; use cargo_util::paths; @@ -194,13 +194,8 @@ impl LinkArgTarget { } /// Prepares a `Work` that executes the target as a custom build script. +#[tracing::instrument(skip_all)] pub fn prepare(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult { - let _p = profile::start(format!( - "build script prepare: {}/{}", - unit.pkg, - unit.target.name() - )); - let metadata = build_runner.get_run_build_script_metadata(unit); if build_runner .build_script_outputs diff --git a/src/cargo/core/compiler/fingerprint/mod.rs b/src/cargo/core/compiler/fingerprint/mod.rs index 477543b0b49..4fdbed220c1 100644 --- a/src/cargo/core/compiler/fingerprint/mod.rs +++ b/src/cargo/core/compiler/fingerprint/mod.rs @@ -377,7 +377,7 @@ use crate::core::Package; use crate::util::errors::CargoResult; use crate::util::interning::InternedString; use crate::util::{self, try_canonicalize}; -use crate::util::{internal, path_args, profile, StableHasher}; +use crate::util::{internal, path_args, StableHasher}; use crate::{GlobalContext, CARGO_ENV}; use super::custom_build::BuildDeps; @@ -399,16 +399,15 @@ pub use dirty_reason::DirtyReason; /// transitively propagate throughout the dependency graph, it only forces this /// one unit which is very unlikely to be what you want unless you're /// exclusively talking about top-level units. +#[tracing::instrument( + skip(build_runner, unit), + fields(package_id = %unit.pkg.package_id(), target = unit.target.name()) +)] pub fn prepare_target( build_runner: &mut BuildRunner<'_, '_>, unit: &Unit, force: bool, ) -> CargoResult { - let _p = profile::start(format!( - "fingerprint: {} / {}", - unit.pkg.package_id(), - unit.target.name() - )); let bcx = build_runner.bcx; let loc = build_runner.files().fingerprint_file_path(unit, ""); diff --git a/src/cargo/core/compiler/job_queue/mod.rs b/src/cargo/core/compiler/job_queue/mod.rs index dc34c92a7ae..0ad64dc7650 100644 --- a/src/cargo/core/compiler/job_queue/mod.rs +++ b/src/cargo/core/compiler/job_queue/mod.rs @@ -144,7 +144,7 @@ use crate::util::diagnostic_server::{self, DiagnosticPrinter}; use crate::util::errors::AlreadyPrintedError; use crate::util::machine_message::{self, Message as _}; use crate::util::CargoResult; -use crate::util::{self, internal, profile}; +use crate::util::{self, internal}; use crate::util::{DependencyQueue, GlobalContext, Progress, ProgressStyle, Queue}; /// This structure is backed by the `DependencyQueue` type and manages the @@ -467,12 +467,12 @@ impl<'gctx> JobQueue<'gctx> { /// This function will spawn off `config.jobs()` workers to build all of the /// necessary dependencies, in order. Freshness is propagated as far as /// possible along each dependency chain. + #[tracing::instrument(skip_all)] pub fn execute( mut self, build_runner: &mut BuildRunner<'_, '_>, plan: &mut BuildPlan, ) -> CargoResult<()> { - let _p = profile::start("executing the job graph"); self.queue.queue_finished(); let progress = diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 31aa29f573b..bed881d50db 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -93,7 +93,7 @@ use crate::core::{Feature, PackageId, Target, Verbosity}; use crate::util::errors::{CargoResult, VerboseError}; use crate::util::interning::InternedString; use crate::util::machine_message::{self, Message}; -use crate::util::{add_path_args, internal, profile}; +use crate::util::{add_path_args, internal}; use cargo_util::{paths, ProcessBuilder, ProcessError}; use cargo_util_schemas::manifest::TomlDebugInfo; use cargo_util_schemas::manifest::TomlTrimPaths; @@ -158,6 +158,7 @@ impl Executor for DefaultExecutor { /// Note that **no actual work is executed as part of this**, that's all done /// next as part of [`JobQueue::execute`] function which will run everything /// in order with proper parallelism. +#[tracing::instrument(skip(build_runner, jobs, plan, exec))] fn compile<'gctx>( build_runner: &mut BuildRunner<'_, 'gctx>, jobs: &mut JobQueue<'gctx>, @@ -174,7 +175,6 @@ fn compile<'gctx>( // Build up the work to be done to compile this unit, enqueuing it once // we've got everything constructed. - let p = profile::start(format!("preparing: {}/{}", unit.pkg, unit.target.name())); fingerprint::prepare_init(build_runner, unit)?; let job = if unit.mode.is_run_custom_build() { @@ -215,7 +215,6 @@ fn compile<'gctx>( job }; jobs.enqueue(build_runner, unit, job)?; - drop(p); // Be sure to compile all dependencies of this target as well. let deps = Vec::from(build_runner.unit_deps(unit)); // Create vec due to mutable borrow. diff --git a/src/cargo/core/compiler/rustdoc.rs b/src/cargo/core/compiler/rustdoc.rs index 95483cb5688..7a856fe1bc5 100644 --- a/src/cargo/core/compiler/rustdoc.rs +++ b/src/cargo/core/compiler/rustdoc.rs @@ -7,6 +7,7 @@ use crate::sources::CRATES_IO_REGISTRY; use crate::util::errors::{internal, CargoResult}; use cargo_util::ProcessBuilder; use std::collections::HashMap; +use std::collections::HashSet; use std::fmt; use std::hash; use url::Url; @@ -113,8 +114,12 @@ fn build_all_urls( name2url: &HashMap<&String, Url>, map: &RustdocExternMap, unstable_opts: &mut bool, + seen: &mut HashSet, ) { for dep in build_runner.unit_deps(unit) { + if !seen.insert(dep.unit.clone()) { + continue; + } if !dep.unit.target.is_linkable() || dep.unit.mode.is_doc() { continue; } @@ -155,6 +160,7 @@ fn build_all_urls( name2url, map, unstable_opts, + seen, ); } } @@ -199,6 +205,7 @@ pub fn add_root_urls( &name2url, map, &mut unstable_opts, + &mut HashSet::new(), ); let std_url = match &map.std { None | Some(RustdocExternMode::Remote) => None, diff --git a/src/cargo/core/compiler/unit_dependencies.rs b/src/cargo/core/compiler/unit_dependencies.rs index 9040d40fabb..72f47c6491f 100644 --- a/src/cargo/core/compiler/unit_dependencies.rs +++ b/src/cargo/core/compiler/unit_dependencies.rs @@ -81,6 +81,7 @@ impl IsArtifact { /// Then entry point for building a dependency graph of compilation units. /// /// You can find some information for arguments from doc of [`State`]. +#[tracing::instrument(skip_all)] pub fn build_unit_dependencies<'a, 'gctx>( ws: &'a Workspace<'gctx>, package_set: &'a PackageSet<'gctx>, diff --git a/src/cargo/core/global_cache_tracker.rs b/src/cargo/core/global_cache_tracker.rs index 563723b77f1..9add10f26a1 100644 --- a/src/cargo/core/global_cache_tracker.rs +++ b/src/cargo/core/global_cache_tracker.rs @@ -546,12 +546,12 @@ impl GlobalCacheTracker { .with_context(|| "failed to clean entries from the global cache") } + #[tracing::instrument(skip_all)] fn clean_inner( &mut self, clean_ctx: &mut CleanContext<'_>, gc_opts: &GcOpts, ) -> CargoResult<()> { - let _p = crate::util::profile::start("cleaning global cache files"); let gctx = clean_ctx.gctx; let base = BasePaths { index: gctx.registry_index_path().into_path_unlocked(), @@ -696,6 +696,7 @@ impl GlobalCacheTracker { /// /// These orphaned files will be added to `delete_paths` so that the /// caller can delete them. + #[tracing::instrument(skip(conn, gctx, base, delete_paths))] fn sync_db_with_files( conn: &Connection, now: Timestamp, @@ -704,7 +705,6 @@ impl GlobalCacheTracker { sync_size: bool, delete_paths: &mut Vec, ) -> CargoResult<()> { - let _p = crate::util::profile::start("global cache db sync"); debug!(target: "gc", "starting db sync"); // For registry_index and git_db, add anything that is missing in the db. Self::update_parent_for_missing_from_db(conn, now, REGISTRY_INDEX_TABLE, &base.index)?; @@ -795,15 +795,13 @@ impl GlobalCacheTracker { } /// For parent tables, add any entries that are on disk but aren't tracked in the db. + #[tracing::instrument(skip(conn, now, base_path))] fn update_parent_for_missing_from_db( conn: &Connection, now: Timestamp, parent_table_name: &str, base_path: &Path, ) -> CargoResult<()> { - let _p = crate::util::profile::start(format!( - "update parent db for missing from db {parent_table_name}" - )); trace!(target: "gc", "checking for untracked parent to add to {parent_table_name}"); let names = Self::names_from(base_path)?; @@ -822,6 +820,7 @@ impl GlobalCacheTracker { /// /// This could happen for example if the user manually deleted the file or /// any such scenario where the filesystem and db are out of sync. + #[tracing::instrument(skip(conn, base_path))] fn update_db_for_removed( conn: &Connection, parent_table_name: &str, @@ -829,7 +828,6 @@ impl GlobalCacheTracker { table_name: &str, base_path: &Path, ) -> CargoResult<()> { - let _p = crate::util::profile::start(format!("update db for removed {table_name}")); trace!(target: "gc", "checking for db entries to remove from {table_name}"); let mut select_stmt = conn.prepare_cached(&format!( "SELECT {table_name}.rowid, {parent_table_name}.name, {table_name}.name @@ -851,6 +849,7 @@ impl GlobalCacheTracker { } /// Removes database entries for any files that are not on disk for the parent tables. + #[tracing::instrument(skip(conn, base_path, child_base_paths, delete_paths))] fn update_db_parent_for_removed_from_disk( conn: &Connection, parent_table_name: &str, @@ -858,9 +857,6 @@ impl GlobalCacheTracker { child_base_paths: &[&Path], delete_paths: &mut Vec, ) -> CargoResult<()> { - let _p = crate::util::profile::start(format!( - "update db parent for removed from disk {parent_table_name}" - )); trace!(target: "gc", "checking for db entries to remove from {parent_table_name}"); let mut select_stmt = conn.prepare_cached(&format!("SELECT rowid, name FROM {parent_table_name}"))?; @@ -888,12 +884,12 @@ impl GlobalCacheTracker { /// Updates the database to add any `.crate` files that are currently /// not tracked (such as when they are downloaded by an older version of /// cargo). + #[tracing::instrument(skip(conn, now, base_path))] fn populate_untracked_crate( conn: &Connection, now: Timestamp, base_path: &Path, ) -> CargoResult<()> { - let _p = crate::util::profile::start("populate untracked crate"); trace!(target: "gc", "populating untracked crate files"); let mut insert_stmt = conn.prepare_cached( "INSERT INTO registry_crate (registry_id, name, size, timestamp) @@ -922,6 +918,7 @@ impl GlobalCacheTracker { /// Updates the database to add any files that are currently not tracked /// (such as when they are downloaded by an older version of cargo). + #[tracing::instrument(skip(conn, now, gctx, base_path, populate_size))] fn populate_untracked( conn: &Connection, now: Timestamp, @@ -932,7 +929,6 @@ impl GlobalCacheTracker { base_path: &Path, populate_size: bool, ) -> CargoResult<()> { - let _p = crate::util::profile::start(format!("populate untracked {table_name}")); trace!(target: "gc", "populating untracked files for {table_name}"); // Gather names (and make sure they are in the database). let id_names = Self::names_from(&base_path)?; @@ -987,6 +983,7 @@ impl GlobalCacheTracker { /// size. /// /// `update_db_for_removed` should be called before this is called. + #[tracing::instrument(skip(conn, gctx, base_path))] fn update_null_sizes( conn: &Connection, gctx: &GlobalContext, @@ -995,7 +992,6 @@ impl GlobalCacheTracker { table_name: &str, base_path: &Path, ) -> CargoResult<()> { - let _p = crate::util::profile::start(format!("update NULL sizes {table_name}")); trace!(target: "gc", "updating NULL size information in {table_name}"); let mut null_stmt = conn.prepare_cached(&format!( "SELECT {table_name}.rowid, {table_name}.name, {parent_table_name}.name @@ -1560,8 +1556,8 @@ impl DeferredGlobalLastUse { /// Saves all of the deferred information to the database. /// /// This will also clear the state of `self`. + #[tracing::instrument(skip_all)] pub fn save(&mut self, tracker: &mut GlobalCacheTracker) -> CargoResult<()> { - let _p = crate::util::profile::start("saving last-use data"); trace!(target: "gc", "saving last-use data"); if self.is_empty() { return Ok(()); diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index e5ba3a9b369..d9151e1a9a6 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -497,6 +497,7 @@ impl<'gctx> PackageSet<'gctx> { } /// Downloads any packages accessible from the give root ids. + #[tracing::instrument(skip_all)] pub fn download_accessible( &self, resolve: &Resolve, diff --git a/src/cargo/core/resolver/features.rs b/src/cargo/core/resolver/features.rs index 7bf944b7555..b86b96a5dab 100644 --- a/src/cargo/core/resolver/features.rs +++ b/src/cargo/core/resolver/features.rs @@ -444,6 +444,7 @@ pub struct FeatureResolver<'a, 'gctx> { impl<'a, 'gctx> FeatureResolver<'a, 'gctx> { /// Runs the resolution algorithm and returns a new [`ResolvedFeatures`] /// with the result. + #[tracing::instrument(skip_all)] pub fn resolve( ws: &Workspace<'gctx>, target_data: &'a mut RustcTargetData<'gctx>, @@ -454,8 +455,6 @@ impl<'a, 'gctx> FeatureResolver<'a, 'gctx> { requested_targets: &[CompileKind], opts: FeatureOpts, ) -> CargoResult { - use crate::util::profile; - let _p = profile::start("resolve features"); let track_for_host = opts.decouple_host_deps || opts.ignore_inactive_targets; let mut r = FeatureResolver { ws, diff --git a/src/cargo/core/resolver/mod.rs b/src/cargo/core/resolver/mod.rs index c351ed0fe8a..20072331354 100644 --- a/src/cargo/core/resolver/mod.rs +++ b/src/cargo/core/resolver/mod.rs @@ -70,7 +70,6 @@ use crate::core::{Dependency, PackageId, Registry, Summary}; use crate::util::context::GlobalContext; use crate::util::errors::CargoResult; use crate::util::network::PollExt; -use crate::util::profile; use self::context::ResolverContext; use self::dep_cache::RegistryQueryer; @@ -122,6 +121,7 @@ mod version_prefs; /// /// * `config` - a location to print warnings and such, or `None` if no warnings /// should be printed +#[tracing::instrument(skip_all)] pub fn resolve( summaries: &[(Summary, ResolveOpts)], replacements: &[(PackageIdSpec, Dependency)], @@ -130,7 +130,6 @@ pub fn resolve( resolve_version: ResolveVersion, gctx: Option<&GlobalContext>, ) -> CargoResult { - let _p = profile::start("resolving"); let first_version = match gctx { Some(config) if config.cli_unstable().direct_minimal_versions => { Some(VersionOrdering::MinimumVersionsFirst) diff --git a/src/cargo/ops/cargo_add/mod.rs b/src/cargo/ops/cargo_add/mod.rs index b36e4e72955..eeebddaf873 100644 --- a/src/cargo/ops/cargo_add/mod.rs +++ b/src/cargo/ops/cargo_add/mod.rs @@ -11,6 +11,7 @@ use std::str::FromStr; use anyhow::Context as _; use cargo_util::paths; +use cargo_util_schemas::core::PartialVersion; use cargo_util_schemas::manifest::RustVersion; use indexmap::IndexSet; use itertools::Itertools; @@ -615,52 +616,74 @@ fn get_latest_dependency( })?; if gctx.cli_unstable().msrv_policy && honor_rust_version { - fn parse_msrv(comp: &RustVersion) -> (u64, u64, u64) { - (comp.major, comp.minor.unwrap_or(0), comp.patch.unwrap_or(0)) - } + let (req_msrv, is_msrv) = spec + .rust_version() + .cloned() + .map(|msrv| CargoResult::Ok((msrv.clone(), true))) + .unwrap_or_else(|| { + let rustc = gctx.load_global_rustc(None)?; + + // Remove any pre-release identifiers for easier comparison + let current_version = &rustc.version; + let untagged_version = RustVersion::try_from(PartialVersion { + major: current_version.major, + minor: Some(current_version.minor), + patch: Some(current_version.patch), + pre: None, + build: None, + }) + .unwrap(); + Ok((untagged_version, false)) + })?; - if let Some(req_msrv) = spec.rust_version().map(parse_msrv) { - let msrvs = possibilities - .iter() - .map(|s| (s, s.rust_version().map(parse_msrv))) - .collect::>(); - - // Find the latest version of the dep which has a compatible rust-version. To - // determine whether or not one rust-version is compatible with another, we - // compare the lowest possible versions they could represent, and treat - // candidates without a rust-version as compatible by default. - let (latest_msrv, _) = msrvs - .iter() - .filter(|(_, v)| v.map(|msrv| req_msrv >= msrv).unwrap_or(true)) - .last() - .ok_or_else(|| { - // Failing that, try to find the highest version with the lowest - // rust-version to report to the user. - let lowest_candidate = msrvs - .iter() - .min_set_by_key(|(_, v)| v) - .iter() - .map(|(s, _)| s) - .max_by_key(|s| s.version()); - rust_version_incompat_error( - &dependency.name, - spec.rust_version().unwrap(), - lowest_candidate.copied(), + let msrvs = possibilities + .iter() + .map(|s| (s, s.rust_version())) + .collect::>(); + + // Find the latest version of the dep which has a compatible rust-version. To + // determine whether or not one rust-version is compatible with another, we + // compare the lowest possible versions they could represent, and treat + // candidates without a rust-version as compatible by default. + let latest_msrv = latest_compatible(&msrvs, &req_msrv).ok_or_else(|| { + let name = spec.name(); + let dep_name = &dependency.name; + let latest_version = latest.version(); + let latest_msrv = latest + .rust_version() + .expect("as `None` are compatible, we can't be here"); + if is_msrv { + anyhow::format_err!( + "\ +no version of crate `{dep_name}` can maintain {name}'s rust-version of {req_msrv} +help: pass `--ignore-rust-version` to select {dep_name}@{latest_version} which requires rustc {latest_msrv}" ) - })?; - - if latest_msrv.version() < latest.version() { + } else { + anyhow::format_err!( + "\ +no version of crate `{dep_name}` is compatible with rustc {req_msrv} +help: pass `--ignore-rust-version` to select {dep_name}@{latest_version} which requires rustc {latest_msrv}" + ) + } + })?; + + if latest_msrv.version() < latest.version() { + let latest_version = latest.version(); + let latest_rust_version = latest.rust_version().unwrap(); + let name = spec.name(); + if is_msrv { gctx.shell().warn(format_args!( - "ignoring `{dependency}@{latest_version}` (which has a rust-version of \ - {latest_rust_version}) to satisfy this package's rust-version of \ - {rust_version} (use `--ignore-rust-version` to override)", - latest_version = latest.version(), - latest_rust_version = latest.rust_version().unwrap(), - rust_version = spec.rust_version().unwrap(), + "\ +ignoring {dependency}@{latest_version} (which requires rustc {latest_rust_version}) to maintain {name}'s rust-version of {req_msrv}", + ))?; + } else { + gctx.shell().warn(format_args!( + "\ +ignoring {dependency}@{latest_version} (which requires rustc {latest_rust_version}) as it is incompatible with rustc {req_msrv}", ))?; - - latest = latest_msrv; } + + latest = latest_msrv; } } @@ -673,29 +696,20 @@ fn get_latest_dependency( } } -fn rust_version_incompat_error( - dep: &str, - rust_version: &RustVersion, - lowest_rust_version: Option<&Summary>, -) -> anyhow::Error { - let mut error_msg = format!( - "could not find version of crate `{dep}` that satisfies this package's rust-version of \ - {rust_version}\n\ - help: use `--ignore-rust-version` to override this behavior" - ); - - if let Some(lowest) = lowest_rust_version { - // rust-version must be present for this candidate since it would have been selected as - // compatible previously if it weren't. - let version = lowest.version(); - let rust_version = lowest.rust_version().unwrap(); - error_msg.push_str(&format!( - "\nnote: the lowest rust-version available for `{dep}` is {rust_version}, used in \ - version {version}" - )); - } - - anyhow::format_err!(error_msg) +/// Of MSRV-compatible summaries, find the highest version +/// +/// Assumptions: +/// - `msrvs` is sorted by version +fn latest_compatible<'s>( + msrvs: &[(&'s Summary, Option<&RustVersion>)], + req_msrv: &RustVersion, +) -> Option<&'s Summary> { + msrvs + .iter() + .filter(|(_, v)| v.as_ref().map(|msrv| req_msrv >= *msrv).unwrap_or(true)) + .map(|(s, _)| s) + .last() + .copied() } fn select_package( diff --git a/src/cargo/ops/cargo_compile/mod.rs b/src/cargo/ops/cargo_compile/mod.rs index 081e9825369..4aaf4878712 100644 --- a/src/cargo/ops/cargo_compile/mod.rs +++ b/src/cargo/ops/cargo_compile/mod.rs @@ -54,7 +54,7 @@ use crate::ops; use crate::ops::resolve::WorkspaceResolve; use crate::util::context::GlobalContext; use crate::util::interning::InternedString; -use crate::util::{profile, CargoResult, StableHasher}; +use crate::util::{CargoResult, StableHasher}; mod compile_filter; pub use compile_filter::{CompileFilter, FilterRule, LibRule}; @@ -142,6 +142,7 @@ pub fn compile_with_exec<'a>( } /// Like [`compile_with_exec`] but without warnings from manifest parsing. +#[tracing::instrument(skip_all)] pub fn compile_ws<'a>( ws: &Workspace<'a>, options: &CompileOptions, @@ -154,7 +155,6 @@ pub fn compile_ws<'a>( return Compilation::new(&bcx); } crate::core::gc::auto_gc(bcx.gctx); - let _p = profile::start("compiling"); let build_runner = BuildRunner::new(&bcx)?; build_runner.compile(exec) } @@ -197,6 +197,7 @@ pub fn print<'a>( /// /// For how it works and what data it collects, /// please see the [module-level documentation](self). +#[tracing::instrument(skip_all)] pub fn create_bcx<'a, 'gctx>( ws: &'a Workspace<'gctx>, options: &'a CompileOptions, diff --git a/src/cargo/ops/lockfile.rs b/src/cargo/ops/lockfile.rs index a5547f608df..8b7569be7be 100644 --- a/src/cargo/ops/lockfile.rs +++ b/src/cargo/ops/lockfile.rs @@ -6,6 +6,7 @@ use crate::util::Filesystem; use anyhow::Context as _; +#[tracing::instrument(skip_all)] pub fn load_pkg_lockfile(ws: &Workspace<'_>) -> CargoResult> { let lock_root = lock_root(ws); if !lock_root.as_path_unlocked().join("Cargo.lock").exists() { @@ -32,6 +33,7 @@ pub fn resolve_to_string(ws: &Workspace<'_>, resolve: &mut Resolve) -> CargoResu Ok(out) } +#[tracing::instrument(skip_all)] pub fn write_pkg_lockfile(ws: &Workspace<'_>, resolve: &mut Resolve) -> CargoResult<()> { let (orig, mut out, lock_root) = resolve_to_string_orig(ws, resolve); diff --git a/src/cargo/ops/resolve.rs b/src/cargo/ops/resolve.rs index 875edcb7e6b..f9e036b2e05 100644 --- a/src/cargo/ops/resolve.rs +++ b/src/cargo/ops/resolve.rs @@ -71,7 +71,7 @@ use crate::ops; use crate::sources::PathSource; use crate::util::cache_lock::CacheLockMode; use crate::util::errors::CargoResult; -use crate::util::{profile, CanonicalUrl}; +use crate::util::CanonicalUrl; use anyhow::Context as _; use std::collections::{HashMap, HashSet}; use tracing::{debug, trace}; @@ -147,8 +147,6 @@ pub fn resolve_ws_with_opts<'gctx>( // Second, resolve with precisely what we're doing. Filter out // transitive dependencies if necessary, specify features, handle // overrides, etc. - let _p = profile::start("resolving with overrides..."); - add_overrides(&mut registry, ws)?; for (replace_spec, dep) in ws.root_replace() { @@ -234,6 +232,7 @@ pub fn resolve_ws_with_opts<'gctx>( }) } +#[tracing::instrument(skip_all)] fn resolve_with_registry<'gctx>( ws: &Workspace<'gctx>, registry: &mut PackageRegistry<'gctx>, @@ -271,6 +270,7 @@ fn resolve_with_registry<'gctx>( /// /// If `register_patches` is true, then entries from the `[patch]` table in /// the manifest will be added to the given `PackageRegistry`. +#[tracing::instrument(skip_all)] pub fn resolve_with_previous<'gctx>( registry: &mut PackageRegistry<'gctx>, ws: &Workspace<'gctx>, @@ -529,6 +529,7 @@ pub fn resolve_with_previous<'gctx>( /// Read the `paths` configuration variable to discover all path overrides that /// have been configured. +#[tracing::instrument(skip_all)] pub fn add_overrides<'a>( registry: &mut PackageRegistry<'a>, ws: &Workspace<'a>, diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs index 9fb542ee0ea..6996136602f 100644 --- a/src/cargo/util/command_prelude.rs +++ b/src/cargo/util/command_prelude.rs @@ -500,6 +500,7 @@ pub trait ArgMatchesExt { root_manifest(self._value_of("manifest-path").map(Path::new), gctx) } + #[tracing::instrument(skip_all)] fn workspace<'a>(&self, gctx: &'a GlobalContext) -> CargoResult> { let root = self.root_manifest(gctx)?; let mut ws = Workspace::new(&root, gctx)?; diff --git a/src/cargo/util/context/mod.rs b/src/cargo/util/context/mod.rs index c64458990f4..3fc91dd1ef4 100644 --- a/src/cargo/util/context/mod.rs +++ b/src/cargo/util/context/mod.rs @@ -1945,6 +1945,7 @@ impl GlobalContext { /// Locks are usually acquired via [`GlobalContext::acquire_package_cache_lock`] /// or [`GlobalContext::try_acquire_package_cache_lock`]. #[track_caller] + #[tracing::instrument(skip_all)] pub fn assert_package_cache_locked<'a>( &self, mode: CacheLockMode, @@ -1965,6 +1966,7 @@ impl GlobalContext { /// /// See [`crate::util::cache_lock`] for an in-depth discussion of locking /// and lock modes. + #[tracing::instrument(skip_all)] pub fn acquire_package_cache_lock(&self, mode: CacheLockMode) -> CargoResult> { self.package_cache_lock.lock(self, mode) } @@ -1974,6 +1976,7 @@ impl GlobalContext { /// /// See [`crate::util::cache_lock`] for an in-depth discussion of locking /// and lock modes. + #[tracing::instrument(skip_all)] pub fn try_acquire_package_cache_lock( &self, mode: CacheLockMode, diff --git a/src/cargo/util/mod.rs b/src/cargo/util/mod.rs index 09e38190708..cacc88fcb28 100644 --- a/src/cargo/util/mod.rs +++ b/src/cargo/util/mod.rs @@ -54,7 +54,6 @@ pub mod job; mod lockserver; pub mod machine_message; pub mod network; -pub mod profile; mod progress; mod queue; pub mod restricted_names; diff --git a/src/cargo/util/profile.rs b/src/cargo/util/profile.rs deleted file mode 100644 index ede8db1913b..00000000000 --- a/src/cargo/util/profile.rs +++ /dev/null @@ -1,92 +0,0 @@ -//! An internal performance profiler for Cargo itself. -//! -//! > **Note**: This might not be the module you are looking for. -//! > For information about how Cargo handles compiler flags with profiles, -//! > please see the module [`cargo::core::profiles`](crate::core::profiles). - -use std::cell::RefCell; -use std::env; -use std::fmt; -use std::io::{stdout, StdoutLock, Write}; -use std::iter::repeat; -use std::mem; -use std::time; - -thread_local!(static PROFILE_STACK: RefCell> = RefCell::new(Vec::new())); -thread_local!(static MESSAGES: RefCell> = RefCell::new(Vec::new())); - -type Message = (usize, u64, String); - -pub struct Profiler { - desc: String, -} - -fn enabled_level() -> Option { - // ALLOWED: for profiling Cargo itself, not intended to be used beyond Cargo contributors. - #[allow(clippy::disallowed_methods)] - env::var("CARGO_PROFILE").ok().and_then(|s| s.parse().ok()) -} - -pub fn start(desc: T) -> Profiler { - if enabled_level().is_none() { - return Profiler { - desc: String::new(), - }; - } - - PROFILE_STACK.with(|stack| stack.borrow_mut().push(time::Instant::now())); - - Profiler { - desc: desc.to_string(), - } -} - -impl Drop for Profiler { - fn drop(&mut self) { - let Some(enabled) = enabled_level() else { - return; - }; - - let (start, stack_len) = PROFILE_STACK.with(|stack| { - let mut stack = stack.borrow_mut(); - let start = stack.pop().unwrap(); - (start, stack.len()) - }); - let duration = start.elapsed(); - let duration_ms = duration.as_secs() * 1000 + u64::from(duration.subsec_millis()); - - let msg = (stack_len, duration_ms, mem::take(&mut self.desc)); - MESSAGES.with(|msgs| msgs.borrow_mut().push(msg)); - - if stack_len == 0 { - fn print(lvl: usize, msgs: &[Message], enabled: usize, stdout: &mut StdoutLock<'_>) { - if lvl > enabled { - return; - } - let mut last = 0; - for (i, &(l, time, ref msg)) in msgs.iter().enumerate() { - if l != lvl { - continue; - } - writeln!( - stdout, - "{} {:6}ms - {}", - repeat(" ").take(lvl + 1).collect::(), - time, - msg - ) - .expect("printing profiling info to stdout"); - - print(lvl + 1, &msgs[last..i], enabled, stdout); - last = i; - } - } - let stdout = stdout(); - MESSAGES.with(|msgs| { - let mut msgs = msgs.borrow_mut(); - print(0, &msgs, enabled, &mut stdout.lock()); - msgs.clear(); - }); - } - } -} diff --git a/src/cargo/util/rustc.rs b/src/cargo/util/rustc.rs index 158c14363b0..3e0df24fe1a 100644 --- a/src/cargo/util/rustc.rs +++ b/src/cargo/util/rustc.rs @@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize}; use tracing::{debug, info, warn}; use crate::util::interning::InternedString; -use crate::util::{profile, CargoResult, GlobalContext, StableHasher}; +use crate::util::{CargoResult, GlobalContext, StableHasher}; /// Information on the `rustc` executable #[derive(Debug)] @@ -39,6 +39,7 @@ impl Rustc { /// /// If successful this function returns a description of the compiler along /// with a list of its capabilities. + #[tracing::instrument(skip(gctx))] pub fn new( path: PathBuf, wrapper: Option, @@ -47,8 +48,6 @@ impl Rustc { cache_location: Option, gctx: &GlobalContext, ) -> CargoResult { - let _p = profile::start("Rustc::new"); - let mut cache = Cache::load( wrapper.as_deref(), workspace_wrapper.as_deref(), diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 1f10d37d334..b78bce8f546 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -44,6 +44,7 @@ use self::targets::targets; /// within the manifest. For virtual manifests, these paths can only /// come from patched or replaced dependencies. These paths are not /// canonicalized. +#[tracing::instrument(skip(gctx))] pub fn read_manifest( path: &Path, source_id: SourceId, @@ -616,16 +617,20 @@ pub fn to_real_manifest( let default_edition = Edition::default(); let latest_edition = Edition::LATEST_STABLE; - let tip = if msrv_edition == default_edition { - String::new() - } else if msrv_edition == latest_edition { - format!(" while the latest is {latest_edition}") - } else { - format!(" while {msrv_edition} is compatible with `rust-version`") - }; - warnings.push(format!( - "no edition set: defaulting to the {default_edition} edition{tip}", - )); + // We're trying to help the user who might assume they are using a new edition, + // so if they can't use a new edition, don't bother to tell them to set it. + // This also avoids having to worry about whether `package.edition` is compatible with + // their MSRV. + if msrv_edition != default_edition { + let tip = if msrv_edition == latest_edition { + format!(" while the latest is {latest_edition}") + } else { + format!(" while {msrv_edition} is compatible with `rust-version`") + }; + warnings.push(format!( + "no edition set: defaulting to the {default_edition} edition{tip}", + )); + } default_edition }; // Add these lines if start a new unstable edition. diff --git a/src/doc/contrib/src/tests/profiling.md b/src/doc/contrib/src/tests/profiling.md index 1cc980ca3e3..f8410291b13 100644 --- a/src/doc/contrib/src/tests/profiling.md +++ b/src/doc/contrib/src/tests/profiling.md @@ -2,15 +2,24 @@ ## Internal profiler -Cargo has a basic, hierarchical profiler built-in. The environment variable -`CARGO_PROFILE` can be set to an integer which specifies how deep in the -profile stack to print results for. +Cargo leverages [tracing](https://crates.io/crates/tracing) +as a basic, hierarchical built-in profiler. -```sh -# Output first three levels of profiling info -CARGO_PROFILE=3 cargo generate-lockfile +Environment variables: +- `CARGO_LOG_PROFILE=`: log tracing events to a file in the current working directory +- `CARGO_LOG_PROFILE_CAPTURE_ARGS=`: include arguments in the events + +At process exit, your trace will be in a file like `trace-1668480819035032.json`. +Open that file with [ui.perfetto.dev](https://ui.perfetto.dev) (or chrome://tracing) to browse your trace. + +Example: +```console +$ # Output first three levels of profiling info +$ CARGO_LOG_PROFILE=true cargo generate-lockfile ``` +**Note:** This is intended for the development of cargo and there are no compatibility guarantees on this functionality. + ## Benchmarking ### Benchsuite diff --git a/src/doc/src/commands/cargo-add.md b/src/doc/src/commands/cargo-add.md index ffe2f3b6b8f..ae5e420a921 100644 --- a/src/doc/src/commands/cargo-add.md +++ b/src/doc/src/commands/cargo-add.md @@ -108,13 +108,13 @@ which is defined by the registry.default config key which defaults
--public
-
Mark the dependency as public.

+
Mark the dependency as public.

The dependency can be referenced in your library’s public API.

Unstable (nightly-only)

--no-public
-
Mark the dependency as private.

+
Mark the dependency as private.

While you can use the crate in your implementation, it cannot be referenced in your public API.

Unstable (nightly-only)

diff --git a/src/doc/src/commands/cargo-bench.md b/src/doc/src/commands/cargo-bench.md index 582ca4914fb..daf29ab1c6a 100644 --- a/src/doc/src/commands/cargo-bench.md +++ b/src/doc/src/commands/cargo-bench.md @@ -98,7 +98,7 @@ virtual workspace will include all workspace members (equivalent to passing
--package spec
Benchmark only the specified packages. See cargo-pkgid(1) for the SPEC format. This flag may be specified multiple times and supports common Unix -glob patterns like *, ? and []. However, to avoid your shell accidentally +glob patterns like *, ? and []. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern.
diff --git a/src/doc/src/commands/cargo-build.md b/src/doc/src/commands/cargo-build.md index 4c106ffeba1..fff6a45dae3 100644 --- a/src/doc/src/commands/cargo-build.md +++ b/src/doc/src/commands/cargo-build.md @@ -32,7 +32,7 @@ virtual workspace will include all workspace members (equivalent to passing
--package spec
Build only the specified packages. See cargo-pkgid(1) for the SPEC format. This flag may be specified multiple times and supports common Unix -glob patterns like *, ? and []. However, to avoid your shell accidentally +glob patterns like *, ? and []. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern.
diff --git a/src/doc/src/commands/cargo-check.md b/src/doc/src/commands/cargo-check.md index 25771fb9120..b90672c8eee 100644 --- a/src/doc/src/commands/cargo-check.md +++ b/src/doc/src/commands/cargo-check.md @@ -37,7 +37,7 @@ virtual workspace will include all workspace members (equivalent to passing
--package spec
Check only the specified packages. See cargo-pkgid(1) for the SPEC format. This flag may be specified multiple times and supports common Unix -glob patterns like *, ? and []. However, to avoid your shell accidentally +glob patterns like *, ? and []. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern.
diff --git a/src/doc/src/commands/cargo-doc.md b/src/doc/src/commands/cargo-doc.md index 7eb518ec9f5..b3370c82fa7 100644 --- a/src/doc/src/commands/cargo-doc.md +++ b/src/doc/src/commands/cargo-doc.md @@ -54,7 +54,7 @@ virtual workspace will include all workspace members (equivalent to passing
--package spec
Document only the specified packages. See cargo-pkgid(1) for the SPEC format. This flag may be specified multiple times and supports common Unix -glob patterns like *, ? and []. However, to avoid your shell accidentally +glob patterns like *, ? and []. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern.
diff --git a/src/doc/src/commands/cargo-fix.md b/src/doc/src/commands/cargo-fix.md index f53f44ae75f..bc9dc76a688 100644 --- a/src/doc/src/commands/cargo-fix.md +++ b/src/doc/src/commands/cargo-fix.md @@ -117,7 +117,7 @@ virtual workspace will include all workspace members (equivalent to passing
--package spec
Fix only the specified packages. See cargo-pkgid(1) for the SPEC format. This flag may be specified multiple times and supports common Unix -glob patterns like *, ? and []. However, to avoid your shell accidentally +glob patterns like *, ? and []. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern.
diff --git a/src/doc/src/commands/cargo-install.md b/src/doc/src/commands/cargo-install.md index fd9b561fa50..f4b7a611604 100644 --- a/src/doc/src/commands/cargo-install.md +++ b/src/doc/src/commands/cargo-install.md @@ -222,7 +222,7 @@ target artifacts are placed in a separate directory. See the specified with the CARGO_TARGET_DIR environment variable, or the build.target-dir config value. Defaults to a new temporary folder located in the -temporary directory of the platform.

+temporary directory of the platform.

When using --path, by default it will use target directory in the workspace of the local crate unless --target-dir is specified. diff --git a/src/doc/src/commands/cargo-metadata.md b/src/doc/src/commands/cargo-metadata.md index 3af0bb953f0..6d170eb9267 100644 --- a/src/doc/src/commands/cargo-metadata.md +++ b/src/doc/src/commands/cargo-metadata.md @@ -352,7 +352,7 @@ possible value.

--filter-platform triple
This filters the resolve output to only include dependencies for the -given target triple. +given target triple. Without this flag, the resolve includes all targets.

Note that the dependencies listed in the “packages” array still includes all dependencies. Each package definition is intended to be an unaltered diff --git a/src/doc/src/commands/cargo-package.md b/src/doc/src/commands/cargo-package.md index 376f8140b60..aa64b8649ed 100644 --- a/src/doc/src/commands/cargo-package.md +++ b/src/doc/src/commands/cargo-package.md @@ -101,7 +101,7 @@ virtual workspace will include all workspace members (equivalent to passing

--package spec
Package only the specified packages. See cargo-pkgid(1) for the SPEC format. This flag may be specified multiple times and supports common Unix -glob patterns like *, ? and []. However, to avoid your shell accidentally +glob patterns like *, ? and []. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern.
diff --git a/src/doc/src/commands/cargo-test.md b/src/doc/src/commands/cargo-test.md index 54a9f28cc4f..dd7727acc66 100644 --- a/src/doc/src/commands/cargo-test.md +++ b/src/doc/src/commands/cargo-test.md @@ -106,7 +106,7 @@ virtual workspace will include all workspace members (equivalent to passing
--package spec
Test only the specified packages. See cargo-pkgid(1) for the SPEC format. This flag may be specified multiple times and supports common Unix -glob patterns like *, ? and []. However, to avoid your shell accidentally +glob patterns like *, ? and []. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern.
diff --git a/src/doc/src/commands/cargo-tree.md b/src/doc/src/commands/cargo-tree.md index 2bbe546da67..ec930581706 100644 --- a/src/doc/src/commands/cargo-tree.md +++ b/src/doc/src/commands/cargo-tree.md @@ -134,7 +134,7 @@ kind given, then it will automatically include the other dependency kinds.
--target triple
-
Filter dependencies matching the given target triple. +
Filter dependencies matching the given target triple. The default is the host platform. Use the value all to include all targets.
@@ -193,7 +193,7 @@ virtual workspace will include all workspace members (equivalent to passing
--package spec
Display only the specified packages. See cargo-pkgid(1) for the SPEC format. This flag may be specified multiple times and supports common Unix -glob patterns like *, ? and []. However, to avoid your shell accidentally +glob patterns like *, ? and []. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern.
diff --git a/src/doc/src/reference/specifying-dependencies.md b/src/doc/src/reference/specifying-dependencies.md index bdede1e1d32..9ef98e22a01 100644 --- a/src/doc/src/reference/specifying-dependencies.md +++ b/src/doc/src/reference/specifying-dependencies.md @@ -51,7 +51,9 @@ versions before 1.0.0. While SemVer says there is no compatibility before and `x > 0`. It is possible to further tweak the logic for selecting compatible versions -using special operators, though it shouldn't be necessary most of the time. +using special operators as described in the [Version requirement syntax](#version-requirement-syntax) section. + +Use the default version requirement strategy, e.g. `log = "1.2.3"` where possible to maximize compatibility. ## Version requirement syntax @@ -158,16 +160,17 @@ separated with a comma, e.g., `>= 1.2, < 1.5`. ## Specifying dependencies from other registries -To specify a dependency from a registry other than [crates.io], first the -registry must be configured in a `.cargo/config.toml` file. See the [registries -documentation] for more information. In the dependency, set the `registry` key -to the name of the registry to use. +To specify a dependency from a registry other than [crates.io] set the `registry` key +to the name of the registry to use: ```toml [dependencies] some-crate = { version = "1.0", registry = "my-registry" } ``` +where `my-registry` is the registry name configured in `.cargo/config.toml` file. +See the [registries documentation] for more information. + > **Note**: [crates.io] does not allow packages to be published with > dependencies on code published outside of [crates.io]. @@ -183,45 +186,87 @@ you need to specify is the location of the repository with the `git` key: regex = { git = "https://github.com/rust-lang/regex.git" } ``` -Cargo will fetch the `git` repository at this location then look for a -`Cargo.toml` for the requested crate anywhere inside the `git` repository -(not necessarily at the root --- for example, specifying a member crate name -of a workspace and setting `git` to the repository containing the workspace). +Cargo fetches the `git` repository at that location and traverses the file tree to find +`Cargo.toml` file for the requested crate anywhere inside the `git` repository. +For example, `regex-lite` and `regex-syntax` are members of `rust-lang/regex` repo +and can be referred to by the repo's root URL (`https://github.com/rust-lang/regex.git`) +regardless of where in the file tree they reside. + +```toml +regex-lite = { git = "https://github.com/rust-lang/regex.git" } +regex-syntax = { git = "https://github.com/rust-lang/regex.git" } +``` + +The above rule does not apply to [`path` dependencies](#specifying-path-dependencies). -Since we haven’t specified any other information, Cargo assumes that -we intend to use the latest commit on the default branch to build -our package, which may not necessarily be the main branch. -You can combine the `git` key with the `rev`, `tag`, or `branch` keys to -specify something else. Here's an example of specifying that you want to use -the latest commit on a branch named `next`: +### Choice of commit + +Cargo assumes that we intend to use the latest commit on the default branch to build +our package if we only specify the repo URL, as in the examples above. + +You can combine the `git` key with the `rev`, `tag`, or `branch` keys to be more specific about +which commit to use. Here's an example of using the latest commit on a branch named `next`: ```toml [dependencies] regex = { git = "https://github.com/rust-lang/regex.git", branch = "next" } ``` -Anything that is not a branch or tag falls under `rev`. This can be a commit +Anything that is not a branch or a tag falls under `rev` key. This can be a commit hash like `rev = "4c59b707"`, or a named reference exposed by the remote -repository such as `rev = "refs/pull/493/head"`. What references are available -varies by where the repo is hosted; GitHub in particular exposes a reference to -the most recent commit of every pull request as shown, but other git hosts often -provide something equivalent, possibly under a different naming scheme. - -Once a `git` dependency has been added, Cargo will lock that dependency to the -latest commit at the time. New commits will not be pulled down automatically -once the lock is in place. However, they can be pulled down manually with -`cargo update`. - -See [Git Authentication] for help with git authentication for private repos. - -> **Note**: Neither the `git` key nor the `path` key changes the meaning of the -> `version` key: the `version` key always implies that the package is available -> in a registry. `version`, `git`, and `path` keys are considered [separate -> locations](#multiple-locations) for resolving the dependency. -> -> When the dependency is retrieved from `git`, the `version` key will _not_ -> affect which commit is used, but the version information in the dependency's -> `Cargo.toml` file will still be validated against the `version` requirement. +repository such as `rev = "refs/pull/493/head"`. + +What references are available for the `rev` key varies by where the repo is hosted. +GitHub exposes a reference to the most recent commit of every pull request as in the example above. +Other git hosts may provide something equivalent under a different naming scheme. + +**More `git` dependency examples:** + +```toml +# .git suffix can be omitted if the host accepts such URLs - both examples work the same +regex = { git = "https://github.com/rust-lang/regex" } +regex = { git = "https://github.com/rust-lang/regex.git" } + +# a commit with a particular tag +regex = { git = "https://github.com/rust-lang/regex.git", tag = "1.10.3" } + +# a commit by its SHA1 hash +regex = { git = "https://github.com/rust-lang/regex.git", rev = "0c0990399270277832fbb5b91a1fa118e6f63dba" } + +# HEAD commit of PR 493 +regex = { git = "https://github.com/rust-lang/regex.git", rev = "refs/pull/493/head" } + +# INVALID EXAMPLES + +# specifying the commit after # ignores the commit ID and generates a warning +regex = { git = "https://github.com/rust-lang/regex.git#4c59b70" } + +# git and path cannot be used at the same time +regex = { git = "https://github.com/rust-lang/regex.git#4c59b70", path = "../regex" } +``` + +Cargo locks the commits of `git` dependencies in `Cargo.lock` file at the time of their addition +and checks for updates only when you run `cargo update` command. + +### The role of the `version` key + +The `version` key always implies that the package is available in a registry, +regardless of the presence of `git` or `path` keys. + +The `version` key does _not_ affect which commit is used when Cargo retrieves the `git` dependency, +but Cargo checks the version information in the dependency's `Cargo.toml` file +against the `version` key and raises an error if the check fails. + +In this example, Cargo retrieves the HEAD commit of the branch called `next` from Git and checks if the crate's version +is compatible with `version = "1.10.3"`: + +```toml +[dependencies] +regex = { version = "1.10.3", git = "https://github.com/rust-lang/regex.git", branch = "next" } +``` + +`version`, `git`, and `path` keys are considered separate locations for resolving the dependency. +See [Multiple locations](#multiple-locations) section below for detailed explanations. > **Note**: [crates.io] does not allow packages to be published with > dependencies on code published outside of [crates.io] itself @@ -229,7 +274,9 @@ See [Git Authentication] for help with git authentication for private repos. > locations](#multiple-locations) section for a fallback alternative for `git` > and `path` dependencies. -[Git Authentication]: ../appendix/git-authentication.md +### Accessing private Git repositories + +See [Git Authentication](../appendix/git-authentication.md) for help with Git authentication for private repos. ## Specifying path dependencies @@ -237,7 +284,7 @@ Over time, our `hello_world` package from [the guide](../guide/index.md) has grown significantly in size! It’s gotten to the point that we probably want to split out a separate crate for others to use. To do this Cargo supports **path dependencies** which are typically sub-crates that live within one repository. -Let’s start off by making a new crate inside of our `hello_world` package: +Let’s start by making a new crate inside of our `hello_world` package: ```console # inside of hello_world/ @@ -245,7 +292,7 @@ $ cargo new hello_utils ``` This will create a new folder `hello_utils` inside of which a `Cargo.toml` and -`src` folder are ready to be configured. In order to tell Cargo about this, open +`src` folder are ready to be configured. To tell Cargo about this, open up `hello_world/Cargo.toml` and add `hello_utils` to your dependencies: ```toml @@ -254,30 +301,50 @@ hello_utils = { path = "hello_utils" } ``` This tells Cargo that we depend on a crate called `hello_utils` which is found -in the `hello_utils` folder (relative to the `Cargo.toml` it’s written in). +in the `hello_utils` folder, relative to the `Cargo.toml` file it’s written in. + +The next `cargo build` will automatically build `hello_utils` and +all of its dependencies. -And that’s it! The next `cargo build` will automatically build `hello_utils` and -all of its own dependencies, and others can also start using the crate as well. -However, crates that use dependencies specified with only a path are not -permitted on [crates.io]. If we wanted to publish our `hello_world` crate, we -would need to publish a version of `hello_utils` to [crates.io] -and specify its version in the dependencies line as well: +### No local path traversal + +The local paths must point to the exact folder with the dependency's `Cargo.toml`. +Unlike with `git` dependencies, Cargo does not traverse local paths. +For example, if `regex-lite` and `regex-syntax` are members of a +locally cloned `rust-lang/regex` repo, they have to be referred to by the full path: + +```toml +# git key accepts the repo root URL and Cargo traverses the tree to find the crate +[dependencies] +regex-lite = { git = "https://github.com/rust-lang/regex.git" } +regex-syntax = { git = "https://github.com/rust-lang/regex.git" } + +# path key requires the member name to be included in the local path +[dependencies] +regex-lite = { path = "../regex/regex-lite" } +regex-syntax = { path = "../regex/regex-syntax" } +``` + +### Local paths in published crates + +Crates that use dependencies specified with only a path are not +permitted on [crates.io]. + +If we wanted to publish our `hello_world` crate, +we would need to publish a version of `hello_utils` to [crates.io] as a separate crate +and specify its version in the dependencies line of `hello_world`: ```toml [dependencies] hello_utils = { path = "hello_utils", version = "0.1.0" } ``` -> **Note**: Neither the `git` key nor the `path` key changes the meaning of the -> `version` key: the `version` key always implies that the package is available -> in a registry. `version`, `git`, and `path` keys are considered [separate -> locations](#multiple-locations) for resolving the dependency. +The use of `path` and `version` keys together is explained in the [Multiple locations](#multiple-locations) section. > **Note**: [crates.io] does not allow packages to be published with -> dependencies on code published outside of [crates.io] itself -> ([dev-dependencies] are ignored). See the [Multiple -> locations](#multiple-locations) section for a fallback alternative for `git` -> and `path` dependencies. +> dependencies on code outside of [crates.io], except for [dev-dependencies]. +> See the [Multiple locations](#multiple-locations) section +> for a fallback alternative for `git` and `path` dependencies. ## Multiple locations diff --git a/src/etc/man/cargo-add.1 b/src/etc/man/cargo-add.1 index e7b728a6771..fc585fba6f5 100644 --- a/src/etc/man/cargo-add.1 +++ b/src/etc/man/cargo-add.1 @@ -123,7 +123,7 @@ Mark the dependency as \fIrequired\fR \fR \fIenvironment variable\fR is set when the integration test is built so that it can use the @@ -166,11 +166,11 @@ is set when the integration test is built so that it can use the executable. .sp Passing target selection flags will benchmark only the specified -targets. +targets. .sp -Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also -support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your -shell accidentally expanding glob patterns before Cargo handles them, you must +Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also +support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your +shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each glob pattern. .sp \fB\-\-lib\fR diff --git a/src/etc/man/cargo-build.1 b/src/etc/man/cargo-build.1 index 4194d7b77d3..ba6ab38cd46 100644 --- a/src/etc/man/cargo-build.1 +++ b/src/etc/man/cargo-build.1 @@ -27,7 +27,7 @@ virtual workspace will include all workspace members (equivalent to passing .RS 4 Build only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix -glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally +glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE @@ -57,7 +57,7 @@ they have \fBrequired\-features\fR that are missing. .sp Binary targets are automatically built if there is an integration test or benchmark being selected to build. This allows an integration -test to execute the binary to exercise and test its behavior. +test to execute the binary to exercise and test its behavior. The \fBCARGO_BIN_EXE_\fR \fIenvironment variable\fR is set when the integration test is built so that it can use the @@ -65,11 +65,11 @@ is set when the integration test is built so that it can use the executable. .sp Passing target selection flags will build only the specified -targets. +targets. .sp -Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also -support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your -shell accidentally expanding glob patterns before Cargo handles them, you must +Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also +support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your +shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each glob pattern. .sp \fB\-\-lib\fR diff --git a/src/etc/man/cargo-check.1 b/src/etc/man/cargo-check.1 index 43d570058f8..733b4b2fe7d 100644 --- a/src/etc/man/cargo-check.1 +++ b/src/etc/man/cargo-check.1 @@ -32,7 +32,7 @@ virtual workspace will include all workspace members (equivalent to passing .RS 4 Check only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix -glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally +glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE @@ -61,11 +61,11 @@ binary and library targets of the selected packages. Binaries are skipped if they have \fBrequired\-features\fR that are missing. .sp Passing target selection flags will check only the specified -targets. +targets. .sp -Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also -support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your -shell accidentally expanding glob patterns before Cargo handles them, you must +Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also +support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your +shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each glob pattern. .sp \fB\-\-lib\fR diff --git a/src/etc/man/cargo-doc.1 b/src/etc/man/cargo-doc.1 index 69f781de6ae..5a61c0f3de3 100644 --- a/src/etc/man/cargo-doc.1 +++ b/src/etc/man/cargo-doc.1 @@ -47,7 +47,7 @@ virtual workspace will include all workspace members (equivalent to passing .RS 4 Document only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix -glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally +glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE diff --git a/src/etc/man/cargo-fix.1 b/src/etc/man/cargo-fix.1 index 1f10f179be5..27599a1fad1 100644 --- a/src/etc/man/cargo-fix.1 +++ b/src/etc/man/cargo-fix.1 @@ -127,7 +127,7 @@ virtual workspace will include all workspace members (equivalent to passing .RS 4 Fix only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix -glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally +glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE @@ -156,11 +156,11 @@ When no target selection options are given, \fBcargo fix\fR will fix all targets \fBrequired\-features\fR that are missing. .sp Passing target selection flags will fix only the specified -targets. +targets. .sp -Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also -support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your -shell accidentally expanding glob patterns before Cargo handles them, you must +Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also +support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your +shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each glob pattern. .sp \fB\-\-lib\fR diff --git a/src/etc/man/cargo-install.1 b/src/etc/man/cargo-install.1 index 1914ad5b33d..44de0a8053a 100644 --- a/src/etc/man/cargo-install.1 +++ b/src/etc/man/cargo-install.1 @@ -104,8 +104,8 @@ available. .SS "Configuration Discovery" This command operates on system or user level, not project level. This means that the local \fIconfiguration discovery\fR is ignored. -Instead, the configuration discovery begins at \fB$CARGO_HOME/config.toml\fR\&. -If the package is installed with \fB\-\-path $PATH\fR, the local configuration +Instead, the configuration discovery begins at \fB$CARGO_HOME/config.toml\fR\&. +If the package is installed with \fB\-\-path $PATH\fR, the local configuration will be used, beginning discovery at \fB$PATH/.cargo/config.toml\fR\&. .SH "OPTIONS" .SS "Install Options" @@ -254,7 +254,7 @@ Directory for all generated artifacts and intermediate files. May also be specified with the \fBCARGO_TARGET_DIR\fR environment variable, or the \fBbuild.target\-dir\fR \fIconfig value\fR \&. Defaults to a new temporary folder located in the -temporary directory of the platform. +temporary directory of the platform. .sp When using \fB\-\-path\fR, by default it will use \fBtarget\fR directory in the workspace of the local crate unless \fB\-\-target\-dir\fR diff --git a/src/etc/man/cargo-metadata.1 b/src/etc/man/cargo-metadata.1 index fa85c5a9c89..fe27b140075 100644 --- a/src/etc/man/cargo-metadata.1 +++ b/src/etc/man/cargo-metadata.1 @@ -357,7 +357,7 @@ possible value. \fB\-\-filter\-platform\fR \fItriple\fR .RS 4 This filters the \fBresolve\fR output to only include dependencies for the -given \fItarget triple\fR \&. +given \fItarget triple\fR \&. Without this flag, the resolve includes all targets. .sp Note that the dependencies listed in the \[lq]packages\[rq] array still includes all diff --git a/src/etc/man/cargo-package.1 b/src/etc/man/cargo-package.1 index f845cbc04ff..f565ad7d425 100644 --- a/src/etc/man/cargo-package.1 +++ b/src/etc/man/cargo-package.1 @@ -124,7 +124,7 @@ virtual workspace will include all workspace members (equivalent to passing .RS 4 Package only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix -glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally +glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE diff --git a/src/etc/man/cargo-publish.1 b/src/etc/man/cargo-publish.1 index b2d95b9fd87..d16cc4a4173 100644 --- a/src/etc/man/cargo-publish.1 +++ b/src/etc/man/cargo-publish.1 @@ -28,7 +28,7 @@ which registries you are allowed to publish to. .sp .RS 4 \h'-04' 3.\h'+01'Upload the crate to the registry. The server will perform additional -checks on the crate. +checks on the crate. .RE .sp .RS 4 diff --git a/src/etc/man/cargo-run.1 b/src/etc/man/cargo-run.1 index 2ecbbcf6529..29bfae8b8f5 100644 --- a/src/etc/man/cargo-run.1 +++ b/src/etc/man/cargo-run.1 @@ -14,8 +14,8 @@ All the arguments following the two dashes (\fB\-\-\fR) are passed to the binary run. If you\[cq]re passing arguments to both Cargo and the binary, the ones after \fB\-\-\fR go to the binary, the ones before go to Cargo. .sp -Unlike \fBcargo\-test\fR(1) and \fBcargo\-bench\fR(1), \fBcargo run\fR sets the -working directory of the binary executed to the current working directory, same +Unlike \fBcargo\-test\fR(1) and \fBcargo\-bench\fR(1), \fBcargo run\fR sets the +working directory of the binary executed to the current working directory, same as if it was executed in the shell directly. .SH "OPTIONS" .SS "Package Selection" diff --git a/src/etc/man/cargo-rustc.1 b/src/etc/man/cargo-rustc.1 index f3535b0f0c1..1fc7d74b04f 100644 --- a/src/etc/man/cargo-rustc.1 +++ b/src/etc/man/cargo-rustc.1 @@ -43,7 +43,7 @@ binary and library targets of the selected package. .sp Binary targets are automatically built if there is an integration test or benchmark being selected to build. This allows an integration -test to execute the binary to exercise and test its behavior. +test to execute the binary to exercise and test its behavior. The \fBCARGO_BIN_EXE_\fR \fIenvironment variable\fR is set when the integration test is built so that it can use the @@ -51,11 +51,11 @@ is set when the integration test is built so that it can use the executable. .sp Passing target selection flags will build only the specified -targets. +targets. .sp -Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also -support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your -shell accidentally expanding glob patterns before Cargo handles them, you must +Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also +support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your +shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each glob pattern. .sp \fB\-\-lib\fR diff --git a/src/etc/man/cargo-rustdoc.1 b/src/etc/man/cargo-rustdoc.1 index 9dff7f12ab5..93773ae2fdb 100644 --- a/src/etc/man/cargo-rustdoc.1 +++ b/src/etc/man/cargo-rustdoc.1 @@ -53,11 +53,11 @@ if its name is the same as the lib target. Binaries are skipped if they have \fBrequired\-features\fR that are missing. .sp Passing target selection flags will document only the specified -targets. +targets. .sp -Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also -support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your -shell accidentally expanding glob patterns before Cargo handles them, you must +Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also +support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your +shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each glob pattern. .sp \fB\-\-lib\fR diff --git a/src/etc/man/cargo-test.1 b/src/etc/man/cargo-test.1 index 46700014789..b4eb1172167 100644 --- a/src/etc/man/cargo-test.1 +++ b/src/etc/man/cargo-test.1 @@ -98,7 +98,7 @@ virtual workspace will include all workspace members (equivalent to passing .RS 4 Test only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix -glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally +glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE @@ -172,7 +172,7 @@ for more information on per\-target settings. .sp Binary targets are automatically built if there is an integration test or benchmark being selected to test. This allows an integration -test to execute the binary to exercise and test its behavior. +test to execute the binary to exercise and test its behavior. The \fBCARGO_BIN_EXE_\fR \fIenvironment variable\fR is set when the integration test is built so that it can use the @@ -180,11 +180,11 @@ is set when the integration test is built so that it can use the executable. .sp Passing target selection flags will test only the specified -targets. +targets. .sp -Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also -support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your -shell accidentally expanding glob patterns before Cargo handles them, you must +Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also +support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your +shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each glob pattern. .sp \fB\-\-lib\fR diff --git a/src/etc/man/cargo-tree.1 b/src/etc/man/cargo-tree.1 index 2abad97320b..2fab70be971 100644 --- a/src/etc/man/cargo-tree.1 +++ b/src/etc/man/cargo-tree.1 @@ -167,7 +167,7 @@ The default is \fBnormal,build,dev\fR\&. .sp \fB\-\-target\fR \fItriple\fR .RS 4 -Filter dependencies matching the given \fItarget triple\fR \&. +Filter dependencies matching the given \fItarget triple\fR \&. The default is the host platform. Use the value \fBall\fR to include \fIall\fR targets. .RE .SS "Tree Formatting Options" @@ -240,7 +240,7 @@ virtual workspace will include all workspace members (equivalent to passing .RS 4 Display only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix -glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally +glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE diff --git a/tests/testsuite/cargo_add/invalid_manifest/stderr.term.svg b/tests/testsuite/cargo_add/invalid_manifest/stderr.term.svg index 636a4075104..b3ca44189ba 100644 --- a/tests/testsuite/cargo_add/invalid_manifest/stderr.term.svg +++ b/tests/testsuite/cargo_add/invalid_manifest/stderr.term.svg @@ -19,19 +19,19 @@ - error: invalid string + error: invalid string - expected `"`, `'` + expected `"`, `'` - --> Cargo.toml:9:7 + --> Cargo.toml:9:7 - | + | - 9 | key = invalid-value + 9 | key = invalid-value - | ^ + | ^ - | + | diff --git a/tests/testsuite/cargo_add/mod.rs b/tests/testsuite/cargo_add/mod.rs index bf52f6e7f51..8800ac23c67 100644 --- a/tests/testsuite/cargo_add/mod.rs +++ b/tests/testsuite/cargo_add/mod.rs @@ -123,6 +123,10 @@ mod rust_version_ignore; mod rust_version_incompatible; mod rust_version_latest; mod rust_version_older; +mod rustc_ignore; +mod rustc_incompatible; +mod rustc_latest; +mod rustc_older; mod sorted_table_with_dotted_item; mod target; mod target_cfg; diff --git a/tests/testsuite/cargo_add/rust_version_incompatible/stderr.term.svg b/tests/testsuite/cargo_add/rust_version_incompatible/stderr.term.svg index 916d611ad03..8983eae2f2f 100644 --- a/tests/testsuite/cargo_add/rust_version_incompatible/stderr.term.svg +++ b/tests/testsuite/cargo_add/rust_version_incompatible/stderr.term.svg @@ -1,4 +1,4 @@ - +