Example #1
0
def main(argv):
    assert len(argv) == 1, "No arguments expected"
    upfn = upstream
    cur = current_branch()
    if cur == "HEAD":
        upfn = lambda b: git_hash(upstream(b))
        cur = git_hash(cur)
    downstreams = [b for b in branches() if upfn(b) == cur]
    if not downstreams:
        return "No downstream branches"
    elif len(downstreams) == 1:
        run_git("checkout", downstreams[0])
    else:
        high = len(downstreams) - 1
        print
        while True:
            print "Please select a downstream branch"
            for i, b in enumerate(downstreams):
                print "  %d. %s" % (i, b)
            r = raw_input("Selection (0-%d)[0]: " % high).strip() or "0"
            if not r.isdigit() or (0 > int(r) > high):
                print "Invalid choice."
            else:
                run_git("checkout", downstreams[int(r)])
                break
Example #2
0
def rebase(parent, start, branch, abort=False):
  try:
    run_git('rebase', '--onto', parent, start, branch)
    return RebaseRet(True, '')
  except CalledProcessError as cpe:
    if abort:
      run_git('rebase', '--abort')
    return RebaseRet(False, cpe.output)
Example #3
0
def resolve(target):
  """Return the generation number for target.

  As a side effect, record any new calculated data to the git repository.
  """
  num = get_num(target)
  if num is not None:
    return num

  if git_tree(REF) is None:
    empty = git_mktree({})
    ref = run_git('commit-tree', '-m', 'Initial commit from git-number', empty)
    run_git('update-ref', REF, ref)

  with ScopedPool() as pool:
    available = pool.apply_async(git_tree, args=(REF,), kwds={'recurse': True})
    preload = set()
    rev_list = []

    with StatusPrinter('Loading commits: %d') as inc:
      for line in run_git('rev-list', '--topo-order', '--parents',
                         '--reverse', hexlify(target), '^'+REF).splitlines():
        toks = map(unhexlify, line.split())
        rev_list.append((toks[0], toks[1:]))
        preload.update(t[:PREFIX_LEN] for t in toks)
        inc()

    preload.intersection_update(
      unhexlify(k.replace('/', ''))
      for k in available.get().iterkeys()
    )
    preload.difference_update((x,) for x in get_num_tree.cache)

    if preload:
      preload_iter = pool.imap_unordered(preload_tree, preload)
      with StatusPrinter('Preloading nurbs: (%%d/%d)' % len(preload)) as inc:
        for prefix, tree in preload_iter:
          get_num_tree.cache[prefix,] = tree
          inc()

  get_num_tree.default_enabled = True


  for ref, pars in rev_list:
    num = set_num(ref, max(map(get_num, pars)) + 1 if pars else 0)

  finalize(hexlify(target))

  return num
Example #4
0
def fix_head(target):
  try:
    git_dir = run_git('rev-parse', '--git-dir')
    with open(os.path.join(git_dir, 'HEAD'), 'wb') as f:
      f.write(target)
  except CalledProcessError as e:
    print e, e.out_err
Example #5
0
def main():
  force = '-f' in sys.argv
  if force:
    sys.argv.remove('-f')

  StatusPrinter.ENABLED = True

  target = hexlify(parse_one_committish())
  print 'Got Target: %s' % target
  fix_head(target)
  run_git('reset', '-q', target)

  if force:
    force_checkout(git_tree(target, recurse=True))
  else:
    fancy_checkout()
Example #6
0
def finalize(target):
  """After calculating the generation number for |target|, call finalize to
  save all our work to the git repository.
  """
  if not DIRTY_TREES:
    return

  msg = 'git-number Added %s numbers' % sum(DIRTY_TREES.itervalues())


  idx = os.path.join(run_git('rev-parse', '--git-dir'), 'number.idx')
  env = {'GIT_INDEX_FILE': idx}

  with StatusPrinter('Finalizing: (%%d/%d)' % len(DIRTY_TREES)) as inc:
    run_git('read-tree', REF, env=env)

    prefixes_trees = ((p, get_num_tree(p)) for p in sorted(DIRTY_TREES))
    updater = subprocess.Popen(['git', 'update-index', '-z', '--index-info'],
                               stdin=subprocess.PIPE, env=env)

    with ScopedPool() as leaf_pool:
      for item in leaf_pool.imap(leaf_map_fn, prefixes_trees):
        updater.stdin.write(item)
        inc()

    updater.stdin.close()
    updater.wait()

    run_git('update-ref', REF,
            run_git('commit-tree', '-m', msg,
                    '-p', git_hash(REF), '-p', target,
                    run_git('write-tree', env=env)))
