Compare commits
2 Commits
Author | SHA1 | Date |
---|---|---|
Matteo Cypriani | bf7e090fbf | |
Matteo Cypriani | 20baa5ecd9 |
|
@ -1,7 +1,7 @@
|
||||||
gcp 0.1.3 (20/06/11):
|
gcp 0.1.3 (20/06/11):
|
||||||
- fixed exit status
|
- fixed exit status
|
||||||
- updated manpage with exit status
|
- updated manpage with exit status
|
||||||
- gcp DIR1 DIR2 syntax fixed
|
- gcp DIR1 DIR2 syntax fixed
|
||||||
- tests
|
- tests
|
||||||
gcp 0.1.2 (16/06/11):
|
gcp 0.1.2 (16/06/11):
|
||||||
- removed bad fd close
|
- removed bad fd close
|
||||||
|
@ -10,12 +10,12 @@ gcp 0.1.2 (16/06/11):
|
||||||
- unaccessible source dir crash fix
|
- unaccessible source dir crash fix
|
||||||
- os.stat precision fix
|
- os.stat precision fix
|
||||||
- manpage
|
- manpage
|
||||||
- install script
|
- install script
|
||||||
gcp 0.1.1 (30/09/10):
|
gcp 0.1.1 (30/09/10):
|
||||||
- double entry check in journal
|
- double entry check in journal
|
||||||
- unicode source_path send via dbus (second instance of gcp) fixed
|
- unicode source_path send via dbus (second instance of gcp) fixed
|
||||||
- errors are now shown after copy
|
- errors are now shown after copy
|
||||||
- fixed bad closure when a file already exists
|
- fixed bad closure when a file already exists
|
||||||
- added "gcp SOURCE_FILE DEST_FILE" syntax management
|
- added "gcp SOURCE_FILE DEST_FILE" syntax management
|
||||||
gcp 0.1 (28/09/10):
|
gcp 0.1 (28/09/10):
|
||||||
**INITIAL PUBLIC RELEASE**
|
**INITIAL PUBLIC RELEASE**
|
||||||
|
|
2
README
2
README
|
@ -35,7 +35,7 @@ gcp is a file copier, loosely inspired from cp, but with high level functionalit
|
||||||
gcp is at an early stage of development, and really experimental: use at your own risks !
|
gcp is at an early stage of development, and really experimental: use at your own risks !
|
||||||
|
|
||||||
** How to use it ? **
|
** How to use it ? **
|
||||||
Pretty much like cp (see gcp --help).
|
Pretty much like cp (see gcp --help).
|
||||||
Please note that the behaviour is not exactly the same as cp, even if gcp want to be option-compatible. Mainly, the destination filenames can be changed (by default, can be deactivated).
|
Please note that the behaviour is not exactly the same as cp, even if gcp want to be option-compatible. Mainly, the destination filenames can be changed (by default, can be deactivated).
|
||||||
gcp doesn't implement yet all the options from cp, but it's planed.
|
gcp doesn't implement yet all the options from cp, but it's planed.
|
||||||
|
|
||||||
|
|
59
gcp
59
gcp
|
@ -69,10 +69,11 @@ This software is an advanced file copier
|
||||||
Get the latest version at http://wiki.goffi.org/wiki/Gcp
|
Get the latest version at http://wiki.goffi.org/wiki/Gcp
|
||||||
""")
|
""")
|
||||||
|
|
||||||
const_DBUS_INTERFACE = "org.goffi.gcp"
|
const_DBUS_INTERFACE = "org.goffi.gcp"
|
||||||
const_DBUS_PATH = "/org/goffi/gcp"
|
const_DBUS_PATH = "/org/goffi/gcp"
|
||||||
const_BUFF_SIZE = 4096
|
const_BUFF_SIZE = 4096
|
||||||
const_PRESERVE = set(['mode','ownership','timestamps'])
|
const_PRESERVE = set(['mode','ownership','timestamps'])
|
||||||
|
const_FS_FIX = set(['auto','force','no'])
|
||||||
const_FILES_DIR = "~/.gcp"
|
const_FILES_DIR = "~/.gcp"
|
||||||
const_JOURNAL_PATH = const_FILES_DIR + "/journal"
|
const_JOURNAL_PATH = const_FILES_DIR + "/journal"
|
||||||
const_SAVED_LIST = const_FILES_DIR + "/saved_list"
|
const_SAVED_LIST = const_FILES_DIR + "/saved_list"
|
||||||
|
@ -86,7 +87,7 @@ class DbusObject(dbus.service.Object):
|
||||||
dbus.service.Object.__init__(self, bus, path)
|
dbus.service.Object.__init__(self, bus, path)
|
||||||
debug(_("Init DbusObject..."))
|
debug(_("Init DbusObject..."))
|
||||||
self.cb={}
|
self.cb={}
|
||||||
|
|
||||||
@dbus.service.method(const_DBUS_INTERFACE,
|
@dbus.service.method(const_DBUS_INTERFACE,
|
||||||
in_signature='', out_signature='s')
|
in_signature='', out_signature='s')
|
||||||
def getVersion(self):
|
def getVersion(self):
|
||||||
|
@ -294,7 +295,7 @@ class GCP():
|
||||||
dest_path = os.path.normpath(os.path.join(source_dir, args.pop()))
|
dest_path = os.path.normpath(os.path.join(source_dir, args.pop()))
|
||||||
except OSError,e:
|
except OSError,e:
|
||||||
error (_("Invalid dest_path: %s"),e)
|
error (_("Invalid dest_path: %s"),e)
|
||||||
|
|
||||||
for path in args:
|
for path in args:
|
||||||
abspath = os.path.normpath(os.path.join(os.path.expanduser(source_dir), path))
|
abspath = os.path.normpath(os.path.join(os.path.expanduser(source_dir), path))
|
||||||
if not os.path.exists(abspath):
|
if not os.path.exists(abspath):
|
||||||
|
@ -312,7 +313,7 @@ class GCP():
|
||||||
|
|
||||||
def __copyNextFile(self):
|
def __copyNextFile(self):
|
||||||
"""Take the last file in the list, and launch the copy using glib io_watch event
|
"""Take the last file in the list, and launch the copy using glib io_watch event
|
||||||
@return: True a file was added, False else"""
|
@return: True a file was added, False else"""
|
||||||
if self.copy_list:
|
if self.copy_list:
|
||||||
source_file, dest_path, options = self.copy_list.pop()
|
source_file, dest_path, options = self.copy_list.pop()
|
||||||
self.journal.startFile(source_file)
|
self.journal.startFile(source_file)
|
||||||
|
@ -341,7 +342,7 @@ class GCP():
|
||||||
self.journal.closeFile()
|
self.journal.closeFile()
|
||||||
source_fd.close()
|
source_fd.close()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
gobject.io_add_watch(source_fd,gobject.IO_IN,self._copyFile,
|
gobject.io_add_watch(source_fd,gobject.IO_IN,self._copyFile,
|
||||||
(dest_fd, options), priority=gobject.PRIORITY_DEFAULT)
|
(dest_fd, options), priority=gobject.PRIORITY_DEFAULT)
|
||||||
if not self.progress:
|
if not self.progress:
|
||||||
|
@ -362,7 +363,7 @@ class GCP():
|
||||||
self.journal.closeFile()
|
self.journal.closeFile()
|
||||||
source_fd.close()
|
source_fd.close()
|
||||||
dest_fd.close()
|
dest_fd.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _copyFile(self, source_fd, condition, data):
|
def _copyFile(self, source_fd, condition, data):
|
||||||
|
@ -411,7 +412,7 @@ class GCP():
|
||||||
@return: fixed filename"""
|
@return: fixed filename"""
|
||||||
fixed_filename = filename
|
fixed_filename = filename
|
||||||
|
|
||||||
if self.getFsType(filename) == 'vfat' and options.fs_fix:
|
if options.fs_fix == 'force' or (options.fs_fix == 'auto' and self.getFsType(filename) == 'vfat'):
|
||||||
fixed_filename = filename.replace('\\','_')\
|
fixed_filename = filename.replace('\\','_')\
|
||||||
.replace(':',';')\
|
.replace(':',';')\
|
||||||
.replace('*','+')\
|
.replace('*','+')\
|
||||||
|
@ -520,7 +521,7 @@ class GCP():
|
||||||
|
|
||||||
if options.sources_save or options.sources_replace:
|
if options.sources_save or options.sources_replace:
|
||||||
if saved_files.has_key(options.sources_save) and not options.sources_replace:
|
if saved_files.has_key(options.sources_save) and not options.sources_replace:
|
||||||
error(_("There is already a saved sources with this name, skipping --sources-save"))
|
error(_("There is already a saved sources with this name, skipping --sources-save"))
|
||||||
else:
|
else:
|
||||||
if len(args)>1:
|
if len(args)>1:
|
||||||
saved_files[options.sources_save] = map(os.path.abspath,args[:-1])
|
saved_files[options.sources_save] = map(os.path.abspath,args[:-1])
|
||||||
|
@ -552,38 +553,41 @@ class GCP():
|
||||||
if isinstance(full_args[idx], unicode):
|
if isinstance(full_args[idx], unicode):
|
||||||
#We don't want unicode as some filenames can be invalid unicode
|
#We don't want unicode as some filenames can be invalid unicode
|
||||||
full_args[idx] = full_args[idx].encode('utf-8')
|
full_args[idx] = full_args[idx].encode('utf-8')
|
||||||
|
|
||||||
parser = OptionParser(usage=_usage,version=ABOUT)
|
parser = OptionParser(usage=_usage,version=ABOUT)
|
||||||
|
|
||||||
parser.add_option("-r", "--recursive", action="store_true", default=False,
|
parser.add_option("-r", "--recursive", action="store_true", default=False,
|
||||||
help=_("copy directories recursively"))
|
help=_("copy directories recursively"))
|
||||||
|
|
||||||
parser.add_option("-f", "--force", action="store_true", default=False,
|
parser.add_option("-f", "--force", action="store_true", default=False,
|
||||||
help=_("force overwriting of existing files"))
|
help=_("force overwriting of existing files"))
|
||||||
|
|
||||||
parser.add_option("--preserve", action="store", default='mode,ownership,timestamps',
|
parser.add_option("--preserve", action="store", default='mode,ownership,timestamps',
|
||||||
help=_("preserve the specified attributes"))
|
help=_("preserve the specified attributes"))
|
||||||
|
|
||||||
parser.add_option("-L", "--dereference", action="store_true", default=False,
|
parser.add_option("-L", "--dereference", action="store_true", default=False,
|
||||||
help=_("always follow symbolic links in sources"))
|
help=_("always follow symbolic links in sources"))
|
||||||
|
|
||||||
parser.add_option("-P", "--no-dereference", action="store_false", dest='dereference',
|
parser.add_option("-P", "--no-dereference", action="store_false", dest='dereference',
|
||||||
help=_("never follow symbolic links in sources"))
|
help=_("never follow symbolic links in sources"))
|
||||||
|
|
||||||
#parser.add_option("--no-unicode-fix", action="store_false", dest='unicode_fix', default=True,
|
#parser.add_option("--no-unicode-fix", action="store_false", dest='unicode_fix', default=True,
|
||||||
# help=_("don't fix name encoding errors")) #TODO
|
# help=_("don't fix name encoding errors")) #TODO
|
||||||
|
|
||||||
parser.add_option("--no-fs-fix", action="store_false", dest='fs_fix', default=True,
|
parser.add_option("--fs-fix", action="store", dest='fs_fix', default='auto',
|
||||||
help=_("don't fix filesystem name incompatibily"))
|
help=_("fix filesystem name incompatibily; can be 'auto' (default), 'force' or 'no'"))
|
||||||
|
|
||||||
|
parser.add_option("--no-fs-fix", action="store_true", dest='no_fs_fix', default=False,
|
||||||
|
help=_("same as --fs-fix=no (overrides --fs-fix)"))
|
||||||
|
|
||||||
parser.add_option("--no-progress", action="store_false", dest="progress", default=True,
|
parser.add_option("--no-progress", action="store_false", dest="progress", default=True,
|
||||||
help=_("deactivate progress bar"))
|
help=_("deactivate progress bar"))
|
||||||
|
|
||||||
parser.add_option("-v", "--verbose", action="store_true", default=False,
|
parser.add_option("-v", "--verbose", action="store_true", default=False,
|
||||||
help=_("Show what is currently done"))
|
help=_("Show what is currently done"))
|
||||||
|
|
||||||
group_saving = OptionGroup(parser, "sources saving")
|
group_saving = OptionGroup(parser, "sources saving")
|
||||||
|
|
||||||
group_saving.add_option("--sources-save", action="store",
|
group_saving.add_option("--sources-save", action="store",
|
||||||
help=_("Save source arguments"))
|
help=_("Save source arguments"))
|
||||||
|
|
||||||
|
@ -592,19 +596,19 @@ class GCP():
|
||||||
|
|
||||||
group_saving.add_option("--sources-load", action="store",
|
group_saving.add_option("--sources-load", action="store",
|
||||||
help=_("Load source arguments"))
|
help=_("Load source arguments"))
|
||||||
|
|
||||||
group_saving.add_option("--sources-del", action="store",
|
group_saving.add_option("--sources-del", action="store",
|
||||||
help=_("delete saved sources"))
|
help=_("delete saved sources"))
|
||||||
|
|
||||||
group_saving.add_option("--sources-list", action="store_true", default=False,
|
group_saving.add_option("--sources-list", action="store_true", default=False,
|
||||||
help=_("List names of saved sources"))
|
help=_("List names of saved sources"))
|
||||||
|
|
||||||
group_saving.add_option("--sources-full-list", action="store_true", default=False,
|
group_saving.add_option("--sources-full-list", action="store_true", default=False,
|
||||||
help=_("List names of saved sources and files in it"))
|
help=_("List names of saved sources and files in it"))
|
||||||
|
|
||||||
parser.add_option_group(group_saving)
|
parser.add_option_group(group_saving)
|
||||||
|
|
||||||
|
|
||||||
(options, args) = parser.parse_args(full_args)
|
(options, args) = parser.parse_args(full_args)
|
||||||
options.directdir = False #True only in the special case: we are copying a dir and it doesn't exists
|
options.directdir = False #True only in the special case: we are copying a dir and it doesn't exists
|
||||||
#options check
|
#options check
|
||||||
|
@ -617,9 +621,18 @@ class GCP():
|
||||||
if options.verbose:
|
if options.verbose:
|
||||||
logging.getLogger().setLevel(logging.DEBUG)
|
logging.getLogger().setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
if options.no_fs_fix:
|
||||||
|
options.fs_fix = 'no'
|
||||||
|
else:
|
||||||
|
if not options.fs_fix in const_FS_FIX:
|
||||||
|
error (_("Invalid --fs-fix value\nvalid values are:"))
|
||||||
|
for value in const_FS_FIX:
|
||||||
|
error('- %s' % value)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
preserve = set(options.preserve.split(','))
|
preserve = set(options.preserve.split(','))
|
||||||
if not preserve.issubset(const_PRESERVE):
|
if not preserve.issubset(const_PRESERVE):
|
||||||
error (_("Invalide --preserve value\nvalid values are:"))
|
error (_("Invalid --preserve value\nvalid values are:"))
|
||||||
for value in const_PRESERVE:
|
for value in const_PRESERVE:
|
||||||
error('- %s' % value)
|
error('- %s' % value)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
@ -642,7 +655,7 @@ class GCP():
|
||||||
options.dest_file = None
|
options.dest_file = None
|
||||||
else:
|
else:
|
||||||
options.dest_file = None
|
options.dest_file = None
|
||||||
|
|
||||||
#if there is an other instance of gcp, we send options to it
|
#if there is an other instance of gcp, we send options to it
|
||||||
if not self._main_instance:
|
if not self._main_instance:
|
||||||
info (_("There is already one instance of %s running, pluging to it") % NAME_SHORT)
|
info (_("There is already one instance of %s running, pluging to it") % NAME_SHORT)
|
||||||
|
|
|
@ -59,8 +59,8 @@ def dirCheck(dir_path):
|
||||||
if isdir(full_path):
|
if isdir(full_path):
|
||||||
recursive_sum(full_path, result)
|
recursive_sum(full_path, result)
|
||||||
else:
|
else:
|
||||||
result[full_path] = sha1sum(full_path)
|
result[full_path] = sha1sum(full_path)
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
_ori_dir = getcwd()
|
_ori_dir = getcwd()
|
||||||
chdir(dir_path)
|
chdir(dir_path)
|
||||||
|
@ -94,7 +94,7 @@ def makeRandomFile(path, size=S10K, buf_size=4096):
|
||||||
def makeTestDir(path):
|
def makeTestDir(path):
|
||||||
"""Helper method to easily create a test dir
|
"""Helper method to easily create a test dir
|
||||||
@param path: where the dir must be created"""
|
@param path: where the dir must be created"""
|
||||||
|
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
subdir = join(path,'subdir_%d' % i)
|
subdir = join(path,'subdir_%d' % i)
|
||||||
makedirs(subdir)
|
makedirs(subdir)
|
||||||
|
@ -198,7 +198,7 @@ class TestCopyCases(unittest.TestCase):
|
||||||
self.assertEqual(ret,0)
|
self.assertEqual(ret,0)
|
||||||
check_2 = dirCheck('dest_dir')
|
check_2 = dirCheck('dest_dir')
|
||||||
self.assertEqual(check_1, check_2)
|
self.assertEqual(check_1, check_2)
|
||||||
|
|
||||||
def test_mixt_copy_existing_dest_nonrecursive(self):
|
def test_mixt_copy_existing_dest_nonrecursive(self):
|
||||||
"""Check that a mixt copy (files + dir) to an existing dest without the recursive option work as expected"""
|
"""Check that a mixt copy (files + dir) to an existing dest without the recursive option work as expected"""
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
|
|
Loading…
Reference in New Issue