1#!/usr/bin/env python3 2import argparse 3import os 4import shutil 5import sys 6 7def main(): 8 parser = argparse.ArgumentParser( 9 description="Given a list of directories, this script will copy the contents of all of " 10 "them into the first directory, erroring out if any duplicate files are found." 11 ) 12 parser.add_argument( 13 "--ignore-duplicates", 14 action="store_true", 15 help="Don't error out on duplicate files, just skip them. The file from the earliest " 16 "directory listed on the command line will be the winner." 17 ) 18 parser.add_argument( 19 "--file-list", 20 help="Path to a text file containing paths relative to in_dir. Only these paths will be " 21 "copied out of in_dir." 22 ) 23 parser.add_argument("out_dir") 24 parser.add_argument("in_dir") 25 args = parser.parse_args() 26 27 if not os.path.isdir(args.out_dir): 28 sys.exit(f"error: {args.out_dir} must be a directory") 29 if not os.path.isdir(args.in_dir): 30 sys.exit(f"error: {args.in_dir} must be a directory") 31 32 file_list = None 33 if args.file_list: 34 with open(file_list_file, "r") as f: 35 file_list = f.read().strip().splitlines() 36 37 in_dir = args.in_dir 38 for root, dirs, files in os.walk(in_dir): 39 rel_root = os.path.relpath(root, in_dir) 40 dst_root = os.path.join(args.out_dir, rel_root) 41 made_parent_dirs = False 42 for f in files: 43 src = os.path.join(root, f) 44 dst = os.path.join(dst_root, f) 45 p = os.path.normpath(os.path.join(rel_root, f)) 46 if file_list is not None and p not in file_list: 47 continue 48 if os.path.lexists(dst): 49 if args.ignore_duplicates: 50 continue 51 sys.exit(f"error: {p} exists in both {args.out_dir} and {in_dir}") 52 53 if not made_parent_dirs: 54 os.makedirs(dst_root, exist_ok=True) 55 made_parent_dirs = True 56 57 shutil.copy2(src, dst, follow_symlinks=False) 58 59if __name__ == "__main__": 60 main() 61