2021-09-07 03:15:03 +00:00
|
|
|
"""
|
|
|
|
A tree deduplicator and archiver tool.
|
|
|
|
"""
|
|
|
|
|
|
|
|
import argparse
|
2021-09-20 00:05:22 +00:00
|
|
|
from pathlib import Path
|
2021-09-07 03:54:12 +00:00
|
|
|
from shutil import copy2 as copyfile
|
2021-09-07 03:15:03 +00:00
|
|
|
|
2021-09-25 06:43:50 +00:00
|
|
|
from .util import *
|
2021-09-20 00:05:22 +00:00
|
|
|
|
2021-10-11 03:40:27 +00:00
|
|
|
|
2021-09-07 03:15:03 +00:00
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
parser.add_argument("from_dir", type=Path)
|
|
|
|
parser.add_argument("to_dir", type=Path)
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
opts, args = parser.parse_known_args()
|
|
|
|
|
|
|
|
for abs_src_path in opts.from_dir.glob("**/*"):
|
|
|
|
rel_src_path = abs_src_path.relative_to(opts.from_dir)
|
|
|
|
abs_dest_path = opts.to_dir / rel_src_path
|
|
|
|
|
|
|
|
if abs_src_path.is_dir():
|
|
|
|
print("dir", abs_src_path, "->", abs_dest_path)
|
|
|
|
abs_dest_path.mkdir(exist_ok=True)
|
|
|
|
|
|
|
|
elif abs_src_path.is_file():
|
|
|
|
print("file", abs_src_path, "->", abs_dest_path)
|
|
|
|
|
|
|
|
if not abs_dest_path.exists():
|
|
|
|
copyfile(abs_src_path, abs_dest_path)
|
|
|
|
|
|
|
|
else:
|
|
|
|
# If you trust mtime, this can go a lot faster
|
|
|
|
trust_mtime = False
|
|
|
|
|
2021-09-25 04:37:38 +00:00
|
|
|
if (
|
|
|
|
trust_mtime
|
|
|
|
and abs_dest_path.stat().st_mtime < abs_src_path.stat().st_mtime
|
|
|
|
):
|
|
|
|
pass
|
|
|
|
|
2021-09-25 06:43:50 +00:00
|
|
|
elif (src_checksum := checksum_path(abs_src_path)) != (
|
|
|
|
dest_checksum := checksum_path(abs_dest_path)
|
2021-09-25 04:37:38 +00:00
|
|
|
):
|
|
|
|
print(
|
|
|
|
f"file conflict (src {src_checksum}, dest {dest_checksum}), correcting..."
|
|
|
|
)
|
2021-09-07 03:15:03 +00:00
|
|
|
copyfile(abs_src_path, abs_dest_path)
|
|
|
|
|
|
|
|
abs_src_path.unlink()
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|