summaryrefslogtreecommitdiffstats
path: root/src/tools/cargo/crates
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /src/tools/cargo/crates
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/cargo/crates')
-rw-r--r--src/tools/cargo/crates/cargo-platform/Cargo.toml4
-rw-r--r--src/tools/cargo/crates/cargo-test-macro/Cargo.toml1
-rw-r--r--src/tools/cargo/crates/cargo-test-support/Cargo.toml41
-rw-r--r--src/tools/cargo/crates/cargo-test-support/src/install.rs6
-rw-r--r--src/tools/cargo/crates/cargo-test-support/src/lib.rs33
-rw-r--r--src/tools/cargo/crates/cargo-test-support/src/publish.rs4
-rw-r--r--src/tools/cargo/crates/cargo-test-support/src/registry.rs15
-rw-r--r--src/tools/cargo/crates/cargo-util/Cargo.toml28
-rw-r--r--src/tools/cargo/crates/crates-io/Cargo.toml14
-rw-r--r--src/tools/cargo/crates/crates-io/lib.rs3
-rw-r--r--src/tools/cargo/crates/credential/README.md8
-rw-r--r--src/tools/cargo/crates/credential/cargo-credential-1password/Cargo.toml12
-rw-r--r--src/tools/cargo/crates/credential/cargo-credential-1password/src/main.rs314
-rw-r--r--src/tools/cargo/crates/credential/cargo-credential-gnome-secret/Cargo.toml13
-rw-r--r--src/tools/cargo/crates/credential/cargo-credential-gnome-secret/build.rs3
-rw-r--r--src/tools/cargo/crates/credential/cargo-credential-gnome-secret/src/main.rs194
-rw-r--r--src/tools/cargo/crates/credential/cargo-credential-macos-keychain/Cargo.toml11
-rw-r--r--src/tools/cargo/crates/credential/cargo-credential-macos-keychain/src/main.rs50
-rw-r--r--src/tools/cargo/crates/credential/cargo-credential-wincred/Cargo.toml11
-rw-r--r--src/tools/cargo/crates/credential/cargo-credential-wincred/src/main.rs111
-rw-r--r--src/tools/cargo/crates/credential/cargo-credential/Cargo.toml9
-rw-r--r--src/tools/cargo/crates/credential/cargo-credential/README.md41
-rw-r--r--src/tools/cargo/crates/credential/cargo-credential/src/lib.rs86
-rw-r--r--src/tools/cargo/crates/home/CHANGELOG.md11
-rw-r--r--src/tools/cargo/crates/home/Cargo.toml4
-rw-r--r--src/tools/cargo/crates/home/src/env.rs2
-rw-r--r--src/tools/cargo/crates/home/src/lib.rs42
-rw-r--r--src/tools/cargo/crates/mdman/Cargo.lock459
-rw-r--r--src/tools/cargo/crates/mdman/Cargo.toml17
-rwxr-xr-xsrc/tools/cargo/crates/mdman/build-man.sh7
-rw-r--r--src/tools/cargo/crates/mdman/doc/mdman.md2
-rw-r--r--src/tools/cargo/crates/mdman/doc/out/mdman.18
-rw-r--r--src/tools/cargo/crates/mdman/doc/out/mdman.md6
-rw-r--r--src/tools/cargo/crates/mdman/doc/out/mdman.txt8
-rw-r--r--src/tools/cargo/crates/resolver-tests/Cargo.toml15
-rw-r--r--src/tools/cargo/crates/resolver-tests/src/lib.rs4
-rw-r--r--src/tools/cargo/crates/semver-check/Cargo.toml11
-rw-r--r--src/tools/cargo/crates/semver-check/src/main.rs293
-rw-r--r--src/tools/cargo/crates/xtask-build-man/Cargo.toml7
-rw-r--r--src/tools/cargo/crates/xtask-build-man/src/main.rs108
-rw-r--r--src/tools/cargo/crates/xtask-stale-label/Cargo.toml8
-rw-r--r--src/tools/cargo/crates/xtask-stale-label/src/main.rs91
-rw-r--r--src/tools/cargo/crates/xtask-unpublished/Cargo.toml12
-rw-r--r--src/tools/cargo/crates/xtask-unpublished/src/main.rs15
-rw-r--r--src/tools/cargo/crates/xtask-unpublished/src/xtask.rs200
45 files changed, 905 insertions, 1437 deletions
diff --git a/src/tools/cargo/crates/cargo-platform/Cargo.toml b/src/tools/cargo/crates/cargo-platform/Cargo.toml
index a5e51ee5d..423cf491d 100644
--- a/src/tools/cargo/crates/cargo-platform/Cargo.toml
+++ b/src/tools/cargo/crates/cargo-platform/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "cargo-platform"
-version = "0.1.2"
+version = "0.1.3"
edition = "2021"
license = "MIT OR Apache-2.0"
homepage = "https://github.com/rust-lang/cargo"
@@ -9,4 +9,4 @@ documentation = "https://docs.rs/cargo-platform"
description = "Cargo's representation of a target platform."
[dependencies]
-serde = "1.0.82"
+serde.workspace = true
diff --git a/src/tools/cargo/crates/cargo-test-macro/Cargo.toml b/src/tools/cargo/crates/cargo-test-macro/Cargo.toml
index 04dafc028..e40602ae3 100644
--- a/src/tools/cargo/crates/cargo-test-macro/Cargo.toml
+++ b/src/tools/cargo/crates/cargo-test-macro/Cargo.toml
@@ -7,6 +7,7 @@ homepage = "https://github.com/rust-lang/cargo"
repository = "https://github.com/rust-lang/cargo"
documentation = "https://github.com/rust-lang/cargo"
description = "Helper proc-macro for Cargo's testsuite."
+publish = false
[lib]
proc-macro = true
diff --git a/src/tools/cargo/crates/cargo-test-support/Cargo.toml b/src/tools/cargo/crates/cargo-test-support/Cargo.toml
index 91e6e4e34..305c809a8 100644
--- a/src/tools/cargo/crates/cargo-test-support/Cargo.toml
+++ b/src/tools/cargo/crates/cargo-test-support/Cargo.toml
@@ -3,30 +3,31 @@ name = "cargo-test-support"
version = "0.1.0"
license = "MIT OR Apache-2.0"
edition = "2021"
+publish = false
[lib]
doctest = false
[dependencies]
-anyhow = "1.0.34"
-cargo-test-macro = { path = "../cargo-test-macro" }
-cargo-util = { path = "../cargo-util" }
-crates-io = { path = "../crates-io" }
-filetime = "0.2"
-flate2 = { version = "1.0", default-features = false, features = ["zlib"] }
-git2 = "0.17.0"
-glob = "0.3"
-itertools = "0.10.0"
-lazy_static = "1.0"
-pasetors = { version = "0.6.4", features = ["v3", "paserk", "std", "serde"] }
-serde = { version = "1.0.123", features = ["derive"] }
-serde_json = "1.0"
-snapbox = { version = "0.4.0", features = ["diff", "path"] }
-tar = { version = "0.4.38", default-features = false }
-termcolor = "1.1.2"
-time = { version = "0.3", features = ["parsing", "formatting"]}
-toml = "0.7.0"
-url = "2.2.2"
+anyhow.workspace = true
+cargo-test-macro.workspace = true
+cargo-util.workspace = true
+crates-io.workspace = true
+filetime.workspace = true
+flate2.workspace = true
+git2.workspace = true
+glob.workspace = true
+itertools.workspace = true
+lazy_static.workspace = true
+pasetors.workspace = true
+serde = { workspace = true, features = ["derive"] }
+serde_json.workspace = true
+snapbox.workspace = true
+tar.workspace = true
+termcolor.workspace = true
+time.workspace = true
+toml.workspace = true
+url.workspace = true
[target.'cfg(windows)'.dependencies]
-windows-sys = { version = "0.45.0", features = ["Win32_Storage_FileSystem"] }
+windows-sys = { workspace = true, features = ["Win32_Storage_FileSystem"] }
diff --git a/src/tools/cargo/crates/cargo-test-support/src/install.rs b/src/tools/cargo/crates/cargo-test-support/src/install.rs
index 478b482d2..02842ef7b 100644
--- a/src/tools/cargo/crates/cargo-test-support/src/install.rs
+++ b/src/tools/cargo/crates/cargo-test-support/src/install.rs
@@ -4,8 +4,12 @@ use std::path::{Path, PathBuf};
/// Used by `cargo install` tests to assert an executable binary
/// has been installed. Example usage:
+/// ```no_run
+/// use cargo_test_support::install::assert_has_installed_exe;
+/// use cargo_test_support::install::cargo_home;
///
-/// assert_has_installed_exe(cargo_home(), "foo");
+/// assert_has_installed_exe(cargo_home(), "foo");
+/// ```
#[track_caller]
pub fn assert_has_installed_exe<P: AsRef<Path>>(path: P, name: &'static str) {
assert!(check_has_installed_exe(path, name));
diff --git a/src/tools/cargo/crates/cargo-test-support/src/lib.rs b/src/tools/cargo/crates/cargo-test-support/src/lib.rs
index 04d6ce9f8..d27aab44f 100644
--- a/src/tools/cargo/crates/cargo-test-support/src/lib.rs
+++ b/src/tools/cargo/crates/cargo-test-support/src/lib.rs
@@ -59,8 +59,8 @@ pub fn panic_error(what: &str, err: impl Into<anyhow::Error>) -> ! {
fn pe(what: &str, err: anyhow::Error) -> ! {
let mut result = format!("{}\nerror: {}", what, err);
for cause in err.chain().skip(1) {
- drop(writeln!(result, "\nCaused by:"));
- drop(write!(result, "{}", cause));
+ let _ = writeln!(result, "\nCaused by:");
+ let _ = write!(result, "{}", cause);
}
panic!("\n{}", result);
}
@@ -517,6 +517,29 @@ pub fn cargo_exe() -> PathBuf {
snapbox::cmd::cargo_bin("cargo")
}
+/// A wrapper around `rustc` instead of calling `clippy`.
+pub fn wrapped_clippy_driver() -> PathBuf {
+ let clippy_driver = project()
+ .at(paths::global_root().join("clippy-driver"))
+ .file("Cargo.toml", &basic_manifest("clippy-driver", "0.0.1"))
+ .file(
+ "src/main.rs",
+ r#"
+ fn main() {
+ let mut args = std::env::args_os();
+ let _me = args.next().unwrap();
+ let rustc = args.next().unwrap();
+ let status = std::process::Command::new(rustc).args(args).status().unwrap();
+ std::process::exit(status.code().unwrap_or(1));
+ }
+ "#,
+ )
+ .build();
+ clippy_driver.cargo("build").run();
+
+ clippy_driver.bin("clippy-driver")
+}
+
/// This is the raw output from the process.
///
/// This is similar to `std::process::Output`, however the `status` is
@@ -677,13 +700,15 @@ impl Execs {
/// The substrings are matched as `contains`. Example:
///
/// ```no_run
- /// execs.with_stderr_line_without(
+ /// use cargo_test_support::execs;
+ ///
+ /// execs().with_stderr_line_without(
/// &[
/// "[RUNNING] `rustc --crate-name build_script_build",
/// "-C opt-level=3",
/// ],
/// &["-C debuginfo", "-C incremental"],
- /// )
+ /// );
/// ```
///
/// This will check that a build line includes `-C opt-level=3` but does
diff --git a/src/tools/cargo/crates/cargo-test-support/src/publish.rs b/src/tools/cargo/crates/cargo-test-support/src/publish.rs
index 64774bc43..dccc8356d 100644
--- a/src/tools/cargo/crates/cargo-test-support/src/publish.rs
+++ b/src/tools/cargo/crates/cargo-test-support/src/publish.rs
@@ -165,6 +165,7 @@ pub(crate) fn create_index_line(
features: crate::registry::FeatureMap,
yanked: bool,
links: Option<String>,
+ rust_version: Option<&str>,
v: Option<u32>,
) -> String {
// This emulates what crates.io does to retain backwards compatibility.
@@ -185,6 +186,9 @@ pub(crate) fn create_index_line(
if let Some(v) = v {
json["v"] = serde_json::json!(v);
}
+ if let Some(rust_version) = rust_version {
+ json["rust_version"] = serde_json::json!(rust_version);
+ }
json.to_string()
}
diff --git a/src/tools/cargo/crates/cargo-test-support/src/registry.rs b/src/tools/cargo/crates/cargo-test-support/src/registry.rs
index 5faf23540..0cf82cb70 100644
--- a/src/tools/cargo/crates/cargo-test-support/src/registry.rs
+++ b/src/tools/cargo/crates/cargo-test-support/src/registry.rs
@@ -450,7 +450,10 @@ impl RegistryBuilder {
/// `VendorPackage` which implements directory sources.
///
/// # Example
-/// ```
+/// ```no_run
+/// use cargo_test_support::registry::Package;
+/// use cargo_test_support::project;
+///
/// // Publish package "a" depending on "b".
/// Package::new("a", "1.0.0")
/// .dep("b", "1.0.0")
@@ -1144,6 +1147,7 @@ fn save_new_crate(
false,
new_crate.links,
None,
+ None,
);
write_to_index(registry_path, &new_crate.name, line, false);
@@ -1240,7 +1244,7 @@ impl Package {
}
/// Adds a normal dependency. Example:
- /// ```
+ /// ```toml
/// [dependencies]
/// foo = {version = "1.0"}
/// ```
@@ -1249,7 +1253,7 @@ impl Package {
}
/// Adds a dependency with the given feature. Example:
- /// ```
+ /// ```toml
/// [dependencies]
/// foo = {version = "1.0", "features": ["feat1", "feat2"]}
/// ```
@@ -1272,7 +1276,7 @@ impl Package {
}
/// Adds a dev-dependency. Example:
- /// ```
+ /// ```toml
/// [dev-dependencies]
/// foo = {version = "1.0"}
/// ```
@@ -1281,7 +1285,7 @@ impl Package {
}
/// Adds a build-dependency. Example:
- /// ```
+ /// ```toml
/// [build-dependencies]
/// foo = {version = "1.0"}
/// ```
@@ -1400,6 +1404,7 @@ impl Package {
self.features.clone(),
self.yanked,
self.links.clone(),
+ self.rust_version.as_deref(),
self.v,
);
diff --git a/src/tools/cargo/crates/cargo-util/Cargo.toml b/src/tools/cargo/crates/cargo-util/Cargo.toml
index 7427ceb1a..f01705fca 100644
--- a/src/tools/cargo/crates/cargo-util/Cargo.toml
+++ b/src/tools/cargo/crates/cargo-util/Cargo.toml
@@ -8,21 +8,21 @@ repository = "https://github.com/rust-lang/cargo"
description = "Miscellaneous support code used by Cargo."
[dependencies]
-anyhow = "1.0.34"
-sha2 = "0.10.6"
-filetime = "0.2.9"
-hex = "0.4.2"
-jobserver = "0.1.26"
-libc = "0.2.88"
-log = "0.4.6"
-same-file = "1.0.6"
-shell-escape = "0.1.4"
-tempfile = "3.1.0"
-walkdir = "2.3.1"
+anyhow.workspace = true
+sha2.workspace = true
+filetime.workspace = true
+hex.workspace = true
+jobserver.workspace = true
+libc.workspace = true
+log.workspace = true
+same-file.workspace = true
+shell-escape.workspace = true
+tempfile.workspace = true
+walkdir.workspace = true
[target.'cfg(target_os = "macos")'.dependencies]
-core-foundation = { version = "0.9.0", features = ["mac_os_10_7_support"] }
+core-foundation.workspace = true
[target.'cfg(windows)'.dependencies]
-miow = "0.5.0"
-windows-sys = { version = "0.45.0", features = ["Win32_Storage_FileSystem", "Win32_Foundation", "Win32_System_Console"] }
+miow.workspace = true
+windows-sys = { workspace = true, features = ["Win32_Storage_FileSystem", "Win32_Foundation", "Win32_System_Console"] }
diff --git a/src/tools/cargo/crates/crates-io/Cargo.toml b/src/tools/cargo/crates/crates-io/Cargo.toml
index 004e2daff..034c2fca5 100644
--- a/src/tools/cargo/crates/crates-io/Cargo.toml
+++ b/src/tools/cargo/crates/crates-io/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "crates-io"
-version = "0.36.0"
+version = "0.37.0"
edition = "2021"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/cargo"
@@ -13,9 +13,9 @@ name = "crates_io"
path = "lib.rs"
[dependencies]
-anyhow = "1.0.34"
-curl = "0.4"
-percent-encoding = "2.0"
-serde = { version = "1.0", features = ['derive'] }
-serde_json = "1.0"
-url = "2.0"
+anyhow.workspace = true
+curl.workspace = true
+percent-encoding.workspace = true
+serde = { workspace = true, features = ["derive"] }
+serde_json.workspace = true
+url.workspace = true
diff --git a/src/tools/cargo/crates/crates-io/lib.rs b/src/tools/cargo/crates/crates-io/lib.rs
index e0197568a..243808098 100644
--- a/src/tools/cargo/crates/crates-io/lib.rs
+++ b/src/tools/cargo/crates/crates-io/lib.rs
@@ -57,6 +57,7 @@ pub struct NewCrate {
pub repository: Option<String>,
pub badges: BTreeMap<String, BTreeMap<String, String>>,
pub links: Option<String>,
+ pub rust_version: Option<String>,
}
#[derive(Serialize, Deserialize)]
@@ -199,7 +200,7 @@ impl Registry {
/// let mut handle = Easy::new();
/// // If connecting to crates.io, a user-agent is required.
/// handle.useragent("my_crawler (example.com/info)");
- /// let mut reg = Registry::new_handle(String::from("https://crates.io"), None, handle);
+ /// let mut reg = Registry::new_handle(String::from("https://crates.io"), None, handle, true);
/// ```
pub fn new_handle(
host: String,
diff --git a/src/tools/cargo/crates/credential/README.md b/src/tools/cargo/crates/credential/README.md
deleted file mode 100644
index 168cc71c3..000000000
--- a/src/tools/cargo/crates/credential/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
-# Cargo Credential Packages
-
-This directory contains Cargo packages for handling storage of tokens in a
-secure manner.
-
-`cargo-credential` is a generic library to assist writing a credential
-process. The other directories contain implementations that integrate with
-specific credential systems.
diff --git a/src/tools/cargo/crates/credential/cargo-credential-1password/Cargo.toml b/src/tools/cargo/crates/credential/cargo-credential-1password/Cargo.toml
deleted file mode 100644
index 093fde8e5..000000000
--- a/src/tools/cargo/crates/credential/cargo-credential-1password/Cargo.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-[package]
-name = "cargo-credential-1password"
-version = "0.2.0"
-edition = "2021"
-license = "MIT OR Apache-2.0"
-repository = "https://github.com/rust-lang/cargo"
-description = "A Cargo credential process that stores tokens in a 1password vault."
-
-[dependencies]
-cargo-credential = { version = "0.2.0", path = "../cargo-credential" }
-serde = { version = "1.0.117", features = ["derive"] }
-serde_json = "1.0.59"
diff --git a/src/tools/cargo/crates/credential/cargo-credential-1password/src/main.rs b/src/tools/cargo/crates/credential/cargo-credential-1password/src/main.rs
deleted file mode 100644
index 4f512b717..000000000
--- a/src/tools/cargo/crates/credential/cargo-credential-1password/src/main.rs
+++ /dev/null
@@ -1,314 +0,0 @@
-//! Cargo registry 1password credential process.
-
-use cargo_credential::{Credential, Error};
-use serde::Deserialize;
-use std::io::Read;
-use std::process::{Command, Stdio};
-
-const CARGO_TAG: &str = "cargo-registry";
-
-/// Implementation of 1password keychain access for Cargo registries.
-struct OnePasswordKeychain {
- account: Option<String>,
- vault: Option<String>,
-}
-
-/// 1password Login item type, used for the JSON output of `op item get`.
-#[derive(Deserialize)]
-struct Login {
- fields: Vec<Field>,
-}
-
-#[derive(Deserialize)]
-struct Field {
- id: String,
- value: Option<String>,
-}
-
-/// 1password item from `op items list`.
-#[derive(Deserialize)]
-struct ListItem {
- id: String,
- urls: Vec<Url>,
-}
-
-#[derive(Deserialize)]
-struct Url {
- href: String,
-}
-
-impl OnePasswordKeychain {
- fn new() -> Result<OnePasswordKeychain, Error> {
- let mut args = std::env::args().skip(1);
- let mut action = false;
- let mut account = None;
- let mut vault = None;
- while let Some(arg) = args.next() {
- match arg.as_str() {
- "--account" => {
- account = Some(args.next().ok_or("--account needs an arg")?);
- }
- "--vault" => {
- vault = Some(args.next().ok_or("--vault needs an arg")?);
- }
- s if s.starts_with('-') => {
- return Err(format!("unknown option {}", s).into());
- }
- _ => {
- if action {
- return Err("too many arguments".into());
- } else {
- action = true;
- }
- }
- }
- }
- Ok(OnePasswordKeychain { account, vault })
- }
-
- fn signin(&self) -> Result<Option<String>, Error> {
- // If there are any session env vars, we'll assume that this is the
- // correct account, and that the user knows what they are doing.
- if std::env::vars().any(|(name, _)| name.starts_with("OP_SESSION_")) {
- return Ok(None);
- }
- let mut cmd = Command::new("op");
- cmd.args(&["signin", "--raw"]);
- cmd.stdout(Stdio::piped());
- self.with_tty(&mut cmd)?;
- let mut child = cmd
- .spawn()
- .map_err(|e| format!("failed to spawn `op`: {}", e))?;
- let mut buffer = String::new();
- child
- .stdout
- .as_mut()
- .unwrap()
- .read_to_string(&mut buffer)
- .map_err(|e| format!("failed to get session from `op`: {}", e))?;
- if let Some(end) = buffer.find('\n') {
- buffer.truncate(end);
- }
- let status = child
- .wait()
- .map_err(|e| format!("failed to wait for `op`: {}", e))?;
- if !status.success() {
- return Err(format!("failed to run `op signin`: {}", status).into());
- }
- if buffer.is_empty() {
- // When using CLI integration, `op signin` returns no output,
- // so there is no need to set the session.
- return Ok(None);
- }
- Ok(Some(buffer))
- }
-
- fn make_cmd(&self, session: &Option<String>, args: &[&str]) -> Command {
- let mut cmd = Command::new("op");
- cmd.args(args);
- if let Some(account) = &self.account {
- cmd.arg("--account");
- cmd.arg(account);
- }
- if let Some(vault) = &self.vault {
- cmd.arg("--vault");
- cmd.arg(vault);
- }
- if let Some(session) = session {
- cmd.arg("--session");
- cmd.arg(session);
- }
- cmd
- }
-
- fn with_tty(&self, cmd: &mut Command) -> Result<(), Error> {
- #[cfg(unix)]
- const IN_DEVICE: &str = "/dev/tty";
- #[cfg(windows)]
- const IN_DEVICE: &str = "CONIN$";
- let stdin = std::fs::OpenOptions::new()
- .read(true)
- .write(true)
- .open(IN_DEVICE)?;
- cmd.stdin(stdin);
- Ok(())
- }
-
- fn run_cmd(&self, mut cmd: Command) -> Result<String, Error> {
- cmd.stdout(Stdio::piped());
- let mut child = cmd
- .spawn()
- .map_err(|e| format!("failed to spawn `op`: {}", e))?;
- let mut buffer = String::new();
- child
- .stdout
- .as_mut()
- .unwrap()
- .read_to_string(&mut buffer)
- .map_err(|e| format!("failed to read `op` output: {}", e))?;
- let status = child
- .wait()
- .map_err(|e| format!("failed to wait for `op`: {}", e))?;
- if !status.success() {
- return Err(format!("`op` command exit error: {}", status).into());
- }
- Ok(buffer)
- }
-
- fn search(&self, session: &Option<String>, index_url: &str) -> Result<Option<String>, Error> {
- let cmd = self.make_cmd(
- session,
- &[
- "items",
- "list",
- "--categories",
- "Login",
- "--tags",
- CARGO_TAG,
- "--format",
- "json",
- ],
- );
- let buffer = self.run_cmd(cmd)?;
- let items: Vec<ListItem> = serde_json::from_str(&buffer)
- .map_err(|e| format!("failed to deserialize JSON from 1password list: {}", e))?;
- let mut matches = items
- .into_iter()
- .filter(|item| item.urls.iter().any(|url| url.href == index_url));
- match matches.next() {
- Some(login) => {
- // Should this maybe just sort on `updatedAt` and return the newest one?
- if matches.next().is_some() {
- return Err(format!(
- "too many 1password logins match registry `{}`, \
- consider deleting the excess entries",
- index_url
- )
- .into());
- }
- Ok(Some(login.id))
- }
- None => Ok(None),
- }
- }
-
- fn modify(
- &self,
- session: &Option<String>,
- id: &str,
- token: &str,
- _name: Option<&str>,
- ) -> Result<(), Error> {
- let cmd = self.make_cmd(
- session,
- &["item", "edit", id, &format!("password={}", token)],
- );
- self.run_cmd(cmd)?;
- Ok(())
- }
-
- fn create(
- &self,
- session: &Option<String>,
- index_url: &str,
- token: &str,
- name: Option<&str>,
- ) -> Result<(), Error> {
- let title = match name {
- Some(name) => format!("Cargo registry token for {}", name),
- None => "Cargo registry token".to_string(),
- };
- let mut cmd = self.make_cmd(
- session,
- &[
- "item",
- "create",
- "--category",
- "Login",
- &format!("password={}", token),
- &format!("url={}", index_url),
- "--title",
- &title,
- "--tags",
- CARGO_TAG,
- ],
- );
- // For unknown reasons, `op item create` seems to not be happy if
- // stdin is not a tty. Otherwise it returns with a 0 exit code without
- // doing anything.
- self.with_tty(&mut cmd)?;
- self.run_cmd(cmd)?;
- Ok(())
- }
-
- fn get_token(&self, session: &Option<String>, id: &str) -> Result<String, Error> {
- let cmd = self.make_cmd(session, &["item", "get", "--format=json", id]);
- let buffer = self.run_cmd(cmd)?;
- let item: Login = serde_json::from_str(&buffer)
- .map_err(|e| format!("failed to deserialize JSON from 1password get: {}", e))?;
- let password = item.fields.into_iter().find(|item| item.id == "password");
- match password {
- Some(password) => password
- .value
- .ok_or_else(|| format!("missing password value for entry").into()),
- None => Err("could not find password field".into()),
- }
- }
-
- fn delete(&self, session: &Option<String>, id: &str) -> Result<(), Error> {
- let cmd = self.make_cmd(session, &["item", "delete", id]);
- self.run_cmd(cmd)?;
- Ok(())
- }
-}
-
-impl Credential for OnePasswordKeychain {
- fn name(&self) -> &'static str {
- env!("CARGO_PKG_NAME")
- }
-
- fn get(&self, index_url: &str) -> Result<String, Error> {
- let session = self.signin()?;
- if let Some(id) = self.search(&session, index_url)? {
- self.get_token(&session, &id)
- } else {
- return Err(format!(
- "no 1password entry found for registry `{}`, try `cargo login` to add a token",
- index_url
- )
- .into());
- }
- }
-
- fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> {
- let session = self.signin()?;
- // Check if an item already exists.
- if let Some(id) = self.search(&session, index_url)? {
- self.modify(&session, &id, token, name)
- } else {
- self.create(&session, index_url, token, name)
- }
- }
-
- fn erase(&self, index_url: &str) -> Result<(), Error> {
- let session = self.signin()?;
- // Check if an item already exists.
- if let Some(id) = self.search(&session, index_url)? {
- self.delete(&session, &id)?;
- } else {
- eprintln!("not currently logged in to `{}`", index_url);
- }
- Ok(())
- }
-}
-
-fn main() {
- let op = match OnePasswordKeychain::new() {
- Ok(op) => op,
- Err(e) => {
- eprintln!("error: {}", e);
- std::process::exit(1);
- }
- };
- cargo_credential::main(op);
-}
diff --git a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/Cargo.toml b/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/Cargo.toml
deleted file mode 100644
index 12e25cfb6..000000000
--- a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/Cargo.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-[package]
-name = "cargo-credential-gnome-secret"
-version = "0.2.0"
-edition = "2021"
-license = "MIT OR Apache-2.0"
-repository = "https://github.com/rust-lang/cargo"
-description = "A Cargo credential process that stores tokens with GNOME libsecret."
-
-[dependencies]
-cargo-credential = { version = "0.2.0", path = "../cargo-credential" }
-
-[build-dependencies]
-pkg-config = "0.3.19"
diff --git a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/build.rs b/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/build.rs
deleted file mode 100644
index 9283535af..000000000
--- a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/build.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
- pkg_config::probe_library("libsecret-1").unwrap();
-}
diff --git a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/src/main.rs b/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/src/main.rs
deleted file mode 100644
index 40972b05d..000000000
--- a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/src/main.rs
+++ /dev/null
@@ -1,194 +0,0 @@
-//! Cargo registry gnome libsecret credential process.
-
-use cargo_credential::{Credential, Error};
-use std::ffi::{CStr, CString};
-use std::os::raw::{c_char, c_int};
-use std::ptr::{null, null_mut};
-
-#[allow(non_camel_case_types)]
-type gchar = c_char;
-
-#[allow(non_camel_case_types)]
-type gboolean = c_int;
-
-type GQuark = u32;
-
-#[repr(C)]
-struct GError {
- domain: GQuark,
- code: c_int,
- message: *mut gchar,
-}
-
-#[repr(C)]
-struct GCancellable {
- _private: [u8; 0],
-}
-
-#[repr(C)]
-struct SecretSchema {
- name: *const gchar,
- flags: SecretSchemaFlags,
- attributes: [SecretSchemaAttribute; 32],
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-struct SecretSchemaAttribute {
- name: *const gchar,
- attr_type: SecretSchemaAttributeType,
-}
-
-#[repr(C)]
-enum SecretSchemaFlags {
- None = 0,
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-enum SecretSchemaAttributeType {
- String = 0,
-}
-
-extern "C" {
- fn secret_password_store_sync(
- schema: *const SecretSchema,
- collection: *const gchar,
- label: *const gchar,
- password: *const gchar,
- cancellable: *mut GCancellable,
- error: *mut *mut GError,
- ...
- ) -> gboolean;
- fn secret_password_clear_sync(
- schema: *const SecretSchema,
- cancellable: *mut GCancellable,
- error: *mut *mut GError,
- ...
- ) -> gboolean;
- fn secret_password_lookup_sync(
- schema: *const SecretSchema,
- cancellable: *mut GCancellable,
- error: *mut *mut GError,
- ...
- ) -> *mut gchar;
-}
-
-struct GnomeSecret;
-
-fn label(index_url: &str) -> CString {
- CString::new(format!("cargo-registry:{}", index_url)).unwrap()
-}
-
-fn schema() -> SecretSchema {
- let mut attributes = [SecretSchemaAttribute {
- name: null(),
- attr_type: SecretSchemaAttributeType::String,
- }; 32];
- attributes[0] = SecretSchemaAttribute {
- name: b"url\0".as_ptr() as *const gchar,
- attr_type: SecretSchemaAttributeType::String,
- };
- SecretSchema {
- name: b"org.rust-lang.cargo.registry\0".as_ptr() as *const gchar,
- flags: SecretSchemaFlags::None,
- attributes,
- }
-}
-
-impl Credential for GnomeSecret {
- fn name(&self) -> &'static str {
- env!("CARGO_PKG_NAME")
- }
-
- fn get(&self, index_url: &str) -> Result<String, Error> {
- let mut error: *mut GError = null_mut();
- let attr_url = CString::new("url").unwrap();
- let index_url_c = CString::new(index_url).unwrap();
- let schema = schema();
- unsafe {
- let token_c = secret_password_lookup_sync(
- &schema,
- null_mut(),
- &mut error,
- attr_url.as_ptr(),
- index_url_c.as_ptr(),
- null() as *const gchar,
- );
- if !error.is_null() {
- return Err(format!(
- "failed to get token: {}",
- CStr::from_ptr((*error).message).to_str()?
- )
- .into());
- }
- if token_c.is_null() {
- return Err(format!("cannot find token for {}", index_url).into());
- }
- let token = CStr::from_ptr(token_c)
- .to_str()
- .map_err(|e| format!("expected utf8 token: {}", e))?
- .to_string();
- Ok(token)
- }
- }
-
- fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> {
- let label = label(name.unwrap_or(index_url));
- let token = CString::new(token).unwrap();
- let mut error: *mut GError = null_mut();
- let attr_url = CString::new("url").unwrap();
- let index_url_c = CString::new(index_url).unwrap();
- let schema = schema();
- unsafe {
- secret_password_store_sync(
- &schema,
- b"default\0".as_ptr() as *const gchar,
- label.as_ptr(),
- token.as_ptr(),
- null_mut(),
- &mut error,
- attr_url.as_ptr(),
- index_url_c.as_ptr(),
- null() as *const gchar,
- );
- if !error.is_null() {
- return Err(format!(
- "failed to store token: {}",
- CStr::from_ptr((*error).message).to_str()?
- )
- .into());
- }
- }
- Ok(())
- }
-
- fn erase(&self, index_url: &str) -> Result<(), Error> {
- let schema = schema();
- let mut error: *mut GError = null_mut();
- let attr_url = CString::new("url").unwrap();
- let index_url_c = CString::new(index_url).unwrap();
- unsafe {
- secret_password_clear_sync(
- &schema,
- null_mut(),
- &mut error,
- attr_url.as_ptr(),
- index_url_c.as_ptr(),
- null() as *const gchar,
- );
- if !error.is_null() {
- return Err(format!(
- "failed to erase token: {}",
- CStr::from_ptr((*error).message).to_str()?
- )
- .into());
- }
- }
- Ok(())
- }
-}
-
-fn main() {
- cargo_credential::main(GnomeSecret);
-}
diff --git a/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/Cargo.toml b/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/Cargo.toml
deleted file mode 100644
index c2c22a425..000000000
--- a/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/Cargo.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-[package]
-name = "cargo-credential-macos-keychain"
-version = "0.2.0"
-edition = "2021"
-license = "MIT OR Apache-2.0"
-repository = "https://github.com/rust-lang/cargo"
-description = "A Cargo credential process that stores tokens in a macOS keychain."
-
-[dependencies]
-cargo-credential = { version = "0.2.0", path = "../cargo-credential" }
-security-framework = "2.0.0"
diff --git a/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/src/main.rs b/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/src/main.rs
deleted file mode 100644
index 3fef3f92a..000000000
--- a/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/src/main.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-//! Cargo registry macos keychain credential process.
-
-use cargo_credential::{Credential, Error};
-use security_framework::os::macos::keychain::SecKeychain;
-
-struct MacKeychain;
-
-/// The account name is not used.
-const ACCOUNT: &'static str = "";
-
-fn registry(registry_name: &str) -> String {
- format!("cargo-registry:{}", registry_name)
-}
-
-impl Credential for MacKeychain {
- fn name(&self) -> &'static str {
- env!("CARGO_PKG_NAME")
- }
-
- fn get(&self, index_url: &str) -> Result<String, Error> {
- let keychain = SecKeychain::default().unwrap();
- let service_name = registry(index_url);
- let (pass, _item) = keychain.find_generic_password(&service_name, ACCOUNT)?;
- String::from_utf8(pass.as_ref().to_vec())
- .map_err(|_| "failed to convert token to UTF8".into())
- }
-
- fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> {
- let keychain = SecKeychain::default().unwrap();
- let service_name = registry(name.unwrap_or(index_url));
- if let Ok((_pass, mut item)) = keychain.find_generic_password(&service_name, ACCOUNT) {
- item.set_password(token.as_bytes())?;
- } else {
- keychain.add_generic_password(&service_name, ACCOUNT, token.as_bytes())?;
- }
- Ok(())
- }
-
- fn erase(&self, index_url: &str) -> Result<(), Error> {
- let keychain = SecKeychain::default().unwrap();
- let service_name = registry(index_url);
- let (_pass, item) = keychain.find_generic_password(&service_name, ACCOUNT)?;
- item.delete();
- Ok(())
- }
-}
-
-fn main() {
- cargo_credential::main(MacKeychain);
-}
diff --git a/src/tools/cargo/crates/credential/cargo-credential-wincred/Cargo.toml b/src/tools/cargo/crates/credential/cargo-credential-wincred/Cargo.toml
deleted file mode 100644
index 83c38e80d..000000000
--- a/src/tools/cargo/crates/credential/cargo-credential-wincred/Cargo.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-[package]
-name = "cargo-credential-wincred"
-version = "0.2.0"
-edition = "2021"
-license = "MIT OR Apache-2.0"
-repository = "https://github.com/rust-lang/cargo"
-description = "A Cargo credential process that stores tokens with Windows Credential Manager."
-
-[dependencies]
-cargo-credential = { version = "0.2.0", path = "../cargo-credential" }
-windows-sys = { version = "0.45", features = ["Win32_Foundation", "Win32_Security_Credentials"] }
diff --git a/src/tools/cargo/crates/credential/cargo-credential-wincred/src/main.rs b/src/tools/cargo/crates/credential/cargo-credential-wincred/src/main.rs
deleted file mode 100644
index 8ae48f348..000000000
--- a/src/tools/cargo/crates/credential/cargo-credential-wincred/src/main.rs
+++ /dev/null
@@ -1,111 +0,0 @@
-//! Cargo registry windows credential process.
-
-use cargo_credential::{Credential, Error};
-use std::ffi::OsStr;
-use std::os::windows::ffi::OsStrExt;
-
-use windows_sys::core::PWSTR;
-use windows_sys::Win32::Foundation::ERROR_NOT_FOUND;
-use windows_sys::Win32::Foundation::FILETIME;
-use windows_sys::Win32::Foundation::TRUE;
-use windows_sys::Win32::Security::Credentials::CredDeleteW;
-use windows_sys::Win32::Security::Credentials::CredReadW;
-use windows_sys::Win32::Security::Credentials::CredWriteW;
-use windows_sys::Win32::Security::Credentials::CREDENTIALW;
-use windows_sys::Win32::Security::Credentials::CRED_PERSIST_LOCAL_MACHINE;
-use windows_sys::Win32::Security::Credentials::CRED_TYPE_GENERIC;
-
-struct WindowsCredential;
-
-/// Converts a string to a nul-terminated wide UTF-16 byte sequence.
-fn wstr(s: &str) -> Vec<u16> {
- let mut wide: Vec<u16> = OsStr::new(s).encode_wide().collect();
- if wide.iter().any(|b| *b == 0) {
- panic!("nul byte in wide string");
- }
- wide.push(0);
- wide
-}
-
-fn target_name(registry_name: &str) -> Vec<u16> {
- wstr(&format!("cargo-registry:{}", registry_name))
-}
-
-impl Credential for WindowsCredential {
- fn name(&self) -> &'static str {
- env!("CARGO_PKG_NAME")
- }
-
- fn get(&self, index_url: &str) -> Result<String, Error> {
- let target_name = target_name(index_url);
- let p_credential: *mut CREDENTIALW = std::ptr::null_mut() as *mut _;
- unsafe {
- if CredReadW(
- target_name.as_ptr(),
- CRED_TYPE_GENERIC,
- 0,
- p_credential as *mut _ as *mut _,
- ) != TRUE
- {
- return Err(
- format!("failed to fetch token: {}", std::io::Error::last_os_error()).into(),
- );
- }
- let bytes = std::slice::from_raw_parts(
- (*p_credential).CredentialBlob,
- (*p_credential).CredentialBlobSize as usize,
- );
- String::from_utf8(bytes.to_vec()).map_err(|_| "failed to convert token to UTF8".into())
- }
- }
-
- fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> {
- let token = token.as_bytes();
- let target_name = target_name(index_url);
- let comment = match name {
- Some(name) => wstr(&format!("Cargo registry token for {}", name)),
- None => wstr("Cargo registry token"),
- };
- let mut credential = CREDENTIALW {
- Flags: 0,
- Type: CRED_TYPE_GENERIC,
- TargetName: target_name.as_ptr() as PWSTR,
- Comment: comment.as_ptr() as PWSTR,
- LastWritten: FILETIME {
- dwLowDateTime: 0,
- dwHighDateTime: 0,
- },
- CredentialBlobSize: token.len() as u32,
- CredentialBlob: token.as_ptr() as *mut u8,
- Persist: CRED_PERSIST_LOCAL_MACHINE,
- AttributeCount: 0,
- Attributes: std::ptr::null_mut(),
- TargetAlias: std::ptr::null_mut(),
- UserName: std::ptr::null_mut(),
- };
- let result = unsafe { CredWriteW(&mut credential, 0) };
- if result != TRUE {
- let err = std::io::Error::last_os_error();
- return Err(format!("failed to store token: {}", err).into());
- }
- Ok(())
- }
-
- fn erase(&self, index_url: &str) -> Result<(), Error> {
- let target_name = target_name(index_url);
- let result = unsafe { CredDeleteW(target_name.as_ptr(), CRED_TYPE_GENERIC, 0) };
- if result != TRUE {
- let err = std::io::Error::last_os_error();
- if err.raw_os_error() == Some(ERROR_NOT_FOUND as i32) {
- eprintln!("not currently logged in to `{}`", index_url);
- return Ok(());
- }
- return Err(format!("failed to remove token: {}", err).into());
- }
- Ok(())
- }
-}
-
-fn main() {
- cargo_credential::main(WindowsCredential);
-}
diff --git a/src/tools/cargo/crates/credential/cargo-credential/Cargo.toml b/src/tools/cargo/crates/credential/cargo-credential/Cargo.toml
deleted file mode 100644
index 2addaf5af..000000000
--- a/src/tools/cargo/crates/credential/cargo-credential/Cargo.toml
+++ /dev/null
@@ -1,9 +0,0 @@
-[package]
-name = "cargo-credential"
-version = "0.2.0"
-edition = "2021"
-license = "MIT OR Apache-2.0"
-repository = "https://github.com/rust-lang/cargo"
-description = "A library to assist writing Cargo credential helpers."
-
-[dependencies]
diff --git a/src/tools/cargo/crates/credential/cargo-credential/README.md b/src/tools/cargo/crates/credential/cargo-credential/README.md
deleted file mode 100644
index 1f75e598a..000000000
--- a/src/tools/cargo/crates/credential/cargo-credential/README.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# cargo-credential
-
-This package is a library to assist writing a Cargo credential helper, which
-provides an interface to store tokens for authorizing access to a registry
-such as https://crates.io/.
-
-Documentation about credential processes may be found at
-https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process
-
-Example implementations may be found at
-https://github.com/rust-lang/cargo/tree/master/crates/credential
-
-## Usage
-
-Create a Cargo project with this as a dependency:
-
-```toml
-# Add this to your Cargo.toml:
-
-[dependencies]
-cargo-credential = "0.1"
-```
-
-And then include a `main.rs` binary which implements the `Credential` trait, and calls
-the `main` function which will call the appropriate method of the trait:
-
-```rust
-// src/main.rs
-
-use cargo_credential::{Credential, Error};
-
-struct MyCredential;
-
-impl Credential for MyCredential {
- /// implement trait methods here...
-}
-
-fn main() {
- cargo_credential::main(MyCredential);
-}
-```
diff --git a/src/tools/cargo/crates/credential/cargo-credential/src/lib.rs b/src/tools/cargo/crates/credential/cargo-credential/src/lib.rs
deleted file mode 100644
index 3baf42d77..000000000
--- a/src/tools/cargo/crates/credential/cargo-credential/src/lib.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-//! Helper library for writing Cargo credential processes.
-//!
-//! A credential process should have a `struct` that implements the `Credential` trait.
-//! The `main` function should be called with an instance of that struct, such as:
-//!
-//! ```rust,ignore
-//! fn main() {
-//! cargo_credential::main(MyCredential);
-//! }
-//! ```
-//!
-//! This will determine the action to perform (get/store/erase) by looking at
-//! the CLI arguments for the first argument that does not start with `-`. It
-//! will then call the corresponding method of the trait to perform the
-//! requested action.
-
-pub type Error = Box<dyn std::error::Error>;
-
-pub trait Credential {
- /// Returns the name of this credential process.
- fn name(&self) -> &'static str;
-
- /// Retrieves a token for the given registry.
- fn get(&self, index_url: &str) -> Result<String, Error>;
-
- /// Stores the given token for the given registry.
- fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error>;
-
- /// Removes the token for the given registry.
- ///
- /// If the user is not logged in, this should print a message to stderr if
- /// possible indicating that the user is not currently logged in, and
- /// return `Ok`.
- fn erase(&self, index_url: &str) -> Result<(), Error>;
-}
-
-/// Runs the credential interaction by processing the command-line and
-/// environment variables.
-pub fn main(credential: impl Credential) {
- let name = credential.name();
- if let Err(e) = doit(credential) {
- eprintln!("{} error: {}", name, e);
- std::process::exit(1);
- }
-}
-
-fn env(name: &str) -> Result<String, Error> {
- std::env::var(name).map_err(|_| format!("environment variable `{}` is not set", name).into())
-}
-
-fn doit(credential: impl Credential) -> Result<(), Error> {
- let which = std::env::args()
- .skip(1)
- .skip_while(|arg| arg.starts_with('-'))
- .next()
- .ok_or_else(|| "first argument must be the {action}")?;
- let index_url = env("CARGO_REGISTRY_INDEX_URL")?;
- let name = std::env::var("CARGO_REGISTRY_NAME_OPT").ok();
- let result = match which.as_ref() {
- "get" => credential.get(&index_url).and_then(|token| {
- println!("{}", token);
- Ok(())
- }),
- "store" => {
- read_token().and_then(|token| credential.store(&index_url, &token, name.as_deref()))
- }
- "erase" => credential.erase(&index_url),
- _ => {
- return Err(format!(
- "unexpected command-line argument `{}`, expected get/store/erase",
- which
- )
- .into())
- }
- };
- result.map_err(|e| format!("failed to `{}` token: {}", which, e).into())
-}
-
-fn read_token() -> Result<String, Error> {
- let mut buffer = String::new();
- std::io::stdin().read_line(&mut buffer)?;
- if buffer.ends_with('\n') {
- buffer.pop();
- }
- Ok(buffer)
-}
diff --git a/src/tools/cargo/crates/home/CHANGELOG.md b/src/tools/cargo/crates/home/CHANGELOG.md
index 7674667c9..58f960cc3 100644
--- a/src/tools/cargo/crates/home/CHANGELOG.md
+++ b/src/tools/cargo/crates/home/CHANGELOG.md
@@ -4,7 +4,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-<!-- ## [Unreleased] -->
+## 0.5.6
+- Fixed & enhanced documentation.
+ [#12047](https://github.com/rust-lang/cargo/pull/12047)
+
+## 0.5.5 - 2023-04-25
+- The `home` crate has migrated to the <https://github.com/rust-lang/cargo/> repository.
+ [#11359](https://github.com/rust-lang/cargo/pull/11359)
+- Replaced the winapi dependency with windows-sys.
+ [#11656](https://github.com/rust-lang/cargo/pull/11656)
## [0.5.4] - 2022-10-10
- Add `_with_env` variants of functions to support in-process threaded tests for
@@ -38,7 +46,6 @@ Use Rust 1.36.0 as minimum Rust version.
### Removed
- Remove support for `multirust` folder used in old version of `rustup`.
-[Unreleased]: https://github.com/brson/home/compare/v0.5.4...HEAD
[0.5.4]: https://github.com/brson/home/compare/v0.5.3...v0.5.4
[0.5.3]: https://github.com/brson/home/compare/v0.5.2...v0.5.3
[0.5.2]: https://github.com/brson/home/compare/v0.5.1...v0.5.2
diff --git a/src/tools/cargo/crates/home/Cargo.toml b/src/tools/cargo/crates/home/Cargo.toml
index 2c5b92bcb..6c65ecc18 100644
--- a/src/tools/cargo/crates/home/Cargo.toml
+++ b/src/tools/cargo/crates/home/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "home"
-version = "0.5.4" # also update `html_root_url` in `src/lib.rs`
+version = "0.5.6" # also update `html_root_url` in `src/lib.rs`
authors = ["Brian Anderson <andersrb@gmail.com>"]
documentation = "https://docs.rs/home"
edition = "2018"
@@ -17,4 +17,4 @@ repository = "https://github.com/rust-lang/cargo"
description = "Shared definitions of home directories."
[target.'cfg(windows)'.dependencies]
-windows-sys = { version = "0.45.0", features = ["Win32_Foundation", "Win32_UI_Shell"] }
+windows-sys = { workspace = true, features = ["Win32_Foundation", "Win32_UI_Shell"] }
diff --git a/src/tools/cargo/crates/home/src/env.rs b/src/tools/cargo/crates/home/src/env.rs
index e47273bc8..49fea5422 100644
--- a/src/tools/cargo/crates/home/src/env.rs
+++ b/src/tools/cargo/crates/home/src/env.rs
@@ -9,7 +9,7 @@ use std::{
/// Permits parameterizing the home functions via the _from variants - used for
/// in-process unit testing by rustup.
pub trait Env {
- /// Return the path to the the users home dir, or None if any error occurs:
+ /// Return the path to the users home dir, or None if any error occurs:
/// see home_inner.
fn home_dir(&self) -> Option<PathBuf>;
/// Return the current working directory.
diff --git a/src/tools/cargo/crates/home/src/lib.rs b/src/tools/cargo/crates/home/src/lib.rs
index 306026e40..0e1e975e4 100644
--- a/src/tools/cargo/crates/home/src/lib.rs
+++ b/src/tools/cargo/crates/home/src/lib.rs
@@ -1,14 +1,5 @@
//! Canonical definitions of `home_dir`, `cargo_home`, and `rustup_home`.
//!
-//! This provides the definition of `home_dir` used by Cargo and
-//! rustup, as well functions to find the correct value of
-//! `CARGO_HOME` and `RUSTUP_HOME`.
-//!
-//! See also the [`dirs`](https://docs.rs/dirs) crate.
-//!
-//! _Note that as of 2019/08/06 it appears that cargo uses this crate. And
-//! rustup has used this crate since 2019/08/21._
-//!
//! The definition of `home_dir` provided by the standard library is
//! incorrect because it considers the `HOME` environment variable on
//! Windows. This causes surprising situations where a Rust program
@@ -17,15 +8,17 @@
//! rustup use the standard libraries definition - they use the
//! definition here.
//!
-//! This crate further provides two functions, `cargo_home` and
+//! This crate provides two additional functions, `cargo_home` and
//! `rustup_home`, which are the canonical way to determine the
-//! location that Cargo and rustup store their data.
+//! location that Cargo and rustup use to store their data.
+//! The `env` module contains utilities for mocking the process environment
+//! by Cargo and rustup.
//!
//! See also this [discussion].
//!
//! [discussion]: https://github.com/rust-lang/rust/pull/46799#issuecomment-361156935
-#![doc(html_root_url = "https://docs.rs/home/0.5.4")]
+#![doc(html_root_url = "https://docs.rs/home/0.5.6")]
#![deny(rust_2018_idioms)]
pub mod env;
@@ -36,29 +29,34 @@ mod windows;
use std::io;
use std::path::{Path, PathBuf};
-/// Returns the path of the current user's home directory if known.
+/// Returns the path of the current user's home directory using environment
+/// variables or OS-specific APIs.
///
/// # Unix
///
/// Returns the value of the `HOME` environment variable if it is set
-/// and not equal to the empty string. Otherwise, it tries to determine the
-/// home directory by invoking the `getpwuid_r` function on the UID of the
-/// current user.
+/// **even** if it is an empty string. Otherwise, it tries to determine the
+/// home directory by invoking the [`getpwuid_r`][getpwuid] function with
+/// the UID of the current user.
+///
+/// [getpwuid]: https://linux.die.net/man/3/getpwuid_r
///
/// # Windows
///
-/// Returns the value of the `USERPROFILE` environment variable if it
-/// is set and not equal to the empty string. If both do not exist,
-/// [`SHGetFolderPathW`][msdn] is used to return the appropriate path.
+/// Returns the value of the `USERPROFILE` environment variable if it is set
+/// **and** it is not an empty string. Otherwise, it tries to determine the
+/// home directory by invoking the [`SHGetFolderPathW`][shgfp] function with
+/// [`CSIDL_PROFILE`][csidl].
///
-/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetfolderpathw
+/// [shgfp]: https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetfolderpathw
+/// [csidl]: https://learn.microsoft.com/en-us/windows/win32/shell/csidl
///
/// # Examples
///
/// ```
/// match home::home_dir() {
-/// Some(path) => println!("{}", path.display()),
-/// None => println!("Impossible to get your home dir!"),
+/// Some(path) if !path.as_os_str().is_empty() => println!("{}", path.display()),
+/// _ => println!("Unable to get your home dir!"),
/// }
/// ```
pub fn home_dir() -> Option<PathBuf> {
diff --git a/src/tools/cargo/crates/mdman/Cargo.lock b/src/tools/cargo/crates/mdman/Cargo.lock
deleted file mode 100644
index 51fe47a9c..000000000
--- a/src/tools/cargo/crates/mdman/Cargo.lock
+++ /dev/null
@@ -1,459 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "anyhow"
-version = "1.0.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b"
-
-[[package]]
-name = "bitflags"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-
-[[package]]
-name = "block-buffer"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
-dependencies = [
- "block-padding",
- "byte-tools",
- "byteorder",
- "generic-array",
-]
-
-[[package]]
-name = "block-padding"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
-dependencies = [
- "byte-tools",
-]
-
-[[package]]
-name = "byte-tools"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
-
-[[package]]
-name = "byteorder"
-version = "1.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
-
-[[package]]
-name = "cfg-if"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
-
-[[package]]
-name = "ctor"
-version = "0.1.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39858aa5bac06462d4dd4b9164848eb81ffc4aa5c479746393598fd193afa227"
-dependencies = [
- "quote",
- "syn",
-]
-
-[[package]]
-name = "diff"
-version = "0.1.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
-
-[[package]]
-name = "digest"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "fake-simd"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
-
-[[package]]
-name = "form_urlencoded"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
-dependencies = [
- "matches",
- "percent-encoding",
-]
-
-[[package]]
-name = "generic-array"
-version = "0.12.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
-dependencies = [
- "typenum",
-]
-
-[[package]]
-name = "handlebars"
-version = "3.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86dbc8a0746b08f363d2e00da48e6c9ceb75c198ac692d2715fcbb5bee74c87d"
-dependencies = [
- "log",
- "pest",
- "pest_derive",
- "quick-error",
- "serde",
- "serde_json",
- "walkdir",
-]
-
-[[package]]
-name = "idna"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
-dependencies = [
- "matches",
- "unicode-bidi",
- "unicode-normalization",
-]
-
-[[package]]
-name = "itoa"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
-
-[[package]]
-name = "log"
-version = "0.4.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "maplit"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
-
-[[package]]
-name = "matches"
-version = "0.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
-
-[[package]]
-name = "mdman"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "handlebars",
- "pretty_assertions",
- "pulldown-cmark",
- "same-file",
- "serde_json",
- "url",
-]
-
-[[package]]
-name = "memchr"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
-
-[[package]]
-name = "opaque-debug"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
-
-[[package]]
-name = "output_vt100"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "percent-encoding"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
-
-[[package]]
-name = "pest"
-version = "2.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
-dependencies = [
- "ucd-trie",
-]
-
-[[package]]
-name = "pest_derive"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
-dependencies = [
- "pest",
- "pest_generator",
-]
-
-[[package]]
-name = "pest_generator"
-version = "2.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
-dependencies = [
- "pest",
- "pest_meta",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "pest_meta"
-version = "2.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
-dependencies = [
- "maplit",
- "pest",
- "sha-1",
-]
-
-[[package]]
-name = "pretty_assertions"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755"
-dependencies = [
- "ctor",
- "diff",
- "output_vt100",
- "yansi",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
-dependencies = [
- "unicode-xid",
-]
-
-[[package]]
-name = "pulldown-cmark"
-version = "0.9.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63"
-dependencies = [
- "bitflags",
- "memchr",
- "unicase",
-]
-
-[[package]]
-name = "quick-error"
-version = "1.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
-
-[[package]]
-name = "quote"
-version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "ryu"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
-
-[[package]]
-name = "same-file"
-version = "1.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
-dependencies = [
- "winapi-util",
-]
-
-[[package]]
-name = "serde"
-version = "1.0.114"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3"
-
-[[package]]
-name = "serde_json"
-version = "1.0.57"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
-dependencies = [
- "itoa",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "sha-1"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
-dependencies = [
- "block-buffer",
- "digest",
- "fake-simd",
- "opaque-debug",
-]
-
-[[package]]
-name = "syn"
-version = "1.0.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-xid",
-]
-
-[[package]]
-name = "tinyvec"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed"
-
-[[package]]
-name = "typenum"
-version = "1.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
-
-[[package]]
-name = "ucd-trie"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
-
-[[package]]
-name = "unicase"
-version = "2.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
-dependencies = [
- "version_check",
-]
-
-[[package]]
-name = "unicode-bidi"
-version = "0.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
-dependencies = [
- "matches",
-]
-
-[[package]]
-name = "unicode-normalization"
-version = "0.1.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977"
-dependencies = [
- "tinyvec",
-]
-
-[[package]]
-name = "unicode-xid"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
-
-[[package]]
-name = "url"
-version = "2.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
-dependencies = [
- "form_urlencoded",
- "idna",
- "matches",
- "percent-encoding",
-]
-
-[[package]]
-name = "version_check"
-version = "0.9.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
-
-[[package]]
-name = "walkdir"
-version = "2.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
-dependencies = [
- "same-file",
- "winapi",
- "winapi-util",
-]
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-util"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
-name = "yansi"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
diff --git a/src/tools/cargo/crates/mdman/Cargo.toml b/src/tools/cargo/crates/mdman/Cargo.toml
index 92cdf2eb6..812f1393a 100644
--- a/src/tools/cargo/crates/mdman/Cargo.toml
+++ b/src/tools/cargo/crates/mdman/Cargo.toml
@@ -1,17 +1,18 @@
[package]
name = "mdman"
-version = "0.1.0"
+version = "0.0.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Creates a man page page from markdown."
+publish = false
[dependencies]
-anyhow = "1.0.31"
-handlebars = { version = "3.2.1", features = ["dir_source"] }
-pulldown-cmark = { version = "0.9.2", default-features = false }
-same-file = "1.0.6"
-serde_json = "1.0.56"
-url = "2.2.2"
+anyhow.workspace = true
+handlebars.workspace = true
+pulldown-cmark.workspace = true
+same-file.workspace = true
+serde_json.workspace = true
+url.workspace = true
[dev-dependencies]
-pretty_assertions = "1.3.0"
+pretty_assertions.workspace = true
diff --git a/src/tools/cargo/crates/mdman/build-man.sh b/src/tools/cargo/crates/mdman/build-man.sh
deleted file mode 100755
index 9286b17c2..000000000
--- a/src/tools/cargo/crates/mdman/build-man.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-
-set -e
-
-cargo run -- -t md -o doc/out doc/*.md
-cargo run -- -t txt -o doc/out doc/*.md
-cargo run -- -t man -o doc/out doc/*.md
diff --git a/src/tools/cargo/crates/mdman/doc/mdman.md b/src/tools/cargo/crates/mdman/doc/mdman.md
index 2025c13dc..bfa394648 100644
--- a/src/tools/cargo/crates/mdman/doc/mdman.md
+++ b/src/tools/cargo/crates/mdman/doc/mdman.md
@@ -28,7 +28,7 @@ man page:
and `{{/options}}` tags. This tells the processor where the options start
and end.
- Each option must be expressed with a `{{#option}}` block. The parameters to
- the the block are a sequence of strings indicating the option. For example,
+ the block are a sequence of strings indicating the option. For example,
```{{#option "`-p` _spec_..." "`--package` _spec_..."}}``` is an option that
has two different forms. The text within the string is processed as markdown.
It is recommended to use formatting similar to this example.
diff --git a/src/tools/cargo/crates/mdman/doc/out/mdman.1 b/src/tools/cargo/crates/mdman/doc/out/mdman.1
index 0718d6ddb..b114715ae 100644
--- a/src/tools/cargo/crates/mdman/doc/out/mdman.1
+++ b/src/tools/cargo/crates/mdman/doc/out/mdman.1
@@ -6,7 +6,7 @@
.SH "NAME"
mdman \- Converts markdown to a man page
.SH "SYNOPSIS"
-\fBmdman\fR [\fIoptions\fR] \fB\-t\fR \fItype\fR \fB\-o\fR \fIoutdir\fR \fIsources...\fR
+\fBmdman\fR [\fIoptions\fR] \fB\-t\fR \fItype\fR \fB\-o\fR \fIoutdir\fR \fIsources\[u2026]\fR
.SH "DESCRIPTION"
Converts a markdown file to a man page.
.sp
@@ -29,7 +29,7 @@ and end.
.sp
.RS 4
\h'-04'\(bu\h'+02'Each option must be expressed with a \fB{{#option}}\fR block. The parameters to
-the the block are a sequence of strings indicating the option. For example,
+the block are a sequence of strings indicating the option. For example,
\fB{{#option "`\-p` _spec_..." "`\-\-package` _spec_..."}}\fR is an option that
has two different forms. The text within the string is processed as markdown.
It is recommended to use formatting similar to this example.
@@ -83,7 +83,7 @@ Outputs with the \fB\&.md\fR extension.
.RE
.sp
.RS 4
-\h'-04'\(bu\h'+02'\fBtxt\fR \[em] A text file, rendered for situations where a man page viewer isn't
+\h'-04'\(bu\h'+02'\fBtxt\fR \[em] A text file, rendered for situations where a man page viewer isn\[cq]t
available. Outputs with the \fB\&.txt\fR extension.
.RE
.RE
@@ -107,7 +107,7 @@ matching \fB\-\-man\fR entry, then a relative link to a file named \fIname\fR\fB
be used.
.RE
.sp
-\fIsources...\fR
+\fIsources\[u2026]\fR
.RS 4
The source input filename, may be specified multiple times.
.RE
diff --git a/src/tools/cargo/crates/mdman/doc/out/mdman.md b/src/tools/cargo/crates/mdman/doc/out/mdman.md
index d0dd34511..9d2fe9326 100644
--- a/src/tools/cargo/crates/mdman/doc/out/mdman.md
+++ b/src/tools/cargo/crates/mdman/doc/out/mdman.md
@@ -27,7 +27,7 @@ man page:
and `{{/options}}` tags. This tells the processor where the options start
and end.
- Each option must be expressed with a `{{#option}}` block. The parameters to
- the the block are a sequence of strings indicating the option. For example,
+ the block are a sequence of strings indicating the option. For example,
```{{#option "`-p` _spec_..." "`--package` _spec_..."}}``` is an option that
has two different forms. The text within the string is processed as markdown.
It is recommended to use formatting similar to this example.
@@ -61,7 +61,7 @@ man page:
<code>.1</code>) matching the man page section.</li>
<li><code>md</code> — A markdown file, after all handlebars processing has been finished.
Outputs with the <code>.md</code> extension.</li>
-<li><code>txt</code> — A text file, rendered for situations where a man page viewer isn't
+<li><code>txt</code> — A text file, rendered for situations where a man page viewer isn’t
available. Outputs with the <code>.txt</code> extension.</li>
</ul></dd>
@@ -82,7 +82,7 @@ matching <code>--man</code> entry, then a relative link to a file named <em>name
be used.</dd>
-<dt class="option-term" id="option-mdman-sources..."><a class="option-anchor" href="#option-mdman-sources..."></a><em>sources...</em></dt>
+<dt class="option-term" id="option-mdman-sources…"><a class="option-anchor" href="#option-mdman-sources…"></a><em>sources…</em></dt>
<dd class="option-desc">The source input filename, may be specified multiple times.</dd>
diff --git a/src/tools/cargo/crates/mdman/doc/out/mdman.txt b/src/tools/cargo/crates/mdman/doc/out/mdman.txt
index 83fa7de90..6c8dcd65d 100644
--- a/src/tools/cargo/crates/mdman/doc/out/mdman.txt
+++ b/src/tools/cargo/crates/mdman/doc/out/mdman.txt
@@ -4,7 +4,7 @@ NAME
mdman - Converts markdown to a man page
SYNOPSIS
- mdman [options] -t type -o outdir sources...
+ mdman [options] -t type -o outdir sources…
DESCRIPTION
Converts a markdown file to a man page.
@@ -25,7 +25,7 @@ DESCRIPTION
the options start and end.
o Each option must be expressed with a {{#option}} block. The
- parameters to the the block are a sequence of strings indicating the
+ parameters to the block are a sequence of strings indicating the
option. For example, {{#option "`-p` _spec_..." "`--package`
_spec_..."}} is an option that has two different forms. The text
within the string is processed as markdown. It is recommended to use
@@ -65,7 +65,7 @@ OPTIONS
finished. Outputs with the .md extension.
o txt — A text file, rendered for situations where a man page
- viewer isn't available. Outputs with the .txt extension.
+ viewer isn’t available. Outputs with the .txt extension.
-o outdir
Specifies the directory where to save the output.
@@ -81,7 +81,7 @@ OPTIONS
does not have a matching --man entry, then a relative link to a file
named name.md will be used.
- sources...
+ sources…
The source input filename, may be specified multiple times.
EXAMPLES
diff --git a/src/tools/cargo/crates/resolver-tests/Cargo.toml b/src/tools/cargo/crates/resolver-tests/Cargo.toml
index e4aab4325..8a7cab113 100644
--- a/src/tools/cargo/crates/resolver-tests/Cargo.toml
+++ b/src/tools/cargo/crates/resolver-tests/Cargo.toml
@@ -1,12 +1,13 @@
[package]
name = "resolver-tests"
-version = "0.1.0"
+version = "0.0.0"
edition = "2018"
+publish = false
[dependencies]
-cargo = { path = "../.." }
-cargo-util = { path = "../cargo-util" }
-is-terminal = "0.4.0"
-lazy_static = "1.3.0"
-proptest = "1.1.0"
-varisat = "0.2.1"
+cargo.workspace = true
+cargo-util.workspace = true
+is-terminal.workspace = true
+lazy_static.workspace = true
+proptest.workspace = true
+varisat.workspace = true
diff --git a/src/tools/cargo/crates/resolver-tests/src/lib.rs b/src/tools/cargo/crates/resolver-tests/src/lib.rs
index 3ffb6c5d2..01d9b5e6d 100644
--- a/src/tools/cargo/crates/resolver-tests/src/lib.rs
+++ b/src/tools/cargo/crates/resolver-tests/src/lib.rs
@@ -184,6 +184,7 @@ pub fn resolve_with_config_raw(
deps,
&BTreeMap::new(),
None::<&String>,
+ None::<&String>,
)
.unwrap();
let opts = ResolveOpts::everything();
@@ -585,6 +586,7 @@ pub fn pkg_dep<T: ToPkgId>(name: T, dep: Vec<Dependency>) -> Summary {
dep,
&BTreeMap::new(),
link,
+ None::<&String>,
)
.unwrap()
}
@@ -613,6 +615,7 @@ pub fn pkg_loc(name: &str, loc: &str) -> Summary {
Vec::new(),
&BTreeMap::new(),
link,
+ None::<&String>,
)
.unwrap()
}
@@ -627,6 +630,7 @@ pub fn remove_dep(sum: &Summary, ind: usize) -> Summary {
deps,
&BTreeMap::new(),
sum.links().map(|a| a.as_str()),
+ None::<&String>,
)
.unwrap()
}
diff --git a/src/tools/cargo/crates/semver-check/Cargo.toml b/src/tools/cargo/crates/semver-check/Cargo.toml
new file mode 100644
index 000000000..f7b8c7d48
--- /dev/null
+++ b/src/tools/cargo/crates/semver-check/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "semver-check"
+version = "0.0.0"
+authors = ["Eric Huss"]
+edition = "2021"
+publish = false
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+tempfile.workspace = true
diff --git a/src/tools/cargo/crates/semver-check/src/main.rs b/src/tools/cargo/crates/semver-check/src/main.rs
new file mode 100644
index 000000000..fa4639eb7
--- /dev/null
+++ b/src/tools/cargo/crates/semver-check/src/main.rs
@@ -0,0 +1,293 @@
+//! Test runner for the semver compatibility doc chapter.
+//!
+//! This extracts all the "rust" annotated code blocks and tests that they
+//! either fail or succeed as expected. This also checks that the examples are
+//! formatted correctly.
+//!
+//! An example with the word "MINOR" at the top is expected to successfully
+//! build against the before and after. Otherwise it should fail. A comment of
+//! "// Error:" will check that the given message appears in the error output.
+
+use std::error::Error;
+use std::fs;
+use std::path::Path;
+use std::process::{Command, Output};
+
+fn main() {
+ if let Err(e) = doit() {
+ println!("error: {}", e);
+ std::process::exit(1);
+ }
+}
+
+const SEPARATOR: &str = "///////////////////////////////////////////////////////////";
+
+fn doit() -> Result<(), Box<dyn Error>> {
+ let filename = std::env::args().nth(1).unwrap_or_else(|| {
+ Path::new(env!("CARGO_MANIFEST_DIR"))
+ .join("../../src/doc/src/reference/semver.md")
+ .to_str()
+ .unwrap()
+ .to_string()
+ });
+ let contents = fs::read_to_string(filename)?;
+ let mut lines = contents.lines().enumerate();
+
+ loop {
+ // Find a rust block.
+ let (block_start, run_program, deny_warnings) = loop {
+ match lines.next() {
+ Some((lineno, line)) => {
+ if line.trim().starts_with("```rust") && !line.contains("skip") {
+ break (
+ lineno + 1,
+ line.contains("run-fail"),
+ !line.contains("dont-deny"),
+ );
+ }
+ }
+ None => return Ok(()),
+ }
+ };
+ // Read in the code block.
+ let mut block = Vec::new();
+ loop {
+ match lines.next() {
+ Some((_, line)) => {
+ if line.trim() == "```" {
+ break;
+ }
+ block.push(line);
+ }
+ None => {
+ return Err(format!(
+ "rust block did not end for example starting on line {}",
+ block_start
+ )
+ .into());
+ }
+ }
+ }
+ // Split it into the separate source files.
+ let parts: Vec<_> = block.split(|line| line.trim() == SEPARATOR).collect();
+ if parts.len() != 4 {
+ return Err(format!(
+ "expected 4 sections in example starting on line {}, got {}:\n{:?}",
+ block_start,
+ parts.len(),
+ parts
+ )
+ .into());
+ }
+ let join = |part: &[&str]| {
+ let mut result = String::new();
+ result.push_str("#![allow(unused)]\n");
+ if deny_warnings {
+ result.push_str("#![deny(warnings)]\n");
+ }
+ result.push_str(&part.join("\n"));
+ if !result.ends_with('\n') {
+ result.push('\n');
+ }
+ result
+ };
+ let expect_success = parts[0][0].contains("MINOR");
+ println!("Running test from line {}", block_start);
+
+ let result = run_test(
+ join(parts[1]),
+ join(parts[2]),
+ join(parts[3]),
+ expect_success,
+ run_program,
+ );
+
+ if let Err(e) = result {
+ return Err(format!(
+ "test failed for example starting on line {}: {}",
+ block_start, e
+ )
+ .into());
+ }
+ }
+}
+
+const CRATE_NAME: &str = "updated_crate";
+
+fn run_test(
+ before: String,
+ after: String,
+ example: String,
+ expect_success: bool,
+ run_program: bool,
+) -> Result<(), Box<dyn Error>> {
+ let tempdir = tempfile::TempDir::new()?;
+ let before_p = tempdir.path().join("before.rs");
+ let after_p = tempdir.path().join("after.rs");
+ let example_p = tempdir.path().join("example.rs");
+
+ let check_fn = if run_program {
+ run_check
+ } else {
+ compile_check
+ };
+
+ compile_check(before, &before_p, CRATE_NAME, false, true)?;
+ check_fn(example.clone(), &example_p, "example", true, true)?;
+ compile_check(after, &after_p, CRATE_NAME, false, true)?;
+ check_fn(example, &example_p, "example", true, expect_success)?;
+ Ok(())
+}
+
+fn check_formatting(path: &Path) -> Result<(), Box<dyn Error>> {
+ match Command::new("rustfmt")
+ .args(&["--edition=2018", "--check"])
+ .arg(path)
+ .status()
+ {
+ Ok(status) => {
+ if !status.success() {
+ return Err(format!("failed to run rustfmt: {}", status).into());
+ }
+ Ok(())
+ }
+ Err(e) => Err(format!("failed to run rustfmt: {}", e).into()),
+ }
+}
+
+fn compile(
+ contents: &str,
+ path: &Path,
+ crate_name: &str,
+ extern_path: bool,
+) -> Result<Output, Box<dyn Error>> {
+ let crate_type = if contents.contains("fn main()") {
+ "bin"
+ } else {
+ "rlib"
+ };
+
+ fs::write(path, &contents)?;
+ check_formatting(path)?;
+ let out_dir = path.parent().unwrap();
+ let mut cmd = Command::new("rustc");
+ cmd.args(&[
+ "--edition=2021",
+ "--crate-type",
+ crate_type,
+ "--crate-name",
+ crate_name,
+ "--out-dir",
+ ]);
+ cmd.arg(&out_dir);
+ if extern_path {
+ let epath = out_dir.join(format!("lib{}.rlib", CRATE_NAME));
+ cmd.arg("--extern")
+ .arg(format!("{}={}", CRATE_NAME, epath.display()));
+ }
+ cmd.arg(path);
+ cmd.output().map_err(Into::into)
+}
+
+fn compile_check(
+ mut contents: String,
+ path: &Path,
+ crate_name: &str,
+ extern_path: bool,
+ expect_success: bool,
+) -> Result<(), Box<dyn Error>> {
+ // If the example has an error message, remove it so that it can be
+ // compared with the actual output, and also to avoid issues with rustfmt
+ // moving it around.
+ let expected_error = match contents.find("// Error:") {
+ Some(index) => {
+ let start = contents[..index].rfind(|ch| ch != ' ').unwrap();
+ let end = contents[index..].find('\n').unwrap();
+ let error = contents[index + 9..index + end].trim().to_string();
+ contents.replace_range(start + 1..index + end, "");
+ Some(error)
+ }
+ None => None,
+ };
+
+ let output = compile(&contents, path, crate_name, extern_path)?;
+
+ let stderr = std::str::from_utf8(&output.stderr).unwrap();
+ match (output.status.success(), expect_success) {
+ (true, true) => Ok(()),
+ (true, false) => Err(format!(
+ "expected failure, got success {}\n===== Contents:\n{}\n===== Output:\n{}\n",
+ path.display(),
+ contents,
+ stderr
+ )
+ .into()),
+ (false, true) => Err(format!(
+ "expected success, got error {}\n===== Contents:\n{}\n===== Output:\n{}\n",
+ path.display(),
+ contents,
+ stderr
+ )
+ .into()),
+ (false, false) => {
+ if expected_error.is_none() {
+ return Err("failing test should have an \"// Error:\" annotation ".into());
+ }
+ let expected_error = expected_error.unwrap();
+ if !stderr.contains(&expected_error) {
+ Err(format!(
+ "expected error message not found in compiler output\nExpected: {}\nGot:\n{}\n",
+ expected_error, stderr
+ )
+ .into())
+ } else {
+ Ok(())
+ }
+ }
+ }
+}
+
+fn run_check(
+ contents: String,
+ path: &Path,
+ crate_name: &str,
+ extern_path: bool,
+ expect_success: bool,
+) -> Result<(), Box<dyn Error>> {
+ let compile_output = compile(&contents, path, crate_name, extern_path)?;
+
+ if !compile_output.status.success() {
+ let stderr = std::str::from_utf8(&compile_output.stderr).unwrap();
+ return Err(format!(
+ "expected success, got error {}\n===== Contents:\n{}\n===== Output:\n{}\n",
+ path.display(),
+ contents,
+ stderr
+ )
+ .into());
+ }
+
+ let binary_path = path.parent().unwrap().join(crate_name);
+
+ let output = Command::new(binary_path).output()?;
+
+ let stderr = std::str::from_utf8(&output.stderr).unwrap();
+
+ match (output.status.success(), expect_success) {
+ (true, false) => Err(format!(
+ "expected panic, got success {}\n===== Contents:\n{}\n===== Output:\n{}\n",
+ path.display(),
+ contents,
+ stderr
+ )
+ .into()),
+ (false, true) => Err(format!(
+ "expected success, got panic {}\n===== Contents:\n{}\n===== Output:\n{}\n",
+ path.display(),
+ contents,
+ stderr,
+ )
+ .into()),
+ (_, _) => Ok(()),
+ }
+}
diff --git a/src/tools/cargo/crates/xtask-build-man/Cargo.toml b/src/tools/cargo/crates/xtask-build-man/Cargo.toml
new file mode 100644
index 000000000..6d02aa2c3
--- /dev/null
+++ b/src/tools/cargo/crates/xtask-build-man/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "xtask-build-man"
+version = "0.0.0"
+edition = "2021"
+publish = false
+
+[dependencies]
diff --git a/src/tools/cargo/crates/xtask-build-man/src/main.rs b/src/tools/cargo/crates/xtask-build-man/src/main.rs
new file mode 100644
index 000000000..6680c3783
--- /dev/null
+++ b/src/tools/cargo/crates/xtask-build-man/src/main.rs
@@ -0,0 +1,108 @@
+//! ```text
+//! NAME
+//! build-man
+//!
+//! SYNOPSIS
+//! build-man
+//!
+//! DESCRIPTION
+//! Build the man pages for packages `mdman` and `cargo`.
+//! For more, read their doc comments.
+//! ```
+
+use std::fs;
+use std::io;
+use std::path::PathBuf;
+use std::process;
+use std::process::Command;
+
+fn main() -> io::Result<()> {
+ build_mdman()?;
+ build_cargo()?;
+ Ok(())
+}
+
+/// Builds the man pages for `mdman`.
+fn build_mdman() -> io::Result<()> {
+ cwd_to_workspace_root()?;
+
+ let src_paths = &["crates/mdman/doc/mdman.md".into()];
+ let dst_path = "crates/mdman/doc/out";
+ let outs = [("md", dst_path), ("txt", dst_path), ("man", dst_path)];
+
+ build_man("mdman", src_paths, &outs, &[])
+}
+
+/// Builds the man pages for Cargo.
+///
+/// The source for the man pages are located in src/doc/man/ in markdown format.
+/// These also are handlebars templates, see crates/mdman/README.md for details.
+///
+/// The generated man pages are placed in the src/etc/man/ directory. The pages
+/// are also expanded into markdown (after being expanded by handlebars) and
+/// saved in the src/doc/src/commands/ directory. These are included in the
+/// Cargo book, which is converted to HTML by mdbook.
+fn build_cargo() -> io::Result<()> {
+ // Find all `src/doc/man/cargo-*.md`
+ let src_paths = {
+ let mut src_paths = Vec::new();
+ for entry in fs::read_dir("src/doc/man")? {
+ let entry = entry?;
+ let file_name = entry.file_name();
+ let file_name = file_name.to_str().unwrap();
+ if file_name.starts_with("cargo-") && file_name.ends_with(".md") {
+ src_paths.push(entry.path());
+ }
+ }
+ src_paths
+ };
+ let outs = [
+ ("md", "src/doc/src/commands"),
+ ("txt", "src/doc/man/generated_txt"),
+ ("man", "src/etc/man"),
+ ];
+ let args = [
+ "--url",
+ "https://doc.rust-lang.org/cargo/commands/",
+ "--man",
+ "rustc:1=https://doc.rust-lang.org/rustc/index.html",
+ "--man",
+ "rustdoc:1=https://doc.rust-lang.org/rustdoc/index.html",
+ ];
+ build_man("cargo", &src_paths[..], &outs, &args)
+}
+
+/// Change to workspace root.
+///
+/// Assumed this xtask is located in `[WORKSPACE]/crates/xtask-build-man`.
+fn cwd_to_workspace_root() -> io::Result<()> {
+ let pkg_root = std::env!("CARGO_MANIFEST_DIR");
+ let ws_root = format!("{pkg_root}/../..");
+ std::env::set_current_dir(ws_root)
+}
+
+/// Builds the man pages.
+fn build_man(
+ pkg_name: &str,
+ src_paths: &[PathBuf],
+ outs: &[(&str, &str)],
+ extra_args: &[&str],
+) -> io::Result<()> {
+ for (format, dst_path) in outs {
+ eprintln!("Start converting `{format}` for package `{pkg_name}`...");
+ let mut cmd = Command::new(std::env!("CARGO"));
+ cmd.args(["run", "--package", "mdman", "--"])
+ .args(["-t", format, "-o", dst_path])
+ .args(src_paths)
+ .args(extra_args);
+
+ let status = cmd.status()?;
+ if !status.success() {
+ eprintln!("failed to build the man pages for package `{pkg_name}`");
+ eprintln!("failed command: `{cmd:?}`");
+ process::exit(status.code().unwrap_or(1));
+ }
+ }
+
+ Ok(())
+}
diff --git a/src/tools/cargo/crates/xtask-stale-label/Cargo.toml b/src/tools/cargo/crates/xtask-stale-label/Cargo.toml
new file mode 100644
index 000000000..af3218e96
--- /dev/null
+++ b/src/tools/cargo/crates/xtask-stale-label/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "xtask-stale-label"
+version = "0.0.0"
+edition = "2021"
+publish = false
+
+[dependencies]
+toml_edit.workspace = true
diff --git a/src/tools/cargo/crates/xtask-stale-label/src/main.rs b/src/tools/cargo/crates/xtask-stale-label/src/main.rs
new file mode 100644
index 000000000..37675979c
--- /dev/null
+++ b/src/tools/cargo/crates/xtask-stale-label/src/main.rs
@@ -0,0 +1,91 @@
+//! ```text
+//! NAME
+//! stale-label
+//!
+//! SYNOPSIS
+//! stale-label
+//!
+//! DESCRIPTION
+//! Detect stale paths in autolabel definitions in triagebot.toml.
+//! Probably autofix them in the future.
+//! ```
+
+use std::fmt::Write as _;
+use std::path::PathBuf;
+use std::process;
+use toml_edit::Document;
+
+fn main() {
+ let pkg_root = std::env!("CARGO_MANIFEST_DIR");
+ let ws_root = PathBuf::from(format!("{pkg_root}/../.."));
+ let path = {
+ let path = ws_root.join("triagebot.toml");
+ path.canonicalize().unwrap_or(path)
+ };
+
+ eprintln!("Checking file {path:?}\n");
+
+ let mut failed = 0;
+ let mut passed = 0;
+
+ let toml = std::fs::read_to_string(path).expect("read from file");
+ let doc = toml.parse::<Document>().expect("a toml");
+ let autolabel = doc["autolabel"].as_table().expect("a toml table");
+
+ for (label, value) in autolabel.iter() {
+ let Some(trigger_files) = value.get("trigger_files") else {
+ continue
+ };
+ let trigger_files = trigger_files.as_array().expect("an array");
+ let missing_files: Vec<_> = trigger_files
+ .iter()
+ // Hey TOML content is strict UTF-8.
+ .map(|v| v.as_str().unwrap())
+ .filter(|f| {
+ // triagebot checks with `starts_with` only.
+ // See https://github.com/rust-lang/triagebot/blob/0e4b48ca86ffede9cc70fb1611e658e4d013bce2/src/handlers/autolabel.rs#L45
+ let path = ws_root.join(f);
+ if path.exists() {
+ return false;
+ }
+ let Some(mut read_dir) = path.parent().and_then(|p| p.read_dir().ok()) else {
+ return true;
+ };
+ !read_dir.any(|e| {
+ e.unwrap()
+ .path()
+ .strip_prefix(&ws_root)
+ .unwrap()
+ .to_str()
+ .unwrap()
+ .starts_with(f)
+ })
+ })
+ .collect();
+
+ failed += missing_files.len();
+ passed += trigger_files.len() - missing_files.len();
+
+ if missing_files.is_empty() {
+ continue;
+ }
+
+ let mut msg = String::new();
+ writeln!(
+ &mut msg,
+ "missing files defined in `autolabel.{label}.trigger_files`:"
+ )
+ .unwrap();
+ for f in missing_files.iter() {
+ writeln!(&mut msg, "\t {f}").unwrap();
+ }
+ eprintln!("{msg}");
+ }
+
+ let result = if failed == 0 { "ok" } else { "FAILED" };
+ eprintln!("test result: {result}. {passed} passed; {failed} failed;");
+
+ if failed > 0 {
+ process::exit(1);
+ }
+}
diff --git a/src/tools/cargo/crates/xtask-unpublished/Cargo.toml b/src/tools/cargo/crates/xtask-unpublished/Cargo.toml
new file mode 100644
index 000000000..541a34dea
--- /dev/null
+++ b/src/tools/cargo/crates/xtask-unpublished/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "xtask-unpublished"
+version = "0.0.0"
+edition = "2021"
+publish = false
+
+[dependencies]
+anyhow.workspace = true
+cargo.workspace = true
+clap.workspace = true
+env_logger.workspace = true
+log.workspace = true
diff --git a/src/tools/cargo/crates/xtask-unpublished/src/main.rs b/src/tools/cargo/crates/xtask-unpublished/src/main.rs
new file mode 100644
index 000000000..1942a3621
--- /dev/null
+++ b/src/tools/cargo/crates/xtask-unpublished/src/main.rs
@@ -0,0 +1,15 @@
+mod xtask;
+
+fn main() {
+ env_logger::init_from_env("CARGO_LOG");
+ let cli = xtask::cli();
+ let matches = cli.get_matches();
+
+ let mut config = cargo::util::config::Config::default().unwrap_or_else(|e| {
+ let mut eval = cargo::core::shell::Shell::new();
+ cargo::exit_with_error(e.into(), &mut eval)
+ });
+ if let Err(e) = xtask::exec(&matches, &mut config) {
+ cargo::exit_with_error(e, &mut config.shell())
+ }
+}
diff --git a/src/tools/cargo/crates/xtask-unpublished/src/xtask.rs b/src/tools/cargo/crates/xtask-unpublished/src/xtask.rs
new file mode 100644
index 000000000..f1086951f
--- /dev/null
+++ b/src/tools/cargo/crates/xtask-unpublished/src/xtask.rs
@@ -0,0 +1,200 @@
+//! `xtask-unpublished` outputs a table with publish status --- a local version
+//! and a version on crates.io for comparisons.
+//!
+//! This aims to help developers check if there is any crate required a new
+//! publish, as well as detect if a version bump is needed in CI pipeline.
+
+use std::collections::HashSet;
+
+use cargo::core::registry::PackageRegistry;
+use cargo::core::QueryKind;
+use cargo::core::Registry;
+use cargo::core::SourceId;
+use cargo::ops::Packages;
+use cargo::util::command_prelude::*;
+
+pub fn cli() -> clap::Command {
+ clap::Command::new("xtask-unpublished")
+ .arg_package_spec_simple("Package to inspect the published status")
+ .arg(
+ opt(
+ "verbose",
+ "Use verbose output (-vv very verbose/build.rs output)",
+ )
+ .short('v')
+ .action(ArgAction::Count)
+ .global(true),
+ )
+ .arg_quiet()
+ .arg(
+ opt("color", "Coloring: auto, always, never")
+ .value_name("WHEN")
+ .global(true),
+ )
+ .arg(flag("frozen", "Require Cargo.lock and cache are up to date").global(true))
+ .arg(flag("locked", "Require Cargo.lock is up to date").global(true))
+ .arg(flag("offline", "Run without accessing the network").global(true))
+ .arg(multi_opt("config", "KEY=VALUE", "Override a configuration value").global(true))
+ .arg(
+ Arg::new("unstable-features")
+ .help("Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details")
+ .short('Z')
+ .value_name("FLAG")
+ .action(ArgAction::Append)
+ .global(true),
+ )
+}
+
+pub fn exec(args: &clap::ArgMatches, config: &mut cargo::util::Config) -> cargo::CliResult {
+ config_configure(config, args)?;
+
+ unpublished(args, config)?;
+
+ Ok(())
+}
+
+fn config_configure(config: &mut Config, args: &ArgMatches) -> CliResult {
+ let verbose = args.verbose();
+ // quiet is unusual because it is redefined in some subcommands in order
+ // to provide custom help text.
+ let quiet = args.flag("quiet");
+ let color = args.get_one::<String>("color").map(String::as_str);
+ let frozen = args.flag("frozen");
+ let locked = args.flag("locked");
+ let offline = args.flag("offline");
+ let mut unstable_flags = vec![];
+ if let Some(values) = args.get_many::<String>("unstable-features") {
+ unstable_flags.extend(values.cloned());
+ }
+ let mut config_args = vec![];
+ if let Some(values) = args.get_many::<String>("config") {
+ config_args.extend(values.cloned());
+ }
+ config.configure(
+ verbose,
+ quiet,
+ color,
+ frozen,
+ locked,
+ offline,
+ &None,
+ &unstable_flags,
+ &config_args,
+ )?;
+ Ok(())
+}
+
+fn unpublished(args: &clap::ArgMatches, config: &mut cargo::util::Config) -> cargo::CliResult {
+ let ws = args.workspace(config)?;
+
+ let members_to_inspect: HashSet<_> = {
+ let pkgs = args.packages_from_flags()?;
+ if let Packages::Packages(_) = pkgs {
+ HashSet::from_iter(pkgs.get_packages(&ws)?)
+ } else {
+ HashSet::from_iter(ws.members())
+ }
+ };
+
+ let mut results = Vec::new();
+ {
+ let mut registry = PackageRegistry::new(config)?;
+ let _lock = config.acquire_package_cache_lock()?;
+ registry.lock_patches();
+ let source_id = SourceId::crates_io(config)?;
+
+ for member in members_to_inspect {
+ let name = member.name();
+ let current = member.version();
+ if member.publish() == &Some(vec![]) {
+ log::trace!("skipping {name}, `publish = false`");
+ continue;
+ }
+
+ let version_req = format!("<={current}");
+ let query =
+ cargo::core::dependency::Dependency::parse(name, Some(&version_req), source_id)?;
+ let possibilities = loop {
+ // Exact to avoid returning all for path/git
+ match registry.query_vec(&query, QueryKind::Exact) {
+ std::task::Poll::Ready(res) => {
+ break res?;
+ }
+ std::task::Poll::Pending => registry.block_until_ready()?,
+ }
+ };
+ let (last, published) = possibilities
+ .iter()
+ .map(|s| s.version())
+ .max()
+ .map(|last| (last.to_string(), last == current))
+ .unwrap_or(("-".to_string(), false));
+
+ results.push(vec![
+ name.to_string(),
+ last,
+ current.to_string(),
+ if published { "yes" } else { "no" }.to_string(),
+ ]);
+ }
+ }
+ results.sort();
+
+ if results.is_empty() {
+ return Ok(());
+ }
+
+ results.insert(
+ 0,
+ vec![
+ "name".to_owned(),
+ "crates.io".to_owned(),
+ "local".to_owned(),
+ "published?".to_owned(),
+ ],
+ );
+
+ output_table(results);
+
+ Ok(())
+}
+
+/// Outputs a markdown table like this.
+///
+/// ```text
+/// | name | crates.io | local | published? |
+/// |------------------|-----------|--------|------------|
+/// | cargo | 0.70.1 | 0.72.0 | no |
+/// | cargo-platform | 0.1.2 | 0.1.2 | yes |
+/// | cargo-util | - | 0.2.4 | no |
+/// | crates-io | 0.36.0 | 0.36.0 | yes |
+/// | home | - | 0.5.6 | no |
+/// ```
+fn output_table(table: Vec<Vec<String>>) {
+ let header = table.first().unwrap();
+ let paddings = table.iter().fold(vec![0; header.len()], |mut widths, row| {
+ for (width, field) in widths.iter_mut().zip(row) {
+ *width = usize::max(*width, field.len());
+ }
+ widths
+ });
+
+ let print = |row: &[_]| {
+ for (field, pad) in row.iter().zip(&paddings) {
+ print!("| {field:pad$} ");
+ }
+ println!("|");
+ };
+
+ print(header);
+
+ paddings.iter().for_each(|fill| print!("|-{:-<fill$}-", ""));
+ println!("|");
+
+ table.iter().skip(1).for_each(|r| print(r));
+}
+
+#[test]
+fn verify_cli() {
+ cli().debug_assert();
+}