Added some comments
[flexiname.git] / renamer.py
blobddce918db1f5effe0f05ece72bc129b467e327db
1 #!/usr/bin/env python
2 # vim: et st=4 sts=4 ts=4:
4 # Batch file renamer
5 # Copyright (C) 2007 Sebastian Nowicki
6 #
7 # This program is free software; you can redistribute it and/or modify it under
8 # the terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
12 # This program is distributed in the hope that it will be useful, but WITHOUT
13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15 # details.
17 # You should have received a copy of the GNU General Public License along with
18 # this program; if not, write to the Free Software Foundation, Inc.,
19 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 import os, sys, string
22 from optparse import OptionParser
24 import re
26 class Action:
27 """Action holding a callback and arguments"""
28 def __init__(self):
29 self.callback = None
30 self.arguments = None
31 pass
33 def set_callback(self, callback):
34 self.callback = callback
36 def set_arguments(self, arguments):
37 self.arguments = arguments
39 def add_arguments(self, arguments):
40 self.arguments.update(arguments)
42 def execute(self):
43 if self.arguments:
44 return self.callback(**self.arguments)
45 else:
46 return self.callback()
49 class ActionContainer:
50 """Container for various actions"""
52 def __init__(self):
53 self.__actions = []
54 self.__count = 0
55 self.__index = 0
57 def __iter__(self):
58 return self
60 def __getitem__(self, index):
61 return self.__actions[index]
63 def __len__(self):
64 return self.__count
66 def next(self):
67 if self.__index == self.__count:
68 self.__index = 0
69 raise StopIteration
70 action = self.__actions[self.__index]
71 self.__index += 1
72 return action
74 def add(self, action):
75 self.__actions.append(action)
76 self.__count += 1
79 def regex_replace(**kwargs):
80 result = []
81 for source in sources:
82 result.append(re.sub(kwargs['pattern'], kwargs['replace'], source))
83 return result
85 def prefix(**kwargs):
86 result = []
87 for source in sources:
88 result.append(kwargs['prefix'] + source)
89 return result
91 def suffix(**kwargs):
92 result = []
93 for source in sources:
94 result.append(source + kwargs['suffix'])
95 return result
97 def case_title(**kwargs):
98 result = []
99 for source in sources:
100 result.append(source.title())
101 return result
103 def case_lower(**kwargs):
104 result = []
105 for source in sources:
106 result.append(source.lower())
107 return result
109 def case_upper(**kwargs):
110 result = []
111 for source in sources:
112 result.append(source.upper())
113 return result
115 def opts_add_action(option, opt_str, value, parser):
116 action = Action()
117 if opt_str == "-r":
118 action.set_callback(regex_replace)
119 action.set_arguments(dict(pattern=value[0], replace=value[1]))
120 elif opt_str == "-p":
121 action.set_callback(prefix)
122 action.set_arguments(dict(prefix=value))
123 elif opt_str == "-s":
124 action.set_callback(suffix)
125 action.set_arguments(dict(suffix=value))
126 elif opt_str == "-T":
127 action.set_callback(case_title)
128 elif opt_str == "-l":
129 action.set_callback(case_lower)
130 elif opt_str == "-u":
131 action.set_callback(case_upper)
132 actions.add(action)
134 if __name__ == "__main__":
135 VERSION = "0.2"
136 actions = ActionContainer()
137 sources = []
139 parser = OptionParser(usage="Usage: %prog [options] FILE ...",
140 version="%prog " + VERSION)
141 # Add case insensitivity option
142 parser.add_option("-i", "--case-insensitive",
143 action="store_true", dest="case_insensitive",
144 help="Filename case is disregarded when matching")
145 # Add regular expression options
146 parser.add_option("-r",
147 action="callback", callback=opts_add_action,
148 metavar="PATTERN REPLACE", type="string", nargs=2,
149 help="Search for PATTERN and replace with REPLACE")
150 # Prefix
151 parser.add_option("-p", "--prefix",
152 action="callback", callback=opts_add_action, metavar="STRING",
153 type="string", help="Prefix file names with STRING")
154 # Suffix
155 parser.add_option("-s", "--suffix",
156 action="callback", callback=opts_add_action, metavar="STRING",
157 type="string", help="Suffix file names with STRING")
158 # Title Case
159 parser.add_option("-T", "--title-case",
160 action="callback", callback=opts_add_action,
161 help="Title Case File Names Like This")
162 # Lower case
163 parser.add_option("-l", "--lower-case",
164 action="callback", callback=opts_add_action,
165 help="Make file names lower case")
166 # Upper case
167 parser.add_option("-u", "--upper-case",
168 action="callback", callback=opts_add_action,
169 help="Make file names upper case")
170 # Test only
171 parser.add_option("-t", "--test",
172 action="store_true", dest="test",
173 help="Do not rename, just show what would happen",)
174 # Verbose
175 parser.add_option("-v", "--verbose",
176 action="store_true", help="Be verbose", dest="verbose",)
177 # Parse command line arguments
178 options, args = parser.parse_args()
180 sources = args
182 if len(sys.argv) == 1:
183 parser.error("one or more FILEs are required")
184 sys.exit(1)
186 # mv functionality
187 elif len(args) == 2 and len(actions) == 0:
188 print "%s --> %s" % (sources[0], sources[1])
189 else:
190 for action in actions:
191 sources = action.execute()
193 if options.test:
194 for index in range(0, len(args)):
195 print "%s --> %s" % (args[index], sources[index])
196 else:
197 for index in range(0, len(args)):
198 if options.verbose:
199 print "%s --> %s" % (args[index], sources[index])
200 os.renames(args[index], sources[index])