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

Sync and Release automation #13694

Merged
merged 3 commits into from
Nov 19, 2024
Merged
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
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
2 changes: 2 additions & 0 deletions clippy_config/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
[package]
name = "clippy_config"
# begin autogenerated version
version = "0.1.84"
# end autogenerated version
edition = "2021"
publish = false

Expand Down
1 change: 1 addition & 0 deletions clippy_dev/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion clippy_dev/src/dogfood.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion clippy_dev/src/fmt.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
62 changes: 3 additions & 59 deletions clippy_dev/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
2 changes: 1 addition & 1 deletion clippy_dev/src/lint.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down
44 changes: 40 additions & 4 deletions clippy_dev/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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(),
},
}
}

Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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,
}
Comment on lines +305 to +329
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for these two to be subcommands in their own structs? Is there a plan to add new commands to them?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, see #12759

21 changes: 3 additions & 18 deletions clippy_dev/src/new_lint.rs
Original file line number Diff line number Diff line change
@@ -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 _;
Expand Down Expand Up @@ -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 {
Expand Down
27 changes: 27 additions & 0 deletions clippy_dev/src/release.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 33 additions & 0 deletions clippy_dev/src/sync.rs
Original file line number Diff line number Diff line change
@@ -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(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to modify rust-toolchain, as it doesn't contain the comment.

Copy link
Member Author

@flip1995 flip1995 Nov 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh good catch. That must've been lost during a rebase. Added those in the second commit. Nothing else changed in the force push.

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();
},
);
}
71 changes: 1 addition & 70 deletions clippy_dev/src/update_lints.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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.
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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),
Expand Down
Loading