RIIR update_lints: Replace lint count in README.md
This allows the usage of `util/dev update_lints` which will write the new lint_count to the `README.md`.
This commit is contained in:
@@ -101,6 +101,88 @@ fn lint_files() -> impl Iterator<Item=walkdir::DirEntry> {
|
|||||||
.filter(|f| f.path().extension() == Some(OsStr::new("rs")))
|
.filter(|f| f.path().extension() == Some(OsStr::new("rs")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Replace 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.
|
||||||
|
pub fn replace_region_in_file<F>(path: &str, start: &str, end: &str, replace_start: bool, replacements: F) where F: Fn() -> Vec<String> {
|
||||||
|
let mut f = fs::File::open(path).expect(&format!("File not found: {}", path));
|
||||||
|
let mut contents = String::new();
|
||||||
|
f.read_to_string(&mut contents).expect("Something went wrong reading the file");
|
||||||
|
let replaced = replace_region_in_text(&contents, start, end, replace_start, replacements);
|
||||||
|
|
||||||
|
let mut f = fs::File::create(path).expect(&format!("File not found: {}", path));
|
||||||
|
f.write_all(replaced.as_bytes()).expect("Unable to write file");
|
||||||
|
// Ensure we write the changes with a trailing newline so that
|
||||||
|
// the file has the proper line endings.
|
||||||
|
f.write(b"\n").expect("Unable to write file");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace a region in a text delimited by two lines matching regexes.
|
||||||
|
///
|
||||||
|
/// * `text` is the input text on which you want to perform the replacement
|
||||||
|
/// * `start` is a `&str` that describes the delimiter line before the region you want to replace.
|
||||||
|
/// As the `&str` will be converted to a `Regex`, this can contain regex syntax, too.
|
||||||
|
/// * `end` is a `&str` that describes the delimiter line until where the replacement should
|
||||||
|
/// happen. As the `&str` will be converted to a `Regex`, this can contain regex syntax, too.
|
||||||
|
/// * If `replace_start` is true, the `start` delimiter line is replaced as well.
|
||||||
|
/// The `end` delimiter line is never replaced.
|
||||||
|
/// * `replacements` is a closure that has to return a `Vec<String>` which contains the new text.
|
||||||
|
///
|
||||||
|
/// If you want to perform the replacement on files instead of already parsed text,
|
||||||
|
/// use `replace_region_in_file`.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let the_text = "replace_start\nsome text\nthat will be replaced\nreplace_end";
|
||||||
|
/// let result = clippy_dev::replace_region_in_text(
|
||||||
|
/// the_text,
|
||||||
|
/// r#"replace_start"#,
|
||||||
|
/// r#"replace_end"#,
|
||||||
|
/// false,
|
||||||
|
/// || {
|
||||||
|
/// vec!["a different".to_string(), "text".to_string()]
|
||||||
|
/// }
|
||||||
|
/// );
|
||||||
|
/// assert_eq!("replace_start\na different\ntext\nreplace_end", result);
|
||||||
|
/// ```
|
||||||
|
pub fn replace_region_in_text<F>(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> String where F: Fn() -> Vec<String> {
|
||||||
|
let lines = text.lines();
|
||||||
|
let mut in_old_region = false;
|
||||||
|
let mut found = false;
|
||||||
|
let mut new_lines = vec![];
|
||||||
|
let start = Regex::new(start).unwrap();
|
||||||
|
let end = Regex::new(end).unwrap();
|
||||||
|
|
||||||
|
for line in lines {
|
||||||
|
if in_old_region {
|
||||||
|
if end.is_match(&line) {
|
||||||
|
in_old_region = false;
|
||||||
|
new_lines.extend(replacements());
|
||||||
|
new_lines.push(line.to_string());
|
||||||
|
}
|
||||||
|
} else if start.is_match(&line) {
|
||||||
|
if !replace_start {
|
||||||
|
new_lines.push(line.to_string());
|
||||||
|
}
|
||||||
|
in_old_region = true;
|
||||||
|
found = true;
|
||||||
|
} else {
|
||||||
|
new_lines.push(line.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
// This happens if the provided regex in `clippy_dev/src/main.rs` is not found in the
|
||||||
|
// given text or file. Most likely this is an error on the programmer's side and the Regex
|
||||||
|
// is incorrect.
|
||||||
|
println!("regex {:?} not found. You may have to update it.", start);
|
||||||
|
}
|
||||||
|
new_lines.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_contents() {
|
fn test_parse_contents() {
|
||||||
let result: Vec<Lint> = parse_contents(
|
let result: Vec<Lint> = parse_contents(
|
||||||
@@ -140,6 +222,43 @@ declare_deprecated_lint! {
|
|||||||
assert_eq!(expected, result);
|
assert_eq!(expected, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_replace_region() {
|
||||||
|
let text = r#"
|
||||||
|
abc
|
||||||
|
123
|
||||||
|
789
|
||||||
|
def
|
||||||
|
ghi"#;
|
||||||
|
let expected = r#"
|
||||||
|
abc
|
||||||
|
hello world
|
||||||
|
def
|
||||||
|
ghi"#;
|
||||||
|
let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, false, || {
|
||||||
|
vec!["hello world".to_string()]
|
||||||
|
});
|
||||||
|
assert_eq!(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_replace_region_with_start() {
|
||||||
|
let text = r#"
|
||||||
|
abc
|
||||||
|
123
|
||||||
|
789
|
||||||
|
def
|
||||||
|
ghi"#;
|
||||||
|
let expected = r#"
|
||||||
|
hello world
|
||||||
|
def
|
||||||
|
ghi"#;
|
||||||
|
let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, true, || {
|
||||||
|
vec!["hello world".to_string()]
|
||||||
|
});
|
||||||
|
assert_eq!(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_usable_lints() {
|
fn test_usable_lints() {
|
||||||
let lints = vec![
|
let lints = vec![
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ fn main() {
|
|||||||
if let Some(matches) = matches.subcommand_matches("update_lints") {
|
if let Some(matches) = matches.subcommand_matches("update_lints") {
|
||||||
if matches.is_present("print-only") {
|
if matches.is_present("print-only") {
|
||||||
print_lints();
|
print_lints();
|
||||||
|
} else {
|
||||||
|
update_lints();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,3 +57,21 @@ fn print_lints() {
|
|||||||
|
|
||||||
println!("there are {} lints", lint_count);
|
println!("there are {} lints", lint_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_lints() {
|
||||||
|
let lint_list = gather_all();
|
||||||
|
let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list).collect();
|
||||||
|
let lint_count = usable_lints.len();
|
||||||
|
|
||||||
|
replace_region_in_file(
|
||||||
|
"../README.md",
|
||||||
|
r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang-nursery.github.io/rust-clippy/master/index.html\)"#,
|
||||||
|
"",
|
||||||
|
true,
|
||||||
|
|| {
|
||||||
|
vec", lint_count)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user