# HG changeset patch # User Goffi # Date 1285481294 -28800 # Node ID 9feb82bd91aadaaff6e6d7a15476d106d7a10a1d # Parent 6a24b592898070eab574c91e9b728f6bc08da3d0 --preserve option (same default as for cp) & progress bar are now working. also added --force & --verbose options diff -r 6a24b5928980 -r 9feb82bd91aa gcp --- a/gcp Sun Sep 26 12:00:05 2010 +0800 +++ b/gcp Sun Sep 26 14:08:14 2010 +0800 @@ -22,7 +22,7 @@ ### logging ### import logging from logging import debug, info, error, warning -logging.basicConfig(level=logging.DEBUG, +logging.basicConfig(level=logging.INFO, format='%(message)s') ### import sys @@ -67,6 +67,7 @@ const_DBUS_INTERFACE = "org.goffi.gcp" const_DBUS_PATH = "/org/goffi/gcp" const_BUFF_SIZE = 4096 +const_PRESERVE = set(['mode','ownership','timestamps']) class DbusObject(dbus.service.Object): @@ -126,7 +127,8 @@ self.copy_list = [] self.mounts = self.__getMountPoints() self.files_left = 0 - self.bytes_left = 0 + self.bytes_total = 0 + self.bytes_copied = 0 def getFsType(self, path): fs='' @@ -141,7 +143,7 @@ #(check freedesktop mounting signals) ret = {} try: - with open("/proc/mounts",'r') as mounts: + with open("/proc/mounts",'rb') as mounts: for line in mounts.readlines(): fs_spec, fs_file, fs_vfstype, fs_mntops, fs_freq, fs_passno = line.split(' ') ret[fs_file] = fs_vfstype @@ -155,10 +157,9 @@ @param options: options as return by optparse""" debug ("Adding to copy list: %s ==> %s (%s)", path, dest_path, self.getFsType(dest_path)) try: - self.bytes_left+=os.path.getsize(path) + self.bytes_total+=os.path.getsize(path) self.files_left+=1 - self.copy_list.append((path, dest_path, options)) - print "total size:", float(self.bytes_left/1024/1024), "Mb (%i)" % self.files_left + self.copy_list.insert(0,(path, dest_path, options)) except OSError,e: error("Can't copy %(path)s: %(exception)s" % {'path':path, 'exception':e.strerror}) @@ -210,22 +211,25 @@ """Take the last file in the list, and launch the copy using glib io_watch event @return: True a file was added, False else""" if self.copy_list: - source_path, dest_path, options = self.copy_list.pop() - source_fd = open(source_path, 'r') - filename = os.path.basename(source_path) + source_file, dest_path, options = self.copy_list.pop() + source_fd = open(source_file, 'rb') + filename = os.path.basename(source_file) assert(filename) dest_file = os.path.join(dest_path,filename) - if os.path.exists(dest_file): + if os.path.exists(dest_file) and not options.force: warning ("File [%s] already exists, skipping it !" % dest_file) return True - dest_fd = open(dest_file, 'w') + dest_fd = open(dest_file, 'wb') - self.total=0 - gobject.io_add_watch(source_fd,gobject.IO_IN,self._copyFile,(dest_fd,options), priority=gobject.PRIORITY_HIGH) - print "** COPYING",source_path,"==>",dest_file + gobject.io_add_watch(source_fd,gobject.IO_IN,self._copyFile, + (dest_fd, options), priority=gobject.PRIORITY_HIGH) + if not self.progress: + info("COPYING %(source)s ==> %(dest)s" % {"source":source_path,"dest":dest_file}) return True else: #Nothing left to copy, we quit + if self.progress: + self.__pbar_finish() self.loop.quit() def _copyFile(self, source_fd, condition, data): @@ -236,16 +240,52 @@ dest_fd,options = data buff = source_fd.read(self.buffer_size) dest_fd.write(buff) - self.total += len(buff) - sys.stdout.write('%i written\r' % self.total) + self.bytes_copied += len(buff) + if self.progress: + self.__pbar_update() + if len(buff) != self.buffer_size: - sys.stdout.write('\n---\n') source_fd.close() dest_fd.close() + self.__post_copy(source_fd.name, dest_fd.name, options) + self.files_left -= 1 + assert (self.files_left >= 0) return False return True - + def __post_copy(self, source_file, dest_file, options): + """Do post copy traitement (mainly managing --preserve option)""" + st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid, st_size, st_atime, st_mtime, st_ctime = os.stat(source_file) + #TODO: complete log in case of errors + for preserve in options.preserve: + try: + if preserve == 'mode': + os.chmod(dest_file, st_mode) + elif preserve == 'ownership': + os.chown(dest_file, st_uid, st_gid) + elif preserve == 'timestamps': + os.utime(dest_file, (st_atime, st_mtime)) + except OSError,e: + pass #TODO: complete log here + + def __pbar_update(self): + """Update progress bar position, create the bar if it doesn't exist""" + assert(self.progress) + try: + if self.pbar.maxval != self.bytes_total: + self.pbar.maxval = self.bytes_total + except AttributeError: + self.pbar = ProgressBar(self.bytes_total,["Progress: ",Percentage()," ",Bar()," ",FileTransferSpeed()," ",ETA()]) + self.pbar.start() + self.pbar.update(self.bytes_copied) + + def __pbar_finish(self): + """Mark the progression as finished""" + assert(self.progress) + try: + self.pbar.finish() + except AttributeError: + pass def parseArguments(self, full_args=sys.argv[1:], source_path = os.getcwd()): """Parse arguments and add files to queue @@ -268,17 +308,42 @@ parser.add_option("-r", "--recursive", action="store_true", default=False, help="copy directories recursively") + parser.add_option("-f", "--force", action="store_true", default=False, + help="force overwriting of existing files") + + parser.add_option("--preserve", action="store", default='mode,ownership,timestamps', + help="preserve the specified attributes") + parser.add_option("--no-unicode-fix", action="store_true", default=False, help="don't fixe name encoding errors") #TODO parser.add_option("--no-progress", action="store_false", dest="progress", default=True, help="deactivate progress bar") + parser.add_option("-v", "--verbose", action="store_true", default=False, + help="Show what is currently done") + (options, args) = parser.parse_args(full_args) + #options check if options.progress and not pbar_available: warning ("Progress bar is not available, deactivating") - options.progress = False + options.progress = self.progress = False + else: + self.progress = options.progress + + if options.verbose: + logging.getLogger().setLevel(logging.DEBUG) + + preserve = set(options.preserve.split(',')) + if not preserve.issubset(const_PRESERVE): + error ('Invalide --preserve value\nvalid values are:') + for value in const_PRESERVE: + error('- %s' % value) + exit(2) + else: + options.preserve = preserve + #if there is an other instance of gcp, we send options to it if not self._main_instance: info ("There is already one instance of %s running, pluging to it" % NAME_SHORT) #XXX: we have to serialize data as dbus only accept valid unicode, and filenames