cmd/bitwise_or.py

74 lines
2 KiB
Python

'''
bitwise_or
==========
Merge two or more files by performing bitwise or on their bits.
> bitwise_or file1 file2 --output file3
'''
import argparse
import sys
from voussoirkit import betterhelp
from voussoirkit import interactive
from voussoirkit import pathclass
from voussoirkit import pipeable
from voussoirkit import vlogging
log = vlogging.getLogger(__name__, 'bitwise_or')
CHUNK_SIZE = 2**20
def bitwise_or_argparse(args):
patterns = pipeable.input_many(args.files, skip_blank=True, strip=True)
files = list(pathclass.glob_many_files(patterns))
if len(files) < 2:
log.fatal('Need at least two input files.')
return 1
output = pathclass.Path(args.output)
if output.is_dir:
log.fatal('Output path "%s" is a directory.', args.output)
return 1
if any(output == file for file in files):
log.fatal('Output cannot be one of the inputs.')
return 1
if not output.exists:
pass
elif args.overwrite:
pass
elif not interactive.getpermission(f'Overwrite "{output.absolute_path}"?'):
return 1
handles = [file.open('rb') for file in files]
output_handle = output.open('wb')
while True:
chunk = 0
length = 1
for handle in handles[:]:
read = handle.read(CHUNK_SIZE)
length = max(length, len(read))
if not read:
handles.remove(handle)
chunk |= int.from_bytes(read, 'big')
if not handles:
break
output_handle.write(chunk.to_bytes(length, 'big'))
pipeable.stdout(output.absolute_path)
@vlogging.main_decorator
def main(argv):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('files', nargs='+')
parser.add_argument('--output', required=True)
parser.add_argument('--overwrite', action='store_true')
parser.set_defaults(func=bitwise_or_argparse)
return betterhelp.single_main(argv, parser, __doc__)
if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:]))