Commit 1996b90f authored by Marcel Hellkamp's avatar Marcel Hellkamp
Browse files

Make 'put' command save by default (files not overwritten)

parent 4e11acc4
......@@ -124,6 +124,10 @@ class Printer:
if self.verbosity >= 3:
self._print(msg, *args, **kwargs)
def warn(self, msg, *args, **kwargs):
""" Print an error message (if not quiet) in a very visible way."""
self._print("WARN: " + msg, *args, **kwargs)
def error(self, msg, *args, **kwargs):
""" Print an error message (if not quiet) and optionally (-vv or higher) a stacktrace."""
self._print("ERROR: " + msg, *args, **kwargs)
......
......@@ -5,9 +5,9 @@ You can also create new archives and set ACL entries or metadata attributes with
It works a bit as a swiss army knife for simple archive creation or manipulation. For everything not
covered here, there are more specialized commands available.
File upload is save by default: Existing remote files are not overwritten. Use -f to force re-upload or -u to
re-upload newer files only. Note that -u relies on a working clock on both local and remote side, as it compares the
file modification times only.
File upload is save by default: Existing remote files are not overwritten. You can --force re-upload or just --update
newer files. Note that --update relies on a working clock on both local and remote side, as it compares the file
modification times only.
All uploads and changes are wrapped in a transaction. If something goes wrong, nothing is committed on remote side and
you can simply re-run the same command.
......@@ -15,17 +15,20 @@ you can simply re-run the same command.
"""
import os
from pycdstar3 import FormUpdate
from pycdstar3 import FormUpdate, ApiError
from pycdstar3.cli import CliError
from pycdstar3.cli._utils import hbytes, kvtype, globtype
def register(subparsers):
parser = subparsers.add_parser("put", help=__doc__.strip().splitlines()[0], description=__doc__)
# parser.add_argument("-u", "--update", action="store_true",
_grp = parser.add_mutually_exclusive_group()
# _grp.add_argument("-u", "--update", action="store_true",
# help="Update outdated remote files. (default: skip)")
# parser.add_argument("-f", "--force", action="store_true",
# help="Always overwrite remote files, even if they are newer. (default: skip)")
_grp.add_argument("-f", "--force", action="store_true",
help="Always overwrite remote files. (default: skip)")
# parser.add_argument("--delete", action="store_true",
# help="Delete remote files not present locally, if they match a PATH parameter.")
parser.add_argument("-i", "--include", metavar="GLOB", type=globtype, action="append",
......@@ -72,18 +75,6 @@ def collect_files(path, hidden=False):
raise CliError("Not a file: " + path)
def filter_files(files, inc_rules, exc_rules, debug):
for file in files:
if inc_rules and not any(rule.match(file) for rule in inc_rules):
debug("Skipping: {} (not included)", file)
continue
if any(rule.match(file) for rule in exc_rules):
debug("Skipping: {} (excluded)", file)
continue
yield file
def remote_name(base, file, prefix="", flatten=False):
target = os.path.relpath(file, base)
if flatten:
......@@ -101,6 +92,7 @@ def command(ctx, args): # noqa: C901
client = ctx.client
vault = ctx.vault
archive = args.ARCHIVE
force = args.force
prefix = args.prefix
prefix = prefix.lstrip('/')
......@@ -111,12 +103,15 @@ def command(ctx, args): # noqa: C901
uploads = {}
total = 0
for path in args.PATH:
files = collect_files(path, args.include_hidden)
files = filter_files(files, inc_rules, exc_rules, debug=ctx.print.vv)
for file in files:
fstat = os.stat(file)
uploads[remote_name(".", file, prefix, args.flat)] = file, fstat
total += fstat.st_size
for file in collect_files(path, args.include_hidden):
if inc_rules and not any(rule.match(file) for rule in inc_rules):
ctx.print.v("Skipping: {} (not included)", file)
elif any(rule.match(file) for rule in exc_rules):
ctx.print.v("Skipping: {} (excluded)", file)
else:
fstat = os.stat(file)
total += fstat.st_size
uploads[remote_name(".", file, prefix, args.flat)] = file, fstat
meta = {}
for key, val in args.meta or []:
......@@ -172,7 +167,15 @@ def command(ctx, args): # noqa: C901
fp = chunks
else:
ctx.print(line)
client.put_file(vault, archive, target, fp)
try:
client.put_file(vault, archive, target, fp, replace=force)
except ApiError as e:
if e.status == 412:
# TODO: Make more specific as soon as CDSTAR returns a proper error code.
ctx.print.warn("Upload failed (file exists): {}", target)
continue
raise
finally:
if pbar:
pbar.close()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment