Skip to content

Commit 3c79608

Browse files
committed
Fix Cargo.toml.orig detection in presence of # in multi-lines string
CC #25
1 parent c39c610 commit 3c79608

File tree

1 file changed

+105
-2
lines changed

1 file changed

+105
-2
lines changed

lib.rs

+105-2
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,11 @@ fn document_features_impl(args: &Args) -> Result<TokenStream, TokenStream> {
254254
let mut cargo_toml = std::fs::read_to_string(Path::new(&path).join("Cargo.toml"))
255255
.map_err(|e| error(&format!("Can't open Cargo.toml: {:?}", e)))?;
256256

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

271+
/// Check if the Cargo.toml has comments that looks like doc comments.
272+
fn has_doc_comments(cargo_toml: &str) -> bool {
273+
let mut lines = cargo_toml.lines().map(str::trim);
274+
while let Some(line) = lines.next() {
275+
if line.starts_with("## ") || line.starts_with("#! ") {
276+
return true;
277+
}
278+
let before_coment = line.split_once('#').map_or(line, |(before, _)| before);
279+
if line.starts_with("#") {
280+
continue;
281+
}
282+
if let Some((_, mut quote)) = before_coment.split_once("\"\"\"") {
283+
loop {
284+
// skip slashes.
285+
if let Some((_, s)) = quote.split_once('\\') {
286+
quote = s.strip_prefix('\\').or_else(|| s.strip_prefix('"')).unwrap_or(s);
287+
continue;
288+
}
289+
// skip quotes.
290+
if let Some((_, out_quote)) = quote.split_once("\"\"\"") {
291+
let out_quote = out_quote.trim_start_matches('"');
292+
let out_quote =
293+
out_quote.split_once('#').map_or(out_quote, |(before, _)| before);
294+
if let Some((_, q)) = out_quote.split_once("\"\"\"") {
295+
quote = q;
296+
continue;
297+
}
298+
break;
299+
};
300+
match lines.next() {
301+
Some(l) => quote = l,
302+
None => return false,
303+
}
304+
}
305+
}
306+
}
307+
false
308+
}
309+
310+
#[test]
311+
fn test_has_doc_coment() {
312+
assert!(has_doc_comments("foo\nbar\n## comment\nddd"));
313+
assert!(!has_doc_comments("foo\nbar\n#comment\nddd"));
314+
assert!(!has_doc_comments(
315+
r#"
316+
[[package.metadata.release.pre-release-replacements]]
317+
exactly = 1 # not a doc comment
318+
file = "CHANGELOG.md"
319+
replace = """
320+
<!-- next-header -->
321+
## [Unreleased] - ReleaseDate
322+
"""
323+
search = "<!-- next-header -->"
324+
array = ["""foo""", """
325+
bar""", """eee
326+
## not a comment
327+
"""]
328+
"#
329+
));
330+
assert!(has_doc_comments(
331+
r#"
332+
[[package.metadata.release.pre-release-replacements]]
333+
exactly = 1 # """
334+
file = "CHANGELOG.md"
335+
replace = """
336+
<!-- next-header -->
337+
## [Unreleased] - ReleaseDate
338+
"""
339+
search = "<!-- next-header -->"
340+
array = ["""foo""", """
341+
bar""", """eee
342+
## not a comment
343+
"""]
344+
## This is a comment
345+
feature = "45"
346+
"#
347+
));
348+
349+
assert!(!has_doc_comments(
350+
r#"
351+
[[package.metadata.release.pre-release-replacements]]
352+
value = """" string \"""
353+
## within the string
354+
\""""
355+
another_string = """"" # """
356+
## also within"""
357+
"#
358+
));
359+
360+
assert!(has_doc_comments(
361+
r#"
362+
[[package.metadata.release.pre-release-replacements]]
363+
value = """" string \"""
364+
## within the string
365+
\""""
366+
another_string = """"" # """
367+
## also within"""
368+
## out of the string
369+
foo = bar
370+
"#
371+
));
372+
}
373+
271374
fn process_toml(cargo_toml: &str, args: &Args) -> Result<String, String> {
272375
// Get all lines between the "[features]" and the next block
273376
let mut lines = cargo_toml

0 commit comments

Comments
 (0)