diff --git a/tren.py b/tren.py index cce69e5..69895f2 100755 --- a/tren.py +++ b/tren.py @@ -8,7 +8,7 @@ PROGNAME = "tren.py" BASENAME = PROGNAME.split(".py")[0] PROGENV = BASENAME.upper() -RCSID = "$Id: tren.py,v 1.152 2010/02/17 16:31:35 tundra Exp $" +RCSID = "$Id: tren.py,v 1.153 2010/02/17 20:07:53 tundra Exp $" VERSION = RCSID.split()[2] # Copyright Information @@ -107,7 +107,7 @@ ERRORCONTINUE = "ERRORCONTINUE" EXISTSUFFIX = "EXISTSUFFIX" EXTDELIM = "EXTDELIM" -FORCERENAM = "FORCERENAM" +FORCERENAME = "FORCERENAME" GLOBAL = "GLOBAL" MAXLINELEN = "MAXLINELEN" QUIET = "QUIET" @@ -178,7 +178,6 @@ eLINELEN = "Specified line length too short! Must be at least %s" % MINLEN eNAMELONG = "Renaming '%s' to new name '%s' too long! (Maximum length is %s.)" eNAMESHORT = "Renaming '%s' to new name '%s' too short! (Minimum length is %s.)" -eNOTHINGTODO = "Nothing to do!" eNULLARG = "%s cannot be empty!" eTOOMANYINC = "Too many includes! (Max is %d) Possible circular reference?" % MAXINCLUDES @@ -187,9 +186,10 @@ # Informational Messages ##### -iFORCEDREN = "Forced Rename:" -iRENAME = "Rename:" -iSKIPPING = "Target Exists, Rename Skipped:" +iNEWOLDSAME = "New Name '%s' Same As The Old Name. %s" +iNOTHINGTODO = "Nothing to do." +iRENFORCED = "Target '%s' Exists. Creating Backup." +iRENSKIPPED = "Target '%s' Exists. Renaming Of '%s' Skipped." ##### @@ -202,26 +202,26 @@ " where,", " -a Rename within the entire file or directory name (Default)", " -C Do case-sensitive renaming (Default)", - " -c Collapse case when doing string substitution", - " -d Dump debugging information", - " -e Only perform renaming within extension portion of or directory name", - " -E Continue renaming even after an error is encountered", - " -f Force renaming even if target file or directory name already exists", + " -c Collapse case when doing string substitution (Default: False)", + " -d Dump debugging information (Default: False)", + " -e Only perform renaming within extension portion of or directory name (Default: False)", + " -E Continue after an error is encountered (Default: False)", + " -f Force renaming even if target file or directory name already exists (Default: False)", " -G Rename only the first instance of the specified string (Default)", - " -g Replace all instances (global rename) of the old string with the new", - " -h Print help information", + " -g Replace all instances (global rename) of the old string with the new (Default: False)", + " -h Print help information (Default: False)", " -I file Include command line arguments from file", " -L string File extension delimiter string (Default: %s)" % DEFEXT, " -P char Use 'char' as the escape sequence (Default: %s)" % DEFESC, - " -q Quiet mode, do not show progress", + " -q Quiet mode, do not show progress (Default: False)", " -R char Separator character for -r rename arguments (Default: %s)" % DEFSEP, " -r old=new Replace old with new in file or directory names", " -S suffix Suffix to use when renaming existing filenames (Default: %s)" % DEFSUFFIX, - " -t Test mode, don't rename, just show what the program *would* do", - " -v Print detailed program version information and continue", + " -t Test mode, don't rename, just show what the program *would* do (Default: False)", + " -v Print detailed program version information and continue (Default: False)", " -w Line length of diagnostic and error output (Default: %s)" % DEFLEN, " -X Treat the renaming strings literally (Default)", - " -x Treat the old replacement string as a Python regular expression", + " -x Treat the old replacement string as a Python regular expression (Default: False)", ] #----------------------------------------------------------# @@ -240,7 +240,7 @@ ERRORCONTINUE : False, # Do not continue after error EXISTSUFFIX : DEFSUFFIX, # What to tack on when renaming existing targets EXTDELIM : DEFEXT, # Name/Extension delimiter - FORCERENAM : False, # Do not rename if target already exists + FORCERENAME : False, # Do not rename if target already exists GLOBAL : False, # Only rename first instance of old string MAXLINELEN : DEFLEN, # Width of output messages QUIET : False, # Display progress @@ -297,7 +297,7 @@ CASESENSITIVE : case sensitivity flag, ERRORCONTINUE : error continuation flag, EXTDELIM : name/Extension delimiter string, - FORCERENAM : force renaming flag, + FORCERENAME : force renaming flag, GLOBAL : global replace flag, MAXLINELEN : max output line length, QUIET : quiet output flag, @@ -451,21 +451,15 @@ def Rename(self): - - # Make sure we actually have work to do - - if not self.SortViews[ORDERBYCMDLINE] or not self.RenRequests: - - ErrorMsg(eNOTHINGTODO) - return - # Create a list of all renaming to be done. # This includes the renaming of any existing targets. - + renamelist = [] for target in self.SortViews[ORDERBYCMDLINE]: - basename, pathname = self.RenNames[target][BASE], self.RenNames[target][PATHNAME] + oldname, pathname = self.RenNames[target][BASE], self.RenNames[target][PATHNAME] + newname = oldname + for renrequest in self.RenRequests: old, new = self.ResolveRenameStrings(renrequest[OLD], renrequest[NEW]) @@ -478,11 +472,11 @@ # This means to *replace the entire* old name with new. if not old: - old = basename + old = oldname # Collapse case if requested - name = basename + name = oldname if not renrequest[CASESENSITIVE]: name = name.lower() @@ -509,14 +503,90 @@ oldstrings.reverse() for i in oldstrings: - basename = basename[:i] + new + basename[i + len(old):] + newname = newname[:i] + new + newname[i + len(old):] - # Now that we have a new name, attempt the actual renaming - # operation + # If the new name is different from the old one, add + # result to renaming table in the format: + # + # (path, old name, new name) - # First make sure the new name meets length constraints - RenamingError = False + if newname != oldname: + renamelist.append((pathname, oldname, newname)) + + else: + InfoMsg(iNEWOLDSAME % newname) + + # Make sure we actually have something to do + + if not renamelist: + + InfoMsg(iNOTHINGTODO) + return + + # Iterate over the list of renamings + + newnames = [] + for pathname, oldname, newname in renamelist: + + # Get names into absolute path form + + oldname = pathname + oldname + newname = pathname + newname + + # See if our proposed renaming is about to stomp on an + # existing file, and create a backup if forced renaming + # requested. + + # NOTE: We have to keep track of every new name produced. + # When running in test mode, this is the only way to know + # what *would* end up on the disk (in case a previous + # renaming operation creates a filename that is now in + # conflict with a subseqent renaming target. + + if (newname in newnames) or os.path.exists(newname): + + if ProgramOptions[FORCERENAME]: + + # Create the backup + + bkuname = newname + ProgramOptions[EXISTSUFFIX] + newnames.append(bkuname) + InfoMsg(iRENFORCED % newname) + self.RenameIt(newname, bkuname) + + # Rename the original + + newnames.append(newname) + self.RenameIt(oldname, newname) + + + else: + InfoMsg(iRENSKIPPED % (newname, oldname)) + + # No target conflict, just do the requested renaming + + else: + + newnames.append(newname) + self.RenameIt(oldname, newname) + + # End of 'Rename()' + + + ##### + # Actually Rename A File (Or Show What Would Happen) + ##### + + def RenameIt(self, oldname, newname): + return + + # End of 'RenameIt()' + + """ + # First make sure the new name meets length constraints + + RenamingError = False if len(basename) < MINNAMELEN: ErrorMsg(eNAMESHORT% (target, basename, MINNAMELEN), EXIT=not ProgramOptions[ERRORCONTINUE]) RenamingError = True @@ -525,48 +595,8 @@ ErrorMsg(eNAMELONG % (target, basename, MAXNAMELEN), EXIT=not ProgramOptions[ERRORCONTINUE]) RenamingError = True - newname = pathname + basename - if (target != newname) and not RenamingError: - renamejobs = [(target, newname)] - renaming = " %s %s %s %s" % (iRENAME, renamejobs[0][0], ARROW, renamejobs[0][1]) - - # Figure out if the newname already exists - - newexists = False - if os.path.exists(newname): - newexists = True - renameexisting = newname + ProgramOptions[EXISTSUFFIX] - renamejobs.append((newname, renameexisting)) - forcedren = " %s %s %s %s" % (iFORCEDREN, renamejobs[1][0], ARROW, renamejobs[1][1]) - skipping = " %s %s %s %s" % (iSKIPPING, renamejobs[0][0], ARROW, renamejobs[0][1]) - - # In test mode, just show what we would do - - if ProgramOptions[TESTMODE]: - - if newexists: - - # Forced renaming of existing targets - - if ProgramOptions[FORCERENAM]: - InfoMsg(forcedren, TESTMODE) - - # Skip renaming if target already exists - - else: - InfoMsg(skipping, TESTMODE) - - # Target does not exist or forced renaming is in effect, do the rename - - if not newexists or ProgramOptions[FORCERENAM]: - InfoMsg(renaming, TESTMODE) - - # Actually do the renaming - else: - print target + "---->"+ newname - - # End of 'Rename()' + """ ##### @@ -583,7 +613,7 @@ return [old, new] - # End of 'ReolveRenameStrings()' + # End of 'ResolveRenameStrings()' # End of class 'RenameTargets' @@ -682,7 +712,7 @@ ##### -# Print An Error Message +# Print An Error Message, Exiting Program As Required ##### def ErrorMsg(emsg, EXIT=False): @@ -692,7 +722,7 @@ for emsg in l: PrintStderr(PROGNAME + " " + eERROR + ": " + emsg) - if EXIT: + if EXIT or not ProgramOptions[ERRORCONTINUE]: sys.exit(1) # End of 'ErrorMsg()' @@ -742,12 +772,17 @@ # Print An Informational Message ##### -def InfoMsg(dmsg, msgtype): +def InfoMsg(imsg): - l = ConditionLine(dmsg) + l = ConditionLine(imsg) - for dmsg in l: - PrintStdout(PROGNAME + " " + msgtype + ": " + dmsg) + msgtype = "" + if ProgramOptions[TESTMODE]: + msgtype = TESTMODE + + if not ProgramOptions[QUIET]: + for dmsg in l: + PrintStdout(PROGNAME + " " + msgtype + ": " + imsg) # End of 'InfoMsg()' @@ -963,7 +998,7 @@ ProgramOptions[TARGET] = EXT if opt == "-f": - ProgramOptions[FORCERENAM] = True + ProgramOptions[FORCERENAME] = True if opt == "-G": ProgramOptions[GLOBAL] = False