new: ignore vendored rust artifacts in the generated gitignore

This commit is contained in:
2026-09-17 10:37:58 +02:00
parent bac82f0afe
commit bc3d07abaa
4 changed files with 183 additions and 20 deletions
+62 -12
View File
@@ -323,15 +323,25 @@ pub const ROOT_GITIGNORE_ENTRIES: [&str; 6] = [
"target/",
];
/// Merge the root `.gitignore` entries into `existing` (the current file
/// contents, when there is one): missing entries are appended, an existing
/// file is never overwritten just to duplicate entries. Returns the new
/// contents, or `None` when nothing has to be written.
pub fn merge_root_gitignore(existing: Option<&str>) -> Option<String> {
/// Comment heading a root `.gitignore` freshly created by pkh (the skeleton
/// build-artifact section).
pub const ROOT_GITIGNORE_HEADER: &str = "# pkh build artifacts";
/// Merge `entries` into the root `.gitignore` contents `existing` (the
/// current file contents, when there is one): missing entries are appended,
/// an existing file is never overwritten just to duplicate entries. A fresh
/// file is headed by the `header` comment when one is given; appending to a
/// user file adds bare entries. Returns the new contents, or `None` when
/// nothing has to be written.
pub fn merge_gitignore_entries(
existing: Option<&str>,
entries: &[&str],
header: Option<&str>,
) -> Option<String> {
let have: HashSet<&str> = existing
.map(|content| content.lines().map(str::trim).collect())
.unwrap_or_default();
let missing: Vec<&str> = ROOT_GITIGNORE_ENTRIES
let missing: Vec<&str> = entries
.iter()
.copied()
.filter(|entry| !have.contains(entry))
@@ -346,8 +356,11 @@ pub fn merge_root_gitignore(existing: Option<&str>) -> Option<String> {
}
// Section comment only for a fresh file; appending to a user file adds
// bare entries.
if existing.is_none() {
out.push_str("# pkh build artifacts\n");
if existing.is_none()
&& let Some(header) = header
{
out.push_str(header);
out.push('\n');
}
for entry in missing {
out.push_str(entry);
@@ -746,17 +759,30 @@ mod tests {
}
#[test]
fn root_gitignore_merge() {
fn gitignore_merge() {
// Fresh file: header + all entries.
let fresh = merge_root_gitignore(None).unwrap();
let fresh =
merge_gitignore_entries(None, &ROOT_GITIGNORE_ENTRIES, Some(ROOT_GITIGNORE_HEADER))
.unwrap();
assert!(fresh.starts_with("# pkh build artifacts\n"));
for entry in ROOT_GITIGNORE_ENTRIES {
assert!(fresh.contains(entry), "{entry} missing");
}
// A fresh file without a header carries the bare entries.
assert_eq!(
merge_gitignore_entries(None, &["a/", "b"], None).unwrap(),
"a/\nb\n"
);
// Existing file: only the missing entries are appended, nothing lost.
let existing = "*.deb\nnode_modules/\n";
let merged = merge_root_gitignore(Some(existing)).unwrap();
let merged = merge_gitignore_entries(
Some(existing),
&ROOT_GITIGNORE_ENTRIES,
Some(ROOT_GITIGNORE_HEADER),
)
.unwrap();
assert!(merged.starts_with(existing));
assert!(merged.contains("*.dsc\n"));
assert!(!merged.contains("*.deb\n*.deb"));
@@ -766,7 +792,31 @@ mod tests {
.iter()
.map(|e| format!("{e}\n"))
.collect();
assert!(merge_root_gitignore(Some(&full)).is_none());
assert!(
merge_gitignore_entries(
Some(&full),
&ROOT_GITIGNORE_ENTRIES,
Some(ROOT_GITIGNORE_HEADER),
)
.is_none()
);
}
/// The vendoring entries of the rust template merge into an existing
/// user `.gitignore` like any other entry set: appended after the
/// user's lines, no header comment, idempotent.
#[test]
fn gitignore_merge_appends_template_entries() {
let entries = ["vendor/", ".cargo/config.toml"];
let merged =
merge_gitignore_entries(Some("# my project\n*.log\n"), &entries, None).unwrap();
assert_eq!(merged, "# my project\n*.log\nvendor/\n.cargo/config.toml\n");
// Already ignored: nothing to write.
assert!(
merge_gitignore_entries(Some("vendor/\n.cargo/config.toml\n"), &entries, None)
.is_none()
);
}
#[test]