Skip to content

feat(copy): use rsync by default with scp fallback#297

Open
immanuel-peter wants to merge 3 commits intobrevdev:mainfrom
immanuel-peter:main
Open

feat(copy): use rsync by default with scp fallback#297
immanuel-peter wants to merge 3 commits intobrevdev:mainfrom
immanuel-peter:main

Conversation

@immanuel-peter
Copy link

@immanuel-peter immanuel-peter commented Feb 26, 2026

Summary

  • switch brev copy to attempt rsync first for file/directory transfers
  • retain scp as an automatic fallback when rsync fails
  • add tests for transfer strategy and argument construction

Why rsync first

rsync is generally better for repeated and large transfers because it supports incremental/delta transfer, can reduce bytes sent, and is typically faster and more bandwidth-efficient than scp for changed files/directories.

Compatibility

We keep scp as a fallback path so environments that lack working rsync still succeed with the previous transfer mechanism.

Verification

  • go test ./pkg/cmd/copy
  • go test ./pkg/cmd/...

Copilot AI review requested due to automatic review settings February 26, 2026 16:45
@immanuel-peter immanuel-peter requested a review from a team as a code owner February 26, 2026 16:45
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

This PR updates the brev copy command to prefer rsync for transfers (for better incremental performance) while preserving compatibility by falling back to scp when rsync fails.

Changes:

  • Switch transfer execution to attempt rsync first with automatic scp fallback.
  • Factor transfer argument construction into helper functions for rsync/scp.
  • Add unit tests covering argument construction and fallback behavior.

Reviewed changes

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

File Description
pkg/cmd/copy/copy.go Implements rsync-first transfer strategy with scp fallback and refactors argument building.
pkg/cmd/copy/copy_test.go Adds tests for rsync/scp arg construction and fallback execution behavior.

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


startTime := time.Now()
func combinedOutputRunner(name string, args ...string) ([]byte, error) {
cmd := exec.Command(name, args...) //nolint:gosec
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

//nolint:gosec here suppresses a security linter finding without any justification. Elsewhere in the codebase, nolint:gosec is consistently annotated with a short reason (e.g., agentskill.go uses //nolint:gosec // skill files are not sensitive). Add a brief rationale here (and, if applicable, note what input validation makes this safe) to avoid masking real issues in future changes.

Suggested change
cmd := exec.Command(name, args...) //nolint:gosec
cmd := exec.Command(name, args...) //nolint:gosec // name is restricted to rsync/scp and args are validated paths, so command injection risk is controlled

Copilot uses AI. Check for mistakes.
Comment on lines 215 to 219
startTime := time.Now()
fellBack, err := transferWithFallback(sshAlias, localPath, remotePath, isUpload, combinedOutputRunner)
if fellBack {
t.Vprint(t.Yellow("rsync failed, falling back to scp...\n"))
}
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The fallback status message is printed after transferWithFallback returns, which means the user will see "falling back to scp..." only after scp has already completed (or failed). Consider moving the rsync/scp orchestration into runCopyWithFallback (or providing a callback from transferWithFallback) so the message is emitted immediately before invoking scp.

Copilot uses AI. Check for mistakes.

scpErr := runSCPCommand(sshAlias, localPath, remotePath, isUpload, runner)
if scpErr != nil {
return true, fmt.Errorf("rsync failed: %v\nscp fallback failed: %w", err, scpErr)
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

transferWithFallback wraps the rsync error with an additional "rsync failed:" prefix even though runRsyncCommand already returns an error starting with "rsync failed:". This results in duplicated prefixes (e.g., rsync failed: rsync failed: ...) and makes the combined error harder to read. Consider either removing the prefix from runRsyncCommand/runSCPCommand or changing this formatting to avoid repeating it (and keep the output sections intact).

Suggested change
return true, fmt.Errorf("rsync failed: %v\nscp fallback failed: %w", err, scpErr)
return true, fmt.Errorf("%v\nscp fallback failed: %w", err, scpErr)

Copilot uses AI. Check for mistakes.
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.

2 participants