def test_item_mode(): with no_lingering_errors(): mode = S_IFDIR | 0o755 meta = metadata.from_path('.') oid = '\0' * 20 wvpasseq(mode, vfs.item_mode(vfs.Item(oid=oid, meta=mode))) wvpasseq(meta.mode, vfs.item_mode(vfs.Item(oid=oid, meta=meta)))
def test_item_mode(): with no_lingering_errors(): mode = S_IFDIR | 0o755 meta = metadata.from_path('.') oid = '\0' * 20 wvpasseq(mode, vfs.item_mode(vfs.Item(oid=oid, meta=mode))) wvpasseq(meta.mode, vfs.item_mode(vfs.Item(oid=oid, meta=meta)))
def display_info(name, item, resolved_item, display_name=None): global opt # link should be based on fully resolved type to avoid extra # HTTP redirect. link = tornado.escape.url_escape(name, plus=False) if stat.S_ISDIR(vfs.item_mode(resolved_item)): link += '/' link = link.encode('ascii') size = vfs.item_size(repo, item) if opt.human_readable: display_size = format_filesize(size) else: display_size = size if not display_name: mode = vfs.item_mode(item) if stat.S_ISDIR(mode): display_name = name + b'/' elif stat.S_ISLNK(mode): display_name = name + b'@' else: display_name = name return display_name, link + url_query, display_size
def item_info(item, name, show_hash = False, commit_hash=False, long_fmt = False, classification = None, numeric_ids = False, human_readable = False): """Return a string containing the information to display for the VFS item. Classification may be "all", "type", or None. """ result = '' if show_hash: oid = item_hash(item, commit_hash) result += '%s ' % (oid.encode('hex') if oid else '0000000000000000000000000000000000000000') if long_fmt: meta = item.meta.copy() meta.path = name # FIXME: need some way to track fake vs real meta items? result += metadata.summary_str(meta, numeric_ids=numeric_ids, classification=classification, human_readable=human_readable) else: result += name if classification: result += xstat.classification_str(vfs.item_mode(item), classification == 'all') return result
def item_info(item, name, show_hash=False, commit_hash=False, long_fmt=False, classification=None, numeric_ids=False, human_readable=False): """Return bytes containing the information to display for the VFS item. Classification may be "all", "type", or None. """ result = b'' if show_hash: oid = item_hash(item, commit_hash) result += b'%s ' % (hexlify(oid) if oid else b'0000000000000000000000000000000000000000') if long_fmt: meta = item.meta.copy() meta.path = name # FIXME: need some way to track fake vs real meta items? result += metadata.summary_bytes(meta, numeric_ids=numeric_ids, classification=classification, human_readable=human_readable) else: result += name if classification: cls = xstat.classification_str(vfs.item_mode(item), classification == 'all') result += cls.encode('ascii') return result
def completer(text, iteration): global repo global _last_line global _last_res global rl_completion_suppress_append if rl_completion_suppress_append is not None: rl_completion_suppress_append.value = 1 try: line = readline.get_line_buffer()[:readline.get_endidx()] if _last_line != line: _last_res = _completer_get_subs(repo, line) _last_line = line (dir, name, qtype, lastword, subs) = _last_res if iteration < len(subs): path = subs[iteration] leaf_name, leaf_item = path[-1] res = vfs.try_resolve(repo, leaf_name, parent=path[:-1]) leaf_name, leaf_item = res[-1] fullname = os.path.join(*(name for name, item in res)) if stat.S_ISDIR(vfs.item_mode(leaf_item)): ret = shquote.what_to_add(qtype, lastword, fullname+'/', terminate=False) else: ret = shquote.what_to_add(qtype, lastword, fullname, terminate=True) + ' ' return text + ret except Exception as e: log('\n') try: import traceback traceback.print_tb(sys.exc_traceback) except Exception as e2: log('Error printing traceback: %s\n' % e2) log('\nError in completion: %s\n' % e)
def enter_completion(text, iteration): global repo global _attempt_end global _last_line global _last_res try: line = _helpers.get_line_buffer()[:_attempt_end] if _last_line != line: _last_res = _completer_get_subs(repo, line) _last_line = line qtype, lastword, subs = _last_res if iteration < len(subs): path = subs[iteration] leaf_name, leaf_item = path[-1] res = vfs.try_resolve(repo, leaf_name, parent=path[:-1]) leaf_name, leaf_item = res[-1] fullname = os.path.join(*(name for name, item in res)) if stat.S_ISDIR(vfs.item_mode(leaf_item)): ret = shquote.what_to_add(qtype, lastword, fullname + b'/', terminate=False) else: ret = shquote.what_to_add( qtype, lastword, fullname, terminate=True) + b' ' return text + ret except Exception as e: log('\n') try: import traceback traceback.print_tb(sys.exc_traceback) except Exception as e2: log('Error printing traceback: %s\n' % e2) log('\nError in completion: %s\n' % e)
def completer(text, iteration): global repo global _last_line global _last_res global rl_completion_suppress_append if rl_completion_suppress_append is not None: rl_completion_suppress_append.value = 1 try: line = readline.get_line_buffer()[:readline.get_endidx()] if _last_line != line: _last_res = _completer_get_subs(repo, line) _last_line = line (dir, name, qtype, lastword, subs) = _last_res if iteration < len(subs): path = subs[iteration] leaf_name, leaf_item = path[-1] res = vfs.try_resolve(repo, leaf_name, parent=path[:-1]) leaf_name, leaf_item = res[-1] fullname = os.path.join(*(name for name, item in res)) if stat.S_ISDIR(vfs.item_mode(leaf_item)): ret = shquote.what_to_add(qtype, lastword, fullname+'/', terminate=False) else: ret = shquote.what_to_add(qtype, lastword, fullname, terminate=True) + ' ' return text + ret except Exception as e: log('\n') try: import traceback traceback.print_tb(sys.exc_traceback) except Exception as e2: log('Error printing traceback: %s\n' % e2) log('\nError in completion: %s\n' % e)
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 display_info(name, item, resolved_item, display_name=None, omitsize=False): global opt # link should be based on fully resolved type to avoid extra # HTTP redirect. link = tornado.escape.url_escape(name, plus=False) if stat.S_ISDIR(vfs.item_mode(resolved_item)): link += '/' link = link.encode('ascii') if not omitsize: size = vfs.item_size(repo, item) if args.hsizes: display_size = format_filesize(size) else: display_size = size else: display_size = None if not display_name: mode = vfs.item_mode(item) if stat.S_ISDIR(mode): display_name = name + b'/' display_size = None elif stat.S_ISLNK(mode): display_name = name + b'@' display_size = None else: display_name = name meta = resolved_item.meta if not isinstance(meta, Metadata): meta = None try: oidx = hexlify(resolved_item.oid) except AttributeError: oidx = '' return display_name, link + args, display_size, meta, oidx
def display_info(name, item, resolved_item, display_name=None): # link should be based on fully resolved type to avoid extra # HTTP redirect. if stat.S_ISDIR(vfs.item_mode(resolved_item)): link = urllib.quote(name) + '/' else: link = urllib.quote(name) size = vfs.item_size(repo, item) if opt.human_readable: display_size = format_filesize(size) else: display_size = size if not display_name: mode = vfs.item_mode(item) if stat.S_ISDIR(mode): display_name = name + '/' elif stat.S_ISLNK(mode): display_name = name + '@' else: display_name = name return display_name, link + url_query, display_size
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 display_info(name, item, resolved_item, display_name=None): # link should be based on fully resolved type to avoid extra # HTTP redirect. if stat.S_ISDIR(vfs.item_mode(resolved_item)): link = urllib.quote(name) + '/' else: link = urllib.quote(name) size = vfs.item_size(repo, item) if opt.human_readable: display_size = format_filesize(size) else: display_size = size if not display_name: mode = vfs.item_mode(item) if stat.S_ISDIR(mode): display_name = name + '/' elif stat.S_ISLNK(mode): display_name = name + '@' else: display_name = name return display_name, link + url_query, display_size
def find_vfs_item(name, repo): res = repo.resolve(name, follow=False, want_meta=False) leaf_name, leaf_item = res[-1] if not leaf_item: return None kind = type(leaf_item) if kind == vfs.Root: kind = 'root' elif kind == vfs.Tags: kind = 'tags' elif kind == vfs.RevList: kind = 'branch' elif kind == vfs.Commit: if len(res) > 1 and isinstance(res[-2][1], vfs.RevList): kind = 'save' else: kind = 'commit' elif kind == vfs.Item: if S_ISDIR(vfs.item_mode(leaf_item)): kind = 'tree' else: kind = 'blob' elif kind == vfs.Chunky: kind = 'tree' elif kind == vfs.FakeLink: # Don't have to worry about ELOOP, excepting malicious # remotes, since "latest" is the only FakeLink. assert leaf_name == b'latest' res = repo.resolve(leaf_item.target, parent=res[:-1], follow=False, want_meta=False) leaf_name, leaf_item = res[-1] assert leaf_item assert isinstance(leaf_item, vfs.Commit) name = b'/'.join(x[0] for x in res) kind = 'save' else: raise Exception('unexpected resolution for %s: %r' % (path_msg(name), res)) path = b'/'.join(name for name, item in res) if hasattr(leaf_item, 'coid'): result = Loc(type=kind, hash=leaf_item.coid, path=path) elif hasattr(leaf_item, 'oid'): result = Loc(type=kind, hash=leaf_item.oid, path=path) else: result = Loc(type=kind, hash=None, path=path) return result
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()) elif opt.meta: augmented = vfs.augment_item_meta(repo, leaf_item, include_size=True) sys.stdout.write(augmented.meta.encode()) else: if stat.S_ISREG(mode): with vfs.fopen(repo, leaf_item) as f: for b in chunkyreader(f):
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()
def test_item_mode(): mode = S_IFDIR | 0o755 meta = metadata.from_path(b'.') oid = b'\0' * 20 wvpasseq(mode, vfs.item_mode(vfs.Item(oid=oid, meta=mode))) wvpasseq(meta.mode, vfs.item_mode(vfs.Item(oid=oid, meta=meta)))
def restore(repo, parent_path, name, item, top, sparse, numeric_ids, owner_map, exclude_rxs, verbosity, hardlinks): global total_restored mode = vfs.item_mode(item) treeish = S_ISDIR(mode) fullname = parent_path + b'/' + name # Match behavior of index --exclude-rx with respect to paths. if should_rx_exclude_path(fullname + (b'/' if treeish else b''), exclude_rxs): return if not treeish: # Do this now so we'll have meta.symlink_target for verbose output item = vfs.augment_item_meta(repo, item, include_size=True) meta = item.meta assert (meta.mode == mode) if stat.S_ISDIR(mode): if verbosity >= 1: out.write(b'%s/\n' % fullname) elif stat.S_ISLNK(mode): assert (meta.symlink_target) if verbosity >= 2: out.write(b'%s@ -> %s\n' % (fullname, meta.symlink_target)) else: if verbosity >= 2: out.write(fullname + b'\n') orig_cwd = os.getcwd() try: if treeish: # Assumes contents() returns '.' with the full metadata first sub_items = vfs.contents(repo, item, want_meta=True) dot, item = next(sub_items, None) assert (dot == b'.') item = vfs.augment_item_meta(repo, item, include_size=True) meta = item.meta meta.create_path(name) os.chdir(name) total_restored += 1 if verbosity >= 0: qprogress('Restoring: %d\r' % total_restored) for sub_name, sub_item in sub_items: restore(repo, fullname, sub_name, sub_item, top, sparse, numeric_ids, owner_map, exclude_rxs, verbosity, hardlinks) os.chdir(b'..') apply_metadata(meta, name, numeric_ids, owner_map) else: created_hardlink = False if meta.hardlink_target: created_hardlink = hardlink_if_possible( fullname, item, top, hardlinks) if not created_hardlink: meta.create_path(name) if stat.S_ISREG(meta.mode): if sparse: write_file_content_sparsely(repo, name, item) else: write_file_content(repo, name, item) total_restored += 1 if verbosity >= 0: qprogress('Restoring: %d\r' % total_restored) if not created_hardlink: apply_metadata(meta, name, numeric_ids, owner_map) finally: os.chdir(orig_cwd)
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
words = [word for (wordstart,word) in shquote.quotesplit(line)] cmd = words[0].lower() #log('execute: %r %r\n' % (cmd, parm)) try: if cmd == 'ls': # FIXME: respect pwd (perhaps via ls accepting resolve path/parent) do_ls(repo, words[1:]) elif cmd == 'cd': np = pwd for parm in words[1:]: res = vfs.resolve(repo, parm, parent=np) _, leaf_item = res[-1] if not leaf_item: raise Exception('%r does not exist' % '/'.join(name for name, item in res)) if not stat.S_ISDIR(vfs.item_mode(leaf_item)): raise Exception('%r is not a directory' % parm) np = res pwd = np elif cmd == 'pwd': if len(pwd) == 1: sys.stdout.write('/') print('/'.join(name for name, item in pwd)) elif cmd == 'cat': for parm in words[1:]: res = vfs.resolve(repo, parm, parent=pwd) _, leaf_item = res[-1] if not leaf_item: raise Exception('%r does not exist' % '/'.join(name for name, item in res)) with vfs.fopen(repo, leaf_item) as srcfile:
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)
#log('execute: %r %r\n' % (cmd, parm)) try: if cmd == b'ls': # FIXME: respect pwd (perhaps via ls accepting resolve path/parent) do_ls(repo, 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 Exception('%s does not exist' % path_msg(b'/'.join(name for name, item in res))) if not stat.S_ISDIR(vfs.item_mode(leaf_item)): raise Exception('%s 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 Exception('%s does not exist' % path_msg(b'/'.join(name
def restore(repo, parent_path, name, item, top, sparse, numeric_ids, owner_map, exclude_rxs, verbosity, hardlinks): global total_restored mode = vfs.item_mode(item) treeish = S_ISDIR(mode) fullname = parent_path + '/' + name # Match behavior of index --exclude-rx with respect to paths. if should_rx_exclude_path(fullname + ('/' if treeish else ''), exclude_rxs): return if not treeish: # Do this now so we'll have meta.symlink_target for verbose output item = vfs.augment_item_meta(repo, item, include_size=True) meta = item.meta assert(meta.mode == mode) if stat.S_ISDIR(mode): if verbosity >= 1: print('%s/' % fullname) elif stat.S_ISLNK(mode): assert(meta.symlink_target) if verbosity >= 2: print('%s@ -> %s' % (fullname, meta.symlink_target)) else: if verbosity >= 2: print(fullname) orig_cwd = os.getcwd() try: if treeish: # Assumes contents() returns '.' with the full metadata first sub_items = vfs.contents(repo, item, want_meta=True) dot, item = next(sub_items, None) assert(dot == '.') item = vfs.augment_item_meta(repo, item, include_size=True) meta = item.meta meta.create_path(name) os.chdir(name) total_restored += 1 if verbosity >= 0: qprogress('Restoring: %d\r' % total_restored) for sub_name, sub_item in sub_items: restore(repo, fullname, sub_name, sub_item, top, sparse, numeric_ids, owner_map, exclude_rxs, verbosity, hardlinks) os.chdir('..') apply_metadata(meta, name, numeric_ids, owner_map) else: created_hardlink = False if meta.hardlink_target: created_hardlink = hardlink_if_possible(fullname, item, top, hardlinks) if not created_hardlink: meta.create_path(name) if stat.S_ISREG(meta.mode): if sparse: write_file_content_sparsely(repo, name, item) else: write_file_content(repo, name, item) total_restored += 1 if verbosity >= 0: qprogress('Restoring: %d\r' % total_restored) if not created_hardlink: apply_metadata(meta, name, numeric_ids, owner_map) finally: os.chdir(orig_cwd)
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()
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.lresolve(repo, target) 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()) elif opt.meta: augmented = vfs.augment_item_meta(repo, leaf_item, include_size=True) sys.stdout.write(augmented.meta.encode()) else: if stat.S_ISREG(mode): with vfs.fopen(repo, leaf_item) as f: for b in chunkyreader(f):