File: android-deltas-sync/_etc/find-all-symlinks.py (original) (raw)

#!/usr/bin/env python3 """

find-all-symlinks.py: an Android Deltas Sync utility

Runs on: any Python 3.X, and any host platform License: provided freely, but with no warranties of any kind Attrib: © M. Lutz (https://learning-python.com), Oct-2022

Synopsis: Locate and report all symlinks in the folder tree whose pathname is passed in as a sole argument (or in '.' if no argument is passed).

Though context dependent, symlinks may not survive trips to and from 
some platforms and filesystems (e.g., exFAT and Android).  This script
does not mod symlinks, but points them out as a portability caution.
Run manually as needed before propagating content with main scripts, 
and see **CAUTION** in ../x-export-phone-part1-phone.py for more info.

Coding: os.walk() does not step from a link into a folder when passed 
followlinks=False, which is its default.  To make this a more explicit 
option here, we pass True, and trim the subfolders list.  Even so, you
generally don't want to follow symlinks to folders/dirs; they can exit
the tree being scanned, visit folders more than once, and trigger loops.

Example output: ~$ python3 $Code/find-all-symlinks.py ~/MY-STUFF/ Scanning /Users/me/MY-STUFF ...

Visited 177249 files and 17690 folders in 2.09 seconds
Total symlinks found: 161
Display links' paths (y=yes)? n
Bye

Alternatives: You can get the same results from a Unix find command, where available:

~$ find ~/Desktop -type l -print 
...link paths here...
~$ find ~/Desktop -type l -print | wc -l
     153

But Python code is more portable, customizable, and fun:

~$ python3 $Code/find-all-symlinks.py ~/Desktop
Scanning /Users/me/Desktop ...

Visited 105728 files and 12732 folders in 2.65 seconds
Total symlinks found: 153
Display links' paths (y=yes)? y
Paths of links found:
 ...link paths here...
Bye

======================================================================================= """

CODE

import sys, os, time helpmsg = 'Usage: python3 find-all-symlinks.py [folderrootpath]'

trimdlinks = True # true = do not follow links to folders trace = lambda *args: None # print = display folder links skipped

get arg

if len(sys.argv) > 1 and sys.argv[1] in ('?', '-help', '--help'): print(helpmsg) sys.exit(1) elif len(sys.argv) < 2: root = os.path.abspath(os.getcwd()) else: root = os.path.abspath(sys.argv[1]) assert os.path.isdir(root), 'argument must be a folder path' if len(sys.argv) > 2: print('Extra arguments ignored')

walk folder tree

start = time.perf_counter() print('Scanning', root, '...')

linkpaths = [] numlinks = numfiles = numdirs = 0 walker = os.walk(root, followlinks=True)

for (thisdir, subshere, fileshere) in walker: # for all folders in tree numdirs += len(subshere) # symlinks in subs/fileshere numfiles += len(fileshere)

for name in subshere + fileshere:                   # for all subfolders and files
    path = os.path.join(thisdir, name)
    if os.path.islink(path):
        numlinks += 1
        linkpaths.append(path)

        if trimdlinks and name in subshere:         # skip links to dirs on walk
            subshere.remove(name)                   # else may exit tree, loop, etc
            trace(' Trimmed linked dir:', path)     # okay to mod: + made a copy

elapsed = time.perf_counter() - start print('\nVisited %d files and %d folders in %.2f seconds' % (numfiles, numdirs, elapsed)) print('Total symlinks found: %d' % numlinks)

if numlinks > 0 and input('Display links' paths (y=yes)? ').lower() in ['y', 'yes']: print('Paths of links found:') for path in sorted(linkpaths): print('', path)

print('Bye\n')