blob: 3f8631bab27e70e46840b3edd19100b1531efbfe [file] [log] [blame]
Cole Faust4a2a7c92024-03-12 12:44:40 -07001#!/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()