+ 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.lresolve(repo, path, want_meta=True)
+ 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)