Skip to content

Commit c03857e

Browse files
committed
Introduce utils mod in clippy_dev
There was some dependence between the different subcommands of clippy_dev. And this dependence will increased with the introduction of the sync and release subcommands. This moves the common functions to a `utils` module, to decouple the other modules.
1 parent 537ab6c commit c03857e

File tree

8 files changed

+154
-154
lines changed

8 files changed

+154
-154
lines changed

clippy_dev/src/dogfood.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{clippy_project_root, exit_if_err};
1+
use crate::utils::{clippy_project_root, exit_if_err};
22
use std::process::Command;
33

44
/// # Panics

clippy_dev/src/fmt.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::clippy_project_root;
1+
use crate::utils::clippy_project_root;
22
use itertools::Itertools;
33
use shell_escape::escape;
44
use std::ffi::{OsStr, OsString};

clippy_dev/src/lib.rs

+1-59
Original file line numberDiff line numberDiff line change
@@ -16,69 +16,11 @@
1616
extern crate rustc_driver;
1717
extern crate rustc_lexer;
1818

19-
use std::io;
20-
use std::path::PathBuf;
21-
use std::process::{self, ExitStatus};
22-
2319
pub mod dogfood;
2420
pub mod fmt;
2521
pub mod lint;
2622
pub mod new_lint;
2723
pub mod serve;
2824
pub mod setup;
2925
pub mod update_lints;
30-
31-
#[cfg(not(windows))]
32-
static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
33-
#[cfg(windows)]
34-
static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
35-
36-
/// Returns the path to the `cargo-clippy` binary
37-
///
38-
/// # Panics
39-
///
40-
/// Panics if the path of current executable could not be retrieved.
41-
#[must_use]
42-
pub fn cargo_clippy_path() -> PathBuf {
43-
let mut path = std::env::current_exe().expect("failed to get current executable name");
44-
path.set_file_name(CARGO_CLIPPY_EXE);
45-
path
46-
}
47-
48-
/// Returns the path to the Clippy project directory
49-
///
50-
/// # Panics
51-
///
52-
/// Panics if the current directory could not be retrieved, there was an error reading any of the
53-
/// Cargo.toml files or ancestor directory is the clippy root directory
54-
#[must_use]
55-
pub fn clippy_project_root() -> PathBuf {
56-
let current_dir = std::env::current_dir().unwrap();
57-
for path in current_dir.ancestors() {
58-
let result = std::fs::read_to_string(path.join("Cargo.toml"));
59-
if let Err(err) = &result {
60-
if err.kind() == io::ErrorKind::NotFound {
61-
continue;
62-
}
63-
}
64-
65-
let content = result.unwrap();
66-
if content.contains("[package]\nname = \"clippy\"") {
67-
return path.to_path_buf();
68-
}
69-
}
70-
panic!("error: Can't determine root of project. Please run inside a Clippy working dir.");
71-
}
72-
73-
/// # Panics
74-
/// Panics if given command result was failed.
75-
pub fn exit_if_err(status: io::Result<ExitStatus>) {
76-
match status.expect("failed to run command").code() {
77-
Some(0) => {},
78-
Some(n) => process::exit(n),
79-
None => {
80-
eprintln!("Killed by signal");
81-
process::exit(1);
82-
},
83-
}
84-
}
26+
pub mod utils;

clippy_dev/src/lint.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{cargo_clippy_path, exit_if_err};
1+
use crate::utils::{cargo_clippy_path, exit_if_err};
22
use std::process::{self, Command};
33
use std::{env, fs};
44

clippy_dev/src/main.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#![warn(rust_2018_idioms, unused_lifetimes)]
44

55
use clap::{Args, Parser, Subcommand};
6-
use clippy_dev::{dogfood, fmt, lint, new_lint, serve, setup, update_lints};
6+
use clippy_dev::{dogfood, fmt, lint, new_lint, serve, setup, update_lints, utils};
77
use std::convert::Infallible;
88

