diff options
author | vg <vgm+dev@devys.org> | 2022-08-30 09:57:12 +0200 |
---|---|---|
committer | vg <vgm+dev@devys.org> | 2022-08-30 09:57:12 +0200 |
commit | 77c76b4e0407250fc0ba8ee0309a528a4a8f1f09 (patch) | |
tree | e07eced6c7a6fadbc5c12fb53ccd369c11674285 /gamechestcli/extract.py | |
parent | 7fe1ae0d26c3790ac81a0ee7b1bf01a383388575 (diff) | |
download | gamechest-77c76b4e0407250fc0ba8ee0309a528a4a8f1f09.tar.gz gamechest-77c76b4e0407250fc0ba8ee0309a528a4a8f1f09.tar.bz2 gamechest-77c76b4e0407250fc0ba8ee0309a528a4a8f1f09.zip |
git-sync on boo
Diffstat (limited to 'gamechestcli/extract.py')
-rw-r--r-- | gamechestcli/extract.py | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/gamechestcli/extract.py b/gamechestcli/extract.py new file mode 100644 index 0000000..2ac7fde --- /dev/null +++ b/gamechestcli/extract.py @@ -0,0 +1,109 @@ +#!/usr/bin/python3 + +import os +import re +import subprocess + +import humanfriendly + +from structures import Progress + +class Extract: + + _progress_re = re.compile(r'^\s*(\S+)\s+\[([^]]+)/s\]\s+ETA\s+(\S+)\s*$') + + def __init__(self, src, dst): + common_parameters = dict( + encoding='utf8', + env={**os.environ, + **{'LC_ALL':'C.UTF-8', + 'LANG':'C.UTF-8', + 'LANGUAGE':'C.UTF-8', + }}, + ) + self.src_size = os.stat(src).st_size + self.pv_proc = subprocess.Popen( + [ + 'pv', + '--force', + '--format', '%b %a %e', + src, + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + **common_parameters, + ) + lzip_command = '/usr/bin/lzip' + plzip_command = '/usr/bin/plzip' + lzip_command_to_use = lzip_command + if os.path.exists(plzip_command): + lzip_command_to_use = plzip_command + self.zip_proc = subprocess.Popen( + [ + lzip_command_to_use, + '--decompress', + ], + stdin=self.pv_proc.stdout, + stdout=subprocess.PIPE, + **common_parameters, + ) + self.tar_proc = subprocess.Popen( + [ + 'tar', + '-C', dst, + '-xf', '-' + ], + stdin=self.zip_proc.stdout, + **common_parameters, + ) + self.last_progress = Progress() + + def select_fd(self): + 'useful to use selectors with the process most meaningful fd' + return self.pv_proc.stderr + + def progress_read(self): + line = self.pv_proc.stderr.readline() + if match := self._progress_re.search(line): + written_bytes = humanfriendly.parse_size(match.group(1)) + self.last_progress = Progress( + written_bytes, + int(100 * written_bytes / self.src_size), + humanfriendly.parse_size(match.group(2)), + match.group(3), + ) + return self.last_progress + + def terminate(self): + for proc in (self.pv_proc, self.zip_proc, self.tar_proc): + proc.terminate() + + def poll(self): + 'returns None if not terminated, otherwise return returncode' + return self.tar_proc.poll() + + def wait(self, timeout=None): + self.pv_proc.wait(timeout) + self.zip_proc.wait(timeout) + return self.tar_proc.wait(timeout) + + def __enter__(self): + return self + + def __exit__(self, exc_type, value, traceback): + self.terminate() + self.wait() + + +if __name__ == '__main__': + import sys + import contextlib + with contextlib.suppress(KeyboardInterrupt): + with Extract(sys.argv[1], sys.argv[2]) as extract: + while extract.poll() is None: + progress = extract.progress_read() + print(f'{progress.bytes}b {progress.percent}% ' + f'{progress.speed}b/s {progress.eta}') + rc = extract.poll() + print(f'ended with code: {rc}') + print('test main ended') |