def ensure_repo_id(self): val = self.config(b'bup.repo-id') if val is not None: return # create lots of random bits ... randgen = random.SystemRandom() chars = b'abcdefghijklmnopqrstuvwxyz0123456789' new_id = b''.join( bytes_from_byte(randgen.choice(chars)) for x in range(31)) self.write_repo_id(new_id)
def __init__(self, infd, outp): BaseConn.__init__(self, outp) # Anything that comes through before the sync string was not # multiplexed and can be assumed to be debug/log before mux init. stderr = byte_stream(sys.stderr) cookie = b'BUPMUX' pos = 0 while True: b = os.read(infd, 1) # Make sure to write all pre-BUPMUX output to stderr if not b: ex = IOError('demux: unexpected EOF during initialization') with pending_raise(ex): stderr.write(cookie[:pos]) stderr.flush() if b == bytes_from_byte(cookie[pos]): pos += 1 if pos == len(cookie): break continue # If we can't find a new char of 'BUPMUX' then we must have some # pre-mux log messages - output those as soon and as complete as # possible. # # \r\n interacts badly with print_clean_line() in the main bup # so remove all the \r so we see the full the lines. This assumes # that nothing at this point will intentionally delete lines, but # as we're just during SSH init that seems reasonable. if b == b'\r': continue stderr.write(cookie[:pos]) # could be we have "BU" in the logs or so pos = 0 stderr.write(b) # pre-mux log messages stderr.flush() self.infd = infd self.reader = None self.buf = None self.closed = False
def test_valid_save_name(): valid = helpers.valid_save_name WVPASS(valid(b'x')) WVPASS(valid(b'x@')) WVFAIL(valid(b'@')) WVFAIL(valid(b'/')) WVFAIL(valid(b'/foo')) WVFAIL(valid(b'foo/')) WVFAIL(valid(b'/foo/')) WVFAIL(valid(b'foo//bar')) WVFAIL(valid(b'.')) WVFAIL(valid(b'bar.')) WVFAIL(valid(b'foo@{')) for x in b' ~^:?*[\\': WVFAIL(valid(b'foo' + bytes_from_byte(x))) for i in range(20): WVFAIL(valid(b'foo' + bytes_from_uint(i))) WVFAIL(valid(b'foo' + bytes_from_uint(0x7f))) WVFAIL(valid(b'foo..bar')) WVFAIL(valid(b'bar.lock/baz')) WVFAIL(valid(b'foo/bar.lock/baz')) WVFAIL(valid(b'.bar/baz')) WVFAIL(valid(b'foo/.bar/baz'))
def unfinished_word(line): """Returns the quotechar,word of any unfinished word at the end of 'line'. You can use this to determine if 'line' is a completely parseable line (ie. one that quotesplit() will finish successfully) or if you need to read more bytes first. Args: line: bytes Returns: quotechar,word: the initial quote char (or None), and the partial word. """ try: for (wordstart, word) in _quotesplit(line): pass except QuoteError: firstchar = bytes_from_byte(line[wordstart]) if firstchar in [q, qq]: return (firstchar, word) else: return (None, word) else: return (None, b'')
def _quotesplit(line): inquote = None inescape = None wordstart = 0 word = b'' for i in range(len(line)): c = bytes_from_byte(line[i]) if inescape: if inquote == q and c != q: word += b'\\' # single-q backslashes can only quote single-q word += c inescape = False elif c == b'\\': inescape = True elif c == inquote: inquote = None # this is un-sh-like, but do it for sanity when autocompleting yield (wordstart, word) word = b'' wordstart = i + 1 elif not inquote and not word and c in (q, qq): # the 'not word' constraint on this is un-sh-like, but do it # for sanity when autocompleting inquote = c wordstart = i elif not inquote and c in [b' ', b'\n', b'\r', b'\t']: if word: yield (wordstart, word) word = b'' wordstart = i + 1 else: word += c if word: yield (wordstart, word) if inquote or inescape or word: raise QuoteError()
def parse_tz_offset(s): """UTC offset in seconds.""" tz_off = (int(s[1:3]) * 60 * 60) + (int(s[3:5]) * 60) if bytes_from_byte(s[0]) == b'-': return -tz_off return tz_off
def test_commit_parsing(): def restore_env_var(name, val): if val is None: del environ[name] else: environ[name] = val def showval(commit, val): return readpipe([b'git', b'show', b'-s', b'--pretty=format:%s' % val, commit]).strip() with no_lingering_errors(): with test_tempdir(b'bup-tgit-') as tmpdir: orig_cwd = os.getcwd() workdir = tmpdir + b'/work' repodir = workdir + b'/.git' orig_author_name = environ.get(b'GIT_AUTHOR_NAME') orig_author_email = environ.get(b'GIT_AUTHOR_EMAIL') orig_committer_name = environ.get(b'GIT_COMMITTER_NAME') orig_committer_email = environ.get(b'GIT_COMMITTER_EMAIL') environ[b'GIT_AUTHOR_NAME'] = b'bup test' environ[b'GIT_COMMITTER_NAME'] = environ[b'GIT_AUTHOR_NAME'] environ[b'GIT_AUTHOR_EMAIL'] = b'bup@a425bc70a02811e49bdf73ee56450e6f' environ[b'GIT_COMMITTER_EMAIL'] = environ[b'GIT_AUTHOR_EMAIL'] try: readpipe([b'git', b'init', workdir]) environ[b'GIT_DIR'] = environ[b'BUP_DIR'] = repodir git.check_repo_or_die(repodir) os.chdir(workdir) with open('foo', 'w') as f: print('bar', file=f) readpipe([b'git', b'add', b'.']) readpipe([b'git', b'commit', b'-am', b'Do something', b'--author', b'Someone <someone@somewhere>', b'--date', b'Sat Oct 3 19:48:49 2009 -0400']) commit = readpipe([b'git', b'show-ref', b'-s', b'master']).strip() parents = showval(commit, b'%P') tree = showval(commit, b'%T') cname = showval(commit, b'%cn') cmail = showval(commit, b'%ce') cdate = showval(commit, b'%ct') coffs = showval(commit, b'%ci') coffs = coffs[-5:] coff = (int(coffs[-4:-2]) * 60 * 60) + (int(coffs[-2:]) * 60) if bytes_from_byte(coffs[-5]) == b'-': coff = - coff commit_items = git.get_commit_items(commit, git.cp()) WVPASSEQ(commit_items.parents, []) WVPASSEQ(commit_items.tree, tree) WVPASSEQ(commit_items.author_name, b'Someone') WVPASSEQ(commit_items.author_mail, b'someone@somewhere') WVPASSEQ(commit_items.author_sec, 1254613729) WVPASSEQ(commit_items.author_offset, -(4 * 60 * 60)) WVPASSEQ(commit_items.committer_name, cname) WVPASSEQ(commit_items.committer_mail, cmail) WVPASSEQ(commit_items.committer_sec, int(cdate)) WVPASSEQ(commit_items.committer_offset, coff) WVPASSEQ(commit_items.message, b'Do something\n') with open(b'bar', 'wb') as f: f.write(b'baz\n') readpipe([b'git', b'add', '.']) readpipe([b'git', b'commit', b'-am', b'Do something else']) child = readpipe([b'git', b'show-ref', b'-s', b'master']).strip() parents = showval(child, b'%P') commit_items = git.get_commit_items(child, git.cp()) WVPASSEQ(commit_items.parents, [commit]) finally: os.chdir(orig_cwd) restore_env_var(b'GIT_AUTHOR_NAME', orig_author_name) restore_env_var(b'GIT_AUTHOR_EMAIL', orig_author_email) restore_env_var(b'GIT_COMMITTER_NAME', orig_committer_name) restore_env_var(b'GIT_COMMITTER_EMAIL', orig_committer_email)
def parse_args(args): class GetOpts: pass opt = GetOpts() opt.help = False opt.verbose = 0 opt.quiet = False opt.print_commits = opt.print_trees = opt.print_tags = False opt.bwlimit = None opt.compress = 1 opt.source = opt.remote = None opt.target_specs = [] remaining = args[1:] # Skip argv[0] while remaining: arg = remaining[0] if arg in (b'-h', b'--help'): sys.stdout.write(usage(argspec)) sys.exit(0) elif arg in (b'-v', b'--verbose'): opt.verbose += 1 remaining = remaining[1:] elif arg in (b'--ff', b'--append', b'--pick', b'--force-pick', b'--new-tag', b'--replace', b'--unnamed'): (ref, ), remaining = require_n_args_or_die(1, remaining) opt.target_specs.append( Spec(method=arg[2:].decode('ascii'), src=ref, dest=None)) elif arg in (b'--ff:', b'--append:', b'--pick:', b'--force-pick:', b'--new-tag:', b'--replace:'): (ref, dest), remaining = require_n_args_or_die(2, remaining) opt.target_specs.append( Spec(method=arg[2:-1].decode('ascii'), src=ref, dest=dest)) elif arg in (b'-s', b'--source'): (opt.source, ), remaining = require_n_args_or_die(1, remaining) elif arg in (b'-r', b'--remote'): (opt.remote, ), remaining = require_n_args_or_die(1, remaining) elif arg in (b'-c', b'--print-commits'): opt.print_commits, remaining = True, remaining[1:] elif arg in (b'-t', b'--print-trees'): opt.print_trees, remaining = True, remaining[1:] elif arg == b'--print-tags': opt.print_tags, remaining = True, remaining[1:] elif arg in (b'-0', b'-1', b'-2', b'-3', b'-4', b'-5', b'-6', b'-7', b'-8', b'-9'): opt.compress = int(arg[1:]) remaining = remaining[1:] elif arg == b'--compress': (opt.compress, ), remaining = require_n_args_or_die(1, remaining) opt.compress = int(opt.compress) elif arg == b'--bwlimit': (opt.bwlimit, ), remaining = require_n_args_or_die(1, remaining) opt.bwlimit = int(opt.bwlimit) elif arg.startswith(b'-') and len(arg) > 2 and arg[1] != b'-': # Try to interpret this as -xyz, i.e. "-xyz -> -x -y -z". # We do this last so that --foo -bar is valid if --foo # requires a value. remaining[0:1] = (b'-' + bytes_from_byte(c) for c in arg[1:]) # FIXME continue else: misuse() return opt