penguin/utils

my env utils

python/reg-rename.py

raw ยท 4163 bytes

#!/bin/env python3

import argparse, os, re, sys

# {{{ Argument Parsing
parser = argparse.ArgumentParser(
	description = "Tools for renaming files using regular expressions"
	, formatter_class = argparse.RawDescriptionHelpFormatter
	, epilog = """
  Example:
    %(prog)s -d ~/ -p "/(.+)_.+/" -s "\\1"

  Result:
    R ".mysql_history" will be renamed to ".mysql"
    R ".db_pass" will be renamed to ".db"
    R ".bash_logout" will be renamed to ".bash"
    R ".mysql_pass" will be renamed to ".mysql"
    R ".bash_history" will be renamed to ".bash"
"""
)

parser.add_argument( "-r", action = "store_true", help = "Rename files recursively" )
parser.add_argument( "-d", required = True, metavar = "dirs", nargs = "+", help = "Directories to look over" )
parser.add_argument( "-p", required = True, metavar = "patterns", nargs = "+" , help = "Include patterns")
parser.add_argument( "-s", required = True, metavar = "substitudes", nargs = "+", help = "Strings that will replace the matches" )
parser.add_argument( "-e", metavar = "patterns", nargs = "+", help = "Exclude patterns" )
parser.add_argument( "-t", action = "store_true", help = "Test without modifying anything" )
# End Argement Parsing }}}

args = parser.parse_args()

class ArgumentRequired( Exception ): pass
class InvalidArgument( Exception ): pass

class LevelLogger:
	lv = 0

	def __init__( self, level ):
		self.lv = level
		self.pad = "    " * level

	def log( self, mesg ):
		print( self.pad + mesg )

	def log_all( self, mesgs ):
		for mesg in mesgs:
			self.log( mesg )


class LoggerSpawner:

	lv = 0

	def __enter__( self ):
		self.lv = self.lv + 1
		return LevelLogger( self.lv )

	def __exit__( self, *args ):
		self.lv = self.lv - 1

class RAction:

	def __init__( self, root, _from, _to, exclude ):
		self.root = root
		self._from = _from
		self._to = _to
		self.exc = exclude

	def run( self, test ):
		root, _from, _to = self.root, self._from, self._to

		if self.exc:
			return "= Excluding \"%s\"" % _from

		if test:
			return "R \"%s\" will be renamed to \"%s\"" % ( _from, _to )
		else:
			os.rename( os.path.join( root, _from ), os.path.join( root, _to ) )
			return "R \"%s\" -> \"%s\"" % ( _from, _to )

class RegReplace:

	def __init__( self, includes, replacements, excludes, recursive ):
		self.logger = LoggerSpawner()
		self.recursive = recursive
		self.includes = includes
		self.excludes = excludes
		self.subs = replacements
		self.test = False

	def _exclude( self, k ):
		for ex in self.excludes:
			if ex.match( k ):
				return True
		return False

	def _compile_actions( self, root, files ):
		rlist = []
		for file_name in files:
			for i, p in enumerate( self.includes ):
				if p.match( file_name ):
					if self._exclude( file_name ):
						rlist.append( RAction( root, file_name, file_name, True ) )
					else:
						sub = self.subs[ i ]
						k = p.sub( sub, file_name )
						rlist.append( RAction( root, file_name, k, False ) )

		return rlist

	def searchDirs( self, path ):
		bb = "-\\|/"
		bb_i = 0
		for root, dirs, files in os.walk( path ):
			actions = self._compile_actions( root, files )

			sys.stdout.write( bb[ bb_i ] )
			sys.stdout.flush()
			sys.stdout.write( "\b" )
			bb_i = bb_i + 1
			if 3 < bb_i:
				bb_i = 0

			if actions:
				with self.logger as DirLogger:
					DirLogger.log( "In directory: \"%s\"" % root )

					with self.logger as ActionLogger:
						for action in actions:
							mesg = action.run( self.test )
							ActionLogger.log( mesg )

			if not self.recursive:
				break
		sys.stdout.write( " " )
		sys.stdout.flush()

def _compile_re( patterns ):
	_list = []

	if patterns:
		for p in patterns:

			if not ( p[0] == p[-1] == "/" ):
				raise InvalidArgument( p )

			_list.append( re.compile( p[ 1:-1 ] ) )

	return _list

try:
	includes = _compile_re( args.p )
	excludes = _compile_re( args.e )

	if not args.d:
		raise ArgumentRequired( "-d" )

	if args.t:
		print( "** Test Mode" )

	reg_replace = RegReplace( includes, args.s, excludes, args.r )
	reg_replace.test = args.t
	for _dir in args.d:
		reg_replace.searchDirs( _dir )

except InvalidArgument as ex:
	print( "Invalid argument: %s" % ex )
	sys.exit( 1 )