def BatchListOwners(self, project, branch, paths): """Returns a dictionary {path: [owners]}.""" with git_common.ScopedPool(kind='threads') as pool: return dict( pool.imap_unordered( lambda p: (p, self.ListOwnersForFile(project, branch, p)), paths))
def BatchListOwners(self, paths): """List all owners for a group of files. Returns a dictionary {path: [owners]}. """ with git_common.ScopedPool(kind='threads') as pool: return dict(pool.imap_unordered( lambda p: (p, self.ListOwners(p)), paths))
def load_generation_numbers(targets): """Populates the caches of get_num and get_number_tree so they contain the results for |targets|. Loads cached numbers from disk, and calculates missing numbers if one or more of |targets| is newer than the cached calculations. Args: targets - An iterable of binary-encoded full git commit hashes. """ # In case they pass us a generator, listify targets. targets = list(targets) if all(get_num(t) is not None for t in targets): return if git.tree(REF) is None: empty = git.mktree({}) commit_hash = git.run( # Git user.name and/or user.email may not be configured, so specifying # them explicitly. They are not used, but requried by Git. '-c', 'user.name=%s' % AUTHOR_NAME, '-c', 'user.email=%s' % AUTHOR_EMAIL, 'commit-tree', '-m', 'Initial commit from git-number', empty) git.run('update-ref', REF, commit_hash) with git.ScopedPool(kind=POOL_KIND) as pool: preload_iter = pool.imap_unordered(preload_tree, all_prefixes()) rev_list = [] with git.ProgressPrinter('Loading commits: %(count)d') as inc: # Curiously, buffering the list into memory seems to be the fastest # approach in python (as opposed to iterating over the lines in the # stdout as they're produced). GIL strikes again :/ cmd = [ 'rev-list', '--topo-order', '--parents', '--reverse', '^' + REF, ] + [binascii.hexlify(target).decode() for target in targets] for line in git.run(*cmd).splitlines(): tokens = [binascii.unhexlify(token) for token in line.split()] rev_list.append((tokens[0], tokens[1:])) inc() get_number_tree.update(preload_iter) with git.ProgressPrinter('Counting: %%(count)d/%d' % len(rev_list)) as inc: for commit_hash, pars in rev_list: num = max(map(get_num, pars)) + 1 if pars else 0 prefix = commit_hash[:PREFIX_LEN] get_number_tree(prefix)[commit_hash] = num DIRTY_TREES[prefix] += 1 get_num.set(commit_hash, num) inc()
def finalize(targets): """Saves all cache data to the git repository. After calculating the generation number for |targets|, call finalize() to save all the work to the git repository. This in particular saves the trees referred to by DIRTY_TREES. """ if not DIRTY_TREES: return msg = 'git-number Added %s numbers' % sum(DIRTY_TREES.itervalues()) idx = os.path.join(git.run('rev-parse', '--git-dir'), 'number.idx') env = os.environ.copy() env['GIT_INDEX_FILE'] = idx progress_message = 'Finalizing: (%%(count)d/%d)' % len(DIRTY_TREES) with git.ProgressPrinter(progress_message) as inc: git.run('read-tree', REF, env=env) prefixes_trees = ((p, get_number_tree(p)) for p in sorted(DIRTY_TREES)) updater = subprocess2.Popen( ['git', 'update-index', '-z', '--index-info'], stdin=subprocess2.PIPE, env=env) with git.ScopedPool(kind=POOL_KIND) as leaf_pool: for item in leaf_pool.imap(leaf_map_fn, prefixes_trees): updater.stdin.write(item) inc() updater.stdin.close() updater.wait() assert updater.returncode == 0 tree_id = git.run('write-tree', env=env) commit_cmd = [ # Git user.name and/or user.email may not be configured, so specifying # them explicitly. They are not used, but requried by Git. '-c', 'user.name=%s' % AUTHOR_NAME, '-c', 'user.email=%s' % AUTHOR_EMAIL, 'commit-tree', '-m', msg, '-p' ] + git.hash_multi(REF) for t in targets: commit_cmd.extend(['-p', binascii.hexlify(t)]) commit_cmd.append(tree_id) commit_hash = git.run(*commit_cmd) git.run('update-ref', REF, commit_hash) DIRTY_TREES.clear()