Skip to content

Commit

Permalink
Fix Cargo.toml.orig detection in presence of # in multi-lines string
Browse files Browse the repository at this point in the history
CC #25
  • Loading branch information
ogoffart committed Jul 11, 2024
1 parent c39c610 commit 3c79608
Showing 1 changed file with 105 additions and 2 deletions.
107 changes: 105 additions & 2 deletions lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,11 @@ fn document_features_impl(args: &Args) -> Result<TokenStream, TokenStream> {
let mut cargo_toml = std::fs::read_to_string(Path::new(&path).join("Cargo.toml"))
.map_err(|e| error(&format!("Can't open Cargo.toml: {:?}", e)))?;

if !cargo_toml.contains("\n##") && !cargo_toml.contains("\n#!") {
if !has_doc_comments(&cargo_toml) {
// On crates.io, Cargo.toml is usually "normalized" and stripped of all comments.
// The original Cargo.toml has been renamed Cargo.toml.orig
if let Ok(orig) = std::fs::read_to_string(Path::new(&path).join("Cargo.toml.orig")) {
if orig.contains("##") || orig.contains("#!") {
if has_doc_comments(&orig) {
cargo_toml = orig;
}
}
Expand All @@ -268,6 +268,109 @@ fn document_features_impl(args: &Args) -> Result<TokenStream, TokenStream> {
Ok(std::iter::once(proc_macro::TokenTree::from(proc_macro::Literal::string(&result))).collect())
}

/// Check if the Cargo.toml has comments that looks like doc comments.
fn has_doc_comments(cargo_toml: &str) -> bool {
let mut lines = cargo_toml.lines().map(str::trim);
while let Some(line) = lines.next() {
if line.starts_with("## ") || line.starts_with("#! ") {
return true;
}
let before_coment = line.split_once('#').map_or(line, |(before, _)| before);
if line.starts_with("#") {
continue;
}
if let Some((_, mut quote)) = before_coment.split_once("\"\"\"") {
loop {
// skip slashes.
if let Some((_, s)) = quote.split_once('\\') {
quote = s.strip_prefix('\\').or_else(|| s.strip_prefix('"')).unwrap_or(s);
continue;
}
// skip quotes.
if let Some((_, out_quote)) = quote.split_once("\"\"\"") {
let out_quote = out_quote.trim_start_matches('"');
let out_quote =
out_quote.split_once('#').map_or(out_quote, |(before, _)| before);
if let Some((_, q)) = out_quote.split_once("\"\"\"") {
quote = q;
continue;
}
break;
};
match lines.next() {
Some(l) => quote = l,
None => return false,
}
}
}
}
false
}

#[test]
fn test_has_doc_coment() {
assert!(has_doc_comments("foo\nbar\n## comment\nddd"));
assert!(!has_doc_comments("foo\nbar\n#comment\nddd"));
assert!(!has_doc_comments(
r#"
[[package.metadata.release.pre-release-replacements]]
exactly = 1 # not a doc comment
file = "CHANGELOG.md"
replace = """
<!-- next-header -->
## [Unreleased] - ReleaseDate
"""
search = "<!-- next-header -->"
array = ["""foo""", """
bar""", """eee
## not a comment
"""]
"#
));
assert!(has_doc_comments(
r#"
[[package.metadata.release.pre-release-replacements]]
exactly = 1 # """
file = "CHANGELOG.md"
replace = """
<!-- next-header -->
## [Unreleased] - ReleaseDate
"""
search = "<!-- next-header -->"
array = ["""foo""", """
bar""", """eee
## not a comment
"""]
## This is a comment
feature = "45"
"#
));

assert!(!has_doc_comments(
r#"
[[package.metadata.release.pre-release-replacements]]
value = """" string \"""
## within the string
\""""
another_string = """"" # """
## also within"""
"#
));

assert!(has_doc_comments(
r#"
[[package.metadata.release.pre-release-replacements]]
value = """" string \"""
## within the string
\""""
another_string = """"" # """
## also within"""
## out of the string
foo = bar
"#
));
}

fn process_toml(cargo_toml: &str, args: &Args) -> Result<String, String> {
// Get all lines between the "[features]" and the next block
let mut lines = cargo_toml
Expand Down

0 comments on commit 3c79608

Please sign in to comment.