X-Git-Url: https://arthur.barton.de/gitweb/?a=blobdiff_plain;f=cmd%2Fsave-cmd.py;h=bf2877ba240a0ff90c79745c5104217c4c1849ea;hb=aeafe13a9330e7deca3dc6b9c0496937d904663a;hp=66d56e2449a45a4db61a378d77fce694caa0ef8c;hpb=16f9f9829038f25aec80ebfae3c882a66281e145;p=bup.git diff --git a/cmd/save-cmd.py b/cmd/save-cmd.py index 66d56e2..bf2877b 100755 --- a/cmd/save-cmd.py +++ b/cmd/save-cmd.py @@ -1,8 +1,22 @@ -#!/usr/bin/env python -import sys, stat, time, math +#!/bin/sh +"""": # -*-python-*- +bup_python="$(dirname "$0")/bup-python" || exit $? +exec "$bup_python" "$0" ${1+"$@"} +""" +# end of bup preamble + +from __future__ import absolute_import, print_function +from errno import EACCES +from io import BytesIO +import os, sys, stat, time, math + from bup import hashsplit, git, options, index, client, metadata, hlinkdb -from bup.helpers import * from bup.hashsplit import GIT_MODE_TREE, GIT_MODE_FILE, GIT_MODE_SYMLINK +from bup.helpers import (add_error, grafted_path_components, handle_ctrl_c, + hostname, istty2, log, parse_date_or_fatal, parse_num, + path_components, progress, qprogress, resolve_parent, + saved_errors, stripped_path_components, + userfullname, username, valid_save_name) optspec = """ @@ -61,19 +75,24 @@ if opt.graft: old_path, new_path = splitted_parameter if not (old_path and new_path): o.fatal("a graft point cannot be empty") - graft_points.append((realpath(old_path), realpath(new_path))) + graft_points.append((resolve_parent(old_path), + resolve_parent(new_path))) is_reverse = os.environ.get('BUP_SERVER_REVERSE') if is_reverse and opt.remote: o.fatal("don't use -r in reverse mode; it's automatic") -if opt.name and opt.name.startswith('.'): +if opt.name and not valid_save_name(opt.name): o.fatal("'%s' is not a valid branch name" % opt.name) refname = opt.name and 'refs/heads/%s' % opt.name or None if opt.remote or is_reverse: - cli = client.Client(opt.remote) + try: + cli = client.Client(opt.remote) + except client.ClientError as e: + log('error: %s' % e) + sys.exit(1) oldref = refname and cli.read_ref(refname) or None - w = cli.new_packwriter() + w = cli.new_packwriter(compression_level=opt.compress) else: cli = None oldref = refname and git.read_ref(refname) or None @@ -124,13 +143,32 @@ def _pop(force_tree, dir_metadata=None): part = parts.pop() shalist = shalists.pop() metalist = metalists.pop() - if metalist: + if metalist and not force_tree: if dir_metadata: # Override the original metadata pushed for this dir. metalist = [('', dir_metadata)] + metalist[1:] sorted_metalist = sorted(metalist, key = lambda x : x[0]) metadata = ''.join([m[1].encode() for m in sorted_metalist]) - shalist.append((0100644, '.bupm', w.new_blob(metadata))) - tree = force_tree or w.new_tree(shalist) + metadata_f = BytesIO(metadata) + mode, id = hashsplit.split_to_blob_or_tree(w.new_blob, w.new_tree, + [metadata_f], + keep_boundaries=False) + shalist.append((mode, '.bupm', id)) + # FIXME: only test if collision is possible (i.e. given --strip, etc.)? + if force_tree: + tree = force_tree + else: + names_seen = set() + clean_list = [] + for x in shalist: + name = x[1] + if name in names_seen: + parent_path = '/'.join(parts) + '/' + add_error('error: ignoring duplicate path %r in %r' + % (name, parent_path)) + else: + names_seen.add(name) + clean_list.append(x) + tree = w.new_tree(clean_list) if shalists: shalists[-1].append((GIT_MODE_TREE, git.mangle_name(part, @@ -180,10 +218,13 @@ def progress_report(n): indexfile = opt.indexfile or git.repo('bupindex') r = index.Reader(indexfile) -if not os.access(indexfile + '.meta', os.W_OK|os.R_OK): - log('error: cannot access "%s"; have you run bup index?' % indexfile) +try: + msr = index.MetaStoreReader(indexfile + '.meta') +except IOError as ex: + if ex.errno != EACCES: + raise + log('error: cannot access %r; have you run bup index?' % indexfile) sys.exit(1) -msr = index.MetaStoreReader(indexfile + '.meta') hlink_db = hlinkdb.HLinkDB(indexfile + '.hlink') def already_saved(ent): @@ -264,7 +305,8 @@ for (transname,ent) in r.filter(extra, wantrecurse=wantrecurse_during): continue if opt.smaller and ent.size >= opt.smaller: if exists and not hashvalid: - add_error('skipping large file "%s"' % ent.name) + if opt.verbose: + log('skipping large file "%s"\n' % ent.name) lastskip_name = ent.name continue @@ -293,16 +335,7 @@ for (transname,ent) in r.filter(extra, wantrecurse=wantrecurse_during): # ...]. if first_root == None: - dir_name, fs_path = dirp[0] first_root = dirp[0] - # Not indexed, so just grab the FS metadata or use empty metadata. - try: - meta = metadata.from_path(fs_path) if fs_path else metadata.Metadata() - except (OSError, IOError), e: - add_error(e) - lastskip_name = dir_name - else: - _push(dir_name, meta) elif first_root != dirp[0]: root_collision = True @@ -316,11 +349,11 @@ for (transname,ent) in r.filter(extra, wantrecurse=wantrecurse_during): # Not indexed, so just grab the FS metadata or use empty metadata. try: meta = metadata.from_path(fs_path) if fs_path else metadata.Metadata() - except (OSError, IOError), e: + except (OSError, IOError) as e: add_error(e) lastskip_name = dir_name - else: - _push(dir_name, meta) + meta = metadata.Metadata() + _push(dir_name, meta) if not file: if len(parts) == 1: @@ -355,7 +388,7 @@ for (transname,ent) in r.filter(extra, wantrecurse=wantrecurse_during): if stat.S_ISREG(ent.mode): try: f = hashsplit.open_noatime(ent.name) - except (IOError, OSError), e: + except (IOError, OSError) as e: add_error(e) lastskip_name = ent.name else: @@ -363,7 +396,7 @@ for (transname,ent) in r.filter(extra, wantrecurse=wantrecurse_during): (mode, id) = hashsplit.split_to_blob_or_tree( w.new_blob, w.new_tree, [f], keep_boundaries=False) - except (IOError, OSError), e: + except (IOError, OSError) as e: add_error('%s: %s' % (ent.name, e)) lastskip_name = ent.name else: @@ -372,7 +405,7 @@ for (transname,ent) in r.filter(extra, wantrecurse=wantrecurse_during): elif stat.S_ISLNK(ent.mode): try: rl = os.readlink(ent.name) - except (OSError, IOError), e: + except (OSError, IOError) as e: add_error(e) lastskip_name = ent.name else: @@ -393,7 +426,7 @@ for (transname,ent) in r.filter(extra, wantrecurse=wantrecurse_during): hlink = find_hardlink_target(hlink_db, ent) try: meta = metadata.from_path(ent.name, hardlink_target=hlink) - except (OSError, IOError), e: + except (OSError, IOError) as e: add_error(e) lastskip_name = ent.name else: @@ -420,12 +453,14 @@ tree = _pop(force_tree = None, dir_metadata = metadata.Metadata() if root_collision else None) if opt.tree: - print tree.encode('hex') + print(tree.encode('hex')) if opt.commit or opt.name: - msg = 'bup save\n\nGenerated by command:\n%r' % sys.argv - commit = w.new_commit(oldref, tree, date, msg) + msg = 'bup save\n\nGenerated by command:\n%r\n' % sys.argv + userline = '%s <%s@%s>' % (userfullname(), username(), hostname()) + commit = w.new_commit(tree, oldref, userline, date, None, + userline, date, None, msg) if opt.commit: - print commit.encode('hex') + print(commit.encode('hex')) msr.close() w.close() # must close before we can update the ref