Skip to content

Commit 51d6e05

Browse files
committed
Fixed rsync subprocesses by prepending them with 'bash -c'
1 parent 47cd211 commit 51d6e05

File tree

1 file changed

+32
-9
lines changed

1 file changed

+32
-9
lines changed

src/murfey/client/rsync.py

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -381,13 +381,15 @@ def parse_stderr(line: str):
381381
logger.warning(f"rsync stderr: {line!r}")
382382

383383
# Generate list of relative filenames for this batch of transferred files
384+
# Relative filenames will be safe to use on both Windows and Unix
384385
relative_filenames: List[Path] = []
385386
for f in files:
386387
try:
387388
relative_filenames.append(f.relative_to(self._basepath))
388389
except ValueError:
389390
raise ValueError(f"File '{f}' is outside of {self._basepath}") from None
390391

392+
# Encode files to rsync as bytestring
391393
if self._remove_files:
392394
if self._required_substrings_for_removal:
393395
rsync_stdin_remove = b"\n".join(
@@ -416,24 +418,36 @@ def parse_stderr(line: str):
416418
rsync_stdin = b"\n".join(os.fsencode(f) for f in relative_filenames)
417419

418420
# Create and run rsync subprocesses
419-
# rsync commands to pass to subprocess
421+
# rsync default settings
420422
rsync_cmd = [
421423
"rsync",
422424
"-iiv",
423425
"--times",
424426
"--progress",
425427
"--outbuf=line",
426-
"--files-from=-",
427-
"-p", # preserve permissions
428-
"--chmod=D0750,F0750", # 4: Read, 2: Write, 1: Execute | User, Group, Others
428+
"--files-from=-", # '-' indicates reading from standard input
429+
# Needed as a pair to trigger permission modifications
430+
# Ref: https://serverfault.com/a/796341
431+
"-p",
432+
"--chmod=D0750,F0750", # Use extended chmod format
429433
]
434+
# Add file locations
430435
rsync_cmd.extend([".", self._remote])
431-
result: subprocess.CompletedProcess | None = None
436+
437+
# Transfer files to destination
438+
result: subprocess.CompletedProcess[bytes] | None = None
432439
success = True
433440
if rsync_stdin:
441+
# Wrap rsync command in a bash command
442+
bash_cmd = [
443+
"bash",
444+
"-c",
445+
# rsync command passed in as a single string
446+
" ".join(rsync_cmd),
447+
]
434448
result = subprocess.run(
435-
rsync_cmd,
436-
cwd=str(self._basepath),
449+
bash_cmd,
450+
cwd=self._basepath, # As-is Path is fine
437451
capture_output=True,
438452
input=rsync_stdin,
439453
)
@@ -443,15 +457,24 @@ def parse_stderr(line: str):
443457
parse_stderr(stderr_line)
444458
success = result.returncode == 0
445459

460+
# Remove files from source
446461
if rsync_stdin_remove:
462+
# Insert flag file removal flag before locations
447463
rsync_cmd.insert(-2, "--remove-source-files")
464+
# Wrap rsync command in a bash command
465+
bash_cmd = [
466+
"bash",
467+
"-c",
468+
# Pass rsync command as single string
469+
" ".join(rsync_cmd),
470+
]
448471
result = subprocess.run(
449472
rsync_cmd,
450473
cwd=str(self._basepath),
474+
capture_output=True,
451475
input=rsync_stdin_remove,
452476
)
453-
for stdout_line in result.stdout.decode("utf8", "replace").split("\n"):
454-
parse_stdout(stdout_line)
477+
# Only error log should be needed for file removal rsync process
455478
for stderr_line in result.stderr.decode("utf8", "replace").split("\n"):
456479
parse_stderr(stderr_line)
457480

0 commit comments

Comments
 (0)