diff options
Diffstat (limited to 'gamechestcli/gamechest/runners/download.py')
-rw-r--r-- | gamechestcli/gamechest/runners/download.py | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/gamechestcli/gamechest/runners/download.py b/gamechestcli/gamechest/runners/download.py new file mode 100644 index 0000000..0dfbd05 --- /dev/null +++ b/gamechestcli/gamechest/runners/download.py @@ -0,0 +1,68 @@ +import os +import re +import subprocess + +import humanfriendly + +from ..structures import Progress +from .runnerbase import RunnerBase, neutral_locale_variables + + +class Download(RunnerBase): + + _rsync_progress_re = re.compile(r'^\s*(\S+)\s+(\d+)%\s+(\S+)\s+(\S+)\s+$') + + def __init__(self, src, dst): + self.proc = subprocess.Popen( + [ + 'rsync', + '--partial', + # --no-h: not human, easier to parse (but speed still appears + # in human form). + '--no-h', + '--info=progress2', + src, + dst, + ], + stdout=subprocess.PIPE, + encoding='utf8', + env={**os.environ, + **neutral_locale_variables, + }, + ) + self.last_progress = Progress() + + def get_read_fd(self): + return self.proc.stdout + + def progress_read(self): + line = self.proc.stdout.readline() + if match := self._rsync_progress_re.search(line): + self.last_progress = Progress( + nbbytes=int(match.group(1)), + percent=int(match.group(2)), + speed=humanfriendly.parse_size(match.group(3), binary=True), + eta=match.group(4), + ) + return self.last_progress + + def terminate(self): + self.proc.terminate() + + def poll(self): + return self.proc.poll() + + def close(self): + self.proc.wait() + + +if __name__ == '__main__': + import sys + import contextlib + with contextlib.ExitStack() as stack: + stack.enter_context(contextlib.suppress(KeyboardInterrupt)) + runner = stack.enter_context(Download(sys.argv[1], sys.argv[2])) + while (rc := runner.poll()) is None: + print(runner.progress_read()) + print('runner ended with code:', rc) + print('test main ended') |