mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-24 05:33:27 +00:00
Sync and Release automation (#13694)
Based on https://github.com/rust-lang/rust-clippy/pull/13693 Adds 2 subcommands to `cargo dev`: - `cargo dev sync update_nightly`: Which updates the nightly versions in `rust-toolchain` and `clippy_utils/README.md` - `cargo dev release bump_version`: Bumps the version in all relevant `Cargo.toml` files Those are pulled out of https://github.com/rust-lang/rust-clippy/pull/12759, which I'll rebase on this. Next step is to update the documentation, which I'll partly pull out of https://github.com/rust-lang/rust-clippy/pull/12762 r? @blyxyas (as you reviewed the first PR in the chain and were assigned to the second one) cc https://github.com/rust-lang/rust-clippy/issues/13556 changelog: none
This commit is contained in:
commit
a19d69d273
16 changed files with 263 additions and 154 deletions
|
@ -1,6 +1,8 @@
|
|||
[package]
|
||||
name = "clippy"
|
||||
# begin autogenerated version
|
||||
version = "0.1.84"
|
||||
# end autogenerated version
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
[package]
|
||||
name = "clippy_config"
|
||||
# begin autogenerated version
|
||||
version = "0.1.84"
|
||||
# end autogenerated version
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
aho-corasick = "1.0"
|
||||
chrono = { version = "0.4.38", default-features = false, features = ["clock"] }
|
||||
clap = { version = "4.4", features = ["derive"] }
|
||||
indoc = "1.0"
|
||||
itertools = "0.12"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{clippy_project_root, exit_if_err};
|
||||
use crate::utils::{clippy_project_root, exit_if_err};
|
||||
use std::process::Command;
|
||||
|
||||
/// # Panics
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::clippy_project_root;
|
||||
use crate::utils::clippy_project_root;
|
||||
use itertools::Itertools;
|
||||
use rustc_lexer::{TokenKind, tokenize};
|
||||
use shell_escape::escape;
|
||||
|
|
|
@ -14,69 +14,13 @@
|
|||
extern crate rustc_driver;
|
||||
extern crate rustc_lexer;
|
||||
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{self, ExitStatus};
|
||||
|
||||
pub mod dogfood;
|
||||
pub mod fmt;
|
||||
pub mod lint;
|
||||
pub mod new_lint;
|
||||
pub mod release;
|
||||
pub mod serve;
|
||||
pub mod setup;
|
||||
pub mod sync;
|
||||
pub mod update_lints;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
|
||||
#[cfg(windows)]
|
||||
static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
|
||||
|
||||
/// Returns the path to the `cargo-clippy` binary
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the path of current executable could not be retrieved.
|
||||
#[must_use]
|
||||
pub fn cargo_clippy_path() -> PathBuf {
|
||||
let mut path = std::env::current_exe().expect("failed to get current executable name");
|
||||
path.set_file_name(CARGO_CLIPPY_EXE);
|
||||
path
|
||||
}
|
||||
|
||||
/// Returns the path to the Clippy project directory
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the current directory could not be retrieved, there was an error reading any of the
|
||||
/// Cargo.toml files or ancestor directory is the clippy root directory
|
||||
#[must_use]
|
||||
pub fn clippy_project_root() -> PathBuf {
|
||||
let current_dir = std::env::current_dir().unwrap();
|
||||
for path in current_dir.ancestors() {
|
||||
let result = std::fs::read_to_string(path.join("Cargo.toml"));
|
||||
if let Err(err) = &result {
|
||||
if err.kind() == io::ErrorKind::NotFound {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let content = result.unwrap();
|
||||
if content.contains("[package]\nname = \"clippy\"") {
|
||||
return path.to_path_buf();
|
||||
}
|
||||
}
|
||||
panic!("error: Can't determine root of project. Please run inside a Clippy working dir.");
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
/// Panics if given command result was failed.
|
||||
pub fn exit_if_err(status: io::Result<ExitStatus>) {
|
||||
match status.expect("failed to run command").code() {
|
||||
Some(0) => {},
|
||||
Some(n) => process::exit(n),
|
||||
None => {
|
||||
eprintln!("Killed by signal");
|
||||
process::exit(1);
|
||||
},
|
||||
}
|
||||
}
|
||||
pub mod utils;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{cargo_clippy_path, exit_if_err};
|
||||
use crate::utils::{cargo_clippy_path, exit_if_err};
|
||||
use std::process::{self, Command};
|
||||
use std::{env, fs};
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
use clippy_dev::{dogfood, fmt, lint, new_lint, serve, setup, update_lints};
|
||||
use clippy_dev::{dogfood, fmt, lint, new_lint, release, serve, setup, sync, update_lints, utils};
|
||||
use std::convert::Infallible;
|
||||
|
||||
fn main() {
|
||||
|
@ -23,9 +23,9 @@ fn main() {
|
|||
if print_only {
|
||||
update_lints::print_lints();
|
||||
} else if check {
|
||||
update_lints::update(update_lints::UpdateMode::Check);
|
||||
update_lints::update(utils::UpdateMode::Check);
|
||||
} else {
|
||||
update_lints::update(update_lints::UpdateMode::Change);
|
||||
update_lints::update(utils::UpdateMode::Change);
|
||||
}
|
||||
},
|
||||
DevCommand::NewLint {
|
||||
|
@ -35,7 +35,7 @@ fn main() {
|
|||
r#type,
|
||||
msrv,
|
||||
} => match new_lint::create(&pass, &name, &category, r#type.as_deref(), msrv) {
|
||||
Ok(()) => update_lints::update(update_lints::UpdateMode::Change),
|
||||
Ok(()) => update_lints::update(utils::UpdateMode::Change),
|
||||
Err(e) => eprintln!("Unable to create lint: {e}"),
|
||||
},
|
||||
DevCommand::Setup(SetupCommand { subcommand }) => match subcommand {
|
||||
|
@ -75,6 +75,12 @@ fn main() {
|
|||
uplift,
|
||||
} => update_lints::rename(&old_name, new_name.as_ref().unwrap_or(&old_name), uplift),
|
||||
DevCommand::Deprecate { name, reason } => update_lints::deprecate(&name, &reason),
|
||||
DevCommand::Sync(SyncCommand { subcommand }) => match subcommand {
|
||||
SyncSubcommand::UpdateNightly => sync::update_nightly(),
|
||||
},
|
||||
DevCommand::Release(ReleaseCommand { subcommand }) => match subcommand {
|
||||
ReleaseSubcommand::BumpVersion => release::bump_version(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,6 +231,10 @@ enum DevCommand {
|
|||
/// The reason for deprecation
|
||||
reason: String,
|
||||
},
|
||||
/// Sync between the rust repo and the Clippy repo
|
||||
Sync(SyncCommand),
|
||||
/// Manage Clippy releases
|
||||
Release(ReleaseCommand),
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
|
@ -291,3 +301,29 @@ enum RemoveSubcommand {
|
|||
/// Remove the tasks added with 'cargo dev setup vscode-tasks'
|
||||
VscodeTasks,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct SyncCommand {
|
||||
#[command(subcommand)]
|
||||
subcommand: SyncSubcommand,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum SyncSubcommand {
|
||||
#[command(name = "update_nightly")]
|
||||
/// Update nightly version in rust-toolchain and `clippy_utils`
|
||||
UpdateNightly,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct ReleaseCommand {
|
||||
#[command(subcommand)]
|
||||
subcommand: ReleaseSubcommand,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum ReleaseSubcommand {
|
||||
#[command(name = "bump_version")]
|
||||
/// Bump the version in the Cargo.toml files
|
||||
BumpVersion,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::clippy_project_root;
|
||||
use crate::utils::{clippy_project_root, clippy_version};
|
||||
use indoc::{formatdoc, writedoc};
|
||||
use std::fmt;
|
||||
use std::fmt::Write as _;
|
||||
|
@ -186,23 +186,8 @@ fn to_camel_case(name: &str) -> String {
|
|||
}
|
||||
|
||||
pub(crate) fn get_stabilization_version() -> String {
|
||||
fn parse_manifest(contents: &str) -> Option<String> {
|
||||
let version = contents
|
||||
.lines()
|
||||
.filter_map(|l| l.split_once('='))
|
||||
.find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))?;
|
||||
let Some(("0", version)) = version.get(1..version.len() - 1)?.split_once('.') else {
|
||||
return None;
|
||||
};
|
||||
let (minor, patch) = version.split_once('.')?;
|
||||
Some(format!(
|
||||
"{}.{}.0",
|
||||
minor.parse::<u32>().ok()?,
|
||||
patch.parse::<u32>().ok()?
|
||||
))
|
||||
}
|
||||
let contents = fs::read_to_string("Cargo.toml").expect("Unable to read `Cargo.toml`");
|
||||
parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
|
||||
let (minor, patch) = clippy_version();
|
||||
format!("{minor}.{patch}.0")
|
||||
}
|
||||
|
||||
fn get_test_file_contents(lint_name: &str, msrv: bool) -> String {
|
||||
|
|
27
clippy_dev/src/release.rs
Normal file
27
clippy_dev/src/release.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
use std::fmt::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::utils::{UpdateMode, clippy_version, replace_region_in_file};
|
||||
|
||||
const CARGO_TOML_FILES: [&str; 4] = [
|
||||
"clippy_config/Cargo.toml",
|
||||
"clippy_lints/Cargo.toml",
|
||||
"clippy_utils/Cargo.toml",
|
||||
"Cargo.toml",
|
||||
];
|
||||
|
||||
pub fn bump_version() {
|
||||
let (minor, mut patch) = clippy_version();
|
||||
patch += 1;
|
||||
for file in &CARGO_TOML_FILES {
|
||||
replace_region_in_file(
|
||||
UpdateMode::Change,
|
||||
Path::new(file),
|
||||
"# begin autogenerated version\n",
|
||||
"# end autogenerated version",
|
||||
|res| {
|
||||
writeln!(res, "version = \"0.{minor}.{patch}\"").unwrap();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
33
clippy_dev/src/sync.rs
Normal file
33
clippy_dev/src/sync.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
use std::fmt::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use chrono::offset::Utc;
|
||||
|
||||
use crate::utils::{UpdateMode, replace_region_in_file};
|
||||
|
||||
pub fn update_nightly() {
|
||||
// Update rust-toolchain nightly version
|
||||
let date = Utc::now().format("%Y-%m-%d").to_string();
|
||||
replace_region_in_file(
|
||||
UpdateMode::Change,
|
||||
Path::new("rust-toolchain"),
|
||||
"# begin autogenerated nightly\n",
|
||||
"# end autogenerated nightly",
|
||||
|res| {
|
||||
writeln!(res, "channel = \"nightly-{date}\"").unwrap();
|
||||
},
|
||||
);
|
||||
|
||||
// Update clippy_utils nightly version
|
||||
replace_region_in_file(
|
||||
UpdateMode::Change,
|
||||
Path::new("clippy_utils/README.md"),
|
||||
"<!-- begin autogenerated nightly -->\n",
|
||||
"<!-- end autogenerated nightly -->",
|
||||
|res| {
|
||||
writeln!(res, "```").unwrap();
|
||||
writeln!(res, "nightly-{date}").unwrap();
|
||||
writeln!(res, "```").unwrap();
|
||||
},
|
||||
);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use crate::clippy_project_root;
|
||||
use crate::utils::{UpdateMode, clippy_project_root, exit_with_failure, replace_region_in_file};
|
||||
use aho_corasick::AhoCorasickBuilder;
|
||||
use itertools::Itertools;
|
||||
use rustc_lexer::{LiteralKind, TokenKind, tokenize, unescape};
|
||||
|
@ -17,12 +17,6 @@ const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev u
|
|||
|
||||
const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html";
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum UpdateMode {
|
||||
Check,
|
||||
Change,
|
||||
}
|
||||
|
||||
/// Runs the `update_lints` command.
|
||||
///
|
||||
/// This updates various generated values from the lint source code.
|
||||
|
@ -511,14 +505,6 @@ fn process_file(path: impl AsRef<Path>, update_mode: UpdateMode, content: &str)
|
|||
}
|
||||
}
|
||||
|
||||
fn exit_with_failure() {
|
||||
println!(
|
||||
"Not all lints defined properly. \
|
||||
Please run `cargo dev update_lints` to make sure all lints are defined properly."
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
/// Lint data parsed from the Clippy source code.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
struct Lint {
|
||||
|
@ -851,61 +837,6 @@ fn remove_line_splices(s: &str) -> String {
|
|||
});
|
||||
res
|
||||
}
|
||||
|
||||
/// Replaces a region in a file delimited by two lines matching regexes.
|
||||
///
|
||||
/// `path` is the relative path to the file on which you want to perform the replacement.
|
||||
///
|
||||
/// See `replace_region_in_text` for documentation of the other options.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the path could not read or then written
|
||||
fn replace_region_in_file(
|
||||
update_mode: UpdateMode,
|
||||
path: &Path,
|
||||
start: &str,
|
||||
end: &str,
|
||||
write_replacement: impl FnMut(&mut String),
|
||||
) {
|
||||
let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display()));
|
||||
let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) {
|
||||
Ok(x) => x,
|
||||
Err(delim) => panic!("Couldn't find `{delim}` in file `{}`", path.display()),
|
||||
};
|
||||
|
||||
match update_mode {
|
||||
UpdateMode::Check if contents != new_contents => exit_with_failure(),
|
||||
UpdateMode::Check => (),
|
||||
UpdateMode::Change => {
|
||||
if let Err(e) = fs::write(path, new_contents.as_bytes()) {
|
||||
panic!("Cannot write to `{}`: {e}", path.display());
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters
|
||||
/// were found, or the missing delimiter if not.
|
||||
fn replace_region_in_text<'a>(
|
||||
text: &str,
|
||||
start: &'a str,
|
||||
end: &'a str,
|
||||
mut write_replacement: impl FnMut(&mut String),
|
||||
) -> Result<String, &'a str> {
|
||||
let (text_start, rest) = text.split_once(start).ok_or(start)?;
|
||||
let (_, text_end) = rest.split_once(end).ok_or(end)?;
|
||||
|
||||
let mut res = String::with_capacity(text.len() + 4096);
|
||||
res.push_str(text_start);
|
||||
res.push_str(start);
|
||||
write_replacement(&mut res);
|
||||
res.push_str(end);
|
||||
res.push_str(text_end);
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
|
||||
match OpenOptions::new().create_new(true).write(true).open(new_name) {
|
||||
Ok(file) => drop(file),
|
||||
|
|
142
clippy_dev/src/utils.rs
Normal file
142
clippy_dev/src/utils.rs
Normal file
|
@ -0,0 +1,142 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::process::{self, ExitStatus};
|
||||
use std::{fs, io};
|
||||
|
||||
#[cfg(not(windows))]
|
||||
static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
|
||||
#[cfg(windows)]
|
||||
static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
|
||||
|
||||
/// Returns the path to the `cargo-clippy` binary
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the path of current executable could not be retrieved.
|
||||
#[must_use]
|
||||
pub fn cargo_clippy_path() -> PathBuf {
|
||||
let mut path = std::env::current_exe().expect("failed to get current executable name");
|
||||
path.set_file_name(CARGO_CLIPPY_EXE);
|
||||
path
|
||||
}
|
||||
|
||||
/// Returns the path to the Clippy project directory
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the current directory could not be retrieved, there was an error reading any of the
|
||||
/// Cargo.toml files or ancestor directory is the clippy root directory
|
||||
#[must_use]
|
||||
pub fn clippy_project_root() -> PathBuf {
|
||||
let current_dir = std::env::current_dir().unwrap();
|
||||
for path in current_dir.ancestors() {
|
||||
let result = fs::read_to_string(path.join("Cargo.toml"));
|
||||
if let Err(err) = &result {
|
||||
if err.kind() == io::ErrorKind::NotFound {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let content = result.unwrap();
|
||||
if content.contains("[package]\nname = \"clippy\"") {
|
||||
return path.to_path_buf();
|
||||
}
|
||||
}
|
||||
panic!("error: Can't determine root of project. Please run inside a Clippy working dir.");
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
/// Panics if given command result was failed.
|
||||
pub fn exit_if_err(status: io::Result<ExitStatus>) {
|
||||
match status.expect("failed to run command").code() {
|
||||
Some(0) => {},
|
||||
Some(n) => process::exit(n),
|
||||
None => {
|
||||
eprintln!("Killed by signal");
|
||||
process::exit(1);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn clippy_version() -> (u32, u32) {
|
||||
fn parse_manifest(contents: &str) -> Option<(u32, u32)> {
|
||||
let version = contents
|
||||
.lines()
|
||||
.filter_map(|l| l.split_once('='))
|
||||
.find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))?;
|
||||
let Some(("0", version)) = version.get(1..version.len() - 1)?.split_once('.') else {
|
||||
return None;
|
||||
};
|
||||
let (minor, patch) = version.split_once('.')?;
|
||||
Some((minor.parse().ok()?, patch.parse().ok()?))
|
||||
}
|
||||
let contents = fs::read_to_string("Cargo.toml").expect("Unable to read `Cargo.toml`");
|
||||
parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum UpdateMode {
|
||||
Check,
|
||||
Change,
|
||||
}
|
||||
|
||||
pub(crate) fn exit_with_failure() {
|
||||
println!(
|
||||
"Not all lints defined properly. \
|
||||
Please run `cargo dev update_lints` to make sure all lints are defined properly."
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
/// Replaces a region in a file delimited by two lines matching regexes.
|
||||
///
|
||||
/// `path` is the relative path to the file on which you want to perform the replacement.
|
||||
///
|
||||
/// See `replace_region_in_text` for documentation of the other options.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the path could not read or then written
|
||||
pub(crate) fn replace_region_in_file(
|
||||
update_mode: UpdateMode,
|
||||
path: &Path,
|
||||
start: &str,
|
||||
end: &str,
|
||||
write_replacement: impl FnMut(&mut String),
|
||||
) {
|
||||
let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display()));
|
||||
let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) {
|
||||
Ok(x) => x,
|
||||
Err(delim) => panic!("Couldn't find `{delim}` in file `{}`", path.display()),
|
||||
};
|
||||
|
||||
match update_mode {
|
||||
UpdateMode::Check if contents != new_contents => exit_with_failure(),
|
||||
UpdateMode::Check => (),
|
||||
UpdateMode::Change => {
|
||||
if let Err(e) = fs::write(path, new_contents.as_bytes()) {
|
||||
panic!("Cannot write to `{}`: {e}", path.display());
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters
|
||||
/// were found, or the missing delimiter if not.
|
||||
pub(crate) fn replace_region_in_text<'a>(
|
||||
text: &str,
|
||||
start: &'a str,
|
||||
end: &'a str,
|
||||
mut write_replacement: impl FnMut(&mut String),
|
||||
) -> Result<String, &'a str> {
|
||||
let (text_start, rest) = text.split_once(start).ok_or(start)?;
|
||||
let (_, text_end) = rest.split_once(end).ok_or(end)?;
|
||||
|
||||
let mut res = String::with_capacity(text.len() + 4096);
|
||||
res.push_str(text_start);
|
||||
res.push_str(start);
|
||||
write_replacement(&mut res);
|
||||
res.push_str(end);
|
||||
res.push_str(text_end);
|
||||
|
||||
Ok(res)
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
[package]
|
||||
name = "clippy_lints"
|
||||
# begin autogenerated version
|
||||
version = "0.1.84"
|
||||
# end autogenerated version
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
[package]
|
||||
name = "clippy_utils"
|
||||
# begin autogenerated version
|
||||
version = "0.1.84"
|
||||
# end autogenerated version
|
||||
edition = "2021"
|
||||
description = "Helpful tools for writing lints, provided as they are used in Clippy"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
[toolchain]
|
||||
# begin autogenerated nightly
|
||||
channel = "nightly-2024-11-14"
|
||||
# end autogenerated nightly
|
||||
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
|
||||
profile = "minimal"
|
||||
|
|
Loading…
Reference in a new issue