Example #7
0
def check_versions(args, packages):
    error = False

    # Get relevant commits: compare HEAD against upstream branch or HEAD~1
    # (the latter if this CI check is running on upstream branch). Note that
    # for the common.get_changed_files() code, we don't check against
    # upstream branch HEAD, but against the latest common ancestor. This is not
    # desired here, since we already know what packages changed, and really
    # want to check if the version was increased towards *current* upstream
    # branch HEAD.
    commit = f"upstream/{common.get_upstream_branch()}"
    if common.run_git(["rev-parse", "HEAD"]) == common.run_git(["rev-parse",
                                                                commit]):
        print(f"NOTE: {commit} is on same commit as HEAD, comparing"
              " HEAD against HEAD~1.")
        commit = "HEAD~1"

    for package in packages:
        # Get versions, skip new packages
        head = get_package_version(args, package, "HEAD")
        upstream = get_package_version(args, package, commit, False)
        if not upstream:
            if head.rpartition('r')[2] != "0":
                print(f"- {package}: {head} (HEAD) (new package) [ERROR]")
                error = True
            else:
                print(f"- {package}: {head} (HEAD) (new package)")
            continue

        # Compare head and upstream versions
        result = pmb.parse.version.compare(head, upstream)
        if result != 1:
            error = True

        # Print result line ("- hello-world: 1-r2 (HEAD) > 1-r1 (HEAD~1)")
        formatstr = "- {}: {} (HEAD) {} {} ({})"
        if result != 1:
            formatstr += " [ERROR]"
        operator = version_compare_operator(result)
        print(formatstr.format(package, head, operator, upstream, commit))

    if error:
        exit_with_error_message()
Example #8
0
def main():
  if '--clean' in sys.argv:
    clean_refs()
    return 0

  orig_branch = current_branch()
  if orig_branch == 'HEAD':
    orig_branch = git_hash('HEAD')

  if 'origin' in run_git('remote').splitlines():
    run_git('fetch', 'origin', stderr=None)
  else:
    run_git('svn', 'fetch', stderr=None)
  branch_tree = {}
  for branch in branches():
    parent = upstream(branch)
    if not parent:
      print 'Skipping %s: No upstream specified' % branch
      continue
    branch_tree[branch] = parent

  starting_refs = {}
  for branch, parent in branch_tree.iteritems():
    starting_refs[branch] = get_or_create_merge_base_tag(branch, parent)

  if VERBOSE:
    pprint(branch_tree)
    pprint(starting_refs)

  # XXX There is a more efficient way to do this, but for now...
  while branch_tree:
    this_pass = [i for i in branch_tree.items() if i[1] not in branch_tree]
    for branch, parent in this_pass:
      clean_branch(branch, parent, starting_refs[branch])
      del branch_tree[branch]

  clean_refs()

  bclean()

  if orig_branch in branches():
    run_git('checkout', orig_branch)
  else:
    run_git('checkout', 'origin/master')

  return 0
Example #9
0
def clean_branch(branch, parent, starting_ref):
  if (git_hash(parent) != git_hash(starting_ref)
      and git_hash(branch) != git_hash(starting_ref)):
    print 'Rebasing:', branch

    # Try a plain rebase first
    if rebase(parent, starting_ref, branch, abort=True).success:
      return

    # Maybe squashing will help?
    print "Failed! Attempting to squash", branch, "...",
    squash_branch = branch+"_squash_attempt"
    run_git('checkout', '-b', squash_branch)
    squash()

    squash_ret = rebase(parent, starting_ref, squash_branch, abort=True)
    run_git('checkout', branch)
    run_git('branch', '-D', squash_branch)

    if squash_ret.success:
      print 'Success!'
      squash()
    final_rebase = rebase(parent, starting_ref, branch)
    assert final_rebase.success == squash_ret.success

    if not squash_ret.success:
      print squash_ret.message
      print 'Failure :('
      print 'Your working copy is in mid-rebase. Please completely resolve and'
      print 'run `git reup` again.'
      sys.exit(1)
Example #10
0
def main(argv):
  assert 2 <= len(argv) < 3, "Must supply (<newname>) or (<oldname> <newname>)"
  if len(argv) == 2:
    old_name = current_branch()
    new_name = argv[1]
  else:
    old_name = argv[1]
    new_name = argv[2]
  assert old_name in branches(), "<oldname> must exist"
  assert new_name not in branches(), "<newname> must not exist"

  run_git('branch', '-m', old_name, new_name)

  matcher = re.compile(r'^branch\.(.*)\.merge$')
  branches_to_fix = []
  for line in run_git('config', '-l').splitlines():
    key, value = line.split('=', 1)
    if value == 'refs/heads/' + old_name:
      m = matcher.match(key)
      if m:
        branch = m.group(1)
        remote = run_git('config', '--get', 'branch.%s.remote' % branch)
        if remote == '.':
          branches_to_fix.append(branch)
  for b in branches_to_fix:
    run_git('config', 'branch.%s.merge' % b, 'refs/heads/' + new_name)
