Mercurial > gcp
comparison gcp @ 5:7edbb0e0d9dd
gettext inclusion & French translation
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 27 Sep 2010 13:09:42 +0800 |
parents | 9feb82bd91aa |
children | 5f53dc5beec9 |
comparison
equal
deleted
inserted
replaced
4:9feb82bd91aa | 5:7edbb0e0d9dd |
---|---|
23 import logging | 23 import logging |
24 from logging import debug, info, error, warning | 24 from logging import debug, info, error, warning |
25 logging.basicConfig(level=logging.INFO, | 25 logging.basicConfig(level=logging.INFO, |
26 format='%(message)s') | 26 format='%(message)s') |
27 ### | 27 ### |
28 | |
29 import gettext | |
30 gettext.install('gcp', "i18n", unicode=True) | |
31 | |
28 import sys | 32 import sys |
29 import os,os.path | 33 import os,os.path |
30 from optparse import OptionParser #To be replaced by argparse ASAP | 34 from optparse import OptionParser #To be replaced by argparse ASAP |
31 import cPickle as pickle | 35 import cPickle as pickle |
32 try: | 36 try: |
34 #DBus | 38 #DBus |
35 import dbus, dbus.glib | 39 import dbus, dbus.glib |
36 import dbus.service | 40 import dbus.service |
37 import dbus.mainloop.glib | 41 import dbus.mainloop.glib |
38 except ImportError,e: | 42 except ImportError,e: |
39 error("Error during import") | 43 error(_("Error during import")) |
40 error("Please check dependecies:",e) | 44 error(_("Please check dependecies:"),e) |
41 exit(2) | 45 exit(2) |
42 try: | 46 try: |
43 from progressbar import ProgressBar, Percentage, Bar, ETA, FileTransferSpeed | 47 from progressbar import ProgressBar, Percentage, Bar, ETA, FileTransferSpeed |
44 pbar_available=True | 48 pbar_available=True |
45 except ImportError, e: | 49 except ImportError, e: |
46 info ('ProgressBar not available, please download it at http://pypi.python.org/pypi/progressbar') | 50 info (_('ProgressBar not available, please download it at http://pypi.python.org/pypi/progressbar')) |
47 info ('Progress bar deactivated\n--\n') | 51 info (_('Progress bar deactivated\n--\n')) |
48 pbar_available=False | 52 pbar_available=False |
49 | 53 |
50 NAME = "gcp (Goffi's copier)" | 54 NAME = "gcp (Goffi's copier)" |
51 NAME_SHORT = "gcp" | 55 NAME_SHORT = "gcp" |
52 VERSION = '0.1' | 56 VERSION = '0.1' |
53 | 57 |
54 ABOUT = NAME+" v"+VERSION+""" (c) Jérôme Poisson (aka Goffi) 2010 | 58 ABOUT = NAME+u" v"+VERSION+u""" (c) Jérôme Poisson (aka Goffi) 2010 |
55 | 59 |
56 --- | 60 --- |
57 """+NAME+""" Copyright (C) 2010 Jérôme Poisson | 61 """+NAME+u""" Copyright (C) 2010 Jérôme Poisson |
58 This program comes with ABSOLUTELY NO WARRANTY; | 62 """ + _(u"""This program comes with ABSOLUTELY NO WARRANTY; |
59 This is free software, and you are welcome to redistribute it | 63 This is free software, and you are welcome to redistribute it |
60 under certain conditions. | 64 under certain conditions. |
61 --- | 65 --- |
62 | 66 |
63 This software is an advanced file copier | 67 This software is an advanced file copier |
64 Get the latest version at http://www.goffi.org | 68 Get the latest version at http://www.goffi.org |
65 """ | 69 """) |
66 | 70 |
67 const_DBUS_INTERFACE = "org.goffi.gcp" | 71 const_DBUS_INTERFACE = "org.goffi.gcp" |
68 const_DBUS_PATH = "/org/goffi/gcp" | 72 const_DBUS_PATH = "/org/goffi/gcp" |
69 const_BUFF_SIZE = 4096 | 73 const_BUFF_SIZE = 4096 |
70 const_PRESERVE = set(['mode','ownership','timestamps']) | 74 const_PRESERVE = set(['mode','ownership','timestamps']) |
73 class DbusObject(dbus.service.Object): | 77 class DbusObject(dbus.service.Object): |
74 | 78 |
75 def __init__(self, gcp, bus, path): | 79 def __init__(self, gcp, bus, path): |
76 self._gcp = gcp | 80 self._gcp = gcp |
77 dbus.service.Object.__init__(self, bus, path) | 81 dbus.service.Object.__init__(self, bus, path) |
78 debug("Init DbusObject...") | 82 debug(_("Init DbusObject...")) |
79 self.cb={} | 83 self.cb={} |
80 | 84 |
81 @dbus.service.method(const_DBUS_INTERFACE, | 85 @dbus.service.method(const_DBUS_INTERFACE, |
82 in_signature='', out_signature='s') | 86 in_signature='', out_signature='s') |
83 def getVersion(self): | 87 def getVersion(self): |
93 @param args: serialized (wich pickle) list of strings - without command name -, as given by sys.argv[1:]. | 97 @param args: serialized (wich pickle) list of strings - without command name -, as given by sys.argv[1:]. |
94 @return: success (boolean) and error message if any (string)""" | 98 @return: success (boolean) and error message if any (string)""" |
95 try: | 99 try: |
96 args = pickle.loads(str(args)) | 100 args = pickle.loads(str(args)) |
97 except TypeError, pickle.UnpicklingError: | 101 except TypeError, pickle.UnpicklingError: |
98 return (False, "INTERNAL ERROR: invalid arguments") | 102 return (False, _("INTERNAL ERROR: invalid arguments")) |
99 return self._gcp.parseArguments(args, source_path) | 103 return self._gcp.parseArguments(args, source_path) |
100 | 104 |
101 class GCP(): | 105 class GCP(): |
102 | 106 |
103 def __init__(self): | 107 def __init__(self): |
110 self._main_instance = False | 114 self._main_instance = False |
111 | 115 |
112 except dbus.exceptions.DBusException,e: | 116 except dbus.exceptions.DBusException,e: |
113 if e._dbus_error_name=='org.freedesktop.DBus.Error.ServiceUnknown': | 117 if e._dbus_error_name=='org.freedesktop.DBus.Error.ServiceUnknown': |
114 self.launchDbusMainInstance() | 118 self.launchDbusMainInstance() |
115 debug ("gcp launched") | 119 debug (_("gcp launched")) |
116 self._main_instance = True | 120 self._main_instance = True |
117 self.buffer_size = const_BUFF_SIZE | 121 self.buffer_size = const_BUFF_SIZE |
118 else: | 122 else: |
119 raise e | 123 raise e |
120 | 124 |
121 def launchDbusMainInstance(self): | 125 def launchDbusMainInstance(self): |
122 debug ("Init DBus...") | 126 debug (_("Init DBus...")) |
123 session_bus = dbus.SessionBus() | 127 session_bus = dbus.SessionBus() |
124 self.dbus_name = dbus.service.BusName(const_DBUS_INTERFACE, session_bus) | 128 self.dbus_name = dbus.service.BusName(const_DBUS_INTERFACE, session_bus) |
125 self.dbus_object = DbusObject(self, session_bus, const_DBUS_PATH) | 129 self.dbus_object = DbusObject(self, session_bus, const_DBUS_PATH) |
126 | 130 |
127 self.copy_list = [] | 131 self.copy_list = [] |
146 with open("/proc/mounts",'rb') as mounts: | 150 with open("/proc/mounts",'rb') as mounts: |
147 for line in mounts.readlines(): | 151 for line in mounts.readlines(): |
148 fs_spec, fs_file, fs_vfstype, fs_mntops, fs_freq, fs_passno = line.split(' ') | 152 fs_spec, fs_file, fs_vfstype, fs_mntops, fs_freq, fs_passno = line.split(' ') |
149 ret[fs_file] = fs_vfstype | 153 ret[fs_file] = fs_vfstype |
150 except: | 154 except: |
151 error ("Can't read mounts table") | 155 error (_("Can't read mounts table")) |
152 return ret | 156 return ret |
153 | 157 |
154 def __appendToList(self, path, dest_path, options): | 158 def __appendToList(self, path, dest_path, options): |
155 """Add a file to the copy list | 159 """Add a file to the copy list |
156 @param path: absolute path of file | 160 @param path: absolute path of file |
157 @param options: options as return by optparse""" | 161 @param options: options as return by optparse""" |
158 debug ("Adding to copy list: %s ==> %s (%s)", path, dest_path, self.getFsType(dest_path)) | 162 debug (_("Adding to copy list: %(path)s ==> %(dest_path)s (%(fs_type)s)") % {"path":path, |
163 "dest_path":dest_path, | |
164 "fs_type":self.getFsType(dest_path)} ) | |
159 try: | 165 try: |
160 self.bytes_total+=os.path.getsize(path) | 166 self.bytes_total+=os.path.getsize(path) |
161 self.files_left+=1 | 167 self.files_left+=1 |
162 self.copy_list.insert(0,(path, dest_path, options)) | 168 self.copy_list.insert(0,(path, dest_path, options)) |
163 except OSError,e: | 169 except OSError,e: |
164 error("Can't copy %(path)s: %(exception)s" % {'path':path, 'exception':e.strerror}) | 170 error(_("Can't copy %(path)s: %(exception)s") % {'path':path, 'exception':e.strerror}) |
165 | 171 |
166 | 172 |
167 def __appendDirToList(self, dirpath, dest_path, options): | 173 def __appendDirToList(self, dirpath, dest_path, options): |
168 """Add recursively directory to the copy list | 174 """Add recursively directory to the copy list |
169 @param path: absolute path of dir | 175 @param path: absolute path of dir |
170 @param options: options as return by optparse""" | 176 @param options: options as return by optparse""" |
171 #We first check that the dest path exists, and create it if needed | 177 #We first check that the dest path exists, and create it if needed |
172 if not os.path.exists(dest_path): | 178 if not os.path.exists(dest_path): |
173 debug ("Creating directory %s" % dest_path) | 179 debug (_("Creating directory %s") % dest_path) |
174 os.makedirs(dest_path) #TODO: check permissions | 180 os.makedirs(dest_path) #TODO: check permissions |
175 #TODO: check that dest_path is an accessible dir, | 181 #TODO: check that dest_path is an accessible dir, |
176 # and skip file/write error in log if needed | 182 # and skip file/write error in log if needed |
177 try: | 183 try: |
178 for filename in os.listdir(dirpath): | 184 for filename in os.listdir(dirpath): |
181 full_dest_path = os.path.join(dest_path,filename) | 187 full_dest_path = os.path.join(dest_path,filename) |
182 self.__appendDirToList(filepath, full_dest_path, options) | 188 self.__appendDirToList(filepath, full_dest_path, options) |
183 else: | 189 else: |
184 self.__appendToList(filepath, dest_path, options) | 190 self.__appendToList(filepath, dest_path, options) |
185 except OSError,e: | 191 except OSError,e: |
186 error("Can't copy %(path)s: %(exception)s" % {'path':dirpath, 'exception':e.strerror}) | 192 error(_("Can't copy %(path)s: %(exception)s") % {'path':dirpath, 'exception':e.strerror}) |
187 | 193 |
188 def __checkArgs(self, options, source_path, args): | 194 def __checkArgs(self, options, source_path, args): |
189 """Check thats args are files, and add them to copy list""" | 195 """Check thats args are files, and add them to copy list""" |
190 assert(len (args)>=2) | 196 assert(len (args)>=2) |
191 try: | 197 try: |
192 dest_path = os.path.normpath(os.path.join(os.path.expanduser(source_path), args.pop())) | 198 dest_path = os.path.normpath(os.path.join(os.path.expanduser(source_path), args.pop())) |
193 except OSError,e: | 199 except OSError,e: |
194 error ("Invalid dest_path: %s",e) | 200 error (_("Invalid dest_path: %s"),e) |
195 | 201 |
196 for path in args: | 202 for path in args: |
197 abspath = os.path.normpath(os.path.join(os.path.expanduser(source_path), path)) | 203 abspath = os.path.normpath(os.path.join(os.path.expanduser(source_path), path)) |
198 if not os.path.exists(abspath): | 204 if not os.path.exists(abspath): |
199 warning("The path given in arg doesn't exist or is not accessible: %s",abspath) | 205 warning(_("The path given in arg doesn't exist or is not accessible: %s") % abspath) |
200 else: | 206 else: |
201 if os.path.isdir(abspath): | 207 if os.path.isdir(abspath): |
202 full_dest_path = dest_path if os.path.isabs(path) else os.path.normpath(os.path.join(dest_path, path)) | 208 full_dest_path = dest_path if os.path.isabs(path) else os.path.normpath(os.path.join(dest_path, path)) |
203 if not options.recursive: | 209 if not options.recursive: |
204 warning ('omitting directory "%s"' % abspath) | 210 warning (_('omitting directory "%s"') % abspath) |
205 else: | 211 else: |
206 self.__appendDirToList(abspath, full_dest_path, options) | 212 self.__appendDirToList(abspath, full_dest_path, options) |
207 else: | 213 else: |
208 self.__appendToList(abspath, dest_path, options) | 214 self.__appendToList(abspath, dest_path, options) |
209 | 215 |
215 source_fd = open(source_file, 'rb') | 221 source_fd = open(source_file, 'rb') |
216 filename = os.path.basename(source_file) | 222 filename = os.path.basename(source_file) |
217 assert(filename) | 223 assert(filename) |
218 dest_file = os.path.join(dest_path,filename) | 224 dest_file = os.path.join(dest_path,filename) |
219 if os.path.exists(dest_file) and not options.force: | 225 if os.path.exists(dest_file) and not options.force: |
220 warning ("File [%s] already exists, skipping it !" % dest_file) | 226 warning (_("File [%s] already exists, skipping it !") % dest_file) |
221 return True | 227 return True |
222 dest_fd = open(dest_file, 'wb') | 228 dest_fd = open(dest_file, 'wb') |
223 | 229 |
224 gobject.io_add_watch(source_fd,gobject.IO_IN,self._copyFile, | 230 gobject.io_add_watch(source_fd,gobject.IO_IN,self._copyFile, |
225 (dest_fd, options), priority=gobject.PRIORITY_HIGH) | 231 (dest_fd, options), priority=gobject.PRIORITY_HIGH) |
226 if not self.progress: | 232 if not self.progress: |
227 info("COPYING %(source)s ==> %(dest)s" % {"source":source_path,"dest":dest_file}) | 233 info(_("COPYING %(source)s ==> %(dest)s") % {"source":source_path,"dest":dest_file}) |
228 return True | 234 return True |
229 else: | 235 else: |
230 #Nothing left to copy, we quit | 236 #Nothing left to copy, we quit |
231 if self.progress: | 237 if self.progress: |
232 self.__pbar_finish() | 238 self.__pbar_finish() |
273 assert(self.progress) | 279 assert(self.progress) |
274 try: | 280 try: |
275 if self.pbar.maxval != self.bytes_total: | 281 if self.pbar.maxval != self.bytes_total: |
276 self.pbar.maxval = self.bytes_total | 282 self.pbar.maxval = self.bytes_total |
277 except AttributeError: | 283 except AttributeError: |
278 self.pbar = ProgressBar(self.bytes_total,["Progress: ",Percentage()," ",Bar()," ",FileTransferSpeed()," ",ETA()]) | 284 self.pbar = ProgressBar(self.bytes_total,[_("Progress: "),Percentage()," ",Bar()," ",FileTransferSpeed()," ",ETA()]) |
279 self.pbar.start() | 285 self.pbar.start() |
280 self.pbar.update(self.bytes_copied) | 286 self.pbar.update(self.bytes_copied) |
281 | 287 |
282 def __pbar_finish(self): | 288 def __pbar_finish(self): |
283 """Mark the progression as finished""" | 289 """Mark the progression as finished""" |
304 full_args[idx] = full_args[idx].encode('utf-8') | 310 full_args[idx] = full_args[idx].encode('utf-8') |
305 | 311 |
306 parser = OptionParser(usage=_usage,version=ABOUT) | 312 parser = OptionParser(usage=_usage,version=ABOUT) |
307 | 313 |
308 parser.add_option("-r", "--recursive", action="store_true", default=False, | 314 parser.add_option("-r", "--recursive", action="store_true", default=False, |
309 help="copy directories recursively") | 315 help=_("copy directories recursively")) |
310 | 316 |
311 parser.add_option("-f", "--force", action="store_true", default=False, | 317 parser.add_option("-f", "--force", action="store_true", default=False, |
312 help="force overwriting of existing files") | 318 help=_("force overwriting of existing files")) |
313 | 319 |
314 parser.add_option("--preserve", action="store", default='mode,ownership,timestamps', | 320 parser.add_option("--preserve", action="store", default='mode,ownership,timestamps', |
315 help="preserve the specified attributes") | 321 help=_("preserve the specified attributes")) |
316 | 322 |
317 parser.add_option("--no-unicode-fix", action="store_true", default=False, | 323 parser.add_option("--no-unicode-fix", action="store_true", default=False, |
318 help="don't fixe name encoding errors") #TODO | 324 help=_("don't fixe name encoding errors")) #TODO |
319 | 325 |
320 parser.add_option("--no-progress", action="store_false", dest="progress", default=True, | 326 parser.add_option("--no-progress", action="store_false", dest="progress", default=True, |
321 help="deactivate progress bar") | 327 help=_("deactivate progress bar")) |
322 | 328 |
323 parser.add_option("-v", "--verbose", action="store_true", default=False, | 329 parser.add_option("-v", "--verbose", action="store_true", default=False, |
324 help="Show what is currently done") | 330 help=_("Show what is currently done")) |
325 | 331 |
326 (options, args) = parser.parse_args(full_args) | 332 (options, args) = parser.parse_args(full_args) |
327 #options check | 333 #options check |
328 if options.progress and not pbar_available: | 334 if options.progress and not pbar_available: |
329 warning ("Progress bar is not available, deactivating") | 335 warning (_("Progress bar is not available, deactivating")) |
330 options.progress = self.progress = False | 336 options.progress = self.progress = False |
331 else: | 337 else: |
332 self.progress = options.progress | 338 self.progress = options.progress |
333 | 339 |
334 if options.verbose: | 340 if options.verbose: |
335 logging.getLogger().setLevel(logging.DEBUG) | 341 logging.getLogger().setLevel(logging.DEBUG) |
336 | 342 |
337 preserve = set(options.preserve.split(',')) | 343 preserve = set(options.preserve.split(',')) |
338 if not preserve.issubset(const_PRESERVE): | 344 if not preserve.issubset(const_PRESERVE): |
339 error ('Invalide --preserve value\nvalid values are:') | 345 error (_("Invalide --preserve value\nvalid values are:")) |
340 for value in const_PRESERVE: | 346 for value in const_PRESERVE: |
341 error('- %s' % value) | 347 error('- %s' % value) |
342 exit(2) | 348 exit(2) |
343 else: | 349 else: |
344 options.preserve = preserve | 350 options.preserve = preserve |
345 | 351 |
346 #if there is an other instance of gcp, we send options to it | 352 #if there is an other instance of gcp, we send options to it |
347 if not self._main_instance: | 353 if not self._main_instance: |
348 info ("There is already one instance of %s running, pluging to it" % NAME_SHORT) | 354 info (_("There is already one instance of %s running, pluging to it") % NAME_SHORT) |
349 #XXX: we have to serialize data as dbus only accept valid unicode, and filenames | 355 #XXX: we have to serialize data as dbus only accept valid unicode, and filenames |
350 # can have invalid unicode. | 356 # can have invalid unicode. |
351 return self.gcp_main.addArgs(os.getcwd(),pickle.dumps(full_args)) | 357 return self.gcp_main.addArgs(os.getcwd(),pickle.dumps(full_args)) |
352 else: | 358 else: |
353 if len(args) < 2: | 359 if len(args) < 2: |
354 _error_msg = "Wrong number of arguments" | 360 _error_msg = _("Wrong number of arguments") |
355 return (False, _error_msg) | 361 return (False, _error_msg) |
356 debug("adding args to gcp: %s",args) | 362 debug(_("adding args to gcp: %s"),args) |
357 self.__checkArgs(options, source_path, args) | 363 self.__checkArgs(options, source_path, args) |
358 gobject.idle_add(self.__copyNextFile) | 364 gobject.idle_add(self.__copyNextFile) |
359 return (True,'') | 365 return (True,'') |
360 | 366 |
361 def go(self): | 367 def go(self): |
362 """Launch main loop""" | 368 """Launch main loop""" |
363 self.loop = gobject.MainLoop() | 369 self.loop = gobject.MainLoop() |
364 try: | 370 try: |
365 self.loop.run() | 371 self.loop.run() |
366 except KeyboardInterrupt: | 372 except KeyboardInterrupt: |
367 info("User interruption: good bye") | 373 info(_("User interruption: good bye")) |
368 | 374 |
369 | 375 |
370 if __name__ == "__main__": | 376 if __name__ == "__main__": |
371 gcp = GCP() | 377 gcp = GCP() |
372 success,message = gcp.parseArguments() | 378 success,message = gcp.parseArguments() |