99
fn main() {
@@ -23,9 +23,9 @@ fn main() {
2323
if print_only {
2424
update_lints::print_lints();
2525
} else if check {
26-
update_lints::update(update_lints::UpdateMode::Check);
26+
update_lints::update(utils::UpdateMode::Check);
2727
} else {
28-
update_lints::update(update_lints::UpdateMode::Change);
28+
update_lints::update(utils::UpdateMode::Change);
2929
}
3030
},
3131
DevCommand::NewLint {
@@ -35,7 +35,7 @@ fn main() {
3535
r#type,
3636
msrv,
3737
} => match new_lint::create(&pass, &name, &category, r#type.as_deref(), msrv) {
38-
Ok(()) => update_lints::update(update_lints::UpdateMode::Change),
38+
Ok(()) => update_lints::update(utils::UpdateMode::Change),
3939
Err(e) => eprintln!("Unable to create lint: {e}"),
4040
},
4141
DevCommand::Setup(SetupCommand { subcommand }) => match subcommand {

clippy_dev/src/new_lint.rs

+3-18
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::clippy_project_root;
1+
use crate::utils::{clippy_project_root, clippy_version};
22
use indoc::{formatdoc, writedoc};
33
use std::fmt;
44
use std::fmt::Write as _;
@@ -186,23 +186,8 @@ fn to_camel_case(name: &str) -> String {
186186
}
187187

188188
pub(crate) fn get_stabilization_version() -> String {
189-
fn parse_manifest(contents: &str) -> Option<String> {
190-
let version = contents
191-
.lines()
192-
.filter_map(|l| l.split_once('='))
193-
.find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))?;
194-
let Some(("0", version)) = version.get(1..version.len() - 1)?.split_once('.') else {
195-
return None;
196-
};
197-
let (minor, patch) = version.split_once('.')?;
198-
Some(format!(
199-
"{}.{}.0",
200-
minor.parse::<u32>().ok()?,
201-
patch.parse::<u32>().ok()?
202-
))
203-
}
204-
let contents = fs::read_to_string("Cargo.toml").expect("Unable to read `Cargo.toml`");
205-
parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
189+
let (minor, patch) = clippy_version();
190+
format!("{minor}.{patch}.0")
206191
}
207192

208193
fn get_test_file_contents(lint_name: &str, msrv: bool) -> String {

clippy_dev/src/update_lints.rs

+1-70
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::clippy_project_root;
1+
use crate::utils::{clippy_project_root, exit_with_failure, replace_region_in_file, UpdateMode};
22
use aho_corasick::AhoCorasickBuilder;
33
use indoc::writedoc;
44
use itertools::Itertools;
@@ -18,12 +18,6 @@ const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev u
1818

1919
const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html";
2020

21-
#[derive(Clone, Copy, PartialEq, Eq)]
22-
pub enum UpdateMode {
23-
Check,
24-
Change,
25-
}
26-
2721
/// Runs the `update_lints` command.
2822
///
2923
/// This updates various generated values from the lint source code.
@@ -547,14 +541,6 @@ fn process_file(path: impl AsRef<Path>, update_mode: UpdateMode, content: &str)
547541
}
548542
}
549543

