#!/usr/local/bin/python3 """ ================================================================= Mac OS Catalina locked down the '/' root, which breaks symlinks using absolute paths from former root-level folders, as well as content copiers that follow them (e.g., this site's PUBLISH.py). Run this on a folder tree to redirect all its root symlinks. © M.Lutz (learning-python.com) 2020, no warranties provided. Caveats: 1) This does not copy modtimes or permissions as is because they're irrelevant to the handful of links adjusted 2) Symlinks are notoriously platform specific; read more at: learning-python.com/ziptools/ziptools/_README.html#Platforms 3) Absolute symlinks won't usually work on external drives or other computers; use relative paths (e.g., '..') if possible Coding notes: this cannot just loop over fileshere: os.walk() doesn't return links to folders there; if [not followlinks], [fileshere + subshere] works, but os.listdir() works as well. Add an os.path.exists(oldlink) to detect/drop broken links. ================================================================= """ import sys, os assert len(sys.argv) == 2, "Please pass in a folder tree's path" folder = sys.argv # change these LISTONLY = True # True = show, but don't mod OLD_ROOT = '/MY-STUFF' # pre-catalina root-paths start NEW_ROOT = '/Users/me' # prepend this to old root paths nlinks = nfixes = 0 for (thisdir, subshere, fileshere) in os.walk(folder, followlinks=False): for item in os.listdir(thisdir): path = os.path.join(thisdir, item) if os.path.islink(path): nlinks += 1 oldlink = os.readlink(path) context = '%s => %s' % (path, oldlink) if not oldlink.startswith(OLD_ROOT): print('Non-root: ', context) elif LISTONLY: print('Unchanged: ', context) else: try: nfixes += 1 newlink = NEW_ROOT + oldlink os.remove(path) os.symlink(newlink, path) print('Redirected:', context) except: print('Cannot fix:', context) print('Links found:', nlinks) print('Links fixed:', nfixes) """ ================================================================= Example output: ~/MY-STUFF/Websites$ py3 fix-symlinks.py . Redirected: ./Posts/Current/_shrinkpix-info.txt => /MY-STUFF/Websites/_admin/Top-Level-Image-Shrinks-mar1020.txt Non-root: ./Posts/Current/TOOLS.txt => ../../Books/Current/TOOLS.txt ...etc... Redirected: ./OldMain/Current/_shrinkpix-info.txt => /MY-STUFF/Websites/_admin/Top-Level-Image-Shrinks-mar1020.txt Non-root: ./OldMain/Current/TOOLS.txt => ../../Books/Current/TOOLS.txt Non-root: ./OldMain/Current/Complete/_main.css => ../../../Books/Current/Complete/_main.css Links found: 20 Links fixed: 7 ~/MY-STUFF/Websites$ py3 fix-symlinks.py . Non-root: ./Posts/Current/_shrinkpix-info.txt => /Users/me/MY-STUFF/Websites/_admin/Top-Level-Image-Shrinks-mar1020.txt Non-root: ./Posts/Current/TOOLS.txt => ../../Books/Current/TOOLS.txt ..etc... Non-root: ./OldMain/Current/_shrinkpix-info.txt => /Users/me/MY-STUFF/Websites/_admin/Top-Level-Image-Shrinks-mar1020.txt Non-root: ./OldMain/Current/TOOLS.txt => ../../Books/Current/TOOLS.txt Non-root: ./OldMain/Current/Complete/_main.css => ../../../Books/Current/Complete/_main.css Links found: 20 Links fixed: 0 ================================================================= """