Skip to content

feat: implement app/utils#269

Open
emlautarom1 wants to merge 28 commits intomainfrom
emlautarom1/app-utils
Open

feat: implement app/utils#269
emlautarom1 wants to merge 28 commits intomainfrom
emlautarom1/app-utils

Conversation

@emlautarom1
Copy link
Collaborator

Closes #245


The implementation is a lot shorter since the Rust libraries handle several edge cases that are hand-rolled in the reference Go implementation.

Only two dependencies are added to handle tar and gz files:

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements the pluto-app utils module to provide helper functions for short hex formatting, bundling an output directory into a .tar.gz, extracting an archive, and recursively comparing directories (with accompanying unit tests), as requested in #245.

Changes:

  • Added crates/app/src/utils.rs with hex_7, bundle_output, extract_archive, and compare_directories plus tests.
  • Exposed the new module via crates/app/src/lib.rs.
  • Added tar, flate2, tempfile, and test-case dependencies (workspace + crate).

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
crates/app/src/utils.rs New utilities for tar/gzip bundling/extraction and directory comparison; includes tests.
crates/app/src/lib.rs Exposes the new utils module from the crate root.
crates/app/Cargo.toml Adds dependencies required by utils and its tests.
Cargo.toml Adds workspace dependency versions for tar and flate2.
Cargo.lock Locks new dependency graph for tar/flate2 and transitive updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +56 to +62
// Delete all files from the `target_dir`
fs::remove_dir_all(&target_path)?;
fs::create_dir_all(&target_path)?;

// Move the created tarball to the target location
let output_path = path::Path::new(target_path.as_ref()).join(filename.as_ref());
fs::rename(tar_file_path, output_path)?;
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bundle_output deletes target_path (removing the original output) before it knows the archive can be moved into place. If rename fails (e.g., due to an open handle or permissions), this will lose the original directory contents and leave only the temp archive behind. Safer flow is: fully finalize/close the archive, move it into target_path, then delete everything except the archive (or otherwise ensure the move cannot fail before deleting originals).

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

@emlautarom1 emlautarom1 Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The move operation should not fail since we have permissions to manipulate the target_path, and we assume that we can manipulate any temporary file. Nevertheless, this is indeed an unsafe operation.

The original implementation uses the suggested approach, but it can also end up corrupted due to partially deleted data. I think my proposed implementation is better due to its brevity but I'm not against changing it if it's considered appropriate.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is also the chance that fs::create_dir_all fails and we potentially lose data. I would suggest saving everything into target_path and then deleting old files manually, and not by remove_dir_all

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The challenge here is with the implementation: if we put the .tar.gz file in the target directory then we cannot use tar.append_dir_all which does a lot of heavy lifting. I don't see how operations could fail here though (if we can remove the dir then we can create it again, right?)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 3, 2026 00:47
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

dir1: impl AsRef<path::Path>,
dir2: impl AsRef<path::Path>,
) -> Result<()> {
let mut entries1 = fs::read_dir(dir1)?.collect::<std::result::Result<Vec<_>, _>>()?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if it's worth to use tokio::fs here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It gets complicated quickly due to recursive async. Given that the extract_archive function is already sync I would leave this one also sync, and if needed we can wrap it in a tokio::spawn_blocking.

Comment on lines +33 to +37
/// Returns the first 7 (or less) hex chars of the provided bytes.
pub fn hex_7(input: &[u8]) -> String {
let as_string = hex::encode(input);
as_string.chars().take(7).collect()
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same function is used in the peerinfo it would be great to port it there.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, but I don't immediately see a way to extract the common code (does not make sense for the example to depend on the entire pluto_app crate for a single function).
Any suggestions?

Comment on lines +56 to +62
// Delete all files from the `target_dir`
fs::remove_dir_all(&target_path)?;
fs::create_dir_all(&target_path)?;

// Move the created tarball to the target location
let output_path = path::Path::new(target_path.as_ref()).join(filename.as_ref());
fs::rename(tar_file_path, output_path)?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is also the chance that fs::create_dir_all fails and we potentially lose data. I would suggest saving everything into target_path and then deleting old files manually, and not by remove_dir_all

Copilot AI review requested due to automatic review settings March 5, 2026 15:55
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@varex83
Copy link
Collaborator

varex83 commented Mar 5, 2026

@claude review this PR

Copilot AI review requested due to automatic review settings March 6, 2026 14:34
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

varex83 and others added 3 commits March 10, 2026 09:05
* feat: add quic upgrade

* feat: add comment about peer addresses

* fix: linter

* fix: clean up tests

* fix: linter

* fix: review comments

* fix: review comments
* feat: add quic upgrade

* feat: add comment about peer addresses

* fix: linter

* fix: clean up tests

* fix: linter

* feat: add force direct connections

* fix: linter

* fix: review comments

* fix: review comments

* fix: review comments
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Copilot AI review requested due to automatic review settings March 12, 2026 14:31
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +164 to +170
if path1.is_dir() && path2.is_dir() {
compare_directories(&path1, &path2)?;
} else if path1.is_file() && path2.is_file() {
compare_file_contents(&path1, &path2)?;
} else {
return Err(UtilsError::TypeMismatch { path1, path2 });
}
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

compare_directories uses PathBuf::is_dir() / is_file(), which follow symlinks. A symlink loop (or a symlink pointing outside the compared trees) can cause infinite recursion or unintended reads outside the directory being compared. Consider using fs::symlink_metadata and explicitly handling symlinks (e.g., treat as a distinct type mismatch, or compare link targets without following).

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

@varex83 varex83 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement app/utils

4 participants