mirror of
https://codeberg.org/privacy1st/subprocess-util
synced 2025-01-11 00:36:05 +01:00
113 lines
3.7 KiB
Python
113 lines
3.7 KiB
Python
|
#!/usr/bin/env python3
|
||
|
# -*- coding: utf-8 -*-
|
||
|
import argparse
|
||
|
from pathlib import Path
|
||
|
import shlex
|
||
|
|
||
|
from exec_print_transfer import execute_print_transfer_chunks
|
||
|
from common import _get_chunk_file, _get_remote_socket
|
||
|
from transfer_inform import transfer_inform
|
||
|
|
||
|
|
||
|
def main():
|
||
|
args = parse_args()
|
||
|
|
||
|
command_parts = (
|
||
|
['btrfs', 'send'],
|
||
|
['-p', str(args.parent)] if args.parent else [],
|
||
|
['--compress-data'] if args.compressed_data else [],
|
||
|
[str(args.child)]
|
||
|
)
|
||
|
command = [x for xs in command_parts for x in xs]
|
||
|
|
||
|
execute_print_transfer_chunks(
|
||
|
command=command,
|
||
|
chunk_file_tmpl=args.chunk_tmpl,
|
||
|
chunk_transfer_fun=chunk_transfer_fun,
|
||
|
chunk_transfer_args=(args.ssh_target, args.target_path, args.chunk_tmpl),
|
||
|
chunk_size=args.chunk_size,
|
||
|
)
|
||
|
|
||
|
|
||
|
def parse_args():
|
||
|
parser = argparse.ArgumentParser(prog='btrfs-send-chunks')
|
||
|
|
||
|
parser.add_argument('-p',
|
||
|
help='Parent subvolume; forwarded to btrfs-send.',
|
||
|
dest='parent',
|
||
|
default=None,
|
||
|
type=Path,
|
||
|
metavar='PARENT_SUBVOLUME'
|
||
|
)
|
||
|
|
||
|
parser.add_argument('--compressed-data',
|
||
|
help='Forwarded to btrfs-send.',
|
||
|
dest='compressed_data',
|
||
|
action='store_true',
|
||
|
default=False,
|
||
|
)
|
||
|
|
||
|
parser.add_argument('--chunk-tmpl',
|
||
|
help='During btrfs-send, chunks are saved as "CHUNK_TMPL.CHUNK_NUMBER". '
|
||
|
'The default value of CHUNK_TMPL is "CHILD_SUBVOLUME.CHUNK". '
|
||
|
'One can change it to e.g. "/tmp/chunk/CHILD_SUBVOLUME".',
|
||
|
dest='chunk_tmpl',
|
||
|
default=None,
|
||
|
type=Path,
|
||
|
metavar='CHUNK_TMPL'
|
||
|
)
|
||
|
|
||
|
parser.add_argument('--chunk-size',
|
||
|
help='Size in bytes; defaults to 64 MB.',
|
||
|
dest='chunk_size',
|
||
|
type=int,
|
||
|
default=64 * 1024 * 1024,
|
||
|
)
|
||
|
|
||
|
parser.add_argument('child',
|
||
|
help='Forwarded to btrfs-send.',
|
||
|
type=Path,
|
||
|
metavar='CHILD_SUBVOLUME'
|
||
|
)
|
||
|
|
||
|
parser.add_argument('ssh_target',
|
||
|
help='Hostname of target computer; as configured in ~/.ssh/config.',
|
||
|
metavar='SSH_TARGET'
|
||
|
)
|
||
|
|
||
|
parser.add_argument('target_path',
|
||
|
help='Path where the subvolume will be created on the remote ssh target.',
|
||
|
type=Path,
|
||
|
metavar='TARGET_PATH'
|
||
|
)
|
||
|
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
if not args.chunk_tmpl:
|
||
|
child: Path = args.child
|
||
|
args.chunk_tmpl = child.parent.joinpath(f'{child.name}.CHUNK')
|
||
|
|
||
|
return args
|
||
|
|
||
|
|
||
|
def chunk_transfer_fun(chunk_file: Path, ct: int, eof: bool,
|
||
|
ssh_target: str,
|
||
|
target_path: Path,
|
||
|
chunk_tmpl: Path):
|
||
|
target_chunk = _get_chunk_file(chunk_tmpl, ct)
|
||
|
rsync_cmd = ['rsync', str(chunk_file), f'{ssh_target}:{str(target_chunk)}']
|
||
|
|
||
|
message = 'EOF' if eof else 'OK'
|
||
|
target_socket = _get_remote_socket(target_path)
|
||
|
inform_cmd = ['ssh', ssh_target, f'echo {message} | nc -U {shlex.quote(str(target_socket))}']
|
||
|
|
||
|
transfer_inform(
|
||
|
rsync_cmd=rsync_cmd,
|
||
|
inform_cmd=inform_cmd,
|
||
|
user_input_file=chunk_file.parent.joinpath(f'{chunk_file.name}.SOCKET'),
|
||
|
)
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|