| |
---|
| | |
---|
| | PROGNAME = "tren.py" |
---|
| | BASENAME = PROGNAME.split(".py")[0] |
---|
| | PROGENV = BASENAME.upper() |
---|
| | RCSID = "$Id: tren.py,v 1.146 2010/02/05 19:20:25 tundra Exp $" |
---|
| | RCSID = "$Id: tren.py,v 1.147 2010/02/05 21:13:07 tundra Exp $" |
---|
| | VERSION = RCSID.split()[2] |
---|
| | |
---|
| | # Copyright Information |
---|
| | |
---|
| |
---|
| | # Literals |
---|
| | ##### |
---|
| | |
---|
| | ALL = "All" # Rename target is whole filename |
---|
| | ARROW = "--->" # Used for formatting renaming messages |
---|
| | COMMENT = "#" # Comment character in include files |
---|
| | DEFEXT = "." # Default name/extension separator |
---|
| | DEFLEN = 80 # Default output line length |
---|
| | DEFSEP = "=" # Default rename command separator: old=new |
---|
| | DEFSUFFIX = ".backup" # String used to rename existing targets |
---|
| | ESC = "\\" # Escape character |
---|
| | EXT = "Ext" # Rename target is extension |
---|
| | INCL = "I" # Include file command line option |
---|
| | NAM = "Nam" # Rename target is name |
---|
| |
---|
| | |
---|
| | DEBUG = "DEBUG" |
---|
| | CASESENSITIVE = "CASESENSITIVE" |
---|
| | ERRORCONTINUE = "ERRORCONTINUE" |
---|
| | EXISTSUFFIX = "EXISTSUFFIX" |
---|
| | EXTDELIM = "EXTDELIM" |
---|
| | FORCERENAM = "FORCERENAM" |
---|
| | GLOBAL = "GLOBAL" |
---|
| | MAXLINELEN = "MAXLINELEN" |
---|
| |
---|
| | eTOOMANYINC = "Too many includes! (Max is %d) Possible circular reference?" % MAXINCLUDES |
---|
| | |
---|
| | |
---|
| | ##### |
---|
| | # Warning Messages |
---|
| | ##### |
---|
| | # Informational Messages |
---|
| | ##### |
---|
| | |
---|
| | iSKIPPING = "Skipping renaming of '%s' - Newname '%s' Exists!" |
---|
| | |
---|
| | |
---|
| | ##### |
---|
| | # Usage Prompts |
---|
| | ##### |
---|
| | |
---|
| | uTable = [PROGVER, |
---|
| | HOMEPAGE, |
---|
| | "usage: " + PROGNAME + " [-abCcdEefGghqtvwXx] [-I file] [-l string] [-r old=new]... file|dir file|dir ...", |
---|
| | "usage: " + PROGNAME + " [-abCcdEefGghqtvwXx] [-I file] [-l string] [-r old=new]... [-S suffix] file|dir file|dir ...", |
---|
| | " where,", |
---|
| | " -a Rename within the entire file or directory name (Default)", |
---|
| | " -C Do case-sensitive renaming (Default)", |
---|
| | " -c Collapse case when doing string substitution.", |
---|
| | " -c Collapse case when doing string substitution", |
---|
| | " -d Dump debugging information", |
---|
| | " -e Only perform renaming within extension portion of or directory name.", |
---|
| | " -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.", |
---|
| | " -f Force renaming even if target file or directory name already exists", |
---|
| | " -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", |
---|
| | " -h Print help information", |
---|
| | " -I file Include command line arguments from file", |
---|
| | " -l string File extension delimiter string. (Default: .)", |
---|
| | " -q Quiet mode, do not show progress.", |
---|
| | " -R rensep Separator string for -r rename arguments. (Default: =)", |
---|
| | " -r old=new Replace old with new in file or directory names.", |
---|
| | " -l string File extension delimiter string (Default: %s)" % DEFEXT, |
---|
| | " -q Quiet mode, do not show progress", |
---|
| | " -R rensep Separator string 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 exit.", |
---|
| | " -w Line length of diagnostic and error output (Default: 75)", |
---|
| | " -v Print detailed program version information and exit", |
---|
| | " -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", |
---|
| | ] |
---|
| | |
---|
| |
---|
| | |
---|
| | DEBUG : False, # Debugging off |
---|
| | CASESENSITIVE : True, # Search is case-sensitive |
---|
| | 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 |
---|
| | GLOBAL : False, # Only rename first instance of old string |
---|
| | MAXLINELEN : DEFLEN, # Width of output messages |
---|
| |
---|
| | # Now that we have a new name, attempt the actual renaming |
---|
| | # operation |
---|
| | |
---|
| | RenamingError = False |
---|
| | newname = pathname + basename |
---|
| | |
---|
| | # First make sure the new name meets length constraints |
---|
| | |
---|
| | if len(basename) < MINNAMELEN: |
---|
| |
---|
| | if len(basename) > MAXNAMELEN: |
---|
| | ErrorMsg(eNAMELONG % (target, basename, MAXNAMELEN), EXIT=not ProgramOptions[ERRORCONTINUE]) |
---|
| | RenamingError = True |
---|
| | |
---|
| | if not RenamingError: |
---|
| | print ColumnPad([target, pathname + basename], padwidth = 50) |
---|
| | if (target != newname) and not RenamingError: |
---|
| | |
---|
| | # Figure out if the newname already exists |
---|
| | |
---|
| | newexists = False |
---|
| | if os.path.exists(newname): |
---|
| | newexists = True |
---|
| | |
---|
| | # Just show what we would do |
---|
| | |
---|
| | if ProgramOptions[TESTMODE]: |
---|
| | |
---|
| | if newexists: |
---|
| | if ProgramOptions[FORCERENAM]: |
---|
| | |
---|
| | renameexisting = newname + ProgramOptions[EXISTSUFFIX] |
---|
| | InfoMsg(ColumnPad([newname + " %s " % ARROW, renameexisting]), TESTMODE) |
---|
| | |
---|
| | else: |
---|
| | |
---|
| | InfoMsg(iSKIPPING % (target, newname), TESTMODE) |
---|
| | |
---|
| | InfoMsg(ColumnPad([target + " %s " % ARROW, newname]), TESTMODE) |
---|
| | |
---|
| | # Actually do the renaming |
---|
| | else: |
---|
| | |
---|
| | print target + "---->"+ newname |
---|
| | |
---|
| | # End of 'Rename()' |
---|
| | |
---|
| | |
---|
| |
---|
| | ##### |
---|
| | # Turn A List Into Columns With Space Padding |
---|
| | ##### |
---|
| | |
---|
| | def ColumnPad(list, padchar=PADCHAR, padwidth=PADWIDTH): |
---|
| | def ColumnPad(list, PAD=PADCHAR, WIDTH=PADWIDTH): |
---|
| | |
---|
| | retval = "" |
---|
| | for l in list: |
---|
| | l = str(l) |
---|
| | retval += l + ((padwidth - len(l)) * padchar) |
---|
| | retval += l + ((WIDTH - len(l)) * PAD) |
---|
| | |
---|
| | return retval |
---|
| | |
---|
| | # End of 'ColumnPad()' |
---|
| |
---|
| | # Condition Line Length With Fancy Wrap And Formatting |
---|
| | ##### |
---|
| | |
---|
| | def ConditionLine(msg, |
---|
| | padchar=PADCHAR, \ |
---|
| | padwidth=PADWIDTH, \ |
---|
| | PAD=PADCHAR, \ |
---|
| | WIDTH=PADWIDTH, \ |
---|
| | wrapindent=WRAPINDENT ): |
---|
| | |
---|
| | retval = [] |
---|
| | retval.append(msg[:ProgramOptions[MAXLINELEN]]) |
---|
| | msg = msg[ProgramOptions[MAXLINELEN]:] |
---|
| | |
---|
| | while msg: |
---|
| | msg = padchar * (padwidth + wrapindent) + msg |
---|
| | msg = PAD * (WIDTH + wrapindent) + msg |
---|
| | retval.append(msg[:ProgramOptions[MAXLINELEN]]) |
---|
| | msg = msg[ProgramOptions[MAXLINELEN]:] |
---|
| | |
---|
| | return retval |
---|
| |
---|
| | |
---|
| | def DumpList(handler, msg, listname, content): |
---|
| | |
---|
| | handler(msg) |
---|
| | itemarrow = ColumnPad([listname, " "], padwidth=LSTPAD) |
---|
| | itemarrow = ColumnPad([listname, " "], WIDTH=LSTPAD) |
---|
| | handler(ColumnPad([" ", " %s %s" % (itemarrow, content)])) |
---|
| | |
---|
| | # End of 'DumpList()' |
---|
| | |
---|
| |
---|
| | # End of 'GetOldNew()' |
---|
| | |
---|
| | |
---|
| | ##### |
---|
| | # Print An Informational Message |
---|
| | ##### |
---|
| | |
---|
| | def InfoMsg(dmsg, msgtype): |
---|
| | |
---|
| | l = ConditionLine(dmsg) |
---|
| | |
---|
| | for dmsg in l: |
---|
| | PrintStdout(PROGNAME + " " + msgtype + ": " + dmsg) |
---|
| | |
---|
| | # End of 'InfoMsg()' |
---|
| | |
---|
| | |
---|
| | ##### |
---|
| | # Print To stderr |
---|
| | ##### |
---|
| | |
---|
| | def PrintStderr(msg, trailing="\n"): |
---|
| | sys.stderr.write(msg + trailing) |
---|
| | def PrintStderr(msg, TRAILING="\n"): |
---|
| | sys.stderr.write(msg + TRAILING) |
---|
| | |
---|
| | # End of 'PrintStderr()' |
---|
| | |
---|
| | |
---|
| | ##### |
---|
| | # Print To stdout |
---|
| | ##### |
---|
| | |
---|
| | def PrintStdout(msg, trailing="\n"): |
---|
| | sys.stdout.write(msg + trailing) |
---|
| | def PrintStdout(msg, TRAILING="\n"): |
---|
| | sys.stdout.write(msg + TRAILING) |
---|
| | |
---|
| | # End of 'PrintStdout' |
---|
| | |
---|
| | |
---|
| |
---|
| | |
---|
| | # And parse the command line |
---|
| | |
---|
| | try: |
---|
| | opts, args = getopt.getopt(OPTIONS, 'abbCcdEefGghl:qR:r:tvw:Xx]') |
---|
| | opts, args = getopt.getopt(OPTIONS, 'abbCcdEefGghl:qR:r:S:tvw:Xx]') |
---|
| | except getopt.GetoptError as e: |
---|
| | ErrorMsg(eBADARG % e.args[0], EXIT=True) |
---|
| | |
---|
| | # Create and populate an object with rename targets. This must be |
---|
| |
---|
| | req[OLD], req[NEW] = GetOldNew(val) |
---|
| | for opt in ProgramOptions: |
---|
| | req[opt] = ProgramOptions[opt] |
---|
| | targs.RenRequests.append(req) |
---|
| | |
---|
| | if opt == "-S": |
---|
| | ProgramOptions[EXISTSUFFIX] = val |
---|
| | |
---|
| | if opt == "-t": |
---|
| | ProgramOptions[TESTMODE] = True |
---|
| | |
---|
| |
---|
| | |