Example #11
0
def bclean():
  merged = list(branches('--merged', 'origin/master'))

  if VERBOSE:
    print merged

  upstreams = {}
  downstreams = collections.defaultdict(list)
  for branch in branches():
    try:
      parent = upstream(branch)
      upstreams[branch] = parent
      downstreams[parent].append(branch)
    except CalledProcessError:
      pass

  if VERBOSE:
    print upstreams
    print downstreams

  if current_branch() in merged:
    run_git('checkout', 'origin/master')
  for branch in merged:
    for down in downstreams[branch]:
      if down not in merged:
        run_git('branch', '--set-upstream-to', upstreams[branch], down)
        print ('Reparented %s to track %s (was tracking %s)'
               % (down, upstreams[branch], branch))
    print run_git('branch', '-d', branch)

  return 0
def get_package_version(args, package, revision, check=True):
    # Redirect stderr to /dev/null, so git doesn't complain about files not
    # existing in master for new packages
    stderr = None
    if not check:
        stderr = subprocess.DEVNULL

    # Run something like "git show upstream/master:main/hello-world/APKBUILD"
    pmaports_dir = common.get_pmaports_dir()
    pattern = pmaports_dir + "/**/" + package + "/APKBUILD"
    path = glob.glob(pattern, recursive=True)[0][len(pmaports_dir + "/"):]
    apkbuild_content = common.run_git(["show", revision + ":" + path], check,
                                      stderr)
    if not apkbuild_content:
        return None

    # Save APKBUILD to a temporary path and parse it from there. (Not the best
    # way to do things, but good enough for this CI script.)
    with tempfile.TemporaryDirectory() as tempdir:
        with open(tempdir + "/APKBUILD", "w", encoding="utf-8") as handle:
            handle.write(apkbuild_content)
        parsed = pmb.parse.apkbuild(args, tempdir + "/APKBUILD", False, False)

    return parsed["pkgver"] + "-r" + parsed["pkgrel"]
Example #13
0
def fancy_checkout():
  made_dirs = set()

  # Curiously, this is faster than REPO.status(), even on *nix.
  opts = ['--porcelain', '-z', '--ignore-submodules=dirty']
  f_diff = run_git('status', *opts).split('\0')

  total = (len(f_diff) - 1)
  fmt = FMT % total
  if not total:
    return

  with StatusPrinter(fmt) as inc:
    ign_inc = lambda *_: inc()
    with ScopedPool(PROC_COUNT, initializer=init_repo) as pool:
      for mode, path in (x.split(None, 1) for x in f_diff if x):
        # technically, path could be 'from\0to', but that only happens for
        # rename and copy status we don't support.
        if mode[0] in 'DMA?':
          handle_dir(made_dirs, path)
          pool.apply_async(handle_file_lookup, (path,), callback=ign_inc)
        else:
          print ("Got unexpected mode: %s %s" % (mode, path))
          assert False
Example #14
0
def main(argv):
  assert len(argv) == 2, "Must supply new parent"
  branch = current_branch()
  new_parent = argv[1]
  cur_parent = upstream(branch)
  assert branch != 'HEAD', 'Must be on the branch you want to reparent'
  assert cur_parent != new_parent

  get_or_create_merge_base_tag(branch, cur_parent)

  print "Reparenting %s to track %s (was %s)" % (branch, new_parent, cur_parent)
  run_git('branch', '--set-upstream-to', new_parent, branch)
  try:
    cmd = ['reup'] + (['--verbose'] if VERBOSE else [])
    run_git(*cmd, stdout=None, stderr=None)
  except:
    print "Resetting parent back to %s" % (cur_parent)
    run_git('branch', '--set-upstream-to', cur_parent, branch)
    raise

  return 0
Example #15
0
def init_repo():
  global REPO, TREE_ROOT
  if not REPO:
    git_dir = run_git('rev-parse', '--git-dir')
    REPO = pygit2.Repository(git_dir)
    TREE_ROOT = REPO.revparse_single('HEAD').tree
Example #16
0
def squash():
  branch = current_branch()
  parent = upstream(branch)
  merge_base = get_or_create_merge_base_tag(branch, parent)
  run_git('reset', '--soft', merge_base)
  run_git('commit', '-a', '-C', 'HEAD@{1}')