summaryrefslogtreecommitdiffstats
path: root/gamechestcli/gamechest/runners/download.py
diff options
context:
space:
mode:
Diffstat (limited to 'gamechestcli/gamechest/runners/download.py')
-rw-r--r--gamechestcli/gamechest/runners/download.py68
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')