103 lines
3.4 KiB
Python
103 lines
3.4 KiB
Python
import argparse
|
|
import os
|
|
from os.path import relpath
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
from file_type import FileType
|
|
from search_file import search_file
|
|
|
|
class Link(FileType):
|
|
|
|
@classmethod
|
|
def fix(cls, ln_str, tgt_dir_str):
|
|
|
|
link = Path(ln_str)
|
|
tgt_dir = Path(tgt_dir_str)
|
|
|
|
try:
|
|
to_be_fixed = cls.get_file_type(link)
|
|
except Exception as e:
|
|
#print(f"Error: could not access link {ln_str}.")
|
|
sys.exit(f"Error: could not access link {ln_str}.")
|
|
|
|
if not tgt_dir.is_dir():
|
|
sys.exit(f"Error: target dir {tgt_dir} does not seem to exist or be a directory. Abort.")
|
|
|
|
match to_be_fixed:
|
|
case "file":
|
|
sys.exit(f"Error: link {ln_str} is not a link at all. Abort.")
|
|
case "symlink":
|
|
#print(f"Error: link {ln_str} is not broken. Abort.")
|
|
sys.exit(f"Error: link {ln_str} is not broken. Abort.")
|
|
case "broken-link":
|
|
try:
|
|
tgt = search_file(link.resolve().name, tgt_dir)
|
|
except Exception as e:
|
|
#print("No match for link reference filename in target directory.")
|
|
sys.exit("Error: no match for link target in {tgt_dir_str}")
|
|
cls._swap_link(link, tgt)
|
|
case "directory":
|
|
for root, dirs, files in os.walk(to_be_fixed):
|
|
for name in files:
|
|
if get_file_type(name) == "broken-link":
|
|
cls.link_fixer(name, tgt_dir_path)
|
|
|
|
@classmethod
|
|
def _swap_link(cls, lnk, tgt):
|
|
# relnk lnk to tgt as symlink, relative path
|
|
# assumes type verifications already made!
|
|
#lnk: symbolic link to swap, Path
|
|
#tgt: target for new link, Path
|
|
|
|
tpath = Path(tgt)
|
|
if tpath.is_symlink():
|
|
if not tpath.exists():
|
|
raise Exception("Target is also a broken link!")
|
|
elif tpath.readlink().resolve() == lnpath.resolve() :
|
|
raise Exception("Target is a link to link to be fixed...")
|
|
|
|
tmp_suffix = 0
|
|
tmp_prefix = 'temp'
|
|
tmp_name = tmp_prefix + str(tmp_suffix)
|
|
tmp_path = Path(lnk.parent / tmp_name)
|
|
while tmp_path.exists() or tmp_path.is_symlink():
|
|
tmp_suffix += 1
|
|
tmp_name = tmp_prefix + str(tmp_suffix)
|
|
tmp_path = Path(lnk.parent / tmp_name)
|
|
|
|
sym_path = relpath(tgt, lnk.resolve())[3:]
|
|
|
|
try:
|
|
tmp_path.symlink_to(sym_path)
|
|
except Exception as e:
|
|
print(f"Attempted to create tmp link: {tmp_name}")
|
|
#raise Exception("Failed to create new symlink. Check permissions!")
|
|
|
|
try:
|
|
lnk.unlink()
|
|
except Exception:
|
|
tmp_path.unlink()
|
|
#raise Exception("Failed to remove broken link. Check permissions!")
|
|
|
|
tmp_path.rename(lnk)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
parser = argparse.ArgumentParser(
|
|
description='''Fix broken symbolic links.
|
|
Search for file with same name as link in target dir.
|
|
Replace link to point to found file if any.
|
|
'''
|
|
)
|
|
parser.add_argument("link", type=str, help="Broken link, or directory with broken links")
|
|
parser.add_argument("tgt_path", type=str, help="Directory in which to find target(s)")
|
|
args = parser.parse_args()
|
|
|
|
link = args.link
|
|
tgt_dir = args.tgt_path
|
|
|
|
Link.fix(link, tgt_dir)
|
|
|