Skip to content

Instantly share code, notes, and snippets.

@dzogrim
Created February 3, 2019 13:21
Show Gist options
  • Select an option

  • Save dzogrim/3124ed8a36cc9063d9df18e508befd6d to your computer and use it in GitHub Desktop.

Select an option

Save dzogrim/3124ed8a36cc9063d9df18e508befd6d to your computer and use it in GitHub Desktop.
Sort many versions of downloaded application directories and keep the latest version
#!/usr/bin/python3
# -*- coding: utf8 -*-
#-- Need installed `py37-setuptools` & `py37-pip`
import os, os.path
import re
import shutil
import sys
from collections import OrderedDict as ODict
try :
from pkg_resources import parse_version
except ImportError as e :
print( "Python{} package 'pkg_resources' is required! {}".format( sys.version_info.major, e ) )
sys.exit( 1 )
#--
LISTING = "/Volumes/BIG4TB/_TMP4"
DEST_DIR = "{}_LATEST".format( LISTING )
rxVersionParsers = (
re.compile( r'^(?P<appName>.+)v(?P<appVer>[0-9](?:[0-9\.-]+)?(.+)?)(?:\.(?:zip|rar|dmg))' ),
re.compile( r'^(?P<appName>.+)v(?P<appVer>[0-9](?:[0-9\.-]+)?(.+)?)' ),
re.compile( r'^(?P<appName>.+?)[\._\s-]+(?P<appVer>[0-9](?:[0-9\.-]+)?(.+)?)(?:\.(?:zip|rar|dmg))' ),
re.compile( r'^(?P<appName>.+?)[\._\s-]+(?P<appVer>[0-9](?:[0-9\.-]+)?(.+)?)' ),
re.compile( r'^(?P<appName>.+?)(?P<appVer>[0-9](?:[0-9\.-]+)?(.+)?)(?:\.(?:zip|rar|dmg))' ),
re.compile( r'^(?P<appName>.+?)(?P<appVer>[0-9](?:[0-9\.-]+)?(.+)?)' ),
)
rxCleanAppName = (
( re.compile( r'_' ), ' ' ),
( re.compile( r'[\[\]\s-]*$' ), '' ),
)
rxCleanAppVer = (
( re.compile( r'_' ), '.' ),
( re.compile( r'[\[\]\(\)-]+' ), '.' ),
( re.compile( r'[^\d\.]' ), '' ),
( re.compile( r'(?:^[\s\.]+|[\s\.]+$)' ), '' ),
( re.compile( r'\s+' ), '.' ),
( re.compile( r'\.{2,}' ), '.' ),
)
DRYRUN = True
def Print( text = None ) :
if DRYRUN :
text = '[DRYRUN] {}'.format( text )
#--
print( text )
#--
def process_listing( data = None ) :
if not data :
return {}
#--
appList = ODict()
for line in data :
appName = appVer = None
for rx in rxVersionParsers :
res = rx.search( line )
if res :
appName = res.group( 'appName' )
appVer = res.group( 'appVer' )
appVerNorm = appVer
for S, R in rxCleanAppName :
appName = S.sub( R, appName )
#--
for S, R in rxCleanAppVer :
appVerNorm = S.sub( R, appVerNorm )
#--
appNameNorm = appName.lower().replace( ' ', '' )
break
#--
#--
if not appName :
appName = line
appNameNorm = appName.lower().replace( ' ', '' )
appVer = appVerNorm = None
#--
if appNameNorm not in appList and appVer :
appList[ appNameNorm ] = dict( appName = appName, appDir = line, versions = list() )
#--
if appVer :
appList[ appNameNorm ][ 'versions' ].append( [ appVer, appVerNorm, line ] )
#--
#--
return appList
#--
def dispatch_listing( data = None ) :
if not data :
return
#--
if not DRYRUN :
try :
os.mkdir( DEST_DIR )
except FileExistsError :
pass
except Exception as e :
print( "Can not create directory '{}'! {}".format( DEST_DIR, e ) )
return 2
#--
#--
for app, info in data.items() :
versions = info[ 'versions' ]
src = os.path.join( LISTING, info[ 'appDir' ] )
if not versions :
Print( "\x1B[34;1m{}\x1B[0m have no version".format( info[ 'appName' ] ) )
elif len( info[ 'versions' ] ) < 2 :
Print( "\x1B[34;1m{}\x1B[0m is single version '\x1B[31;1m{}\x1B[0m'".format( info[ 'appName' ], versions[ 0 ][ 0 ] ) )
else :
Print( "\x1B[34;1m{}\x1B[0m multi versions '\x1B[31;1m{}\x1B[0m'".format( info[ 'appName' ], "\x1B[0m' '\x1B[31;1m".join( [ i[ 0 ] for i in versions ] ) ) )
bestVersion, otherVersions = versions[ 0 ], versions[ 1: ]
rc = os.path.join( LISTING, bestVersion[ 2 ] )
for aVer, nVer, aDir in otherVersions :
if parse_version( nVer ) > parse_version( bestVersion[ 1 ] ) :
bestVersion = [ aVer, nVer, aDir ]
src = os.path.join( LISTING, aDir )
#--
#--
Print( " => Best version : \x1B[32;1m{}\x1B[0m".format( bestVersion[ 0 ] ) )
#--
if not DRYRUN :
try :
shutil.move( src, DEST_DIR )
except Exception as e :
print( "Can not move '{}' to '{}'! {}".format( src, DEST_DIR, e ) )
return 2
#--
#--
#--
return 0
#--
def main() :
rc = 0
try :
data = os.listdir( LISTING )
except IOError as e :
print( "Can not open '{}'!: {}".format( LISTING, e ) )
rc = 1
else :
data.sort()
res = process_listing( data )
rc = dispatch_listing( res )
#--
return rc
#--
## =======================================================================
## :: Main ::
## =======================================================================
if __name__ == "__main__" :
if len( sys.argv ) > 1 and sys.argv[ 1 ] == 'APPLY' :
DRYRUN = False
#--
sys.exit( main() )
#--
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment