Compare commits

...

9 Commits

Author SHA1 Message Date
Matteo Cypriani 07f53e4109 CHANGELOG: update for release 2018-10-14 22:54:42 +02:00
Matteo Cypriani 35b8fed792 Install man in man/man1
So it ends up in ~/.local/man instead of ~/.local/share/man when
installed with pip.
2018-10-14 22:53:19 +02:00
Matteo Cypriani 63870b25ed LICENSE.txt -> LICENSE
Because it's also supported by Python packaging tools and the extension
is ugly.
2018-10-14 22:10:52 +02:00
Matteo Cypriani 93c37d756d test: add test for --fix-filenames 2018-10-14 21:43:43 +02:00
Matteo Cypriani 7bff021cd3 Update translation files 2018-10-14 20:59:09 +02:00
Matteo Cypriani 81bd453526 Update/rework manpage 2018-10-14 20:23:25 +02:00
Matteo Cypriani 43da9301fa Rename --fs-fix -> --fix-filenames
Also, reorder/group options so that the help message is more readable.
2018-10-14 19:08:31 +02:00
Matteo Cypriani 0995d580c9 README: clarify installation instructions 2018-10-14 16:54:51 +02:00
Matteo Cypriani 007d04dd16 "Rename" gcp
Following Goffi's will, this commit renames Gcp (Goffi's CoPier) into
gcp (Gcp CoPier).
2018-10-14 16:52:27 +02:00
10 changed files with 389 additions and 306 deletions

View File

@ -1,10 +1,11 @@
gcp 0.2.0 (UNRELEASED, Matteo Cypriani):
gcp 0.2.0 (2018-10-14, Matteo Cypriani):
- actually switch to Python3
- cp compatibibility:
+ don't preserve any attributes by default (Jingbei Li)
+ added -p switch (same as --preserve=mode,ownership,timestamps)
+ added -R switch (same as --recursive)
- new --fs-fix option
- new --fix-filenames option
- reworked packaging
gcp 0.1.4.dev1 (unreleased, Jingbei Li):
- main Python3 migration work

View File

@ -1,7 +1,8 @@
gcp
===
gcp (Goffi's cp) is a file copier.
gcp is a user-friendly file copier written in Python. Its name used to stand
for "Goffi's CoPier", but was changed into a recursive acronym: Gcp CoPier.
License
@ -51,16 +52,17 @@ Installing
The Python way
--------------
pip3 install gcp
Note that you should have the following packages installed so that pip can
complete the installation (Debian packages names, but you get the idea):
First, install the following packages on your system (these Debian packages
names, they may be different on other distros/systems):
- libdbus-1-dev
- libdbus-glib-1-dev
- libgirepository1.0-dev
- libcairo2-dev
- python3-cairo-dev
Then install gcp with pip:
pip3 install gcp
On Debian-based systems
-----------------------
@ -145,9 +147,9 @@ Big thanks to contributors and package maintainers.
Contributors
============
* Original author: Jérôme Poisson aka Goffi <goffi@goffi.org> 2010-2011.
* Original author: Jérôme Poisson a.k.a. Goffi <goffi@goffi.org> 2010-2011.
* Thomas Preud'homme <robotux@celest.fr> 2011: manpage, stat resolution fix.
* Jingbei Li aka petronny 2016: conversion to Python3.
* Jingbei Li a.k.a. petronny 2016: conversion to Python3.
* Matteo Cypriani <mcy@lm7.fr> 2018: `--fs-fix` option, Python3 fixes.

189
fr.po
View File

@ -1,36 +1,40 @@
# gcp -- French translation file
#
# Copyright:
# 2010 Jérôme Poisson (Goffi) <goffi@goffi.org>
# 2018 Matteo Cypriani <mcy@lm7.fr>
#
# This file is distributed under the same license as the gcp package.
#, fuzzy
#
msgid ""
msgstr ""
"Project-Id-Version: 0.2.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-09-30 18:05+0800\n"
"PO-Revision-Date: 2018-04-22 20:35+0200\n"
"PO-Revision-Date: 2018-10-14 20:56+0200\n"
"Last-Translator: Matteo Cypriani <mcy@lm7.fr>\n"
"Language: French\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language-Team: \n"
"X-Generator: Poedit 2.2\n"
#: gcp:45
#: gcp:46
msgid "Error during import"
msgstr "Erreur pendant l'import de bibliothèques"
#: gcp:46
#: gcp:47
msgid "Please check dependecies:"
msgstr "Merci de vérifier les dépendances :"
#: gcp:52
#: gcp:54
msgid "ProgressBar not available, please download it at https://pypi.org/"
msgstr ""
"ProgressBar n'est pas disponible, merci de le télécharger depuis"
"https://pypi.org/"
"ProgressBar n'est pas disponible, merci de le télécharger depuishttps://pypi."
"org/"
#: gcp:3
#: gcp:55
msgid ""
"Progress bar deactivated\n"
"--\n"
@ -38,238 +42,245 @@ msgstr ""
"Barre de progression désactivée\n"
"--\n"
#: gcp:88
#: gcp:90
msgid "Init DbusObject..."
msgstr "Initialisation de «DbusObject»"
msgstr "Initialisation de DbusObject..."
#: gcp:109
#: gcp:111
msgid "INTERNAL ERROR: invalid arguments"
msgstr "ERREUR INTERNE : arguments invalides"
#: gcp:114
#: gcp:116
msgid "INTERNAL ERROR: invalid source_dir"
msgstr "ERREUR INTERNE : chemin source invalide"
#: gcp:169
#: gcp:171
msgid "/!\\ THE FOLLOWING FILES WERE *NOT* SUCCESSFULY COPIED:"
msgstr "/!\\ LES FICHIERS SUIVANTS N'ONT *PAS* ÉTÉ COPIÉS :"
#: gcp:175
#: gcp:177
msgid "The following files were copied, but some errors happened:"
msgstr ""
"Les fichiers suivant ont été copiés, mais quelques erreurs sont survenues :"
msgstr "Les fichiers suivant ont été copiés, mais des erreurs sont survenues :"
#: gcp:181
#: gcp:183
#, python-format
msgid "Please check journal: %s"
msgstr "Merci de vérifier le journal : %s"
#: gcp:203
#: gcp:205
msgid "gcp launched"
msgstr "gcp lancé"
#: gcp:211
#: gcp:213
msgid "Init DBus..."
msgstr "Initialisation de Dbus..."
msgstr "Initialisation de DBus..."
#: gcp:241
#: gcp:244
msgid "Can't read mounts table"
msgstr "Impossible de lire la table des montages"
#: gcp:248
#: gcp:251
#, python-format
msgid "Adding to copy list: %(path)s ==> %(dest_path)s (%(fs_type)s)"
msgstr "Ajout à la liste des copies : %(path)s ==> %(dest_path)s (%(fs_type)s)"
#: gcp:253
#: gcp:258
#, python-format
msgid "Can't copy %(path)s: %(exception)s"
msgstr "Impossible de copier %(path)s : %(exception)s"
#: gcp:280
#: gcp:286
#, python-format
msgid "Can't append %(path)s to copy list: %(exception)s"
msgstr ""
"Impossible d'ajouter %(path)s à la liste des fichiers à copier : %(exception)s"
"Impossible d'ajouter %(path)s à la liste des fichiers à copier : "
"%(exception)s"
#: gcp:283
#: gcp:289
#, python-format
msgid "Can't access %(dirpath)s: %(exception)s"
msgstr "Impossible d'accéder à %(dirpath)s : %(exception)s"
#: gcp:295
#: gcp:301
#, python-format
msgid "Invalid dest_path: %s"
msgstr "Chemin de destination invalide : %s"
#: gcp:300
#: gcp:306
#, python-format
msgid "The path given in arg doesn't exist or is not accessible: %s"
msgstr "Le chemin donné en argument n'existe pas ou n'est pas accessible : %s"
#: gcp:304
#: gcp:310
#, python-format
msgid "omitting directory \"%s\""
msgstr "Répertoire \"%s\" ignoré"
msgstr "répertoire \"%s\" ignoré"
#: gcp:329
#: gcp:348
#, python-format
msgid "File [%s] already exists, skipping it!"
msgstr "Le fichier [%s] existe déjà, je le saute !"
#: gcp:347
#: gcp:368
#, python-format
msgid "COPYING %(source)s ==> %(dest)s"
msgstr "COPIE %(source)s ==> %(dest)s"
#: gcp:447
#: gcp:462
#, python-format
msgid "%.2f PiB"
msgstr "%.2f Pio"
#: gcp:449
#: gcp:464
#, python-format
msgid "%.2f TiB"
msgstr "%.2f Tio"
#: gcp:451
#: gcp:466
#, python-format
msgid "%.2f GiB"
msgstr "%.2f Gio"
#: gcp:453
#: gcp:468
#, python-format
msgid "%.2f MiB"
msgstr "%.2f Mio"
#: gcp:455
#: gcp:470
#, python-format
msgid "%.2f KiB"
msgstr "%.2f Kio"
#: gcp:457
#: gcp:471
#, python-format
msgid "%i B"
msgstr "%i o"
#: gcp:465 gcp:470
#: gcp:479 gcp:485
#, python-format
msgid "Copying %s"
msgstr "Copie de %s"
#: gcp:497 gcp:530
#: gcp:515 gcp:548
msgid ""
"No saved sources with this name, check existing names with --sources-list"
msgstr ""
"Aucune sauvegarde de fichiers sources avec ce nom, veuillez vérifier les "
"listes existantes avec --sources-list"
#: gcp:507
#: gcp:525
msgid "Saved sources:"
msgstr "Liste de sources sauvées :"
#: gcp:521
#: gcp:539
msgid ""
"There is already a saved sources with this name, skipping --sources-save"
msgstr "Il y a déjà une liste de sources avec ce nom, --sources-save ignoré"
#: gcp:557
msgid "copy directories recursively"
msgstr "copier les répertoire récursivement"
#: gcp:561
#: gcp:578
msgid "force overwriting of existing files"
msgstr "forcer le remplacement des fichiers déjà existants"
#: gcp:565
#: gcp:582
msgid "always follow symbolic links in sources"
msgstr "toujours suivre les liens symboliques"
#: gcp:586
msgid "never follow symbolic links in sources"
msgstr "ne pas suivre les liens symboliques"
#: gcp:590
#, python-format
msgid "same as --preserve=%s"
msgstr "raccourci pour --preserve=%s"
#: gcp:569
#: gcp:594
#, python-format
msgid ""
"preserve specified attributes; accepted values: 'all', or one or more "
"amongst %s"
"preserve specified attributes; accepted values: 'all', or "
"one or more amongst %s"
msgstr ""
"préserver les attributs spécifiés; valeurs acceptées : "
"'all' ou un ou plusieurs éléments parmi %s"
"préserver les attributs spécifiés; valeurs acceptées : 'all' ou un ou "
"plusieurs éléments parmi %s"
#: gcp:574
msgid "always follow symbolic links in sources"
#: gcp:599
msgid "copy directories recursively"
msgstr "copier les répertoire récursivement"
#: gcp:603
msgid "display what is being done"
msgstr "afficher les opérations effectuées"
#: gcp:614
msgid ""
"fix file names incompatible with the destination file "
"system (default: auto)"
msgstr ""
"corriger les noms de fichiers incompatibles avec le système de fichiers "
"cible (défaut : auto)"
#: gcp:578
msgid "never follow symbolic links in sources"
#: gcp:619
msgid ""
"[DEPRECATED] same as --fix-filename=no (overrides --fix-"
"filenames)"
msgstr ""
"[OBSOLÈTE] identique à --fix-filenames=no (--fix-filenames sera ignoré)"
#: gcp:586
msgid "fix filesystem name incompatibily (default: auto)"
msgstr ""
#: gcp:590
msgid "same as --fs-fix=no (overrides --fs-fix)"
msgstr "raccourci pour --fs-fix=no (--fs-fix sera ignoré)"
#: gcp:594
#: gcp:624
msgid "disable progress bar"
msgstr "désactiver la barre de progression"
#: gcp:598
msgid "Show what is currently done"
msgstr "afficher les opérations effectuées"
#: gcp:607
msgid "Save source arguments"
#: gcp:631
msgid "save sources arguments"
msgstr "sauvegarder la liste des fichiers source"
#: gcp:611
msgid "Save source arguments and replace memory if it already exists"
#: gcp:635
msgid "save sources arguments and replace memory if it already exists"
msgstr ""
"sauvegarder la liste des fichiers source et la remplacer si elle existe déjà"
#: gcp:615
msgid "Load source arguments"
#: gcp:639
msgid "load sources arguments"
msgstr "réutiliser les fichiers source à copier"
#: gcp:619
msgid "delete saved sources"
#: gcp:643
msgid "delete saved sources list"
msgstr "supprimer la liste des fichiers source"
#: gcp:623
msgid "List names of saved sources"
#: gcp:647
msgid "list names of saved sources"
msgstr "afficher les noms des listes de fichiers source"
#: gcp:627
msgid "List names of saved sources and files in it"
#: gcp:651
msgid "list names of saved sources and files in it"
msgstr ""
"afficher les noms des listes de fichiers sources, en incluant les fichiers "
"qu'elles contiennent"
#: gcp:639
#: gcp:663
msgid "Progress bar is not available, deactivating"
msgstr "La barre de progression n'est pas disponible, désactivation"
#: gcp:663
#: gcp:687
#, python-format
msgid "Invalid --preserve value '%s'"
msgstr "Valeur de --preserve invalide « %s »"
#: gcp:690
#: gcp:714
#, python-format
msgid "There is already one instance of %s running, pluging to it"
msgstr "Il y a déjà une instance de %s lancée, je m'y connecte"
#: gcp:696
#: gcp:720
msgid "Wrong number of arguments"
msgstr "Nombre d'arguments invalide"
#: gcp:698
#: gcp:722
#, python-format
msgid "adding args to gcp: %s"
msgstr "ajout des arguments à gcp : %s"
#: gcp:707
#: gcp:731
msgid "User interruption: good bye"
msgstr "Interruption par l'utilisateur : au revoir"

130
gcp
View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""
gcp: Goffi's CoPier
gcp: Gcp CoPier
Copyright (c) 2010, 2011 Jérôme Poisson <goffi@goffi.org>
(c) 2011 Thomas Preud'homme <robotux@celest.fr>
(c) 2016 Jingbei Li <i@jingbei.li>
@ -55,7 +55,7 @@ except ImportError as e:
info (_('Progress bar deactivated\n--\n'))
pbar_available=False
NAME = "gcp (Goffi's copier)"
NAME = "gcp (Gcp CoPier)"
NAME_SHORT = "gcp"
VERSION = '0.2.0'
@ -264,7 +264,7 @@ class GCP():
@param path: absolute path of dir
@param options: options as return by optparse"""
#We first check that the dest path exists, and create it if needed
dest_path = self.__filename_fix(dest_path, options, no_journal=True)
dest_path = self.__fix_filenames(dest_path, options, no_journal=True)
if not os.path.exists(dest_path):
debug ("Creating directory %s" % dest_path)
os.makedirs(dest_path) #TODO: check permissions
@ -340,10 +340,10 @@ class GCP():
filename = os.path.basename(source_file)
assert(filename)
if options.dest_file:
dest_file = self.__filename_fix(options.dest_file, options)
dest_file = self.__fix_filenames(options.dest_file, options)
else:
dest_file = self.__filename_fix(os.path.join(dest_path, filename),
options)
dest_file = self.__fix_filenames(os.path.join(dest_path, filename),
options)
if os.path.exists(dest_file) and not options.force:
warning (_("File [%s] already exists, skipping it!") % dest_file)
self.journal.copyFailed()
@ -417,7 +417,7 @@ class GCP():
except KeyboardInterrupt:
self._userInterruption()
def __filename_fix(self, filename, options, no_journal=False):
def __fix_filenames(self, filename, options, no_journal=False):
"""Fix filenames incompatibilities/mistake according to options
@param filename: full path to the file
@param options: options as parsed on command line
@ -425,7 +425,7 @@ class GCP():
@return: fixed filename"""
fixed_filename = filename
if options.fs_fix == 'force' or (options.fs_fix == 'auto' and self.getFsType(filename) == 'vfat'):
if options.fix_filenames == 'force' or (options.fix_filenames == 'auto' and self.getFsType(filename) == 'vfat'):
fixed_filename = filename.replace('\\','_')\
.replace(':',';')\
.replace('*','+')\
@ -561,8 +561,6 @@ class GCP():
_usage="""
%(prog)s [options] FILE DEST
%(prog)s [options] FILE1 [FILE2 ...] DEST-DIR
%(prog)s --help for options list
"""
for idx in range(len(full_args)):
full_args[idx] = full_args[idx].encode('utf-8')
@ -570,79 +568,87 @@ class GCP():
parser = ArgumentParser(usage=_usage,
formatter_class=RawDescriptionHelpFormatter)
parser.add_argument("-r", "-R", "--recursive",
action="store_true", default=False,
help=_("copy directories recursively")
)
parser.add_argument("-f", "--force",
action="store_true", default=False,
help=_("force overwriting of existing files")
)
parser.add_argument("-p",
action="store_true", default=False,
help=_("same as --preserve=%s" % const_PRESERVE_p)
)
parser.add_argument("--preserve",
action="store", default='',
help=_("preserve specified attributes; accepted values: \
'all', or one or more amongst %s") % str(const_PRESERVE)
)
parser.add_argument("-L", "--dereference",
action="store_true", default=False,
help=_("always follow symbolic links in sources")
)
parser.add_argument("-P", "--no-dereference",
action="store_false", dest='dereference',
help=_("never follow symbolic links in sources")
)
#parser.add_argument("--no-unicode-fix",
# action="store_false", dest='unicode_fix', default=True,
# help=_("don't fix name encoding errors") #TODO
#)
parser.add_argument("--fs-fix",
choices = const_FS_FIX, dest='fs_fix', default='auto',
help=_("fix filesystem name incompatibily (default: auto)")
)
parser.add_argument("--no-fs-fix",
action="store_true", dest='no_fs_fix', default=False,
help=_("same as --fs-fix=no (overrides --fs-fix)")
)
parser.add_argument("--no-progress",
action="store_false", dest="progress", default=True,
help=_("disable progress bar")
)
parser.add_argument("-v", "--verbose",
action="store_true", default=False,
help=_("Show what is currently done")
)
parser.add_argument("-V", "--version",
action="version", version=ABOUT
)
group_cplike = parser.add_argument_group("cp-like options")
group_cplike.add_argument("-f", "--force",
action="store_true", default=False,
help=_("force overwriting of existing files")
)
group_cplike.add_argument("-L", "--dereference",
action="store_true", default=False,
help=_("always follow symbolic links in sources")
)
group_cplike.add_argument("-P", "--no-dereference",
action="store_false", dest='dereference',
help=_("never follow symbolic links in sources")
)
group_cplike.add_argument("-p",
action="store_true", default=False,
help=_("same as --preserve=%s" % const_PRESERVE_p)
)
group_cplike.add_argument("--preserve",
action="store", default='',
help=_("preserve specified attributes; accepted values: \
'all', or one or more amongst %s") % str(const_PRESERVE)
)
group_cplike.add_argument("-r", "-R", "--recursive",
action="store_true", default=False,
help=_("copy directories recursively")
)
group_cplike.add_argument("-v", "--verbose",
action="store_true", default=False,
help=_("display what is being done")
)
parser.add_argument_group(group_cplike)
group_gcpspecific = parser.add_argument_group("gcp-specific options")
#parser.add_argument("--no-unicode-fix",
# action="store_false", dest='unicode_fix', default=True,
# help=_("don't fix name encoding errors") #TODO
#)
group_gcpspecific.add_argument("--fix-filenames",
choices = const_FS_FIX, dest='fix_filenames', default='auto',
help=_("fix file names incompatible with the destination \
file system (default: auto)")
)
group_gcpspecific.add_argument("--no-fs-fix",
action="store_true", dest='no_fs_fix', default=False,
help=_("[DEPRECATED] same as --fix-filename=no (overrides \
--fix-filenames)")
)
group_gcpspecific.add_argument("--no-progress",
action="store_false", dest="progress", default=True,
help=_("disable progress bar")
)
parser.add_argument_group(group_gcpspecific)
group_saving = parser.add_argument_group("sources saving")
group_saving.add_argument("--sources-save",
action="store",
help=_("Save source arguments")
help=_("save sources arguments")
)
group_saving.add_argument("--sources-replace",
action="store",
help=_("Save source arguments and replace memory if it already exists")
help=_("save sources arguments and replace memory if it already exists")
)
group_saving.add_argument("--sources-load",
action="store",
help=_("Load source arguments")
help=_("load sources arguments")
)
group_saving.add_argument("--sources-del",
action="store",
help=_("delete saved sources")
help=_("delete saved sources list")
)
group_saving.add_argument("--sources-list",
action="store_true", default=False,
help=_("List names of saved sources")
help=_("list names of saved sources")
)
group_saving.add_argument("--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_argument_group(group_saving)
@ -663,7 +669,7 @@ class GCP():
logging.getLogger().setLevel(logging.DEBUG)
if options.no_fs_fix:
options.fs_fix = 'no'
options.fix_filenames = 'no'
preserve = set()

159
gcp.1
View File

@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.TH GCP 1 "June 04, 2011"
.TH GCP 1 "October 14, 2018"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
@ -15,6 +15,9 @@
.\" .br insert line break
.\" .sp <n> insert n+1 empty lines
.\" for manpage-specific macros, see man(7)
.\" TeX users may be more comfortable with the \fB<whatever>\fP and
.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
.\" respectively.
.SH NAME
gcp \- Advanced command-line file copier
.SH SYNOPSIS
@ -28,77 +31,109 @@ gcp \- Advanced command-line file copier
.RI [ FILE2 ... ]
.I DEST-DIR
.SH DESCRIPTION
This manual page documents briefly the
.B gcp
command.
.PP
.\" TeX users may be more comfortable with the \fB<whatever>\fP and
.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
.\" respectively.
\fBgcp\fP is a file copier, loosely inspired by cp, but with high level functionalities like:
\- transfer progression indication
\- continuous copying when there is an issue: it skips the problematic file and goes on
\- copy status logging: which files were effectively copied
\- name mangling to handle target filesystem limitations (e.g. removing incompatible chars like "?" or "*" on vfat)
\- forced copy serialization: new files to copy are added to a global queue to avoid hard drive head seeks
\- transfer list management: gcp can save a list of files to copy and reuse it later
\- approximate option compatibility with cp (approximate because the behaviour is not exactly the same, see below)
\fBgcp\fP is a file copier, loosely inspired by cp, but with high level
functionalities like:
.IP \(bu 2
transfer progression indication
.IP \(bu
continuous copying when there is an issue: it skips the problematic file and
goes on
.IP \(bu
copy status logging: which files were effectively copied
.IP \(bu
name mangling to handle target filesystem limitations (e.g. removing
incompatible chars like "?" or "*" on FAT filesystems)
.IP \(bu
forced copy serialization: new files to copy are added to a global queue to
avoid hard drive head seeks
.IP \(bu
transfer list management: gcp can save a list of files to copy and reuse it
later
.IP \(bu
approximate option compatibility with cp (approximate because the behaviour is
not exactly the same, see below)
.SH OPTIONS
These programs follow the usual GNU command line syntax, with long
options starting with two dashes (`-').
By default, calling gcp is equivalent to calling gcp \-\-preserve=mode,ownership,timestamps.
.PP
A summary of options is included below.
.SS "General options"
.TP
.B \-\-version
Show version of program and exit.
.SS General options
.TP
.B \-h, \-\-help
Show summary of options.
.TP
.B \-r, \-R, \-\-recursive
Copy directories recursively.
.TP
.B \-L, \-\-dereference
always follow symbolic links in sources
.TP
.B \-P, \-\-no\-dereference
never follow symbolic links in sources
.B \-V, \-\-version
Show program version and copyright information and exit.
.SS cp-like options
.TP
.B \-f, \-\-force
Overwrite existing files.
.TP
.B \-L, \-\-dereference
Always follow symbolic links in sources.
.TP
.B \-P, \-\-no\-dereference
Never follow symbolic links in sources.
.TP
.B \-p
Same as \-\-preserve=mode,ownership,timestamps
Same as \fB\-\-preserve=mode,ownership,timestamps\fP
.TP
.B \-\-preserve=PRESERVE
Keep specified attributes. Attributes can be mode, ownership and timestamps.
When several attributes are passed, they need to be separated by commas. Note
that timestamps preservation has some limits, see section LIMITATIONS.
.B \-\-preserve=<\fIattributes\fP>
Preserve specified attributes. Attributes can be \fImode\fP, \fIownership\fP
and \fItimestamps\fP.
When several attributes are passed, they need to be separated by commas.
Please note that timestamps preservation has some limits, see section
\fILIMITATIONS\fP.
.TP
.B \-\-no\-fs\-fix
Don't fix file system naming incompatibilities.
.TP
.B \-\-no\-progress
Disable progress bar.
.B \-r, \-R, \-\-recursive
Copy directories recursively.
.TP
.B \-v, \-\-verbose
Display what is being done.
.SS "Sources saving"
.SS gcp-specific options
.TP
.B \-\-sources\-save=SOURCES_SAVE
Save the list of source files in a list named SOURCES_SAVE.
.B \-\-fix\-filenames=<\fIforce\fP|\fIauto\fP|\fIno\fP>
gcp has the ability to modify the destination file name if the target file
system would not accept the original file name.
Offending characters will be replaced with similar-looking ones.
.IP
This option accept the following values:
.RS
.TP
.B \-\-sources\-replace=SOURCES_REPLACE
Save the list of source files in a list named SOURCES_REPLACE and
replace it if it already exists.
\fIauto\fP (default)
gcp will attempt to be smart, i.e. detect incompatibilities and fix them as-needed.
.TP
.B \-\-sources\-load=SOURCES_LOAD
Reuse the list of source file named SOURCES_LOAD.
\fIforce\fP
Always fix file names that could cause problems on any known filesystem or OS.
This is useful e.g. with NTFS, see \fINOTE ON NTFS\fP below.
.TP
.B \-\-sources\-del=SOURCES_DEL
Delete the list of source files named SOURCES_DEL.
\fIno\fP
Renaming is disabled entirely.
.RE
.IP
Currently, gcp is only aware of FAT incompatibilities:
\'\\\', \':\', \'*\', \'?\', \'"\', \'<\', \'>\' and \'|\'.
.TP
.B \-\-no\-fs\-fix (DEPRECATED)
Same as \fB\-\-fix\-filenames=no\fP.
This option will be removed in a future release.
.TP
.B \-\-no\-progress
Disable progress bar.
.SS Sources saving
.TP
.B \-\-sources\-save=\fISOURCES\fP
Save the list of source files in a list named \fISOURCES\fP.
.TP
.B \-\-sources\-replace=\fISOURCES\fP
Save the list of source files in a list named \fISOURCES\fP;
the file is overwritten it already exists.
.TP
.B \-\-sources\-load=\fISOURCES\fP
Use the list of source files named \fISOURCES\fP.
.TP
.B \-\-sources\-del=\fISOURCES\fP
Delete the list of source files named \fISOURCES\fP.
.TP
.B \-\-sources\-list
List the names of source file lists.
@ -108,21 +143,33 @@ List the names of source file lists, including their content.
.SH EXIT STATUS
The exit status can be:
.IP \[bu] 2
\fB0\fP if files have been copied correctly or if another instance of gcp is already running and will do the copy.
\fB0\fP if files have been copied correctly or if another instance of gcp is
already running and will do the copy.
.IP \[bu]
\fB1\fP if at least one file has not been copied, or if something went wrong.
.IP \[bu]
\fB2\fP if all files have been copied but with some issues
.SH LIMITATIONS
Timestamps preservation with \-\-preserve option is limited by the os python
module on POSIX systems. Currently, python only returns timestamps in float
format, which is a smaller precision than what POSIX provides. Progress on this
issue can be seen at http://bugs.python.org/issue11457.
Timestamps preservation with \fB\-\-preserve\fP option is limited by the
\fIos\fP Python module on POSIX systems. Currently, Python only returns
timestamps in float format, which is a smaller precision than what POSIX
provides. Progress on this issue can be seen at
http://bugs.python.org/issue11457.
.PP
The \fB\-\-preserve\fP option cannot currently be used without an attribute
list (\fBgcp \-\-preserve foo bar\fP will behave as \fBgcp \-\-preserve=foo
bar\fP). Use the \fB\-p\fP switch instead.
.SH NOTE ON NTFS
NTFS will not enforce the same file name limitations than FAT, but files that
would not be accepted on a FAT filesystem will still cause problems on Windows.
Hence, it is recommended to use \-\-fix-filenames=force when copying to NTFS
(when Windows compatibility is desired, anyway).
.SH SEE ALSO
.BR cp (1).
.br
.SH AUTHOR
gcp was written by Jérôme Poisson <goffi@goffi.org>.
It is currently maintained by Matteo Cypriani <mcy@lm7.fr>.
.PP
This manual page was written by Thomas Preud'homme <robotux@celest.fr>,
for the Debian project (and may be used by others).
This manual page was initially written by Thomas Preud'homme
<robotux@celest.fr> for the Debian project (and may be used by others).

View File

@ -1,262 +1,265 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
# gcp -- translation template
#
# This file is distributed under the same license as the gcp package.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: 0.2.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-22 20:09+0200\n"
"POT-Creation-Date: 2018-10-14 20:51+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: English\n"
"Language: en\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: gcp:45
#: gcp:46
msgid "Error during import"
msgstr ""
#: gcp:46
#: gcp:47
msgid "Please check dependecies:"
msgstr ""
#: gcp:52
#: gcp:54
msgid "ProgressBar not available, please download it at https://pypi.org/"
msgstr ""
#: gcp:3
#: gcp:55
msgid ""
"Progress bar deactivated\n"
"--\n"
msgstr ""
#: gcp:88
#: gcp:90
msgid "Init DbusObject..."
msgstr ""
#: gcp:109
#: gcp:111
msgid "INTERNAL ERROR: invalid arguments"
msgstr ""
#: gcp:114
#: gcp:116
msgid "INTERNAL ERROR: invalid source_dir"
msgstr ""
#: gcp:169
#: gcp:171
msgid "/!\\ THE FOLLOWING FILES WERE *NOT* SUCCESSFULY COPIED:"
msgstr ""
#: gcp:175
#: gcp:177
msgid "The following files were copied, but some errors happened:"
msgstr ""
#: gcp:181
#: gcp:183
#, python-format
msgid "Please check journal: %s"
msgstr ""
#: gcp:203
#: gcp:205
msgid "gcp launched"
msgstr ""
#: gcp:211
#: gcp:213
msgid "Init DBus..."
msgstr ""
#: gcp:241
#: gcp:244
msgid "Can't read mounts table"
msgstr ""
#: gcp:248
#: gcp:251
#, python-format
msgid "Adding to copy list: %(path)s ==> %(dest_path)s (%(fs_type)s)"
msgstr ""
#: gcp:253
#: gcp:258
#, python-format
msgid "Can't copy %(path)s: %(exception)s"
msgstr ""
#: gcp:280
#: gcp:286
#, python-format
msgid "Can't append %(path)s to copy list: %(exception)s"
msgstr ""
#: gcp:283
#: gcp:289
#, python-format
msgid "Can't access %(dirpath)s: %(exception)s"
msgstr ""
#: gcp:295
#: gcp:301
#, python-format
msgid "Invalid dest_path: %s"
msgstr ""
#: gcp:300
#: gcp:306
#, python-format
msgid "The path given in arg doesn't exist or is not accessible: %s"
msgstr ""
#: gcp:304
#: gcp:310
#, python-format
msgid "omitting directory \"%s\""
msgstr ""
#: gcp:329
#: gcp:348
#, python-format
msgid "File [%s] already exists, skipping it!"
msgstr ""
#: gcp:347
#: gcp:368
#, python-format
msgid "COPYING %(source)s ==> %(dest)s"
msgstr ""
#: gcp:447
#: gcp:462
#, python-format
msgid "%.2f PiB"
msgstr ""
#: gcp:449
#: gcp:464
#, python-format
msgid "%.2f TiB"
msgstr ""
#: gcp:451
#: gcp:466
#, python-format
msgid "%.2f GiB"
msgstr ""
#: gcp:453
#: gcp:468
#, python-format
msgid "%.2f MiB"
msgstr ""
#: gcp:455
#: gcp:470
#, python-format
msgid "%.2f KiB"
msgstr ""
#: gcp:457
#: gcp:471
#, python-format
msgid "%i B"
msgstr ""
#: gcp:465 gcp:470
#: gcp:479 gcp:485
#, python-format
msgid "Copying %s"
msgstr ""
#: gcp:497 gcp:530
#: gcp:515 gcp:548
msgid ""
"No saved sources with this name, check existing names with --sources-list"
msgstr ""
#: gcp:507
#: gcp:525
msgid "Saved sources:"
msgstr ""
#: gcp:521
#: gcp:539
msgid ""
"There is already a saved sources with this name, skipping --sources-save"
msgstr ""
#: gcp:557
msgid "copy directories recursively"
msgstr ""
#: gcp:561
#: gcp:578
msgid "force overwriting of existing files"
msgstr ""
#: gcp:565
#: gcp:582
msgid "always follow symbolic links in sources"
msgstr ""
#: gcp:586
msgid "never follow symbolic links in sources"
msgstr ""
#: gcp:590
#, python-format
msgid "same as --preserve=%s"
msgstr ""
#: gcp:569
#: gcp:594
#, python-format
msgid ""
"preserve specified attributes; accepted values: 'all', or one or more "
"amongst %s"
"preserve specified attributes; accepted values: 'all', or "
"one or more amongst %s"
msgstr ""
#: gcp:574
msgid "always follow symbolic links in sources"
#: gcp:599
msgid "copy directories recursively"
msgstr ""
#: gcp:578
msgid "never follow symbolic links in sources"
#: gcp:603
msgid "display what is being done"
msgstr ""
#: gcp:586
msgid "fix filesystem name incompatibily (default: auto)"
msgstr ""
#: gcp:590
msgid "same as --fs-fix=no (overrides --fs-fix)"
msgstr ""
#: gcp:594
msgid "disable progress bar"
msgstr ""
#: gcp:598
msgid "Show what is currently done"
msgstr ""
#: gcp:607
msgid "Save source arguments"
msgstr ""
#: gcp:611
msgid "Save source arguments and replace memory if it already exists"
msgstr ""
#: gcp:615
msgid "Load source arguments"
#: gcp:614
msgid ""
"fix file names incompatible with the destination file "
"system (default: auto)"
msgstr ""
#: gcp:619
msgid "delete saved sources"
msgid ""
"[DEPRECATED] same as --fix-filename=no (overrides --fix-"
"filenames)"
msgstr ""
#: gcp:623
msgid "List names of saved sources"
#: gcp:624
msgid "disable progress bar"
msgstr ""
#: gcp:627
msgid "List names of saved sources and files in it"
#: gcp:631
msgid "save sources arguments"
msgstr ""
#: gcp:635
msgid "save sources arguments and replace memory if it already exists"
msgstr ""
#: gcp:639
msgid "Progress bar is not available, deactivating"
msgid "load sources arguments"
msgstr ""
#: gcp:643
msgid "delete saved sources list"
msgstr ""
#: gcp:647
msgid "list names of saved sources"
msgstr ""
#: gcp:651
msgid "list names of saved sources and files in it"
msgstr ""
#: gcp:663
msgid "Progress bar is not available, deactivating"
msgstr ""
#: gcp:687
#, python-format
msgid "Invalid --preserve value '%s'"
msgstr ""
#: gcp:690
#: gcp:714
#, python-format
msgid "There is already one instance of %s running, pluging to it"
msgstr ""
#: gcp:696
#: gcp:720
msgid "Wrong number of arguments"
msgstr ""
#: gcp:698
#: gcp:722
#, python-format
msgid "adding args to gcp: %s"
msgstr ""
#: gcp:707
#: gcp:731
msgid "User interruption: good bye"
msgstr ""

Binary file not shown.

View File

@ -41,9 +41,9 @@ setuptools.setup(
# 'console_scripts': ['gcp=gcp:main'],
# },
data_files=[
('man/man1', ["gcp.1"]),
('share/locale/fr/LC_MESSAGES', ['i18n/fr/LC_MESSAGES/gcp.mo']),
('share/man/man1', ["gcp.1"]),
('share/doc/%s' % name, ['CHANGELOG', 'LICENSE.txt', 'README.md']),
('share/doc/%s' % name, ['CHANGELOG', 'LICENSE', 'README.md']),
],
install_requires=['PyGObject', 'dbus-python'],
python_requires='>=3',

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""
gcp: Goffi's CoPier -- unit tests
gcp: Gcp CoPier -- unit tests
Copyright (c) 2010, 2011 Jérôme Poisson <goffi@goffi.org>
Copyright (c) 2018 Matteo Cypriani <mcy@lm7.fr>
@ -239,6 +239,19 @@ class TestCopyCases(unittest.TestCase):
check_after = dirCheck('.')
self.assertEqual(check_before, check_after)
def test_fix_filenames(self):
"""Checks the --fix-filenames option.
"""
source = 'wi||fat<like>this:"file*name"?'
fixed_name = 'wi!!fat[like]this;\'file+name\'_'
makeRandomFile(source, S10K)
source_sha = sha1sum(source)
mkdir('dest_dir')
ret = system(GCP + " --fix-filenames=force '" + source + "' dest_dir")
self.assertNotEqual(ret, 0)
dest = join('dest_dir', fixed_name)
dest_sha = sha1sum(dest)
self.assertEqual(source_sha, dest_sha)
if __name__ == '__main__':
unittest.main()