penguin/utils

my env utils

commit 8a828cdf345dcd2ce7bd57a127ccd8f00c4f143e

author斟酌 鵬兄 <tgckpg@gmail.com>
date2017-12-01T05:15:37Z
subjectDeprecating php's regRename, migrating to python
commit 8a828cdf345dcd2ce7bd57a127ccd8f00c4f143e
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date:   2017-12-01T05:15:37Z

    Deprecating php's regRename, migrating to python
---
 php/astropenguin/botanical/RegRename.php | 225 -------------------------------
 php/regRename.php                        |  47 -------
 python/reg-rename.py                     | 168 +++++++++++++++++++++++
 3 files changed, 168 insertions(+), 272 deletions(-)

diff --git a/php/astropenguin/botanical/RegRename.php b/php/astropenguin/botanical/RegRename.php
deleted file mode 100644
index fbac369..0000000
--- a/php/astropenguin/botanical/RegRename.php
+++ /dev/null
@@ -1,225 +0,0 @@
-<?php
-
-namespace astropenguin\botanical;
-use DirectoryIterator;
-
-class RegRename
-{
-
-	//Define globals
-	private $test = false;
-	private $recursive = false;
-	private $searchDirs = array();
-	private $patterns = array();
-	private $replaceStrs = array();
-	private $excludes = array();
-
-	private $logfile = NULL;
-
-	public function begin()
-	{
-		$this->validateOptions();
-
-		//------- Begin Operations -------
-		foreach ( $this->searchDirs as $dir )
-		{
-			$this->elog("Directory: $dir\nBuilding file list ...");
-			if ( $this->recursive )
-			{
-				$fileList = $this->getWholeFileList($dir);
-			}
-			else
-			{
-				$fileList = $this->getFileList($dir);
-			}
-			$this->elog("Searching ...");
-			foreach ( $fileList as $file )
-			{
-				//
-				// Get the file name
-				// RegExplained:
-				// Example: /foo/bar/foobar.bar
-				//   $matches[0][0] is the whole string "/foo/bar/foobar.bar"
-				//
-				//   ^(.+?)
-				//   This gets the file path "/foo/bar/" for $matches[1][0]
-				//
-				//   ([^\/\\\\]+)$
-				//   This gets the file name "foobar.bar" for $matches[2][0]
-				//
-				preg_match_all('/^(.+?)([^\/\\\\]+)$/', $file, $matches );
-				$newName = $matches[2][0];
-				foreach ( $this->patterns as $key => $pattern )
-				{
-					//Rename over the patterns
-					$newName = preg_replace( $pattern, $this->replaceStrs[$key], $newName );
-				}
-
-				if( $matches[2][0] != $newName )
-				{
-
-					// Excluede any matches
-					foreach ( $this->excludes as $key => $pattern )
-					{
-						if(preg_match_all($pattern, $file))
-						{
-							$this->elog("S File \"{$matches[2][0]}\" excluded on $pattern");
-							continue 2;
-						}
-					}
-
-					if( $this->test )
-					{
-						$this->elog("R File \"{$matches[2][0]}\" will be renamed to \"$newName\"");
-					}
-					else
-					{
-						rename ( $file, "{$matches[1][0]}$newName" );
-					}
-
-					if( $this->logfile )
-					{
-						file_put_contents( $this->logfile, $this->log );
-					}
-				}
-				/*
-				else
-				{
-					echo "File \"{$matches[0][0]}\" will not be renamed\n";
-				}
-				//*/
-			}
-			$this->elog();
-		}
-		if ( $this->test ) $this->elog("*** Test enabled ***\n");
-		//------- End Operations -------*/
-	}
-
-	public function setOption( $item, $value = NULL )
-	{
-		switch($item)
-		{
-			case "-d":
-				if($value)
-				$this->searchDirs[] = $value;
-				break;
-			case "-p":
-				if($value)
-				$this->patterns[] = $value;
-				break;
-			case "-r":
-				$this->recursive = true;
-				break;
-			case "-s":
-				if($value)
-				$this->replaceStrs[] = $value;
-				break;
-			case "-t":
-				$this->test = true;
-				break;
-			case "-e":
-				$this->excludes[] = $value;
-				break;
-			case "-l":
-				$this->logfile = $value;
-				break;
-			default:
-				//Do nothing
-		}
-	}
-
-	//------- Main Functions --------
-
-	function elog( $line = "" )
-	{
-		$this->log .= $line;
-		$this->log .= "\n";
-		echo "$line\n";
-	}
-
-
-	private function getDirName ( $dir )
-	{
-		return is_dir ( $dir ) ? $dir : dirname ( $dir ) ;
-	}
-
-	private function getFileList ( $dir )
-	{
-		$fileList = array();
-		$iterator = new DirectoryIterator ( $this->getDirName ( $dir )  ) ;
-		foreach ( $iterator as $fileinfo )
-		{
-			if ( $fileinfo->isFile() )
-			{
-				$fileList[] = $dir."/".$fileinfo->getFilename();
-			}
-		}
-		return $fileList;
-	}
-
-	private function getDirList ( $dir )
-	{
-		$dirList = array();
-		$iterator = new DirectoryIterator ( $this->getDirName ( $dir ) );
-		foreach ( $iterator as $fileinfo )
-		{
-			if ( $fileinfo->isDir() && !$fileinfo->isDot())
-			{
-				$dirList[] = $fileinfo->getFilename();
-			}
-		}
-
-		return $dirList;
-	}
-
-	private function getWholeDirList ( $dir )
-	{
-		$wholeDirList = array();
-		//getWholeDirList will stop untill getDirList return an empty array.
-		foreach ( $this->getDirList ( $dir ) as $file )
-		{
-				//Store found path
-				$wholeDirList[] = "$dir/$file";
-				//Method getWholeDirList will self-iterate if sub-directories exist.
-				$wholeDirList = array_merge ( $wholeDirList, $this->getWholeDirList ( "$dir/$file" )  ) ;
-		}
-		return $wholeDirList;
-	}
-
-	private function getWholeFileList ( $dir )
-	{
-		//Get the first level list.
-		$wholeFileList = $this->getFileList( $dir );
-		//getWholeDirList and search its files.
-		foreach ( $this->getWholeDirList ( $dir ) as $dir )
-		{
-			$wholeFileList = array_merge ( $wholeFileList, $this->getFileList ( $dir )  ) ;
-		}
-		return $wholeFileList;
-	}
-
-	private function validateOptions (  )
-	{
-		try
-		{
-			if(count($this->searchDirs) == 0)
-			throw new \Exception("Search directory is missing");
-
-			else if(count($this->patterns) == 0)
-			throw new \Exception("Search pattern is missing");
-
-			else if(count($this->replaceStrs) == 0)
-			throw new \Exception("Replacement string is missing");
-
-			else if(count($this->replaceStrs) != count($this->patterns))
-			throw new \Exception("Replacement string and pattern count not match");
-		}
-		catch( \Exception $e )
-		{
-			var_dump( $GLOBALS );
-			die("Error: $e.\n");
-		}
-	}
-
-	//------- End Main Functions --------
-}
diff --git a/php/regRename.php b/php/regRename.php
deleted file mode 100644
index b402b78..0000000
--- a/php/regRename.php
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env php
-<?php
-error_reporting ( E_ALL^E_NOTICE ) ;
-require_once dirname( __FILE__ ) . '/astropenguin/package.php';
-
-use astropenguin\botanical\RegRename;
-use astropenguin\botanical\Args;
-
-
-//----------- Usage -----------
-
-if ( !$argv[1] ) 
-	die (<<<__USAGE__
-Usage: php {$argv[0]} [options] [-d directory] [-p patterns] [-s "first match" "second" ...] [...args]
-
-  -d <paths>	Directories to look over
-  -p <patterns>	Define RegEx patterns
-  -r		Rename file recursively
-  -s <str ...>	Strings that will replace the matches
-
-  Optional:
-	-e <patterns>	Exclude defined pattern
-	-l <File>	Output log file
-	-t		Test without modifying anything
-
-  Example:
-    php regRename.php -d ~/ -p "/(.+)_.+/" -s "\\1"
-
-    Result:
-      R File ".mysql_history" will be renamed to ".mysql"
-      R File ".db_pass" will be renamed to ".db"
-      R File ".bash_logout" will be renamed to ".bash"
-      R File ".mysql_pass" will be renamed to ".mysql"
-      R File ".bash_history" will be renamed to ".bash"
-
-    php regRename.php -d ~/ -p "/(.+)_.+/" -s "\\1"
-
-__USAGE__
-) ;
-
-//------- End Usage -----------
-
-$rrgr = new RegRename();
-Args::PARSE ( $argv, array($rrgr, 'setOption') );
-$rrgr->begin();
-
-
diff --git a/python/reg-rename.py b/python/reg-rename.py
new file mode 100644
index 0000000..033db0c
--- /dev/null
+++ b/python/reg-rename.py
@@ -0,0 +1,168 @@
+#!/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 )