Skip to content

Commit 30e6d55

Browse files
rami3lr7kamura
andcommitted
feat(cli/rustup-mode): add rustup ci subcommand
Co-authored-by: r7kamura <r7kamura@gmail.com>
1 parent 54cbe77 commit 30e6d55

6 files changed

Lines changed: 174 additions & 1 deletion

File tree

src/cli.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/// The CLI specific code lives in the cli module and sub-modules.
22
#[macro_use]
33
pub mod log;
4+
mod ci;
45
pub mod common;
56
mod docs;
67
pub mod errors;

src/cli/ci.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use std::{fmt, io::Write};
2+
3+
use anyhow::Result;
4+
use clap::{ValueEnum, builder::PossibleValue};
5+
6+
use crate::{config::Cfg, utils::ExitCode};
7+
8+
pub(crate) fn problem_matcher(flavor: Flavor, cfg: &Cfg<'_>) -> Result<ExitCode> {
9+
print_str(flavor.problem_matcher(), cfg)
10+
}
11+
12+
fn print_str(s: &str, cfg: &Cfg<'_>) -> Result<ExitCode> {
13+
let stdout = cfg.process.stdout();
14+
write!(stdout.lock(), "{s}")?;
15+
Ok(ExitCode::SUCCESS)
16+
}
17+
18+
#[derive(Copy, Clone, Debug, PartialEq)]
19+
pub(crate) enum Flavor {
20+
Github,
21+
}
22+
23+
impl Flavor {
24+
fn problem_matcher(&self) -> &'static str {
25+
match self {
26+
Self::Github => include_str!("ci/matcher/github.json"),
27+
}
28+
}
29+
}
30+
31+
impl ValueEnum for Flavor {
32+
fn value_variants<'a>() -> &'a [Self] {
33+
&[Self::Github]
34+
}
35+
36+
fn to_possible_value<'a>(&self) -> Option<PossibleValue> {
37+
Some(match self {
38+
Self::Github => PossibleValue::new("github"),
39+
})
40+
}
41+
}
42+
43+
impl fmt::Display for Flavor {
44+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45+
match self.to_possible_value() {
46+
Some(v) => write!(f, "{}", v.get_name()),
47+
None => unreachable!(),
48+
}
49+
}
50+
}

src/cli/ci/matcher/github.json

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"problemMatcher": [
3+
{
4+
"owner": "rust-compiler",
5+
"pattern": [
6+
{
7+
"regexp": "^(?:\\x1B\\[[0-9;]*[a-zA-Z])*(warning|warn|error)(\\[(\\S*)\\])?(?:\\x1B\\[[0-9;]*[a-zA-Z])*: (.*?)(?:\\x1B\\[[0-9;]*[a-zA-Z])*$",
8+
"severity": 1,
9+
"message": 4,
10+
"code": 3
11+
},
12+
{
13+
"regexp": "^(?:\\x1B\\[[0-9;]*[a-zA-Z])*\\s+(?:\\x1B\\[[0-9;]*[a-zA-Z])*-->\\s(?:\\x1B\\[[0-9;]*[a-zA-Z])*(\\S+):(\\d+):(\\d+)(?:\\x1B\\[[0-9;]*[a-zA-Z])*$",
14+
"file": 1,
15+
"line": 2,
16+
"column": 3
17+
}
18+
]
19+
},
20+
{
21+
"owner": "rust-formatter",
22+
"pattern": [
23+
{
24+
"regexp": "^(Diff in (\\S+)) at line (\\d+):",
25+
"message": 1,
26+
"file": 2,
27+
"line": 3
28+
}
29+
]
30+
},
31+
{
32+
"owner": "rust-panic",
33+
"pattern": [
34+
{
35+
"regexp": "^.*panicked\\s+at\\s+'(.*)',\\s+(.*):(\\d+):(\\d+)$",
36+
"message": 1,
37+
"file": 2,
38+
"line": 3,
39+
"column": 4
40+
}
41+
]
42+
}
43+
]
44+
}

src/cli/rustup_mode.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use tracing_subscriber::{EnvFilter, Registry, reload::Handle};
3232

3333
use crate::{
3434
cli::{
35+
ci,
3536
common::{self, PackageUpdate, update_console_filter},
3637
docs,
3738
errors::CliError,
@@ -304,6 +305,13 @@ enum RustupSubcmd {
304305
#[arg(default_value = "rustup")]
305306
command: CompletionCommand,
306307
},
308+
309+
/// Generate CI-specific configurations
310+
#[command(hide = true)]
311+
Ci {
312+
#[command(subcommand)]
313+
subcmd: CiSubcmd,
314+
},
307315
}
308316

309317
fn update_toolchain_value_parser(s: &str) -> Result<PartialToolchainDesc> {
@@ -326,6 +334,7 @@ impl RustupSubcmd {
326334
// These subcommands don't require the active toolchain, so auto-installing it should be
327335
// disabled to avoid surprises.
328336
Self::Check { .. }
337+
| Self::Ci { .. }
329338
| Self::Completions { .. }
330339
| Self::Component { .. }
331340
| Self::Default { .. }
@@ -347,7 +356,10 @@ impl RustupSubcmd {
347356
fn should_warn_empty_setup(&self) -> bool {
348357
match self {
349358
// These subcommands are not about toolchains, so the hint would be noise.
350-
Self::Completions { .. } | Self::DumpTestament | Self::Self_ { .. } => false,
359+
Self::Ci { .. }
360+
| Self::Completions { .. }
361+
| Self::DumpTestament
362+
| Self::Self_ { .. } => false,
351363

352364
// For all other subcommands, the hint may be useful if rustup is still unusable after
353365
// the command has completed.
@@ -674,6 +686,17 @@ enum SetSubcmd {
674686
},
675687
}
676688

689+
#[derive(Debug, Subcommand)]
690+
#[command(arg_required_else_help = true, subcommand_required = true)]
691+
enum CiSubcmd {
692+
/// Show the example problem matcher for the given CI flavor
693+
#[command(alias = "matcher")]
694+
ProblemMatcher {
695+
#[arg(value_enum)]
696+
flavor: ci::Flavor,
697+
},
698+
}
699+
677700
#[tracing::instrument(level = "trace", fields(args = format!("{:?}", process.args_os().collect::<Vec<_>>())), skip(process, console_filter))]
678701
pub async fn main(
679702
current_dir: PathBuf,
@@ -869,6 +892,9 @@ pub async fn main(
869892
RustupSubcmd::Completions { shell, command } => {
870893
output_completion_script(shell, command, process)
871894
}
895+
RustupSubcmd::Ci { subcmd } => match subcmd {
896+
CiSubcmd::ProblemMatcher { flavor } => ci::problem_matcher(flavor, cfg),
897+
},
872898
}?;
873899

874900
if should_warn && cfg.list_toolchains()?.is_empty() && cfg.get_default()?.is_none() {

tests/suite/cli_rustup_ui.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,11 @@ fn rustup_upgrade_cmd_help_flag() {
535535
test_help("rustup_upgrade_cmd_help_flag", &["upgrade", "--help"]);
536536
}
537537

538+
#[test]
539+
fn rustup_ci_cmd_help_flag() {
540+
test_help("rustup_ci_cmd_help_flag", &["ci", "--help"]);
541+
}
542+
538543
#[test]
539544
fn rustup_which_cmd_help_flag() {
540545
test_help("rustup_which_cmd_help_flag", &["which", "--help"]);
Lines changed: 47 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)