Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cargo msrv doctor #1055

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ pub struct CargoMsrvOpts {
#[derive(Debug, Subcommand)]
#[command(propagate_version = true)]
pub enum SubCommand {
/// Find & fix MSRV related issues
Doctor(DoctorOpts),
/// Find the MSRV
Find(FindOpts),
/// Display the MSRV's of dependencies
Expand All @@ -118,6 +120,14 @@ pub enum SubCommand {
Verify(VerifyOpts),
}

#[derive(Debug, Args)]
#[command(next_help_heading = "Doctor options")]
pub struct DoctorOpts {
/// Try to fix the reported issues
#[arg(long)]
pub fix: bool,
}

// Cli Options for top-level cargo-msrv (find) command
#[derive(Debug, Args)]
#[command(next_help_heading = "Find MSRV options")]
Expand Down
34 changes: 34 additions & 0 deletions src/context/doctor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use crate::cli::{CargoMsrvOpts, SubCommand};
use crate::context::EnvironmentContext;
use crate::error::CargoMSRVError;

#[derive(Debug)]
pub struct DoctorContext {
/// Try and fix the issues found!
pub fix: bool,

/// Resolved environment options
pub environment: EnvironmentContext,
}

impl TryFrom<CargoMsrvOpts> for DoctorContext {
type Error = CargoMSRVError;

fn try_from(opts: CargoMsrvOpts) -> Result<Self, Self::Error> {
let CargoMsrvOpts {
shared_opts,
subcommand,
..
} = opts;

let doctor_opts = match subcommand {
SubCommand::Doctor(opts) => opts,
_ => unreachable!("This should never happen. The subcommand is not `doctor`!"),
};

Ok(Self {
fix: doctor_opts.fix,
environment: (&shared_opts).try_into()?,
})
}
}
51 changes: 31 additions & 20 deletions src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,27 @@ use std::path::Path;
use std::str::FromStr;
use std::{env, fmt};

pub mod find;
pub mod list;
pub mod set;
pub mod show;
pub mod verify;

use crate::cli::custom_check_opts::CustomCheckOpts;
use crate::cli::rust_releases_opts::Edition;
use crate::cli::{CargoMsrvOpts, SubCommand};
use crate::log_level::LogLevel;
use crate::reporter::event::SelectedPackage;
use crate::rust::default_target::default_target;

pub use doctor::DoctorContext;
pub use find::FindContext;
pub use list::ListContext;
pub use set::SetContext;
pub use show::ShowContext;
pub use verify::VerifyContext;

pub mod doctor;
pub mod find;
pub mod list;
pub mod set;
pub mod show;
pub mod verify;

/// A `context` in `cargo-msrv`, is a definitive and flattened set of options,
/// required for the program (and its selected sub-command) to function.
///
Expand All @@ -57,6 +60,7 @@ pub use verify::VerifyContext;
/// data.
#[derive(Debug)]
pub enum Context {
Doctor(DoctorContext),
Find(FindContext),
List(ListContext),
Set(SetContext),
Expand All @@ -67,6 +71,7 @@ pub enum Context {
impl Context {
pub fn reporting_name(&self) -> &'static str {
match self {
Context::Doctor(_) => "Doctor",
Context::Find(_) => "find",
Context::List(_) => "list",
Context::Set(_) => "set",
Expand All @@ -77,6 +82,7 @@ impl Context {

pub fn environment_context(&self) -> &EnvironmentContext {
match self {
Context::Doctor(ctx) => &ctx.environment,
Context::Find(ctx) => &ctx.environment,
Context::List(ctx) => &ctx.environment,
Context::Set(ctx) => &ctx.environment,
Expand All @@ -85,22 +91,26 @@ impl Context {
}
}

/// Returns the inner find context, if it was present.
pub fn to_find_context(self) -> Option<FindContext> {
if let Self::Find(ctx) = self {
Some(ctx)
} else {
None
}
/// Returns the inner find context
///
/// **Panics**
///
/// Panics if the context does not match with `Find`
pub fn to_find_context(self) -> FindContext {
let Self::Find(ctx) = self else {
unreachable!("Find Context does not exist")
};

ctx
}

/// Returns the inner find context, if it was present.
pub fn to_verify_context(self) -> Option<VerifyContext> {
if let Self::Verify(ctx) = self {
Some(ctx)
} else {
None
}
/// Returns the inner verify context
pub fn to_verify_context(self) -> VerifyContext {
let Self::Verify(ctx) = self else {
unreachable!("Find Context does not exist")
};

ctx
}
}

Expand All @@ -109,6 +119,7 @@ impl TryFrom<CargoMsrvOpts> for Context {

fn try_from(opts: CargoMsrvOpts) -> Result<Self, Self::Error> {
let ctx = match opts.subcommand {
SubCommand::Doctor(_) => Self::Doctor(DoctorContext::try_from(opts)?),
SubCommand::Find(_) => Self::Find(FindContext::try_from(opts)?),
SubCommand::List(_) => Self::List(ListContext::try_from(opts)?),
SubCommand::Set(_) => Self::Set(SetContext::try_from(opts)?),
Expand Down
5 changes: 4 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ extern crate tracing;

pub use crate::context::{Context, OutputFormat, TracingOptions, TracingTargetOption};
pub use crate::outcome::Compatibility;
pub use crate::sub_command::{Find, List, Set, Show, SubCommand, Verify};
pub use crate::sub_command::{Doctor, Find, List, Set, Show, SubCommand, Verify};

use crate::compatibility::RustupToolchainCheck;
use crate::context::ReleaseSource;
Expand Down Expand Up @@ -61,6 +61,9 @@ pub fn run_app(ctx: &Context, reporter: &impl Reporter) -> TResult<()> {
reporter.report_event(SubcommandInit::new(ctx.reporting_name()))?;

match ctx {
Context::Doctor(ctx) => {
Doctor.run(ctx, reporter)?;
}
Context::Find(ctx) => {
let index = release_index::fetch_index(reporter, ctx.rust_releases.release_source)?;

Expand Down
29 changes: 29 additions & 0 deletions src/sub_command/doctor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use crate::cli::rust_releases_opts::Edition;
use crate::context::DoctorContext;
use crate::error::TResult;
use crate::manifest::bare_version::BareVersion;
use crate::reporter::Reporter;
use crate::sub_command::verify::RustVersion;

Check warning on line 6 in src/sub_command/doctor.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `crate::sub_command::verify::RustVersion`

warning: unused import: `crate::sub_command::verify::RustVersion` --> src/sub_command/doctor.rs:6:5 | 6 | use crate::sub_command::verify::RustVersion; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default

Check warning on line 6 in src/sub_command/doctor.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `crate::sub_command::verify::RustVersion`

warning: unused import: `crate::sub_command::verify::RustVersion` --> src/sub_command/doctor.rs:6:5 | 6 | use crate::sub_command::verify::RustVersion; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default
use crate::SubCommand;

#[derive(Default)]
pub struct Doctor;

impl SubCommand for Doctor {
type Context = DoctorContext;
type Output = ();

fn run(&self, _ctx: &Self::Context, _reporter: &impl Reporter) -> TResult<Self::Output> {
todo!("Implement cargo msrv doctor!")
}
}

struct IssueAnalyzer {

Check warning on line 21 in src/sub_command/doctor.rs

View workflow job for this annotation

GitHub Actions / clippy

struct `IssueAnalyzer` is never constructed

warning: struct `IssueAnalyzer` is never constructed --> src/sub_command/doctor.rs:21:8 | 21 | struct IssueAnalyzer { | ^^^^^^^^^^^^^ | = note: `#[warn(dead_code)]` on by default

Check warning on line 21 in src/sub_command/doctor.rs

View workflow job for this annotation

GitHub Actions / clippy

struct `IssueAnalyzer` is never constructed

warning: struct `IssueAnalyzer` is never constructed --> src/sub_command/doctor.rs:21:8 | 21 | struct IssueAnalyzer { | ^^^^^^^^^^^^^ | = note: `#[warn(dead_code)]` on by default
msrv_cargo_toml: BareVersion,
edition: Edition,
}

struct MsrvSource {

Check warning on line 26 in src/sub_command/doctor.rs

View workflow job for this annotation

GitHub Actions / clippy

struct `MsrvSource` is never constructed

warning: struct `MsrvSource` is never constructed --> src/sub_command/doctor.rs:26:8 | 26 | struct MsrvSource { | ^^^^^^^^^^

Check warning on line 26 in src/sub_command/doctor.rs

View workflow job for this annotation

GitHub Actions / clippy

struct `MsrvSource` is never constructed

warning: struct `MsrvSource` is never constructed --> src/sub_command/doctor.rs:26:8 | 26 | struct MsrvSource { | ^^^^^^^^^^
cargo_toml: Option<BareVersion>,
clippy_toml: Option<BareVersion>,
}
16 changes: 12 additions & 4 deletions src/sub_command/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
use crate::reporter::Reporter;
use crate::TResult;

/// Find MSRV related issues
///
/// # Example (CLI)
///
/// `cargo msrv doctor`
pub use doctor::Doctor;

/// Find the MSRV of a Rust package.
///
/// # Example (CLI)
///
/// `cargo msrv`
/// `cargo msrv find`
pub use find::Find;

/// List the MSRV's of libraries you depend on.
Expand Down Expand Up @@ -38,9 +48,7 @@ pub use set::Set;
/// `cargo msrv show`
pub use show::Show;

use crate::reporter::Reporter;
use crate::TResult;

pub mod doctor;
pub mod find;
pub mod list;
pub mod set;
Expand Down
2 changes: 1 addition & 1 deletion tests/common/sub_cmd_find.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub fn find_msrv_with_releases<
let matches = CargoCli::parse_args(with_args);
let opts = matches.to_cargo_msrv_cli().to_opts();
let ctx = Context::try_from(opts)?;
let find_ctx = ctx.to_find_context().unwrap();
let find_ctx = ctx.to_find_context();

// Limit the available versions: this ensures we don't need to incrementally install more toolchains
// as more Rust toolchains become available.
Expand Down
2 changes: 1 addition & 1 deletion tests/common/sub_cmd_verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ where
let matches = CargoCli::parse_args(with_args);
let opts = matches.to_cargo_msrv_cli().to_opts();
let ctx = Context::try_from(opts)?;
let verify_ctx = ctx.to_verify_context().unwrap();
let verify_ctx = ctx.to_verify_context();

// Limit the available versions: this ensures we don't need to incrementally install more toolchains
// as more Rust toolchains become available.
Expand Down
Loading