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()