def run_augment_item_meta_tests(repo, file_path, file_size, link_path, link_target): _, file_item = vfs.resolve(repo, file_path)[-1] _, link_item = vfs.resolve(repo, link_path, follow=False)[-1] wvpass(isinstance(file_item.meta, Metadata)) wvpass(isinstance(link_item.meta, Metadata)) # Note: normally, modifying item.meta values is forbidden file_item.meta.size = file_item.meta.size or vfs.item_size(repo, file_item) link_item.meta.size = link_item.meta.size or vfs.item_size(repo, link_item) ## Ensure a fully populated item is left alone augmented = vfs.augment_item_meta(repo, file_item) wvpass(augmented is file_item) wvpass(augmented.meta is file_item.meta) augmented = vfs.augment_item_meta(repo, file_item, include_size=True) wvpass(augmented is file_item) wvpass(augmented.meta is file_item.meta) ## Ensure a missing size is handled poperly file_item.meta.size = None augmented = vfs.augment_item_meta(repo, file_item) wvpass(augmented is file_item) wvpass(augmented.meta is file_item.meta) augmented = vfs.augment_item_meta(repo, file_item, include_size=True) wvpass(augmented is not file_item) wvpasseq(file_size, augmented.meta.size) ## Ensure a meta mode is handled properly mode_item = file_item._replace(meta=vfs.default_file_mode) augmented = vfs.augment_item_meta(repo, mode_item) augmented_w_size = vfs.augment_item_meta(repo, mode_item, include_size=True) for item in (augmented, augmented_w_size): meta = item.meta wvpass(item is not file_item) wvpass(isinstance(meta, Metadata)) wvpasseq(vfs.default_file_mode, meta.mode) wvpasseq((0, 0, 0, 0, 0), (meta.uid, meta.gid, meta.atime, meta.mtime, meta.ctime)) wvpass(augmented.meta.size is None) wvpasseq(file_size, augmented_w_size.meta.size) ## Ensure symlinks are handled properly mode_item = link_item._replace(meta=vfs.default_symlink_mode) augmented = vfs.augment_item_meta(repo, mode_item) wvpass(augmented is not mode_item) wvpass(isinstance(augmented.meta, Metadata)) wvpasseq(link_target, augmented.meta.symlink_target) wvpasseq(len(link_target), augmented.meta.size) augmented = vfs.augment_item_meta(repo, mode_item, include_size=True) wvpass(augmented is not mode_item) wvpass(isinstance(augmented.meta, Metadata)) wvpasseq(link_target, augmented.meta.symlink_target) wvpasseq(len(link_target), augmented.meta.size)
def test_duplicate_save_dates(): with no_lingering_errors(): with test_tempdir('bup-tvfs-') as tmpdir: bup_dir = tmpdir + '/bup' environ['GIT_DIR'] = bup_dir environ['BUP_DIR'] = bup_dir environ['TZ'] = 'UTC' git.repodir = bup_dir data_path = tmpdir + '/src' os.mkdir(data_path) with open(data_path + '/file', 'w+') as tmpfile: tmpfile.write(b'canary\n') ex((bup_path, 'init')) ex((bup_path, 'index', '-v', data_path)) for i in range(11): ex((bup_path, 'save', '-d', '100000', '-n', 'test', data_path)) repo = LocalRepo() res = vfs.resolve(repo, '/test') wvpasseq(2, len(res)) name, revlist = res[-1] wvpasseq('test', name) wvpasseq(('.', '1970-01-02-034640-00', '1970-01-02-034640-01', '1970-01-02-034640-02', '1970-01-02-034640-03', '1970-01-02-034640-04', '1970-01-02-034640-05', '1970-01-02-034640-06', '1970-01-02-034640-07', '1970-01-02-034640-08', '1970-01-02-034640-09', '1970-01-02-034640-10', 'latest'), tuple(sorted(x[0] for x in vfs.contents(repo, revlist))))
def readlink(self, path): if self.verbose > 0: log('--readlink(%r)\n' % path) res = vfs.resolve(self.repo, path, follow=False) name, item = res[-1] if not item: return -errno.ENOENT return vfs.readlink(repo, item)
def test_misc(): with no_lingering_errors(): with test_tempdir('bup-tvfs-') as tmpdir: bup_dir = tmpdir + '/bup' environ['GIT_DIR'] = bup_dir environ['BUP_DIR'] = bup_dir git.repodir = bup_dir data_path = tmpdir + '/src' os.mkdir(data_path) with open(data_path + '/file', 'w+') as tmpfile: tmpfile.write(b'canary\n') symlink('file', data_path + '/symlink') ex((bup_path, 'init')) ex((bup_path, 'index', '-v', data_path)) ex((bup_path, 'save', '-d', '100000', '-tvvn', 'test', '--strip', data_path)) repo = LocalRepo() wvstart('readlink') ls_tree = exo(('git', 'ls-tree', 'test', 'symlink')).out mode, typ, oidx, name = ls_tree.strip().split(None, 3) assert name == 'symlink' link_item = vfs.Item(oid=oidx.decode('hex'), meta=int(mode, 8)) wvpasseq('file', vfs.readlink(repo, link_item)) ls_tree = exo(('git', 'ls-tree', 'test', 'file')).out mode, typ, oidx, name = ls_tree.strip().split(None, 3) assert name == 'file' file_item = vfs.Item(oid=oidx.decode('hex'), meta=int(mode, 8)) wvexcept(Exception, vfs.readlink, repo, file_item) wvstart('item_size') wvpasseq(4, vfs.item_size(repo, link_item)) wvpasseq(7, vfs.item_size(repo, file_item)) meta = metadata.from_path(__file__) meta.size = 42 fake_item = file_item._replace(meta=meta) wvpasseq(42, vfs.item_size(repo, fake_item)) wvstart('augment_item_meta') run_augment_item_meta_tests(repo, '/test/latest/file', 7, '/test/latest/symlink', 'file') wvstart('copy_item') # FIXME: this caused StopIteration #_, file_item = vfs.resolve(repo, '/file')[-1] _, file_item = vfs.resolve(repo, '/test/latest/file')[-1] file_copy = vfs.copy_item(file_item) wvpass(file_copy is not file_item) wvpass(file_copy.meta is not file_item.meta) wvpass(isinstance(file_copy, tuple)) wvpass(file_item.meta.user) wvpass(file_copy.meta.user) file_copy.meta.user = None wvpass(file_item.meta.user)
def read(self, path, size, offset): if self.verbose > 0: log('--read(%r)\n' % path) res = vfs.resolve(self.repo, path, follow=False) name, item = res[-1] if not item: return -errno.ENOENT with vfs.fopen(repo, item) as f: f.seek(offset) return f.read(size)
def open(self, path, flags): if self.verbose > 0: log('--open(%r)\n' % path) res = vfs.resolve(self.repo, path, follow=False) name, item = res[-1] if not item: return -errno.ENOENT accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR if (flags & accmode) != os.O_RDONLY: return -errno.EACCES
def readdir(self, path, offset): assert not offset # We don't return offsets, so offset should be unused res = vfs.resolve(self.repo, path, follow=False) dir_name, dir_item = res[-1] if not dir_item: yield -errno.ENOENT yield fuse.Direntry('..') # FIXME: make sure want_meta=False is being completely respected for ent_name, ent_item in vfs.contents(repo, dir_item, want_meta=False): yield fuse.Direntry(ent_name.replace('/', '-'))
def run_augment_item_meta_tests(repo, file_path, file_size, link_path, link_target): _, file_item = vfs.resolve(repo, file_path)[-1] _, link_item = vfs.lresolve(repo, link_path)[-1] wvpass(isinstance(file_item.meta, Metadata)) wvpass(isinstance(link_item.meta, Metadata)) # Note: normally, modifying item.meta values is forbidden file_item.meta.size = file_item.meta.size or vfs.item_size(repo, file_item) link_item.meta.size = link_item.meta.size or vfs.item_size(repo, link_item) ## Ensure a fully populated item is left alone augmented = vfs.augment_item_meta(repo, file_item) wvpass(augmented is file_item) wvpass(augmented.meta is file_item.meta) augmented = vfs.augment_item_meta(repo, file_item, include_size=True) wvpass(augmented is file_item) wvpass(augmented.meta is file_item.meta) ## Ensure a missing size is handled poperly file_item.meta.size = None augmented = vfs.augment_item_meta(repo, file_item) wvpass(augmented is file_item) wvpass(augmented.meta is file_item.meta) augmented = vfs.augment_item_meta(repo, file_item, include_size=True) wvpass(augmented is not file_item) wvpasseq(file_size, augmented.meta.size) ## Ensure a meta mode is handled properly mode_item = file_item._replace(meta=vfs.default_file_mode) augmented = vfs.augment_item_meta(repo, mode_item) augmented_w_size = vfs.augment_item_meta(repo, mode_item, include_size=True) for item in (augmented, augmented_w_size): meta = item.meta wvpass(item is not file_item) wvpass(isinstance(meta, Metadata)) wvpasseq(vfs.default_file_mode, meta.mode) wvpasseq((0, 0, 0, 0, 0), (meta.uid, meta.gid, meta.atime, meta.mtime, meta.ctime)) wvpass(augmented.meta.size is None) wvpasseq(file_size, augmented_w_size.meta.size) ## Ensure symlinks are handled properly mode_item = link_item._replace(meta=vfs.default_symlink_mode) augmented = vfs.augment_item_meta(repo, mode_item) wvpass(augmented is not mode_item) wvpass(isinstance(augmented.meta, Metadata)) wvpasseq(link_target, augmented.meta.symlink_target) wvpasseq(len(link_target), augmented.meta.size) augmented = vfs.augment_item_meta(repo, mode_item, include_size=True) wvpass(augmented is not mode_item) wvpass(isinstance(augmented.meta, Metadata)) wvpasseq(link_target, augmented.meta.symlink_target) wvpasseq(len(link_target), augmented.meta.size)
def main(argv): o = options.Options(optspec) opt, flags, extra = o.parse_bytes(argv[1:]) git.check_repo_or_die() if not extra: o.fatal('must specify a target') if len(extra) > 1: o.fatal('only one target file allowed') if opt.bupm and opt.meta: o.fatal('--meta and --bupm are incompatible') target = argv_bytes(extra[0]) if not re.match(br'/*[^/]+/[^/]+', target): o.fatal("path %r doesn't include a branch and revision" % target) with LocalRepo() as repo: resolved = vfs.resolve(repo, target, follow=False) leaf_name, leaf_item = resolved[-1] if not leaf_item: log('error: cannot access %r in %r\n' % (b'/'.join(name for name, item in resolved), target)) sys.exit(1) mode = vfs.item_mode(leaf_item) sys.stdout.flush() out = byte_stream(sys.stdout) if opt.bupm: if not stat.S_ISDIR(mode): o.fatal('%r is not a directory' % target) _, bupm_oid = vfs.tree_data_and_bupm(repo, leaf_item.oid) if bupm_oid: with vfs.tree_data_reader(repo, bupm_oid) as meta_stream: out.write(meta_stream.read()) elif opt.meta: augmented = vfs.augment_item_meta(repo, leaf_item, include_size=True) out.write(augmented.meta.encode()) else: if stat.S_ISREG(mode): with vfs.fopen(repo, leaf_item) as f: for b in chunkyreader(f): out.write(b) else: o.fatal('%r is not a plain file' % target) if saved_errors: log('warning: %d errors encountered\n' % len(saved_errors)) sys.exit(1)
def read(self, path, size, offset): path = argv_bytes(path) if self.verbose > 0: log('--read(%r)\n' % path) res = vfs.resolve(self.repo, path, follow=False) name, item = res[-1] if not item: return -errno.ENOENT with vfs.fopen(self.repo, item) as f: f.seek(offset) return f.read(size)
def readdir(self, path, offset): assert not offset # We don't return offsets, so offset should be unused res = vfs.resolve(self.repo, path, follow=False) dir_name, dir_item = res[-1] if not dir_item: yield -errno.ENOENT yield fuse.Direntry('..') # FIXME: make sure want_meta=False is being completely respected for ent_name, ent_item in vfs.contents(repo, dir_item, want_meta=False): yield fuse.Direntry(ent_name.replace('/', '-'))
def open(self, path, flags): path = argv_bytes(path) if self.verbose > 0: log('--open(%r)\n' % path) res = vfs.resolve(self.repo, path, follow=False) name, item = res[-1] if not item: return -errno.ENOENT accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR if (flags & accmode) != os.O_RDONLY: return -errno.EACCES
def _completer_get_subs(repo, line): (qtype, lastword) = shquote.unfinished_word(line) (dir,name) = os.path.split(lastword) dir_path = vfs.resolve(repo, dir or '/') _, dir_item = dir_path[-1] if not dir_item: subs = tuple() else: subs = tuple(dir_path + (entry,) for entry in vfs.contents(repo, dir_item) if (entry[0] != '.' and entry[0].startswith(name))) return dir, name, qtype, lastword, subs
def _completer_get_subs(repo, line): (qtype, lastword) = shquote.unfinished_word(line) dir, name = os.path.split(lastword) dir_path = vfs.resolve(repo, dir or b'/') _, dir_item = dir_path[-1] if not dir_item: subs = tuple() else: subs = tuple(dir_path + (entry, ) for entry in vfs.contents(repo, dir_item) if (entry[0] != b'.' and entry[0].startswith(name))) return qtype, lastword, subs
def open(self, path, flags): path = argv_bytes(path) if self.verbose > 0: log('--open(%r)\n' % path) res = vfs.resolve(self.repo, path, follow=False) name, item = res[-1] if not item: return -errno.ENOENT accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR if (flags & accmode) != os.O_RDONLY: return -errno.EACCES # Return None since read doesn't need the file atm... # If we *do* return the file, it'll show up as the last argument #return vfs.fopen(repo, item) return None
def _process_request(self, path): print('Handling request for %s' % path) sys.stdout.flush() # Set want_meta because dir metadata won't be fetched, and if # it's not a dir, then we're going to want the metadata. res = vfs.resolve(self.repo, path, want_meta=True) leaf_name, leaf_item = res[-1] if not leaf_item: self.send_error(404) return mode = vfs.item_mode(leaf_item) if stat.S_ISDIR(mode): self._list_directory(path, res) else: self._get_file(self.repo, path, res)
def _process_request(self, path): path = urllib.unquote(path) print('Handling request for %s' % path) # Set want_meta because dir metadata won't be fetched, and if # it's not a dir, then we're going to want the metadata. res = vfs.resolve(self.repo, path, want_meta=True) leaf_name, leaf_item = res[-1] if not leaf_item: self.send_error(404) return mode = vfs.item_mode(leaf_item) if stat.S_ISDIR(mode): self._list_directory(path, res) else: self._get_file(self.repo, path, res)
def test_contents_with_mismatched_bupm_git_ordering(): with no_lingering_errors(): with test_tempdir(b'bup-tvfs-') as tmpdir: bup_dir = tmpdir + b'/bup' environ[b'GIT_DIR'] = bup_dir environ[b'BUP_DIR'] = bup_dir git.repodir = bup_dir data_path = tmpdir + b'/src' os.mkdir(data_path) os.mkdir(data_path + b'/foo') with open(data_path + b'/foo.', 'wb+') as tmpfile: tmpfile.write(b'canary\n') ex((bup_path, b'init')) ex((bup_path, b'index', b'-v', data_path)) save_utc = 100000 save_name = strftime('%Y-%m-%d-%H%M%S', localtime(save_utc)).encode('ascii') ex((bup_path, b'save', b'-tvvn', b'test', b'-d', b'%d' % save_utc, b'--strip', data_path)) repo = LocalRepo() tip_sref = exo((b'git', b'show-ref', b'refs/heads/test')).out tip_oidx = tip_sref.strip().split()[0] tip_tree_oidx = exo((b'git', b'log', b'--pretty=%T', b'-n1', tip_oidx)).out.strip() tip_tree_oid = unhexlify(tip_tree_oidx) tip_tree = tree_dict(repo, tip_tree_oid) name, item = vfs.resolve(repo, b'/test/latest')[2] wvpasseq(save_name, name) expected = frozenset( (x.name, vfs.Item(oid=x.oid, meta=x.meta)) for x in (tip_tree[name] for name in (b'.', b'foo', b'foo.'))) contents = tuple(vfs.contents(repo, item)) wvpasseq(expected, frozenset(contents)) # Spot check, in case tree_dict shares too much code with the vfs name, item = next(((n, i) for n, i in contents if n == b'foo')) wvpass(S_ISDIR(item.meta)) name, item = next(((n, i) for n, i in contents if n == b'foo.')) wvpass(S_ISREG(item.meta.mode))
def test_metadata_method(): with no_lingering_errors(): with test_tempdir(b'bup-tmetadata-') as tmpdir: bup_dir = tmpdir + b'/bup' data_path = tmpdir + b'/foo' os.mkdir(data_path) ex(b'touch', data_path + b'/file') ex(b'ln', b'-s', b'file', data_path + b'/symlink') test_time1 = 13 * 1000000000 test_time2 = 42 * 1000000000 utime(data_path + b'/file', (0, test_time1)) lutime(data_path + b'/symlink', (0, 0)) utime(data_path, (0, test_time2)) ex(bup_path, b'-d', bup_dir, b'init') ex(bup_path, b'-d', bup_dir, b'index', b'-v', data_path) ex(bup_path, b'-d', bup_dir, b'save', b'-tvvn', b'test', data_path) git.check_repo_or_die(bup_dir) repo = LocalRepo() resolved = vfs.resolve(repo, b'/test/latest' + resolve_parent(data_path), follow=False) leaf_name, leaf_item = resolved[-1] m = leaf_item.meta WVPASS(m.mtime == test_time2) WVPASS(leaf_name == b'foo') contents = tuple(vfs.contents(repo, leaf_item)) WVPASS(len(contents) == 3) WVPASSEQ(frozenset(name for name, item in contents), frozenset((b'.', b'file', b'symlink'))) for name, item in contents: if name == b'file': m = item.meta WVPASS(m.mtime == test_time1) elif name == b'symlink': m = item.meta WVPASSEQ(m.symlink_target, b'file') WVPASSEQ(m.size, 4) WVPASSEQ(m.mtime, 0)
def test_duplicate_save_dates(): with no_lingering_errors(): with test_tempdir(b'bup-tvfs-') as tmpdir: bup_dir = tmpdir + b'/bup' environ[b'GIT_DIR'] = bup_dir environ[b'BUP_DIR'] = bup_dir environ[b'TZ'] = b'UTC' tzset() git.repodir = bup_dir data_path = tmpdir + b'/src' os.mkdir(data_path) with open(data_path + b'/file', 'wb+') as tmpfile: tmpfile.write(b'canary\n') ex((b'env',)) ex((bup_path, b'init')) ex((bup_path, b'index', b'-v', data_path)) for i in range(11): ex((bup_path, b'save', b'-d', b'100000', b'-n', b'test', data_path)) repo = LocalRepo() res = vfs.resolve(repo, b'/test') wvpasseq(2, len(res)) name, revlist = res[-1] wvpasseq(b'test', name) wvpasseq((b'.', b'1970-01-02-034640-00', b'1970-01-02-034640-01', b'1970-01-02-034640-02', b'1970-01-02-034640-03', b'1970-01-02-034640-04', b'1970-01-02-034640-05', b'1970-01-02-034640-06', b'1970-01-02-034640-07', b'1970-01-02-034640-08', b'1970-01-02-034640-09', b'1970-01-02-034640-10', b'latest'), tuple(sorted(x[0] for x in vfs.contents(repo, revlist))))
def test_metadata_method(): with no_lingering_errors(): with test_tempdir('bup-tmetadata-') as tmpdir: bup_dir = tmpdir + '/bup' data_path = tmpdir + '/foo' os.mkdir(data_path) ex('touch', data_path + '/file') ex('ln', '-s', 'file', data_path + '/symlink') test_time1 = 13 * 1000000000 test_time2 = 42 * 1000000000 utime(data_path + '/file', (0, test_time1)) lutime(data_path + '/symlink', (0, 0)) utime(data_path, (0, test_time2)) ex(bup_path, '-d', bup_dir, 'init') ex(bup_path, '-d', bup_dir, 'index', '-v', data_path) ex(bup_path, '-d', bup_dir, 'save', '-tvvn', 'test', data_path) git.check_repo_or_die(bup_dir) repo = LocalRepo() resolved = vfs.resolve(repo, '/test/latest' + resolve_parent(data_path), follow=False) leaf_name, leaf_item = resolved[-1] m = leaf_item.meta WVPASS(m.mtime == test_time2) WVPASS(leaf_name == 'foo') contents = tuple(vfs.contents(repo, leaf_item)) WVPASS(len(contents) == 3) WVPASSEQ(frozenset(name for name, item in contents), frozenset(('.', 'file', 'symlink'))) for name, item in contents: if name == 'file': m = item.meta WVPASS(m.mtime == test_time1) elif name == 'symlink': m = item.meta WVPASSEQ(m.symlink_target, 'file') WVPASSEQ(m.size, 4) WVPASSEQ(m.mtime, 0)
def test_contents_with_mismatched_bupm_git_ordering(): with no_lingering_errors(): with test_tempdir('bup-tvfs-') as tmpdir: bup_dir = tmpdir + '/bup' environ['GIT_DIR'] = bup_dir environ['BUP_DIR'] = bup_dir git.repodir = bup_dir data_path = tmpdir + '/src' os.mkdir(data_path) os.mkdir(data_path + '/foo') with open(data_path + '/foo.', 'w+') as tmpfile: tmpfile.write(b'canary\n') ex((bup_path, 'init')) ex((bup_path, 'index', '-v', data_path)) save_utc = 100000 save_name = strftime('%Y-%m-%d-%H%M%S', localtime(save_utc)) ex((bup_path, 'save', '-tvvn', 'test', '-d', str(save_utc), '--strip', data_path)) repo = LocalRepo() tip_sref = exo(('git', 'show-ref', 'refs/heads/test')).out tip_oidx = tip_sref.strip().split()[0] tip_tree_oidx = exo(('git', 'log', '--pretty=%T', '-n1', tip_oidx)).out.strip() tip_tree_oid = tip_tree_oidx.decode('hex') tip_tree = tree_dict(repo, tip_tree_oid) name, item = vfs.resolve(repo, '/test/latest')[2] wvpasseq(save_name, name) expected = frozenset((x.name, vfs.Item(oid=x.oid, meta=x.meta)) for x in (tip_tree[name] for name in ('.', 'foo', 'foo.'))) contents = tuple(vfs.contents(repo, item)) wvpasseq(expected, frozenset(contents)) # Spot check, in case tree_dict shares too much code with the vfs name, item = next(((n, i) for n, i in contents if n == 'foo')) wvpass(S_ISDIR(item.meta)) name, item = next(((n, i) for n, i in contents if n == 'foo.')) wvpass(S_ISREG(item.meta.mode))
def resolve(conn, args): _init_session() (flags,) = args.split() flags = int(flags) want_meta = bool(flags & 1) follow = bool(flags & 2) have_parent = bool(flags & 4) parent = vfs.read_resolution(conn) if have_parent else None path = vint.read_bvec(conn) if not len(path): raise Exception('Empty resolve path') try: res = list(vfs.resolve(repo, path, parent=parent, want_meta=want_meta, follow=follow)) except vfs.IOError as ex: res = ex if isinstance(res, vfs.IOError): conn.write(b'\x00') # error vfs.write_ioerror(conn, res) else: conn.write(b'\x01') # success vfs.write_resolution(conn, res) conn.ok()
def dead_items(repo, paths): """Return an optimized set of removals, reporting errors via add_error, and if there are any errors, return None, None.""" dead_branches = {} dead_saves = {} # Scan for bad requests, and opportunities to optimize for path in paths: try: resolved = vfs.resolve(repo, path, follow=False) except vfs.IOError as e: add_error(e) continue else: leaf_name, leaf_item = resolved[-1] if not leaf_item: add_error('error: cannot access %s in %s' % (path_msg( b'/'.join(name for name, item in resolved)), path_msg(path))) continue if isinstance(leaf_item, vfs.RevList): # rm /foo branchname = leaf_name dead_branches[branchname] = leaf_item dead_saves.pop(branchname, None) # rm /foo obviates rm /foo/bar elif isinstance(leaf_item, vfs.Commit): # rm /foo/bar if leaf_name == b'latest': add_error("error: cannot delete 'latest' symlink") else: branchname, branchitem = resolved[-2] if branchname not in dead_branches: dead = leaf_item, branchitem dead_saves.setdefault(branchname, []).append(dead) else: add_error("don't know how to remove %s yet" % path_msg(path)) if saved_errors: return None, None return dead_branches, dead_saves
def getattr(self, path): path = argv_bytes(path) if self.verbose > 0: log('--getattr(%r)\n' % path) res = vfs.resolve(self.repo, path, want_meta=(not self.fake_metadata), follow=False) name, item = res[-1] if not item: return -errno.ENOENT if self.fake_metadata: item = vfs.augment_item_meta(self.repo, item, include_size=True) else: item = vfs.ensure_item_has_metadata(self.repo, item, include_size=True) meta = item.meta # FIXME: do we want/need to do anything more with nlink? st = fuse.Stat(st_mode=meta.mode, st_nlink=1, st_size=meta.size) st.st_mode = meta.mode st.st_uid = meta.uid or 0 st.st_gid = meta.gid or 0 st.st_atime = max(0, xstat.fstime_floor_secs(meta.atime)) st.st_mtime = max(0, xstat.fstime_floor_secs(meta.mtime)) st.st_ctime = max(0, xstat.fstime_floor_secs(meta.ctime)) return st
def dead_items(repo, paths): """Return an optimized set of removals, reporting errors via add_error, and if there are any errors, return None, None.""" dead_branches = {} dead_saves = {} # Scan for bad requests, and opportunities to optimize for path in paths: try: resolved = vfs.resolve(repo, path, follow=False) except vfs.IOError as e: add_error(e) continue else: leaf_name, leaf_item = resolved[-1] if not leaf_item: add_error('error: cannot access %r in %r' % ('/'.join(name for name, item in resolved), path)) continue if isinstance(leaf_item, vfs.RevList): # rm /foo branchname = leaf_name dead_branches[branchname] = leaf_item dead_saves.pop(branchname, None) # rm /foo obviates rm /foo/bar elif isinstance(leaf_item, vfs.Commit): # rm /foo/bar if leaf_name == 'latest': add_error("error: cannot delete 'latest' symlink") else: branchname, branchitem = resolved[-2] if branchname not in dead_branches: dead = leaf_item, branchitem dead_saves.setdefault(branchname, []).append(dead) else: add_error("don't know how to remove %r yet" % path) if saved_errors: return None, None return dead_branches, dead_saves
def getattr(self, path): global opt if self.verbose > 0: log('--getattr(%r)\n' % path) res = vfs.resolve(self.repo, path, want_meta=(not self.fake_metadata), follow=False) name, item = res[-1] if not item: return -errno.ENOENT if self.fake_metadata: item = vfs.augment_item_meta(self.repo, item, include_size=True) else: item = vfs.ensure_item_has_metadata(self.repo, item, include_size=True) meta = item.meta # FIXME: do we want/need to do anything more with nlink? st = fuse.Stat(st_mode=meta.mode, st_nlink=1, st_size=meta.size) st.st_mode = meta.mode st.st_uid = meta.uid st.st_gid = meta.gid st.st_atime = max(0, xstat.fstime_floor_secs(meta.atime)) st.st_mtime = max(0, xstat.fstime_floor_secs(meta.mtime)) st.st_ctime = max(0, xstat.fstime_floor_secs(meta.ctime)) return st
log('\nError in completion: %s\n' % e) optspec = """ bup ftp [commands...] """ o = options.Options(optspec) opt, flags, extra = o.parse(compat.argv[1:]) git.check_repo_or_die() sys.stdout.flush() out = byte_stream(sys.stdout) stdin = byte_stream(sys.stdin) repo = LocalRepo() pwd = vfs.resolve(repo, b'/') rv = 0 if extra: lines = (argv_bytes(arg) for arg in extra) else: if hasattr(_helpers, 'readline'): _helpers.set_completer_word_break_characters(b' \t\n\r/') _helpers.set_attempted_completion_function(attempt_completion) _helpers.set_completion_entry_function(enter_completion) if sys.platform.startswith('darwin'): # MacOS uses a slightly incompatible clone of libreadline _helpers.parse_and_bind(b'bind ^I rl_complete') _helpers.parse_and_bind(b'tab: complete') lines = inputiter()
git.check_repo_or_die() if not extra: o.fatal('must specify a target') if len(extra) > 1: o.fatal('only one target file allowed') if opt.bupm and opt.meta: o.fatal('--meta and --bupm are incompatible') target = extra[0] if not re.match(r'/*[^/]+/[^/]+', target): o.fatal("path %r doesn't include a branch and revision" % target) repo = LocalRepo() resolved = vfs.resolve(repo, target, follow=False) leaf_name, leaf_item = resolved[-1] if not leaf_item: log('error: cannot access %r in %r\n' % ('/'.join(name for name, item in resolved), path)) sys.exit(1) mode = vfs.item_mode(leaf_item) if opt.bupm: if not stat.S_ISDIR(mode): o.fatal('%r is not a directory' % target) _, bupm_oid = vfs.tree_data_and_bupm(repo, leaf_item.oid) if bupm_oid: with vfs.tree_data_reader(repo, bupm_oid) as meta_stream: sys.stdout.write(meta_stream.read())
def main(): o = options.Options(optspec) opt, flags, extra = o.parse(sys.argv[1:]) verbosity = opt.verbose if not opt.quiet else -1 git.check_repo_or_die() if not extra: o.fatal('must specify at least one filename to restore') exclude_rxs = parse_rx_excludes(flags, o.fatal) owner_map = {} for map_type in ('user', 'group', 'uid', 'gid'): owner_map[map_type] = parse_owner_mappings(map_type, flags, o.fatal) if opt.outdir: mkdirp(opt.outdir) os.chdir(opt.outdir) repo = RemoteRepo(opt.remote) if opt.remote else LocalRepo() top = os.getcwd() hardlinks = {} for path in extra: if not valid_restore_path(path): add_error("path %r doesn't include a branch and revision" % path) continue try: resolved = vfs.resolve(repo, path, want_meta=True, follow=False) except vfs.IOError as e: add_error(e) continue if len(resolved) == 3 and resolved[2][0] == 'latest': # Follow latest symlink to the actual save try: resolved = vfs.resolve(repo, 'latest', parent=resolved[:-1], want_meta=True) except vfs.IOError as e: add_error(e) continue # Rename it back to 'latest' resolved = tuple(elt if i != 2 else ('latest',) + elt[1:] for i, elt in enumerate(resolved)) path_parent, path_name = os.path.split(path) leaf_name, leaf_item = resolved[-1] if not leaf_item: add_error('error: cannot access %r in %r' % ('/'.join(name for name, item in resolved), path)) continue if not path_name or path_name == '.': # Source is /foo/what/ever/ or /foo/what/ever/. -- extract # what/ever/* to the current directory, and if name == '.' # (i.e. /foo/what/ever/.), then also restore what/ever's # metadata to the current directory. treeish = vfs.item_mode(leaf_item) if not treeish: add_error('%r cannot be restored as a directory' % path) else: items = vfs.contents(repo, leaf_item, want_meta=True) dot, leaf_item = next(items, None) assert(dot == '.') for sub_name, sub_item in items: restore(repo, '', sub_name, sub_item, top, opt.sparse, opt.numeric_ids, owner_map, exclude_rxs, verbosity, hardlinks) if path_name == '.': leaf_item = vfs.augment_item_meta(repo, leaf_item, include_size=True) apply_metadata(leaf_item.meta, '.', opt.numeric_ids, owner_map) else: restore(repo, '', leaf_name, leaf_item, top, opt.sparse, opt.numeric_ids, owner_map, exclude_rxs, verbosity, hardlinks) if verbosity >= 0: progress('Restoring: %d, done.\n' % total_restored) die_if_errors()
traceback.print_tb(sys.exc_traceback) except Exception as e2: log('Error printing traceback: %s\n' % e2) log('\nError in completion: %s\n' % e) optspec = """ bup ftp [commands...] """ o = options.Options(optspec) (opt, flags, extra) = o.parse(sys.argv[1:]) git.check_repo_or_die() repo = LocalRepo() pwd = vfs.resolve(repo, '/') rv = 0 if extra: lines = extra else: try: import readline except ImportError: log('* readline module not available: line editing disabled.\n') readline = None if readline: readline.set_completer_delims(' \t\n\r/') readline.set_completer(completer) if sys.platform.startswith('darwin'):
log('Error printing traceback: %s\n' % e2) log('\nError in completion: %s\n' % e) optspec = """ bup ftp [commands...] """ o = options.Options(optspec) (opt, flags, extra) = o.parse(sys.argv[1:]) git.check_repo_or_die() sys.stdout.flush() out = byte_stream(sys.stdout) repo = LocalRepo() pwd = vfs.resolve(repo, b'/') rv = 0 if extra: lines = extra else: try: import readline except ImportError: log('* readline module not available: line editing disabled.\n') readline = None if readline: readline.set_completer_delims(' \t\n\r/') readline.set_completer(completer) if sys.platform.startswith('darwin'):
def present_interface(stdin, out, extra, repo): pwd = vfs.resolve(repo, b'/') if extra: lines = (argv_bytes(arg) for arg in extra) else: if hasattr(_helpers, 'readline'): _helpers.set_completer_word_break_characters(b' \t\n\r/') _helpers.set_attempted_completion_function(attempt_completion) _helpers.set_completion_entry_function(enter_completion) if sys.platform.startswith('darwin'): # MacOS uses a slightly incompatible clone of libreadline _helpers.parse_and_bind(b'bind ^I rl_complete') _helpers.parse_and_bind(b'tab: complete') lines = inputiter(stdin, pwd, out) for line in lines: if not line.strip(): continue words = [word for (wordstart, word) in shquote.quotesplit(line)] cmd = words[0].lower() #log('execute: %r %r\n' % (cmd, parm)) try: if cmd == b'ls': do_ls(repo, pwd, words[1:], out) out.flush() elif cmd == b'cd': np = pwd for parm in words[1:]: res = vfs.resolve(repo, parm, parent=np) _, leaf_item = res[-1] if not leaf_item: raise CommandError('path does not exist: ' + rpath_msg(res)) if not stat.S_ISDIR(vfs.item_mode(leaf_item)): raise CommandError('path is not a directory: ' + path_msg(parm)) np = res pwd = np elif cmd == b'pwd': if len(pwd) == 1: out.write(b'/') out.write(b'/'.join(name for name, item in pwd) + b'\n') out.flush() elif cmd == b'cat': for parm in words[1:]: res = vfs.resolve(repo, parm, parent=pwd) _, leaf_item = res[-1] if not leaf_item: raise CommandError('path does not exist: ' + rpath_msg(res)) with vfs.fopen(repo, leaf_item) as srcfile: write_to_file(srcfile, out) out.flush() elif cmd == b'get': if len(words) not in [2, 3]: raise CommandError('Usage: get <filename> [localname]') rname = words[1] (dir, base) = os.path.split(rname) lname = len(words) > 2 and words[2] or base res = vfs.resolve(repo, rname, parent=pwd) _, leaf_item = res[-1] if not leaf_item: raise CommandError('path does not exist: ' + rpath_msg(res)) with vfs.fopen(repo, leaf_item) as srcfile: with open(lname, 'wb') as destfile: log('Saving %s\n' % path_msg(lname)) write_to_file(srcfile, destfile) elif cmd == b'mget': for parm in words[1:]: dir, base = os.path.split(parm) res = vfs.resolve(repo, dir, parent=pwd) _, dir_item = res[-1] if not dir_item: raise CommandError('path does not exist: ' + path_msg(dir)) for name, item in vfs.contents(repo, dir_item): if name == b'.': continue if fnmatch.fnmatch(name, base): if stat.S_ISLNK(vfs.item_mode(item)): deref = vfs.resolve(repo, name, parent=res) deref_name, deref_item = deref[-1] if not deref_item: raise CommandError( 'path does not exist: ' + rpath_msg(res)) item = deref_item with vfs.fopen(repo, item) as srcfile: with open(name, 'wb') as destfile: log('Saving %s\n' % path_msg(name)) write_to_file(srcfile, destfile) elif cmd in (b'help', b'?'): out.write(b'Commands: ls cd pwd cat get mget help quit\n') out.flush() elif cmd in (b'quit', b'exit', b'bye'): break else: raise CommandError('no such command: ' + cmd.encode(errors='backslashreplace')) except CommandError as ex: out.write(b'error: %s\n' % str(ex).encode(errors='backslashreplace')) out.flush()
def within_repo(repo, opt): if opt.commit_hash: opt.hash = True def item_line(item, name): return item_info(item, name, show_hash=opt.hash, commit_hash=opt.commit_hash, long_fmt=opt.long_listing, classification=opt.classification, numeric_ids=opt.numeric_ids, human_readable=opt.human_readable) ret = 0 pending = [] for path in opt.paths: try: if opt.directory: resolved = vfs.resolve(repo, path, follow=False) else: resolved = vfs.try_resolve(repo, path) leaf_name, leaf_item = resolved[-1] if not leaf_item: log('error: cannot access %r in %r\n' % ('/'.join(name for name, item in resolved), path)) ret = 1 continue if not opt.directory and S_ISDIR(vfs.item_mode(leaf_item)): items = vfs.contents(repo, leaf_item) if opt.show_hidden == 'all': # Match non-bup "ls -a ... /". parent = resolved[-2] if len(resolved) > 1 else resolved[0] items = chain(items, (('..', parent[1]), )) for sub_name, sub_item in sorted(items, key=lambda x: x[0]): if opt.show_hidden != 'all' and sub_name == '.': continue if sub_name.startswith('.') and \ opt.show_hidden not in ('almost', 'all'): continue if opt.l: sub_item = vfs.ensure_item_has_metadata( repo, sub_item, include_size=True) else: sub_item = vfs.augment_item_meta(repo, sub_item, include_size=True) line = item_line(sub_item, sub_name) if not opt.long_listing and istty1: pending.append(line) else: print(line) else: leaf_item = vfs.augment_item_meta(repo, leaf_item, include_size=True) line = item_line(leaf_item, os.path.normpath(path)) if not opt.long_listing and istty1: pending.append(line) else: print(line) except vfs.IOError as ex: log('bup: %s\n' % ex) ret = 1 if pending: sys.stdout.write(columnate(pending, '')) return ret
def within_repo(repo, opt): if opt.commit_hash: opt.hash = True def item_line(item, name): return item_info(item, name, show_hash=opt.hash, commit_hash=opt.commit_hash, long_fmt=opt.long_listing, classification=opt.classification, numeric_ids=opt.numeric_ids, human_readable=opt.human_readable) ret = 0 pending = [] for path in opt.paths: try: if opt.directory: resolved = vfs.resolve(repo, path, follow=False) else: resolved = vfs.try_resolve(repo, path) leaf_name, leaf_item = resolved[-1] if not leaf_item: log('error: cannot access %r in %r\n' % ('/'.join(name for name, item in resolved), path)) ret = 1 continue if not opt.directory and S_ISDIR(vfs.item_mode(leaf_item)): items = vfs.contents(repo, leaf_item) if opt.show_hidden == 'all': # Match non-bup "ls -a ... /". parent = resolved[-2] if len(resolved) > 1 else resolved[0] items = chain(items, (('..', parent[1]),)) for sub_name, sub_item in sorted(items, key=lambda x: x[0]): if opt.show_hidden != 'all' and sub_name == '.': continue if sub_name.startswith('.') and \ opt.show_hidden not in ('almost', 'all'): continue if opt.l: sub_item = vfs.ensure_item_has_metadata(repo, sub_item, include_size=True) else: sub_item = vfs.augment_item_meta(repo, sub_item, include_size=True) line = item_line(sub_item, sub_name) if not opt.long_listing and istty1: pending.append(line) else: print(line) else: leaf_item = vfs.augment_item_meta(repo, leaf_item, include_size=True) line = item_line(leaf_item, os.path.normpath(path)) if not opt.long_listing and istty1: pending.append(line) else: print(line) except vfs.IOError as ex: log('bup: %s\n' % ex) ret = 1 if pending: sys.stdout.write(columnate(pending, '')) return ret
def main(argv): o = options.Options(optspec) opt, flags, extra = o.parse_bytes(argv[1:]) global repo repo = from_opts(opt, reverse=False) sys.stdout.flush() out = byte_stream(sys.stdout) stdin = byte_stream(sys.stdin) pwd = vfs.resolve(repo, b'/') rv = 0 def inputiter(f): if os.isatty(f.fileno()): while 1: prompt = b'bup %s> ' % (b'/'.join(name for name, item in pwd) or b'/', ) if hasattr(_helpers, 'readline'): try: yield _helpers.readline(prompt) except EOFError: print() # Clear the line for the terminal's next prompt break else: out.write(prompt) out.flush() read_line = f.readline() if not read_line: print('') break yield read_line else: for line in f: yield line if extra: lines = (argv_bytes(arg) for arg in extra) else: if hasattr(_helpers, 'readline'): _helpers.set_completer_word_break_characters(b' \t\n\r/') _helpers.set_attempted_completion_function(attempt_completion) _helpers.set_completion_entry_function(enter_completion) if sys.platform.startswith('darwin'): # MacOS uses a slightly incompatible clone of libreadline _helpers.parse_and_bind(b'bind ^I rl_complete') _helpers.parse_and_bind(b'tab: complete') lines = inputiter(stdin) for line in lines: if not line.strip(): continue words = [word for (wordstart,word) in shquote.quotesplit(line)] cmd = words[0].lower() #log('execute: %r %r\n' % (cmd, parm)) try: if cmd == b'ls': do_ls(repo, pwd, words[1:], out) out.flush() elif cmd == b'cd': np = pwd for parm in words[1:]: res = vfs.resolve(repo, parm, parent=np) _, leaf_item = res[-1] if not leaf_item: raise CommandError(b'"%s" does not exist' % b'/'.join(name for name, item in res)) if not stat.S_ISDIR(vfs.item_mode(leaf_item)): raise CommandError(b'"%s" is not a directory' % parm) np = res pwd = np elif cmd == b'pwd': if len(pwd) == 1: out.write(b'/') out.write(b'/'.join(name for name, item in pwd) + b'\n') out.flush() elif cmd == b'cat': for parm in words[1:]: res = vfs.resolve(repo, parm, parent=pwd) _, leaf_item = res[-1] if not leaf_item: raise CommandError(b'"%s" does not exist' % b'/'.join(name for name, item in res)) with vfs.fopen(repo, leaf_item) as srcfile: write_to_file(srcfile, out) out.flush() elif cmd == b'get': if len(words) not in [2,3]: rv = 1 raise CommandError(b'Usage: get <filename> [localname]') rname = words[1] (dir,base) = os.path.split(rname) lname = len(words) > 2 and words[2] or base res = vfs.resolve(repo, rname, parent=pwd) _, leaf_item = res[-1] if not leaf_item: raise CommandError(b'"%s" does not exist' % b'/'.join(name for name, item in res)) with vfs.fopen(repo, leaf_item) as srcfile: with open(lname, 'wb') as destfile: log('Saving %s\n' % path_msg(lname)) write_to_file(srcfile, destfile) elif cmd == b'mget': for parm in words[1:]: dir, base = os.path.split(parm) res = vfs.resolve(repo, dir, parent=pwd) _, dir_item = res[-1] if not dir_item: raise CommandError(b'"%s" does not exist' % dir) for name, item in vfs.contents(repo, dir_item): if name == b'.': continue if fnmatch.fnmatch(name, base): if stat.S_ISLNK(vfs.item_mode(item)): deref = vfs.resolve(repo, name, parent=res) deref_name, deref_item = deref[-1] if not deref_item: raise CommandError(b'"%s" does not exist' % b'/'.join(name for name, item in res)) item = deref_item with vfs.fopen(repo, item) as srcfile: with open(name, 'wb') as destfile: log('Saving %s\n' % path_msg(name)) write_to_file(srcfile, destfile) elif cmd == b'help' or cmd == b'?': out.write(b'Commands: ls cd pwd cat get mget help quit\n') out.flush() elif cmd in (b'quit', b'exit', b'bye'): break else: rv = 1 raise CommandError(b'no such command "%s"' % cmd) except CommandError as e: rv = 1 out.write(b'error: %s\n' % e.args[0]) out.flush() except Exception as e: rv = 1 out.write(b'error: %s\n' % str(e).encode()) out.flush() sys.exit(rv)
def show_paths(repo, opt, paths, out, pwd, should_columnate, prefix=b''): def item_line(item, name): return item_info(item, prefix + name, show_hash=opt.hash, commit_hash=opt.commit_hash, long_fmt=opt.long_listing, classification=opt.classification, numeric_ids=opt.numeric_ids, human_readable=opt.human_readable) ret = 0 want_meta = bool(opt.long_listing or opt.classification) pending = [] last_n = len(paths) - 1 for n, printpath in enumerate(paths): path = posixpath.join(pwd, printpath) try: if last_n > 0: out.write(b'%s:\n' % printpath) if opt.directory: resolved = vfs.resolve(repo, path, follow=False) else: resolved = vfs.try_resolve(repo, path, want_meta=want_meta) leaf_name, leaf_item = resolved[-1] if not leaf_item: log('error: cannot access %r in %r\n' % ('/'.join(path_msg(name) for name, item in resolved), path_msg(path))) ret = 1 continue if not opt.directory and S_ISDIR(vfs.item_mode(leaf_item)): items = vfs.contents(repo, leaf_item, want_meta=want_meta) if opt.show_hidden == 'all': # Match non-bup "ls -a ... /". parent = resolved[-2] if len(resolved) > 1 else resolved[0] items = chain(items, ((b'..', parent[1]), )) for sub_name, sub_item in sorted(items, key=lambda x: x[0]): if opt.show_hidden != 'all' and sub_name == b'.': continue if sub_name.startswith(b'.') and \ opt.show_hidden not in ('almost', 'all'): continue # always skip . and .. in the subfolders - already printed it anyway if prefix and sub_name in (b'.', b'..'): continue if opt.l: sub_item = vfs.ensure_item_has_metadata( repo, sub_item, include_size=True) elif want_meta: sub_item = vfs.augment_item_meta(repo, sub_item, include_size=True) line = item_line(sub_item, sub_name) if should_columnate: pending.append(line) else: out.write(line) out.write(b'\n') # recurse into subdirectories (apart from . and .., of course) if opt.recursive and S_ISDIR( vfs.item_mode(sub_item)) and sub_name not in ( b'.', b'..'): show_paths(repo, opt, [path + b'/' + sub_name], out, pwd, should_columnate, prefix=prefix + sub_name + b'/') else: if opt.long_listing: leaf_item = vfs.augment_item_meta(repo, leaf_item, include_size=True) line = item_line(leaf_item, os.path.normpath(path)) if should_columnate: pending.append(line) else: out.write(line) out.write(b'\n') except vfs.IOError as ex: log('bup: %s\n' % ex) ret = 1 if pending: out.write(columnate(pending, b'')) pending = [] if n < last_n: out.write(b'\n') return ret
def main(argv): o = options.Options(optspec) opt, flags, extra = o.parse_bytes(argv[1:]) verbosity = (opt.verbose or 0) if not opt.quiet else -1 if opt.remote: opt.remote = argv_bytes(opt.remote) if opt.outdir: opt.outdir = argv_bytes(opt.outdir) git.check_repo_or_die() if not extra: o.fatal('must specify at least one filename to restore') exclude_rxs = parse_rx_excludes(flags, o.fatal) owner_map = {} for map_type in ('user', 'group', 'uid', 'gid'): owner_map[map_type] = parse_owner_mappings(map_type, flags, o.fatal) if opt.outdir: mkdirp(opt.outdir) os.chdir(opt.outdir) repo = RemoteRepo(opt.remote) if opt.remote else LocalRepo() top = fsencode(os.getcwd()) hardlinks = {} for path in [argv_bytes(x) for x in extra]: if not valid_restore_path(path): add_error("path %r doesn't include a branch and revision" % path) continue try: resolved = vfs.resolve(repo, path, want_meta=True, follow=False) except vfs.IOError as e: add_error(e) continue if len(resolved) == 3 and resolved[2][0] == b'latest': # Follow latest symlink to the actual save try: resolved = vfs.resolve(repo, b'latest', parent=resolved[:-1], want_meta=True) except vfs.IOError as e: add_error(e) continue # Rename it back to 'latest' resolved = tuple(elt if i != 2 else (b'latest', ) + elt[1:] for i, elt in enumerate(resolved)) path_parent, path_name = os.path.split(path) leaf_name, leaf_item = resolved[-1] if not leaf_item: add_error('error: cannot access %r in %r' % (b'/'.join(name for name, item in resolved), path)) continue if not path_name or path_name == b'.': # Source is /foo/what/ever/ or /foo/what/ever/. -- extract # what/ever/* to the current directory, and if name == '.' # (i.e. /foo/what/ever/.), then also restore what/ever's # metadata to the current directory. treeish = vfs.item_mode(leaf_item) if not treeish: add_error('%r cannot be restored as a directory' % path) else: items = vfs.contents(repo, leaf_item, want_meta=True) dot, leaf_item = next(items, None) assert dot == b'.' for sub_name, sub_item in items: restore(repo, b'', sub_name, sub_item, top, opt.sparse, opt.numeric_ids, owner_map, exclude_rxs, verbosity, hardlinks) if path_name == b'.': leaf_item = vfs.augment_item_meta(repo, leaf_item, include_size=True) apply_metadata(leaf_item.meta, b'.', opt.numeric_ids, owner_map) else: restore(repo, b'', leaf_name, leaf_item, top, opt.sparse, opt.numeric_ids, owner_map, exclude_rxs, verbosity, hardlinks) if verbosity >= 0: progress('Restoring: %d, done.\n' % total_restored) die_if_errors()
git.check_repo_or_die() if not extra: o.fatal('must specify a target') if len(extra) > 1: o.fatal('only one target file allowed') if opt.bupm and opt.meta: o.fatal('--meta and --bupm are incompatible') target = argv_bytes(extra[0]) if not re.match(br'/*[^/]+/[^/]+', target): o.fatal("path %r doesn't include a branch and revision" % target) repo = LocalRepo() resolved = vfs.resolve(repo, target, follow=False) leaf_name, leaf_item = resolved[-1] if not leaf_item: log('error: cannot access %r in %r\n' % ('/'.join(name for name, item in resolved), path)) sys.exit(1) mode = vfs.item_mode(leaf_item) sys.stdout.flush() out = byte_stream(sys.stdout) if opt.bupm: if not stat.S_ISDIR(mode): o.fatal('%r is not a directory' % target) _, bupm_oid = vfs.tree_data_and_bupm(repo, leaf_item.oid)