|
5 | 5 | import sys |
6 | 6 | import pwd |
7 | 7 | import shutil |
| 8 | +import pathlib |
8 | 9 |
|
9 | 10 | from typing import ( |
10 | 11 | Callable, |
@@ -321,8 +322,6 @@ def dereference_links() -> None: |
321 | 322 | update_progress(int((i + 1) / total_links * 100)) |
322 | 323 |
|
323 | 324 | def find_symlinks(path: str) -> List[List[str]]: |
324 | | - import pathlib |
325 | | - |
326 | 325 | links = [] |
327 | 326 | directory = pathlib.Path(path) |
328 | 327 | for item in directory.rglob("*"): |
@@ -408,8 +407,6 @@ def copy_folder_with_progress( |
408 | 407 | log(f"ignoring: {ignore}\nincluding anyway: {include_override}") |
409 | 408 |
|
410 | 409 | def traverse_folders(path: str) -> List[str]: |
411 | | - import pathlib |
412 | | - |
413 | 410 | allf = [] |
414 | 411 | directory = pathlib.Path(path) |
415 | 412 | for item in directory.rglob("*"): |
@@ -685,13 +682,29 @@ def flatpakrunner(): |
685 | 682 | if os.path.isfile(flatpakrunfile): |
686 | 683 | os.remove(flatpakrunfile) |
687 | 684 |
|
688 | | -# Safe symlink creation function |
689 | | -# Yeeted from: https://zetcode.com/python/os-symlink/ |
690 | | -def create_symlink(src, dst): |
691 | | - try: |
692 | | - os.symlink(src, dst) |
693 | | - except FileExistsError: |
694 | | - if os.path.islink(dst): |
695 | | - # Optionally update existing symlink |
696 | | - os.remove(dst) |
697 | | - os.symlink(src, dst) |
| 685 | +def create_symlink(src: Union[str, pathlib.Path], dst: Union[str, pathlib.Path], replace: Union[bool, None] = True) -> None: |
| 686 | + # Needs src, dest; replace can be True (replace all), None (replace only files and symlinks) or False (don't replace anything) |
| 687 | + src_path = pathlib.Path(src).resolve() |
| 688 | + dst_path = pathlib.Path(dst) |
| 689 | + |
| 690 | + if not src_path.exists(): |
| 691 | + raise FileNotFoundError(f"Source does not exist: {src_path}") |
| 692 | + |
| 693 | + if dst_path.lexists(): # Handle existing destination, still true on broken symlinks |
| 694 | + if dst_path.is_symlink(): |
| 695 | + if dst_path.resolve() == src_path: # Correct symlink – nothing to do |
| 696 | + return |
| 697 | + if replace is False: # Wrong target |
| 698 | + raise OSError(f"Symlink {dst_path} points to {dst_path.resolve()}, expected {src_path}") |
| 699 | + dst_path.unlink() # remove incorrect link |
| 700 | + else: |
| 701 | + if replace is False: |
| 702 | + raise OSError(f"{dst_path} exists and is not a symlink") |
| 703 | + elif dst_path.is_dir() and replace is None: |
| 704 | + raise OSError(f"{dst_path} exists and is not a file or symlink") |
| 705 | + if dst_path.is_dir(): |
| 706 | + shutil.rmtree(dst_path) # delete whole directory tree |
| 707 | + else: |
| 708 | + dst_path.unlink() # delete regular file |
| 709 | + |
| 710 | + os.symlink(src_path, dst_path) # Create link |
0 commit comments