(
src: &Path,
dst: &Path,
previous: Option<&Receipt>,
force: bool,
installed: &mut Vec<PathBuf>,
refreshed: &mut Vec<PathBuf>,
skipped: &mut Vec<SkippedFile>,
receipt_f
| 644 | /// (replace the whole file). `--force` always clobbers. |
| 645 | #[allow(clippy::too_many_arguments)] |
| 646 | fn copy_repo_file( |
| 647 | src: &Path, |
| 648 | dst: &Path, |
| 649 | previous: Option<&Receipt>, |
| 650 | force: bool, |
| 651 | installed: &mut Vec<PathBuf>, |
| 652 | refreshed: &mut Vec<PathBuf>, |
| 653 | skipped: &mut Vec<SkippedFile>, |
| 654 | receipt_files: &mut Vec<ReceiptFile>, |
| 655 | ) -> AgentResult<()> { |
| 656 | match repo_file_decision(dst, previous, force)? { |
| 657 | Decision::Install => { |
| 658 | if let Some(parent) = dst.parent() { |
| 659 | std::fs::create_dir_all(parent)?; |
| 660 | } |
| 661 | std::fs::copy(src, dst)?; |
| 662 | installed.push(dst.to_path_buf()); |
| 663 | receipt_files.push(ReceiptFile { |
| 664 | blake3: hash_file(dst)?, |
| 665 | dst: dst.to_path_buf(), |
| 666 | }); |
| 667 | } |
| 668 | Decision::Refresh => { |
| 669 | std::fs::copy(src, dst)?; |
| 670 | refreshed.push(dst.to_path_buf()); |
| 671 | receipt_files.push(ReceiptFile { |
| 672 | blake3: hash_file(dst)?, |
| 673 | dst: dst.to_path_buf(), |
| 674 | }); |
| 675 | } |
| 676 | Decision::Merge => { |
| 677 | // Append the canonical content to the user's existing file with |
| 678 | // a markdown horizontal rule separator. The user's content is |
| 679 | // preserved above; the Atomic workflow content goes below. |
| 680 | let existing = std::fs::read_to_string(dst)?; |
| 681 | let canonical = std::fs::read_to_string(src)?; |
| 682 | let merged = format!("{existing}\n\n---\n\n{canonical}"); |
| 683 | std::fs::write(dst, merged)?; |
| 684 | installed.push(dst.to_path_buf()); |
| 685 | receipt_files.push(ReceiptFile { |
| 686 | blake3: hash_file(dst)?, |
| 687 | dst: dst.to_path_buf(), |
| 688 | }); |
| 689 | } |
| 690 | Decision::Skip(reason) => { |
| 691 | skipped.push(SkippedFile { |
| 692 | dst: dst.to_path_buf(), |
| 693 | reason, |
| 694 | }); |
| 695 | if let Some(old) = previous.and_then(|r| r.files.iter().find(|f| f.dst == dst)) { |
| 696 | receipt_files.push(old.clone()); |
| 697 | } |
| 698 | } |
| 699 | } |
| 700 | Ok(()) |
| 701 | } |
| 702 | |
| 703 | /// Reject `src` paths that would escape the package directory. |
no test coverage detected