550-
fn exit_with_failure() {
551-
println!(
552-
"Not all lints defined properly. \
553-
Please run `cargo dev update_lints` to make sure all lints are defined properly."
554-
);
555-
std::process::exit(1);
556-
}
557-
558544
/// Lint data parsed from the Clippy source code.
559545
#[derive(Clone, PartialEq, Eq, Debug)]
560546
struct Lint {
@@ -936,61 +922,6 @@ fn remove_line_splices(s: &str) -> String {
936922
});
937923
res
938924
}
939-
940-
/// Replaces a region in a file delimited by two lines matching regexes.
941-
///
942-
/// `path` is the relative path to the file on which you want to perform the replacement.
943-
///
944-
/// See `replace_region_in_text` for documentation of the other options.
945-
///
946-
/// # Panics
947-
///
948-
/// Panics if the path could not read or then written
949-
fn replace_region_in_file(
950-
update_mode: UpdateMode,
951-
path: &Path,
952-
start: &str,
953-
end: &str,
954-
write_replacement: impl FnMut(&mut String),
955-
) {
956-
let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display()));
957-
let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) {
958-
Ok(x) => x,
959-
Err(delim) => panic!("Couldn't find `{delim}` in file `{}`", path.display()),
960-
};
961-
962-
match update_mode {
963-
UpdateMode::Check if contents != new_contents => exit_with_failure(),
964-
UpdateMode::Check => (),
965-
UpdateMode::Change => {
966-
if let Err(e) = fs::write(path, new_contents.as_bytes()) {
967-
panic!("Cannot write to `{}`: {e}", path.display());
968-
}
969-
},
970-
}
971-
}
972-
973-
/// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters
974-
/// were found, or the missing delimiter if not.
975-
fn replace_region_in_text<'a>(
976-
text: &str,
977-
start: &'a str,
978-
end: &'a str,
979-
mut write_replacement: impl FnMut(&mut String),
980-
) -> Result<String, &'a str> {
981-
let (text_start, rest) = text.split_once(start).ok_or(start)?;
982-
let (_, text_end) = rest.split_once(end).ok_or(end)?;
983-
984-
let mut res = String::with_capacity(text.len() + 4096);
985-
res.push_str(text_start);
986-
res.push_str(start);
987-
write_replacement(&mut res);
988-
res.push_str(end);
989-
res.push_str(text_end);
990-
991-
Ok(res)
992-
}
993-
994925
fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
995926
match OpenOptions::new().create_new(true).write(true).open(new_name) {
996927
Ok(file) => drop(file),

clippy_dev/src/utils.rs

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
use std::path::{Path, PathBuf};
2+
use std::process::{self, ExitStatus};
3+
use std::{fs, io};
4+
5+
#[cfg(not(windows))]
6+
static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
7+
#[cfg(windows)]
8+
static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
9+
10+
/// Returns the path to the `cargo-clippy` binary
11+
///
12+
/// # Panics
13+
///
14+
/// Panics if the path of current executable could not be retrieved.
15+
#[must_use]
16+
pub fn cargo_clippy_path() -> PathBuf {
17+
let mut path = std::env::current_exe().expect("failed to get current executable name");
18+
path.set_file_name(CARGO_CLIPPY_EXE);
19+
path
20+
}
21+
22+
/// Returns the path to the Clippy project directory
23+
///
24+
/// # Panics
25+
///
26+
/// Panics if the current directory could not be retrieved, there was an error reading any of the
27+
/// Cargo.toml files or ancestor directory is the clippy root directory
28+
#[must_use]
29+
pub fn clippy_project_root() -> PathBuf {
30+
let current_dir = std::env::current_dir().unwrap();
31+
for path in current_dir.ancestors() {
32+
let result = fs::read_to_string(path.join("Cargo.toml"));
33+
if let Err(err) = &result {
34+
if err.kind() == io::ErrorKind::NotFound {
35+
continue;
36+
}
37+
}
38+
39+
let content = result.unwrap();
40+
if content.contains("[package]\nname = \"clippy\"") {
41+
return path.to_path_buf();
42+
}
43+
}
44+
panic!("error: Can't determine root of project. Please run inside a Clippy working dir.");
45+
}
46+
47+
/// # Panics
48+
/// Panics if given command result was failed.
49+
pub fn exit_if_err(status: io::Result<ExitStatus>) {
50+
match status.expect("failed to run command").code() {
51+
Some(0) => {},
52+
Some(n) => process::exit(n),
53+
None => {
54+
eprintln!("Killed by signal");
55+
process::exit(1);
56+
},
57+
}
58+
}
59+
60+
pub(crate) fn clippy_version() -> (u32, u32) {
61+
fn parse_manifest(contents: &str) -> Option<(u32, u32)> {
62+
let version = contents
63+
.lines()
64+
.filter_map(|l| l.split_once('='))
65+
.find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))?;
66+
let Some(("0", version)) = version.get(1..version.len() - 1)?.split_once('.') else {
67+
return None;
68+
};
69+
let (minor, patch) = version.split_once('.')?;
70+
Some((minor.parse().ok()?, patch.parse().ok()?))
71+
}
72+
let contents = fs::read_to_string("Cargo.toml").expect("Unable to read `Cargo.toml`");
73+
parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
74+
}
75+
76+
#[derive(Clone, Copy, PartialEq, Eq)]
77+
pub enum UpdateMode {
78+
Check,
79+
Change,
80+
}
81+
82+
pub(crate) fn exit_with_failure() {
83+
println!(
84+
"Not all lints defined properly. \
85+
Please run `cargo dev update_lints` to make sure all lints are defined properly."
86+
);
87+
process::exit(1);
88+
}
89+
90+
/// Replaces a region in a file delimited by two lines matching regexes.
91+
///
92+
/// `path` is the relative path to the file on which you want to perform the replacement.
93+
///
94+
/// See `replace_region_in_text` for documentation of the other options.
95+
///
96+
/// # Panics
97+
///
98+
/// Panics if the path could not read or then written
99+
pub(crate) fn replace_region_in_file(
100+
update_mode: UpdateMode,
101+
path: &Path,
102+
start: &str,
103+
end: &str,
104+
write_replacement: impl FnMut(&mut String),
105+
) {
106+
let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display()));
107+
let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) {
108+
Ok(x) => x,
109+
Err(delim) => panic!("Couldn't find `{delim}` in file `{}`", path.display()),
110+
};
111+
112+
match update_mode {
113+
UpdateMode::Check if contents != new_contents => exit_with_failure(),
114+
UpdateMode::Check => (),
115+
UpdateMode::Change => {
116+
if let Err(e) = fs::write(path, new_contents.as_bytes()) {
117+
panic!("Cannot write to `{}`: {e}", path.display());
118+
}
119+
},
120+
}
121+
}
122+
123+
/// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters
124+
/// were found, or the missing delimiter if not.
125+
pub(crate) fn replace_region_in_text<'a>(
126+
text: &str,
127+
start: &'a str,
128+
end: &'a str,
129+
mut write_replacement: impl FnMut(&mut String),
130+
) -> Result<String, &'a str> {
131+
let (text_start, rest) = text.split_once(start).ok_or(start)?;
132+
let (_, text_end) = rest.split_once(end).ok_or(end)?;
133+
134+
let mut res = String::with_capacity(text.len() + 4096);
135+
res.push_str(text_start);
136+
res.push_str(start);
137+
write_replacement(&mut res);
138+
res.push_str(end);
139+
res.push_str(text_end);
140+
141+
Ok(res)
142+
}

0 commit comments

Comments
 (0)