2021-05-15 00:53:04 +00:00
|
|
|
'''
|
|
|
|
bitwise_or
|
|
|
|
==========
|
|
|
|
|
|
|
|
Merge two or more files by performing bitwise or on their bits.
|
|
|
|
|
|
|
|
> bitwise_or file1 file2 --output file3
|
|
|
|
'''
|
|
|
|
import argparse
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
|
|
|
|
from voussoirkit import betterhelp
|
|
|
|
from voussoirkit import interactive
|
|
|
|
from voussoirkit import operatornotify
|
|
|
|
from voussoirkit import pathclass
|
|
|
|
from voussoirkit import pipeable
|
|
|
|
from voussoirkit import vlogging
|
|
|
|
from voussoirkit import winglob
|
|
|
|
|
|
|
|
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 = [file for pattern in patterns for file in winglob.glob(pattern)]
|
|
|
|
files = [pathclass.Path(file) for file in files]
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2021-05-25 08:34:06 +00:00
|
|
|
if any(output == file for file in files):
|
|
|
|
log.fatal('Output cannot be one of the inputs.')
|
|
|
|
return 1
|
|
|
|
|
2021-05-15 00:53:04 +00:00
|
|
|
if not output.exists:
|
|
|
|
pass
|
|
|
|
elif args.overwrite:
|
|
|
|
pass
|
|
|
|
elif not interactive.getpermission(f'Overwrite "{output.absolute_path}"?'):
|
|
|
|
return 1
|
|
|
|
|
2021-05-25 08:34:06 +00:00
|
|
|
handles = [file.open('rb') for file in files]
|
2021-05-15 00:53:04 +00:00
|
|
|
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)
|
|
|
|
|
2021-06-22 05:11:19 +00:00
|
|
|
@vlogging.main_decorator
|
2021-05-15 00:53:04 +00:00
|
|
|
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:]))
|