Skip to content

Commit

Permalink
Merge pull request #1030 from foresterre/event_detected_cargo_workspa…
Browse files Browse the repository at this point in the history
…ce_packages
  • Loading branch information
foresterre authored Oct 19, 2024
2 parents 5c396b5 + ac2ce77 commit e45483b
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 16 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ the [discussions section](https://github.com/foresterre/cargo-msrv/discussions).

## Unreleased

### Added

* Added `--workspace`, `--all`, `--package` and `--exclude` CLI options for package selection when in a Cargo project (
with limited workspace support for now)

## [0.16.2] - 2024-10-10

### Fixed
Expand Down
5 changes: 4 additions & 1 deletion src/cli/shared_opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use std::path::PathBuf;
#[derive(Debug, Args)]
#[command(group(ArgGroup::new("paths").args(&["path", "manifest_path"])))]
pub struct SharedOpts {
/// Path to cargo project directory
/// Path to project root directory
///
/// This should be used over `--manifest-path` if not in a Cargo project.
/// If you have a Cargo project, prefer `--manifest-path`.
#[arg(long, value_name = "Crate Directory", global = true, value_hint = ValueHint::DirPath)]
pub path: Option<PathBuf>,

Expand Down
82 changes: 73 additions & 9 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use crate::cli::rust_releases_opts::Edition;
use crate::cli::{CargoMsrvOpts, SubCommand};
use crate::default_target::default_target;
use crate::log_level::LogLevel;
use crate::reporter::event::SelectedPackage;
pub use find::FindContext;
pub use list::ListContext;
pub use set::SetContext;
Expand Down Expand Up @@ -74,6 +75,16 @@ impl Context {
}
}

pub fn environment_context(&self) -> &EnvironmentContext {
match self {
Context::Find(ctx) => &ctx.environment,
Context::List(ctx) => &ctx.environment,
Context::Set(ctx) => &ctx.environment,
Context::Show(ctx) => &ctx.environment,
Context::Verify(ctx) => &ctx.environment,
}
}

/// Returns the inner find context, if it was present.
pub fn to_find_context(self) -> Option<FindContext> {
if let Self::Find(ctx) = self {
Expand Down Expand Up @@ -235,6 +246,8 @@ impl From<CustomCheckOpts> for CheckCommandContext {

#[derive(Clone, Debug)]
pub struct EnvironmentContext {
// TODO: Some parts assume a Cargo crate, but that's not strictly a requirement
// of cargo-msrv (only rustup is). We should fix this.
/// The path to the root of a crate.
///
/// Does not include a manifest file like Cargo.toml, so it's easy to append
Expand Down Expand Up @@ -278,13 +291,36 @@ impl<'shared_opts> TryFrom<&'shared_opts SharedOpts> for EnvironmentContext {
CargoMSRVError::Path(PathError::InvalidUtf8(InvalidUtf8Error::from(err)))
})?;

let metadata = cargo_metadata::MetadataCommand::new()
// Only select packages if this is a Cargo project.
// For now, to be pragmatic, we'll take a shortcut and say that it is so,
// if the cargo metadata command succeeds. If it doesn't, we'll fall
// back to just the default package.
let workspace_packages = if let Ok(metadata) = cargo_metadata::MetadataCommand::new()
.manifest_path(root_crate_path.join("Cargo.toml"))
.exec()?;
let workspace = opts.workspace.partition_packages(&metadata);
let workspace_packages = WorkspacePackages::from_iter(workspace.0.into_iter().cloned());
.exec()
{
let partition = opts.workspace.partition_packages(&metadata);
let selected = partition.0.into_iter().cloned().collect();
let excluded = partition.1;

info!(
action = "detect_cargo_workspace_packages",
method = "cargo_metadata",
success = true,
?selected,
?excluded
);

WorkspacePackages::from_vec(selected)
} else {
info!(
action = "detect_cargo_workspace_packages",
method = "cargo_metadata",
success = false,
);

info!(?workspace_packages, workspace_packages_excluded = ?workspace.1);
WorkspacePackages::default()
};

Ok(Self {
root_crate_path,
Expand Down Expand Up @@ -312,17 +348,45 @@ impl EnvironmentContext {

// ---

#[derive(Clone, Debug)]
#[derive(Clone, Debug, Default)]
pub struct WorkspacePackages {
_selected: Vec<cargo_metadata::Package>,
selected: Option<Vec<cargo_metadata::Package>>,
}

impl WorkspacePackages {
pub fn from_iter(selected: impl IntoIterator<Item = cargo_metadata::Package>) -> Self {
pub fn from_vec(selected: Vec<cargo_metadata::Package>) -> Self {
Self {
_selected: selected.into_iter().collect(),
selected: Some(selected),
}
}

pub fn selected(&self) -> Option<Vec<SelectedPackage>> {
self.selected.as_deref().map(|pks| {
pks.iter()
.map(|pkg| SelectedPackage {
name: pkg.name.to_string(),
path: pkg.manifest_path.to_path_buf(),
})
.collect()
})
}

/// The default package is used when either:
/// 1. No packages were selected (e.g. because we are not in a cargo workspace or do not use cargo)
/// 2. No workspace flags like --workspace, --package, --all or --exclude are used
///
/// See [clap_cargo::Workspace](https://docs.rs/clap-cargo/latest/clap_cargo/struct.Workspace.html) which is
/// currently used for the selection.
pub fn use_default_package(&self) -> bool {
self.selected_packages().is_empty()
}

/// The slice of selected packages.
/// If empty, either no workspace selection flag was used, or cargo_metadata failed,
/// for example because it wasn't a cargo workspace.
pub fn selected_packages(&self) -> &[cargo_metadata::Package] {
self.selected.as_deref().unwrap_or_default()
}
}

#[derive(Clone, Copy, Debug, Default, PartialEq, ValueEnum)]
Expand Down
2 changes: 1 addition & 1 deletion src/context/show.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ impl TryFrom<CargoMsrvOpts> for ShowContext {
let CargoMsrvOpts { shared_opts, .. } = opts;

Ok(Self {
environment: (&shared_opts).try_into().unwrap(), // todo!
environment: (&shared_opts).try_into()?,
})
}
}
5 changes: 4 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub use crate::sub_command::{Find, List, Set, Show, SubCommand, Verify};
use crate::check::RustupToolchainCheck;
use crate::context::ReleaseSource;
use crate::error::{CargoMSRVError, TResult};
use crate::reporter::event::{Meta, SubcommandInit};
use crate::reporter::event::{Meta, SelectedPackages, SubcommandInit};
use crate::reporter::{Event, Reporter};
use rust_releases::semver;

Expand Down Expand Up @@ -60,6 +60,9 @@ pub(crate) mod writer;

pub fn run_app(ctx: &Context, reporter: &impl Reporter) -> TResult<()> {
reporter.report_event(Meta::default())?;
reporter.report_event(SelectedPackages::new(
ctx.environment_context().workspace_packages.selected(),
))?;
reporter.report_event(SubcommandInit::new(ctx.reporting_name()))?;

match ctx {
Expand Down
5 changes: 5 additions & 0 deletions src/reporter/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub use fetch_index::FetchIndex;
pub use meta::Meta;
pub use progress::Progress;
pub use search_method::FindMsrv;
pub use selected_packages::{SelectedPackage, SelectedPackages};
pub use setup_toolchain::SetupToolchain;
pub use subcommand_init::SubcommandInit;
pub use subcommand_result::SubcommandResult;
Expand Down Expand Up @@ -48,6 +49,7 @@ mod fetch_index;
mod meta;
mod progress;
mod search_method;
mod selected_packages;
mod setup_toolchain;
mod subcommand_init;
mod subcommand_result;
Expand Down Expand Up @@ -123,6 +125,9 @@ pub enum Message {
// setup
Meta(Meta),

// package selection
SelectedPackages(SelectedPackages),

// get rust-releases index
FetchIndex(FetchIndex), // todo!
UnableToConfirmValidReleaseVersion(UnableToConfirmValidReleaseVersion),
Expand Down
28 changes: 28 additions & 0 deletions src/reporter/event/selected_packages.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use crate::reporter::{Event, Message};
use camino::Utf8PathBuf;

/// Workspace packages selected
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub struct SelectedPackages {
package_names: Option<Vec<SelectedPackage>>,
}

impl SelectedPackages {
pub fn new(package_names: Option<Vec<SelectedPackage>>) -> Self {
Self { package_names }
}
}

impl From<SelectedPackages> for Event {
fn from(it: SelectedPackages) -> Self {
Message::SelectedPackages(it).into()
}
}

#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub struct SelectedPackage {
pub name: String,
pub path: Utf8PathBuf,
}
2 changes: 1 addition & 1 deletion src/sub_command/find/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ fn create_test_context() -> FindContext {
},
environment: EnvironmentContext {
root_crate_path: Utf8PathBuf::new(),
workspace_packages: WorkspacePackages::from_iter([]),
workspace_packages: WorkspacePackages::default(),
},
}
}
6 changes: 3 additions & 3 deletions src/writer/write_msrv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ mod tests {

let env = EnvironmentContext {
root_crate_path: root.to_path_buf(),
workspace_packages: WorkspacePackages::from_iter([]),
workspace_packages: WorkspacePackages::default(),
};

let index = ReleaseIndex::from_iter(vec![rust_releases::Release::new_stable(
Expand Down Expand Up @@ -87,7 +87,7 @@ mod tests {

let env = EnvironmentContext {
root_crate_path: root.to_path_buf(),
workspace_packages: WorkspacePackages::from_iter([]),
workspace_packages: WorkspacePackages::default(),
};

let index = ReleaseIndex::from_iter(vec![]);
Expand Down Expand Up @@ -119,7 +119,7 @@ mod tests {

let env = EnvironmentContext {
root_crate_path: root.to_path_buf(),
workspace_packages: WorkspacePackages::from_iter([]),
workspace_packages: WorkspacePackages::default(),
};

write_msrv(
Expand Down
3 changes: 3 additions & 0 deletions tests/fixtures/rustc/hello.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
dbg!("Hello world!");
}

0 comments on commit e45483b

Please sign in to comment.