Compare commits

...

2 Commits

Author SHA1 Message Date
e730ed5eb3 mirror source directory structure to dest
- remove dest files that do not exist in source
- copy new files
- implement dry run
2025-11-23 12:07:07 +00:00
391d7a3737 ignore pycharm files 2025-11-23 11:51:34 +00:00
2 changed files with 85 additions and 1 deletions

4
.gitignore vendored
View File

@ -1,4 +1,6 @@
# ---> Python
# pycharm
.idea/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]

82
cowcopy.py Normal file
View File

@ -0,0 +1,82 @@
import argparse
from pathlib import Path
SAFETY = 'jellyfin'
def get_args():
parser = argparse.ArgumentParser()
parser.add_argument('source', type=Path)
parser.add_argument('dest', type=Path)
parser.add_argument('--dry', help='Only output changes', action="store_true")
return parser.parse_args()
def main(source: Path, dest: Path, dry: bool):
remove_deleted_files(source, dest, dry)
create_new_links(source, dest, dry)
def remove_deleted_files(source: Path, dest: Path, dry: bool):
for file in dest.iterdir():
if file.is_dir():
original_dir = source / file.name
if original_dir.is_dir():
remove_deleted_files(original_dir, file, dry)
else:
remove_deleted_files(original_dir, file, dry)
if dry:
print(f"Remove directory: {file}")
else:
file.rmdir() # will fail if files have since been created
elif file.is_file():
original_file = source / file.name
if not original_file.exists() or original_file.is_dir():
if SAFETY not in str(file):
raise Exception("Deletion path does not include jellyfin")
if dry:
print(f"Remove file: {file}")
else:
file.unlink()
def create_new_links(source: Path, dest: Path, dry: bool):
for file in source.iterdir():
if file.is_dir():
new_dest = dest / file.name
if not new_dest.exists():
if dry:
print(f"Create directory: {new_dest}")
else:
new_dest.mkdir()
elif new_dest.exists() and not new_dest.is_dir():
raise Exception("Directory expected")
create_new_links(file, new_dest, dry)
elif file.is_file():
new_file = dest / file.name
if not new_file.exists():
if dry:
print(f"Create file: {new_file}")
else:
file.copy(new_file)
if __name__ == '__main__':
args = get_args()
source_directory = args.source
destination_directory = args.dest
dryrun = args.dry
if len(source_directory.parts) < 3 or len(destination_directory.parts) < 3:
raise Exception("Paths too short")
if dryrun:
print("Dry run - no changes will be made")
main(source_directory, destination_directory, dryrun)
if dryrun:
print("Dry run - no changes have been made")