All tests pass!
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
from os.path import relpath
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
from file_type import FileType
|
||||
from search_file import search_file
|
||||
@@ -11,6 +13,8 @@ class Link(FileType):
|
||||
|
||||
@classmethod
|
||||
def fix(cls, ln_str, tgt_dir_str):
|
||||
logging.captureWarnings(True)
|
||||
print()
|
||||
|
||||
link = Path(ln_str)
|
||||
tgt_dir = Path(tgt_dir_str)
|
||||
@@ -21,6 +25,7 @@ class Link(FileType):
|
||||
#print(f"Error: could not access link {ln_str}.")
|
||||
sys.exit(f"Error: could not access link {ln_str}.")
|
||||
|
||||
logging.debug(f"fix called on {ln_str}, determined type: {to_be_fixed}")
|
||||
if not tgt_dir.is_dir():
|
||||
sys.exit(f"Error: target dir {tgt_dir} does not seem to exist or be a directory. Abort.")
|
||||
|
||||
@@ -28,29 +33,40 @@ class Link(FileType):
|
||||
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":
|
||||
pointed = link.readlink().name
|
||||
try:
|
||||
tgt = search_file(link.resolve().name, tgt_dir)
|
||||
tgt = search_file(pointed, tgt_dir)
|
||||
logging.debug(f"Search for matching target {pointed} in {tgt_dir} returned {tgt}")
|
||||
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)
|
||||
warnings.warn(f"No match for link target in {tgt_dir_str}. Link {link} not modified.", Warning)
|
||||
return
|
||||
if tgt != "":
|
||||
cls._swap_link(link, tgt)
|
||||
else:
|
||||
warnings.warn(f"Reaching point at which link is to be fixed, but Variable {tgt} seems to be unset!", Warning)
|
||||
case "directory":
|
||||
for root, dirs, files in os.walk(to_be_fixed):
|
||||
logging.debug(f"Now walking through directory {tgt_dir} searching for broken links")
|
||||
for (root, dirs, files) in os.walk(link):
|
||||
for name in files:
|
||||
if get_file_type(name) == "broken-link":
|
||||
cls.link_fixer(name, tgt_dir_path)
|
||||
filetype = cls.get_file_type(root+"/"+name)
|
||||
logging.debug(f"Checking file {root}/{name}... type: {filetype}")
|
||||
if filetype == "broken-link":
|
||||
logging.info(f"Calling link fixer on {root+"/"+name} targeting {tgt_dir_str}")
|
||||
cls.fix(root+"/"+name, tgt_dir_str)
|
||||
|
||||
@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
|
||||
|
||||
#tgt: target for new link, str
|
||||
|
||||
tpath = Path(tgt)
|
||||
|
||||
logging.debug(f"Swapping {lnk.name} pointee from {lnk.resolve()} to {tgt}")
|
||||
|
||||
if tpath.is_symlink():
|
||||
if not tpath.exists():
|
||||
raise Exception("Target is also a broken link!")
|
||||
@@ -66,21 +82,29 @@ class Link(FileType):
|
||||
tmp_name = tmp_prefix + str(tmp_suffix)
|
||||
tmp_path = Path(lnk.parent / tmp_name)
|
||||
|
||||
sym_path = relpath(tgt, lnk.resolve())[3:]
|
||||
#sym_path = relpath(tgt, lnk.resolve())[3:]
|
||||
sym_path = str(tpath.relative_to(lnk, walk_up=True))[3:]
|
||||
logging.debug(f"symbolic path found: {sym_path}")
|
||||
|
||||
try:
|
||||
tmp_path.symlink_to(sym_path)
|
||||
except Exception as e:
|
||||
print(f"Attempted to create tmp link: {tmp_name}")
|
||||
logging.error(f"Attempted to create temporary link: {tmp_name} failed. Check permission. {lnk} not fixed.")
|
||||
#raise Exception("Failed to create new symlink. Check permissions!")
|
||||
return
|
||||
logging.debug(f"Temporary link created")
|
||||
|
||||
try:
|
||||
lnk.unlink()
|
||||
except Exception:
|
||||
logging.error(f"Failed to replace broken link. Check permissions.{lnk} not fixed.")
|
||||
tmp_path.unlink()
|
||||
#raise Exception("Failed to remove broken link. Check permissions!")
|
||||
return
|
||||
logging.debug("Broken link removed")
|
||||
|
||||
tmp_path.rename(lnk)
|
||||
logging.debug("Temporary link renamed to broken link's name")
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@@ -93,10 +117,17 @@ if __name__ == "__main__":
|
||||
)
|
||||
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)")
|
||||
parser.add_argument("-log", "--loglevel", default="warning", help="Set log level (debug, info, warning, error)")
|
||||
args = parser.parse_args()
|
||||
|
||||
link = args.link
|
||||
tgt_dir = args.tgt_path
|
||||
logger = logging.getLogger('linkfixer')
|
||||
logging.basicConfig(
|
||||
format = '%(asctime)s %(module)s %(levelname)s: %(message)s',
|
||||
level=args.loglevel.upper()
|
||||
)
|
||||
logging.debug(f"Log configuration set")
|
||||
|
||||
Link.fix(link, tgt_dir)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user