|
Benjamin Poirier |
600ead |
#!/usr/bin/python3
|
|
Benjamin Poirier |
0aaea3 |
# -*- coding: utf-8 -*-
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
c7a109 |
# Copyright (C) 2018 SUSE LLC
|
|
Benjamin Poirier |
c7a109 |
#
|
|
Benjamin Poirier |
c7a109 |
# This program is free software; you can redistribute it and/or
|
|
Benjamin Poirier |
c7a109 |
# modify it under the terms of the GNU General Public License
|
|
Benjamin Poirier |
c7a109 |
# as published by the Free Software Foundation; either version 2
|
|
Benjamin Poirier |
c7a109 |
# of the License, or (at your option) any later version.
|
|
Benjamin Poirier |
c7a109 |
#
|
|
Benjamin Poirier |
c7a109 |
# This program is distributed in the hope that it will be useful,
|
|
Benjamin Poirier |
c7a109 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Benjamin Poirier |
c7a109 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Benjamin Poirier |
c7a109 |
# GNU General Public License for more details.
|
|
Benjamin Poirier |
c7a109 |
#
|
|
Benjamin Poirier |
c7a109 |
# You should have received a copy of the GNU General Public License
|
|
Benjamin Poirier |
c7a109 |
# along with this program; if not, write to the Free Software
|
|
Benjamin Poirier |
c7a109 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
Benjamin Poirier |
c7a109 |
# USA.
|
|
Benjamin Poirier |
c7a109 |
|
|
Benjamin Poirier |
0aaea3 |
import argparse
|
|
Benjamin Poirier |
0abe03 |
import bisect
|
|
Benjamin Poirier |
897bbc |
import collections
|
|
Benjamin Poirier |
600ead |
import dbm
|
|
Benjamin Poirier |
404509 |
import functools
|
|
Benjamin Poirier |
e8d72d |
import operator
|
|
Benjamin Poirier |
0aaea3 |
import os
|
|
Benjamin Poirier |
0aaea3 |
import os.path
|
|
Benjamin Poirier |
0aaea3 |
import pprint
|
|
Benjamin Poirier |
897bbc |
import re
|
|
Benjamin Poirier |
0aaea3 |
import shelve
|
|
Benjamin Poirier |
0aaea3 |
import subprocess
|
|
Benjamin Poirier |
0aaea3 |
import sys
|
|
Benjamin Poirier |
587a8d |
import types
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
50602b |
import pygit2_wrapper as pygit2
|
|
Benjamin Poirier |
50602b |
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
e8de5e |
class GSException(BaseException):
|
|
Benjamin Poirier |
e8de5e |
pass
|
|
Benjamin Poirier |
e8de5e |
|
|
Benjamin Poirier |
e8de5e |
|
|
Benjamin Poirier |
e8de5e |
class GSError(GSException):
|
|
Benjamin Poirier |
e8de5e |
pass
|
|
Benjamin Poirier |
e8de5e |
|
|
Benjamin Poirier |
e8de5e |
|
|
Benjamin Poirier |
544f5d |
class GSKeyError(GSException):
|
|
Benjamin Poirier |
544f5d |
pass
|
|
Benjamin Poirier |
544f5d |
|
|
Benjamin Poirier |
544f5d |
|
|
Benjamin Poirier |
0abe03 |
class GSNotFound(GSException):
|
|
Benjamin Poirier |
0abe03 |
pass
|
|
Benjamin Poirier |
0abe03 |
|
|
Benjamin Poirier |
0abe03 |
|
|
Benjamin Poirier |
897bbc |
class RepoURL(object):
|
|
Benjamin Poirier |
897bbc |
k_org_canon_prefix = "git://git.kernel.org/pub/scm/linux/kernel/git/"
|
|
Benjamin Poirier |
897bbc |
proto_match = re.compile("(git|https?)://")
|
|
Benjamin Poirier |
897bbc |
ext = ".git"
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
897bbc |
def __init__(self, url):
|
|
Benjamin Poirier |
2056d7 |
if url is None or url == repr(None):
|
|
Benjamin Poirier |
2056d7 |
self.url = None
|
|
Benjamin Poirier |
2056d7 |
return
|
|
Benjamin Poirier |
2056d7 |
|
|
Benjamin Poirier |
897bbc |
k_org_prefixes = [
|
|
Benjamin Poirier |
720a01 |
"http://git.kernel.org/pub/scm/linux/kernel/git/",
|
|
Benjamin Poirier |
897bbc |
"https://git.kernel.org/pub/scm/linux/kernel/git/",
|
|
Matthias Brugger |
27af81 |
"ssh://git@gitolite.kernel.org/pub/scm/linux/kernel/git/",
|
|
Benjamin Poirier |
897bbc |
"https://kernel.googlesource.com/pub/scm/linux/kernel/git/",
|
|
Benjamin Poirier |
897bbc |
]
|
|
Benjamin Poirier |
897bbc |
for prefix in k_org_prefixes:
|
|
Benjamin Poirier |
897bbc |
if url.startswith(prefix):
|
|
Benjamin Poirier |
897bbc |
url = url.replace(prefix, self.k_org_canon_prefix)
|
|
Benjamin Poirier |
897bbc |
break
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
16928c |
if not self.proto_match.match(url):
|
|
Benjamin Poirier |
897bbc |
url = self.k_org_canon_prefix + url
|
|
Benjamin Poirier |
439e8e |
|
|
Benjamin Poirier |
439e8e |
if not url.endswith(self.ext):
|
|
Benjamin Poirier |
439e8e |
url = url + self.ext
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
5aa06b |
# an undocumented alias
|
|
Benjamin Poirier |
5aa06b |
if url == "git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git":
|
|
Benjamin Poirier |
5aa06b |
url = "git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git"
|
|
Benjamin Poirier |
5aa06b |
|
|
Benjamin Poirier |
897bbc |
self.url = url
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
404509 |
def _is_valid_operand(self, other):
|
|
Benjamin Poirier |
404509 |
return hasattr(other, "url")
|
|
Benjamin Poirier |
404509 |
|
|
Benjamin Poirier |
404509 |
|
|
Benjamin Poirier |
897bbc |
def __eq__(self, other):
|
|
Benjamin Poirier |
404509 |
if not self._is_valid_operand(other):
|
|
Benjamin Poirier |
404509 |
return NotImplemented
|
|
Benjamin Poirier |
897bbc |
return self.url == other.url
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
404509 |
def __ne__(self, other):
|
|
Benjamin Poirier |
404509 |
if not self._is_valid_operand(other):
|
|
Benjamin Poirier |
404509 |
return NotImplemented
|
|
Benjamin Poirier |
404509 |
return self.url != other.url
|
|
Benjamin Poirier |
7b51a6 |
|
|
Benjamin Poirier |
7b51a6 |
|
|
Benjamin Poirier |
897bbc |
def __hash__(self):
|
|
Benjamin Poirier |
897bbc |
return hash(self.url)
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
897bbc |
def __repr__(self):
|
|
Benjamin Poirier |
897bbc |
return "%s" % (self.url,)
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
897bbc |
def __str__(self):
|
|
Benjamin Poirier |
897bbc |
url = self.url
|
|
Benjamin Poirier |
2056d7 |
if url is None:
|
|
Benjamin Poirier |
897bbc |
url = ""
|
|
Benjamin Poirier |
2056d7 |
elif url.startswith(self.k_org_canon_prefix) and url.endswith(self.ext):
|
|
Benjamin Poirier |
2056d7 |
url = url[len(self.k_org_canon_prefix):-1 * len(self.ext)]
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
897bbc |
return url
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
404509 |
@functools.total_ordering
|
|
Benjamin Poirier |
897bbc |
class Head(object):
|
|
Benjamin Poirier |
897bbc |
def __init__(self, repo_url, rev="master"):
|
|
Benjamin Poirier |
897bbc |
self.repo_url = repo_url
|
|
Benjamin Poirier |
897bbc |
self.rev = rev
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
404509 |
def _is_valid_operand(self, other):
|
|
Benjamin Poirier |
404509 |
return hasattr(other, "repo_url") and hasattr(other, "rev")
|
|
Benjamin Poirier |
404509 |
|
|
Benjamin Poirier |
404509 |
|
|
Benjamin Poirier |
404509 |
def _get_index(self):
|
|
Benjamin Poirier |
404509 |
"""
|
|
Benjamin Poirier |
404509 |
A head with no url is considered out of tree. Any other head with a
|
|
Benjamin Poirier |
404509 |
url is upstream of it.
|
|
Benjamin Poirier |
404509 |
"""
|
|
Benjamin Poirier |
404509 |
if self.repo_url == RepoURL(None):
|
|
Benjamin Poirier |
404509 |
return len(remotes)
|
|
Benjamin Poirier |
404509 |
else:
|
|
Benjamin Poirier |
404509 |
return remote_index[self]
|
|
Benjamin Poirier |
404509 |
|
|
Benjamin Poirier |
404509 |
|
|
Benjamin Poirier |
897bbc |
def __eq__(self, other):
|
|
Benjamin Poirier |
404509 |
if not self._is_valid_operand(other):
|
|
Benjamin Poirier |
404509 |
return NotImplemented
|
|
Benjamin Poirier |
897bbc |
return (self.repo_url == other.repo_url and self.rev == other.rev)
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
404509 |
def __lt__(self, other):
|
|
Benjamin Poirier |
404509 |
if not self._is_valid_operand(other):
|
|
Benjamin Poirier |
404509 |
return NotImplemented
|
|
Benjamin Poirier |
404509 |
return self._get_index() < other._get_index()
|
|
Benjamin Poirier |
404509 |
|
|
Benjamin Poirier |
404509 |
|
|
Benjamin Poirier |
897bbc |
def __hash__(self):
|
|
Benjamin Poirier |
897bbc |
return hash((self.repo_url, self.rev,))
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
76bf0c |
def __repr__(self):
|
|
Benjamin Poirier |
897bbc |
return "%s %s" % (repr(self.repo_url), self.rev,)
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
897bbc |
def __str__(self):
|
|
Benjamin Poirier |
897bbc |
url = str(self.repo_url)
|
|
Benjamin Poirier |
897bbc |
if self.rev == "master":
|
|
Benjamin Poirier |
897bbc |
return url
|
|
Benjamin Poirier |
897bbc |
else:
|
|
Benjamin Poirier |
897bbc |
result = "%s %s" % (url, self.rev,)
|
|
Benjamin Poirier |
897bbc |
return result.strip()
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
897bbc |
# a list of each remote head which is indexed by this script
|
|
Benjamin Poirier |
7c5bc6 |
# If the working repository is a clone of linux.git (it fetches from mainline,
|
|
Benjamin Poirier |
7c5bc6 |
# the first remote) and a commit does not appear in one of these remotes, it is
|
|
Benjamin Poirier |
7c5bc6 |
# considered "not upstream" and cannot be sorted.
|
|
Benjamin Poirier |
897bbc |
# Repositories that come first in the list should be pulling/merging from
|
|
Benjamin Poirier |
897bbc |
# repositories lower down in the list. Said differently, commits should trickle
|
|
Benjamin Poirier |
897bbc |
# up from repositories at the end of the list to repositories higher up. For
|
|
Benjamin Poirier |
897bbc |
# example, network commits usually follow "net-next" -> "net" -> "linux.git".
|
|
Benjamin Poirier |
897bbc |
#
|
|
Benjamin Poirier |
4809eb |
# linux-next is not a good reference because it gets rebased. If a commit is in
|
|
Benjamin Poirier |
4809eb |
# linux-next, it comes from some other tree. Please tag the patch accordingly.
|
|
Benjamin Poirier |
4809eb |
#
|
|
Benjamin Poirier |
897bbc |
# Head(RepoURL(remote url), remote branch name)[]
|
|
Benjamin Poirier |
897bbc |
# Note that "remote url" can be abbreviated if it starts with one of the usual
|
|
Benjamin Poirier |
897bbc |
# kernel.org prefixes and "remote branch name" can be omitted if it is "master".
|
|
Benjamin Poirier |
897bbc |
remotes = (
|
|
Benjamin Poirier |
897bbc |
Head(RepoURL("torvalds/linux.git")),
|
|
Michal Kubecek |
445746 |
Head(RepoURL("netdev/net.git")),
|
|
Benjamin Poirier |
897bbc |
Head(RepoURL("davem/net.git")),
|
|
Michal Kubecek |
445746 |
Head(RepoURL("netdev/net-next.git")),
|
|
Benjamin Poirier |
897bbc |
Head(RepoURL("davem/net-next.git")),
|
|
Michal Suchanek |
ec2ea2 |
Head(RepoURL("rdma/rdma.git"), "for-rc"),
|
|
Michal Suchanek |
ec2ea2 |
Head(RepoURL("rdma/rdma.git"), "for-next"),
|
|
Benjamin Poirier |
897bbc |
Head(RepoURL("dledford/rdma.git"), "k.o/for-next"),
|
|
Petr Tesarik |
0e18ba |
Head(RepoURL("jejb/scsi.git"), "for-next"),
|
|
Benjamin Poirier |
897bbc |
Head(RepoURL("bp/bp.git"), "for-next"),
|
|
Benjamin Poirier |
897bbc |
Head(RepoURL("tiwai/sound.git")),
|
|
Benjamin Poirier |
131a90 |
Head(RepoURL("git://linuxtv.org/media_tree.git")),
|
|
Benjamin Poirier |
897bbc |
Head(RepoURL("powerpc/linux.git"), "next"),
|
|
Jeff Mahoney |
1f975c |
Head(RepoURL("powerpc/linux.git"), "fixes"),
|
|
Benjamin Poirier |
897bbc |
Head(RepoURL("tip/tip.git")),
|
|
Benjamin Poirier |
5d61b5 |
Head(RepoURL("shli/md.git"), "for-next"),
|
|
Benjamin Poirier |
5d61b5 |
Head(RepoURL("dhowells/linux-fs.git"), "keys-uefi"),
|
|
Jiri Kosina |
9f5c18 |
Head(RepoURL("tytso/ext4.git"), "dev"),
|
|
Petr Tesarik |
d41c9f |
Head(RepoURL("s390/linux.git"), "fixes"),
|
|
Benjamin Poirier |
131a90 |
Head(RepoURL("https://github.com/kdave/btrfs-devel.git"), "misc-next"),
|
|
Benjamin Poirier |
a3e6d3 |
Head(RepoURL("git://people.freedesktop.org/~airlied/linux"), "drm-next"),
|
|
Thomas Zimmermann |
379ad3 |
Head(RepoURL("git://anongit.freedesktop.org/drm/drm-misc"), "drm-misc-next"),
|
|
Benjamin Poirier |
a3e6d3 |
Head(RepoURL("gregkh/tty.git"), "tty-next"),
|
|
Goldwyn Rodrigues |
d8d320 |
Head(RepoURL("jj/linux-apparmor.git"), "apparmor-next"),
|
|
Michal Kubecek |
daa89d |
Head(RepoURL("pablo/nf.git")),
|
|
Michal Kubecek |
daa89d |
Head(RepoURL("pablo/nf-next.git")),
|
|
Michal Kubecek |
daa89d |
Head(RepoURL("horms/ipvs.git")),
|
|
Michal Kubecek |
daa89d |
Head(RepoURL("horms/ipvs-next.git")),
|
|
Michal Kubecek |
daa89d |
Head(RepoURL("klassert/ipsec.git")),
|
|
Michal Kubecek |
daa89d |
Head(RepoURL("klassert/ipsec-next.git")),
|
|
Petr Tesarik |
46e9bd |
Head(RepoURL("kvalo/wireless-drivers-next.git")),
|
|
Johannes Thumshirn |
8ce95c |
Head(RepoURL("mkp/scsi.git"), "queue"),
|
|
Johannes Thumshirn |
b5a813 |
Head(RepoURL("mkp/scsi.git"), "fixes"),
|
|
Borislav Petkov |
9adbb9 |
Head(RepoURL("git://git.kernel.dk/linux-block.git"), "for-next"),
|
|
Johannes Thumshirn |
40fc9c |
Head(RepoURL("git://git.kernel.org/pub/scm/virt/kvm/kvm.git"), "queue"),
|
|
Daniel Wagner |
3bdd6d |
Head(RepoURL("git://git.infradead.org/nvme.git"), "nvme-5.15"),
|
|
Michal Suchanek |
f433a0 |
Head(RepoURL("dhowells/linux-fs.git")),
|
|
Benjamin Poirier |
64ee72 |
Head(RepoURL("herbert/cryptodev-2.6.git")),
|
|
Olaf Hering |
718b01 |
Head(RepoURL("helgaas/pci.git"), "next"),
|
|
Luis Henriques |
82df85 |
Head(RepoURL("viro/vfs.git"), "for-linus"),
|
|
Goldwyn Rodrigues |
de81e9 |
Head(RepoURL("viro/vfs.git"), "fixes"),
|
|
Jessica Yu |
31d0a4 |
Head(RepoURL("jeyu/linux.git"), "modules-next"),
|
|
Joerg Roedel |
3ac5af |
Head(RepoURL("joro/iommu.git"), "next"),
|
|
Johannes Thumshirn |
2a73ff |
Head(RepoURL("nvdimm/nvdimm.git"), "libnvdimm-for-next"),
|
|
Johannes Thumshirn |
c8c847 |
Head(RepoURL("nvdimm/nvdimm.git"), "libnvdimm-fixes"),
|
|
Johannes Thumshirn |
7d6ade |
Head(RepoURL("djbw/nvdimm.git"), "libnvdimm-pending"),
|
|
|
86af8b |
Head(RepoURL("git://git.linux-nfs.org/projects/anna/linux-nfs.git"), "linux-next"),
|
|
Michal Suchanek |
727e37 |
Head(RepoURL("acme/linux.git"), "perf/core"),
|
|
Matthias Brugger |
3d5eb0 |
Head(RepoURL("will/linux.git"), "for-joerg/arm-smmu/updates"),
|
|
Michal Suchanek |
f74c58 |
Head(RepoURL("herbert/crypto-2.6.git"), "master"),
|
|
Thomas Renninger |
f216f5 |
Head(RepoURL("rafael/linux-pm.git")),
|
|
NeilBrown |
ec6f7e |
Head(RepoURL("git://git.linux-nfs.org/~bfields/linux.git"), "nfsd-next"),
|
|
Michal Suchanek |
99afd5 |
Head(RepoURL("vkoul/soundwire.git"),"fixes"),
|
|
Michal Suchanek |
99afd5 |
Head(RepoURL("vkoul/soundwire.git"),"next"),
|
|
Matthias Brugger |
2e5580 |
Head(RepoURL("arm64/linux.git"), "for-next/core"),
|
|
Nicolas Saenz Julienne |
11db49 |
Head(RepoURL("robh/linux.git"), "for-next"),
|
|
Nicolas Saenz Julienne |
5d9839 |
Head(RepoURL("git://git.infradead.org/users/hch/dma-mapping.git"), "for-next"),
|
|
Matthias Brugger |
84aca3 |
Head(RepoURL("thermal/linux.git"), "thermal/linux-next"),
|
|
Matthias Brugger |
78b705 |
Head(RepoURL("git://github.com/cminyard/linux-ipmi.git"), "for-next"),
|
|
Borislav Petkov |
e71810 |
Head(RepoURL("ras/ras.git"), "edac-for-next"),
|
|
Nicolas Saenz Julienne |
73604d |
Head(RepoURL("linusw/linux-pinctrl.git"), "for-next"),
|
|
Lee, Chun-Yi |
5c191a |
Head(RepoURL("efi/efi.git"), "next"),
|
|
Nicolas Saenz Julienne |
7febf5 |
Head(RepoURL("ulfh/mmc.git"), "next"),
|
|
Jessica Yu |
1ed297 |
Head(RepoURL("masahiroy/linux-kbuild.git"), "for-next"),
|
|
Cho, Yu-Chen |
f7fbbb |
Head(RepoURL("bluetooth/bluetooth-next.git")),
|
|
Nicolas Saenz Julienne |
543517 |
Head(RepoURL("clk/linux.git"), "clk-next"),
|
|
Luis Henriques |
3233d6 |
Head(RepoURL("git://github.com/ceph/ceph-client"), "testing"),
|
|
Gary Lin |
65979e |
Head(RepoURL("bpf/bpf.git")),
|
|
Benjamin Poirier |
897bbc |
)
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
600ead |
remote_index = dict(zip(remotes, list(range(len(remotes)))))
|
|
Benjamin Poirier |
1a4488 |
oot = Head(RepoURL(None), "out-of-tree patches")
|
|
Benjamin Poirier |
8d50e8 |
|
|
Benjamin Poirier |
f17031 |
|
|
Benjamin Poirier |
587a8d |
def get_heads(repo):
|
|
Benjamin Poirier |
587a8d |
"""
|
|
Benjamin Poirier |
587a8d |
Returns
|
|
Benjamin Poirier |
587a8d |
repo_heads[Head]
|
|
Benjamin Poirier |
587a8d |
sha1
|
|
Benjamin Poirier |
587a8d |
"""
|
|
Benjamin Poirier |
587a8d |
result = collections.OrderedDict()
|
|
Benjamin Poirier |
56e868 |
repo_remotes = collections.OrderedDict(
|
|
Benjamin Poirier |
56e868 |
((RepoURL(remote.url), remote,) for remote in repo.remotes))
|
|
Benjamin Poirier |
4f1bbb |
|
|
Benjamin Poirier |
587a8d |
for head in remotes:
|
|
Benjamin Poirier |
7c5bc6 |
if head in result:
|
|
Benjamin Poirier |
7c5bc6 |
raise GSException("head \"%s\" is not unique." % (head,))
|
|
Benjamin Poirier |
7c5bc6 |
|
|
Benjamin Poirier |
76bf0c |
try:
|
|
Benjamin Poirier |
56e868 |
remote = repo_remotes[head.repo_url]
|
|
Benjamin Poirier |
587a8d |
except KeyError:
|
|
Benjamin Poirier |
587a8d |
continue
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
56e868 |
lhs = "refs/heads/%s" % (head.rev,)
|
|
Benjamin Poirier |
56e868 |
rhs = None
|
|
Benjamin Poirier |
56e868 |
nb = len(remote.fetch_refspecs)
|
|
Benjamin Poirier |
56e868 |
if nb == 0:
|
|
Benjamin Poirier |
56e868 |
# `git clone --bare` case
|
|
Benjamin Poirier |
56e868 |
rhs = lhs
|
|
Benjamin Poirier |
56e868 |
else:
|
|
Benjamin Poirier |
56e868 |
for i in range(nb):
|
|
Benjamin Poirier |
56e868 |
r = remote.get_refspec(i)
|
|
Benjamin Poirier |
56e868 |
if r.src_matches(lhs):
|
|
Benjamin Poirier |
56e868 |
rhs = r.transform(lhs)
|
|
Benjamin Poirier |
56e868 |
break
|
|
Benjamin Poirier |
56e868 |
if rhs is None:
|
|
Benjamin Poirier |
56e868 |
raise GSError("No matching fetch refspec for head \"%s\"." %
|
|
Benjamin Poirier |
56e868 |
(head,))
|
|
Benjamin Poirier |
587a8d |
try:
|
|
Benjamin Poirier |
56e868 |
commit = repo.revparse_single(rhs)
|
|
Benjamin Poirier |
587a8d |
except KeyError:
|
|
Benjamin Poirier |
56e868 |
raise GSError("Could not read revision \"%s\". Perhaps you need "
|
|
Benjamin Poirier |
56e868 |
"to fetch from remote \"%s\"" % (rhs, remote.name,))
|
|
Benjamin Poirier |
587a8d |
result[head] = str(commit.id)
|
|
Benjamin Poirier |
587a8d |
|
|
Benjamin Poirier |
600ead |
if len(result) == 0 or list(result.keys())[0] != remotes[0]:
|
|
Benjamin Poirier |
587a8d |
# According to the urls in remotes, this is not a clone of linux.git
|
|
Benjamin Poirier |
587a8d |
# Sort according to commits reachable from the current head
|
|
Benjamin Poirier |
587a8d |
result = collections.OrderedDict(
|
|
Benjamin Poirier |
587a8d |
[(Head(RepoURL(None), "HEAD"),
|
|
Benjamin Poirier |
587a8d |
str(repo.revparse_single("HEAD").id),)])
|
|
Benjamin Poirier |
587a8d |
|
|
Benjamin Poirier |
587a8d |
return result
|
|
Benjamin Poirier |
587a8d |
|
|
Benjamin Poirier |
587a8d |
|
|
Benjamin Poirier |
587a8d |
def get_history(repo, repo_heads):
|
|
Benjamin Poirier |
587a8d |
"""
|
|
Benjamin Poirier |
587a8d |
Returns
|
|
Benjamin Poirier |
587a8d |
history[Head][commit hash represented as string of 40 characters]
|
|
Benjamin Poirier |
587a8d |
index, an ordinal number such that
|
|
Benjamin Poirier |
587a8d |
commit a is an ancestor of commit b -> index(a) < index(b)
|
|
Benjamin Poirier |
587a8d |
"""
|
|
Benjamin Poirier |
587a8d |
processed = []
|
|
Benjamin Poirier |
587a8d |
history = collections.OrderedDict()
|
|
Benjamin Poirier |
587a8d |
args = ["git", "log", "--topo-order", "--pretty=tformat:%H"]
|
|
Benjamin Poirier |
587a8d |
for head, rev in repo_heads.items():
|
|
Benjamin Poirier |
587a8d |
sp = subprocess.Popen(args + processed + [rev],
|
|
Benjamin Poirier |
587a8d |
cwd=repo.path,
|
|
Benjamin Poirier |
587a8d |
env={},
|
|
Benjamin Poirier |
587a8d |
stdout=subprocess.PIPE,
|
|
Benjamin Poirier |
587a8d |
stderr=subprocess.STDOUT)
|
|
Benjamin Poirier |
587a8d |
|
|
Benjamin Poirier |
587a8d |
result = {}
|
|
Benjamin Poirier |
587a8d |
for l in sp.stdout:
|
|
Benjamin Poirier |
600ead |
result[l.decode().strip()] = len(result)
|
|
Benjamin Poirier |
587a8d |
# reverse indexes
|
|
Benjamin Poirier |
587a8d |
history[head] = {commit : len(result) - val for commit, val in
|
|
Benjamin Poirier |
587a8d |
result.items()}
|
|
Benjamin Poirier |
587a8d |
|
|
Benjamin Poirier |
587a8d |
sp.communicate()
|
|
Benjamin Poirier |
587a8d |
if sp.returncode != 0:
|
|
Benjamin Poirier |
587a8d |
raise GSError("git log exited with an error:\n" +
|
|
Benjamin Poirier |
587a8d |
"\n".join(history[head]))
|
|
Benjamin Poirier |
587a8d |
|
|
Benjamin Poirier |
587a8d |
processed.append("^%s" % (rev,))
|
|
Benjamin Poirier |
587a8d |
|
|
Benjamin Poirier |
587a8d |
return history
|
|
Benjamin Poirier |
587a8d |
|
|
Benjamin Poirier |
8d50e8 |
|
|
Benjamin Poirier |
2c7d8e |
class CException(BaseException):
|
|
Benjamin Poirier |
2c7d8e |
pass
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
76bf0c |
|
|
Benjamin Poirier |
2c7d8e |
class CError(CException):
|
|
Benjamin Poirier |
2c7d8e |
pass
|
|
Benjamin Poirier |
f28d0a |
|
|
Benjamin Poirier |
76bf0c |
|
|
Benjamin Poirier |
2c7d8e |
class CNeedsRebuild(CException):
|
|
Benjamin Poirier |
2c7d8e |
pass
|
|
Benjamin Poirier |
76bf0c |
|
|
Benjamin Poirier |
76bf0c |
|
|
Benjamin Poirier |
2c7d8e |
class CAbsent(CNeedsRebuild):
|
|
Benjamin Poirier |
2c7d8e |
pass
|
|
Benjamin Poirier |
76bf0c |
|
|
Benjamin Poirier |
76bf0c |
|
|
Benjamin Poirier |
2c7d8e |
class CKeyError(CNeedsRebuild):
|
|
Benjamin Poirier |
2c7d8e |
pass
|
|
Benjamin Poirier |
76bf0c |
|
|
Benjamin Poirier |
76bf0c |
|
|
Benjamin Poirier |
2c7d8e |
class CUnsupported(CNeedsRebuild):
|
|
Benjamin Poirier |
2c7d8e |
pass
|
|
Benjamin Poirier |
76bf0c |
|
|
Benjamin Poirier |
76bf0c |
|
|
Benjamin Poirier |
2c7d8e |
class CInconsistent(CNeedsRebuild):
|
|
Benjamin Poirier |
2c7d8e |
pass
|
|
Benjamin Poirier |
76bf0c |
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
class Cache(object):
|
|
Benjamin Poirier |
2c7d8e |
"""
|
|
Benjamin Poirier |
2c7d8e |
cache
|
|
Benjamin Poirier |
2c7d8e |
version
|
|
Benjamin Poirier |
2c7d8e |
history[]
|
|
Benjamin Poirier |
2c7d8e |
(url, rev, sha1,
|
|
Benjamin Poirier |
2c7d8e |
history[commit hash represented as string of 40 characters]
|
|
Benjamin Poirier |
2c7d8e |
index (as described in get_history())
|
|
Benjamin Poirier |
2c7d8e |
,)
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
The cache is stored using basic types.
|
|
Benjamin Poirier |
2c7d8e |
"""
|
|
Benjamin Poirier |
2c7d8e |
version = 3
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
def __init__(self, write_enable=False):
|
|
Benjamin Poirier |
2c7d8e |
self.write_enable = write_enable
|
|
Benjamin Poirier |
2c7d8e |
self.closed = True
|
|
Benjamin Poirier |
db0e54 |
try:
|
|
Benjamin Poirier |
db0e54 |
cache_dir = os.environ["XDG_CACHE_HOME"]
|
|
Benjamin Poirier |
db0e54 |
except KeyError:
|
|
Benjamin Poirier |
db0e54 |
cache_dir = os.path.expanduser("~/.cache")
|
|
Benjamin Poirier |
2c7d8e |
cache_path = os.path.join(cache_dir, "git-sort")
|
|
Benjamin Poirier |
2c7d8e |
try:
|
|
Benjamin Poirier |
2c7d8e |
os.stat(cache_path)
|
|
Benjamin Poirier |
2c7d8e |
except OSError as e:
|
|
Benjamin Poirier |
2c7d8e |
if e.errno == 2:
|
|
Benjamin Poirier |
2c7d8e |
if write_enable:
|
|
Benjamin Poirier |
2c7d8e |
if not os.path.isdir(cache_dir):
|
|
Benjamin Poirier |
2c7d8e |
try:
|
|
Benjamin Poirier |
2c7d8e |
os.makedirs(cache_dir)
|
|
Benjamin Poirier |
2c7d8e |
except OSError as err:
|
|
Benjamin Poirier |
2c7d8e |
raise CError("Could not create cache directory:\n" +
|
|
Benjamin Poirier |
2c7d8e |
str(err))
|
|
Benjamin Poirier |
2c7d8e |
else:
|
|
Benjamin Poirier |
2c7d8e |
raise CAbsent
|
|
Benjamin Poirier |
2c7d8e |
else:
|
|
Benjamin Poirier |
2c7d8e |
raise
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
15bd1c |
if write_enable:
|
|
Benjamin Poirier |
15bd1c |
# In case there is already a database file of an unsupported format,
|
|
Benjamin Poirier |
15bd1c |
# one would hope that with flag="n" a new database would be created
|
|
Benjamin Poirier |
15bd1c |
# to overwrite the current one. Alas, that is not the case... :'(
|
|
Benjamin Poirier |
15bd1c |
try:
|
|
Benjamin Poirier |
15bd1c |
os.unlink(cache_path)
|
|
Benjamin Poirier |
15bd1c |
except OSError as e:
|
|
Benjamin Poirier |
15bd1c |
if e.errno != 2:
|
|
Benjamin Poirier |
15bd1c |
raise
|
|
Benjamin Poirier |
15bd1c |
|
|
Benjamin Poirier |
2c7d8e |
flag_map = {False : "r", True : "n"}
|
|
Benjamin Poirier |
15bd1c |
try:
|
|
Benjamin Poirier |
15bd1c |
self.cache = shelve.open(cache_path, flag=flag_map[write_enable])
|
|
Benjamin Poirier |
600ead |
except dbm.error:
|
|
Benjamin Poirier |
600ead |
raise CUnsupported
|
|
Benjamin Poirier |
2c7d8e |
self.closed = False
|
|
Benjamin Poirier |
2c7d8e |
if write_enable:
|
|
Benjamin Poirier |
2c7d8e |
self.cache["version"] = Cache.version
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
def __del__(self):
|
|
Benjamin Poirier |
2c7d8e |
self.close()
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
def __enter__(self):
|
|
Benjamin Poirier |
2c7d8e |
return self
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
def __exit__(self, *args):
|
|
Benjamin Poirier |
2c7d8e |
self.close()
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
def close(self):
|
|
Benjamin Poirier |
2c7d8e |
if not self.closed:
|
|
Benjamin Poirier |
2c7d8e |
self.cache.close()
|
|
Benjamin Poirier |
2c7d8e |
self.closed = True
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
def __getitem__(self, key):
|
|
Benjamin Poirier |
2c7d8e |
"""
|
|
Benjamin Poirier |
2c7d8e |
Supported keys:
|
|
Benjamin Poirier |
2c7d8e |
"version"
|
|
Benjamin Poirier |
2c7d8e |
int
|
|
Benjamin Poirier |
2c7d8e |
"history"
|
|
Benjamin Poirier |
2c7d8e |
OrderedDict((Head, sha1) : history)
|
|
Benjamin Poirier |
2c7d8e |
"""
|
|
Benjamin Poirier |
2c7d8e |
if self.closed:
|
|
Benjamin Poirier |
2c7d8e |
raise ValueError
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
15bd1c |
try:
|
|
Benjamin Poirier |
15bd1c |
version = self.cache["version"]
|
|
Benjamin Poirier |
15bd1c |
except KeyError:
|
|
Benjamin Poirier |
15bd1c |
key_error = True
|
|
Benjamin Poirier |
15bd1c |
except ValueError as err:
|
|
Benjamin Poirier |
15bd1c |
raise CUnsupported(str(err))
|
|
Benjamin Poirier |
15bd1c |
else:
|
|
Benjamin Poirier |
15bd1c |
key_error = False
|
|
Benjamin Poirier |
15bd1c |
|
|
Benjamin Poirier |
2c7d8e |
if key == "version":
|
|
Benjamin Poirier |
15bd1c |
if key_error:
|
|
Benjamin Poirier |
2c7d8e |
raise CKeyError
|
|
Benjamin Poirier |
15bd1c |
else:
|
|
Benjamin Poirier |
15bd1c |
return version
|
|
Benjamin Poirier |
2c7d8e |
elif key == "history":
|
|
Benjamin Poirier |
15bd1c |
if key_error or version != Cache.version:
|
|
Benjamin Poirier |
2c7d8e |
raise CUnsupported
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
db0e54 |
try:
|
|
Benjamin Poirier |
2c7d8e |
cache_history = self.cache["history"]
|
|
Benjamin Poirier |
2c7d8e |
except KeyError:
|
|
Benjamin Poirier |
2c7d8e |
raise CInconsistent
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
bcc8a7 |
# This detailed check may be needed if an older git-sort (which
|
|
Benjamin Poirier |
bcc8a7 |
# didn't set a cache version) modified the cache.
|
|
Benjamin Poirier |
600ead |
if (not isinstance(cache_history, list) or
|
|
Thomas Zimmermann |
c5e56e |
len(cache_history) < 1 or
|
|
Benjamin Poirier |
bcc8a7 |
len(cache_history[0]) != 4 or
|
|
Benjamin Poirier |
600ead |
not isinstance(cache_history[0][3], dict)):
|
|
Benjamin Poirier |
bcc8a7 |
raise CInconsistent
|
|
Benjamin Poirier |
bcc8a7 |
|
|
Benjamin Poirier |
2c7d8e |
return collections.OrderedDict([
|
|
Benjamin Poirier |
2c7d8e |
(
|
|
Benjamin Poirier |
2c7d8e |
(Head(RepoURL(e[0]), e[1]), e[2],),
|
|
Benjamin Poirier |
2c7d8e |
e[3],
|
|
Benjamin Poirier |
2c7d8e |
) for e in cache_history])
|
|
Benjamin Poirier |
2c7d8e |
else:
|
|
Benjamin Poirier |
2c7d8e |
raise KeyError
|
|
Benjamin Poirier |
76bf0c |
|
|
Benjamin Poirier |
76bf0c |
|
|
Benjamin Poirier |
2c7d8e |
def __setitem__(self, key, value):
|
|
Benjamin Poirier |
76bf0c |
"""
|
|
Benjamin Poirier |
2c7d8e |
Supported keys:
|
|
Benjamin Poirier |
2c7d8e |
"history"
|
|
Benjamin Poirier |
2c7d8e |
OrderedDict((Head, sha1) : history)
|
|
Benjamin Poirier |
76bf0c |
"""
|
|
Benjamin Poirier |
2c7d8e |
if self.closed or not self.write_enable:
|
|
Benjamin Poirier |
2c7d8e |
raise ValueError
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
if key == "history":
|
|
Benjamin Poirier |
2c7d8e |
self.cache["history"] = [(
|
|
Benjamin Poirier |
2c7d8e |
repr(desc[0].repo_url), desc[0].rev, desc[1], log,
|
|
Benjamin Poirier |
2c7d8e |
) for desc, log in value.items()]
|
|
Benjamin Poirier |
2c7d8e |
else:
|
|
Benjamin Poirier |
2c7d8e |
raise KeyError
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
395993 |
@functools.total_ordering
|
|
Benjamin Poirier |
395993 |
class IndexedCommit(object):
|
|
Benjamin Poirier |
395993 |
def __init__(self, head, index):
|
|
Benjamin Poirier |
395993 |
self.head = head
|
|
Benjamin Poirier |
395993 |
self.index = index
|
|
Benjamin Poirier |
395993 |
|
|
Benjamin Poirier |
395993 |
|
|
Benjamin Poirier |
395993 |
def _is_valid_operand(self, other):
|
|
Benjamin Poirier |
395993 |
return hasattr(other, "head") and hasattr(other, "index")
|
|
Benjamin Poirier |
395993 |
|
|
Benjamin Poirier |
395993 |
|
|
Benjamin Poirier |
395993 |
def __eq__(self, other):
|
|
Benjamin Poirier |
395993 |
if not self._is_valid_operand(other):
|
|
Benjamin Poirier |
395993 |
return NotImplemented
|
|
Benjamin Poirier |
395993 |
return (self.head == other.head and self.index == other.index)
|
|
Benjamin Poirier |
395993 |
|
|
Benjamin Poirier |
395993 |
|
|
Benjamin Poirier |
395993 |
def __lt__(self, other):
|
|
Benjamin Poirier |
395993 |
if not self._is_valid_operand(other):
|
|
Benjamin Poirier |
395993 |
return NotImplemented
|
|
Benjamin Poirier |
395993 |
if self.head == other.head:
|
|
Benjamin Poirier |
395993 |
return self.index < other.index
|
|
Benjamin Poirier |
395993 |
else:
|
|
Benjamin Poirier |
395993 |
return self.head < other.head
|
|
Benjamin Poirier |
395993 |
|
|
Benjamin Poirier |
395993 |
|
|
Benjamin Poirier |
395993 |
def __hash__(self):
|
|
Benjamin Poirier |
395993 |
return hash((self.head, self.index,))
|
|
Benjamin Poirier |
395993 |
|
|
Benjamin Poirier |
395993 |
|
|
Benjamin Poirier |
395993 |
def __repr__(self):
|
|
Benjamin Poirier |
395993 |
return "%s %d" % (repr(self.head), self.index,)
|
|
Benjamin Poirier |
395993 |
|
|
Benjamin Poirier |
395993 |
|
|
Benjamin Poirier |
2c7d8e |
class SortIndex(object):
|
|
Benjamin Poirier |
2c7d8e |
version_match = re.compile("refs/tags/v(2\.6\.\d+|\d\.\d+)(-rc\d+)?$")
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
897bbc |
|
|
Benjamin Poirier |
2c7d8e |
def __init__(self, repo):
|
|
Benjamin Poirier |
2c7d8e |
self.repo = repo
|
|
Benjamin Poirier |
2c7d8e |
needs_rebuild = False
|
|
Benjamin Poirier |
76bf0c |
try:
|
|
Benjamin Poirier |
2c7d8e |
with Cache() as cache:
|
|
Benjamin Poirier |
2c7d8e |
try:
|
|
Benjamin Poirier |
2c7d8e |
history = cache["history"]
|
|
Benjamin Poirier |
2c7d8e |
except CNeedsRebuild:
|
|
Benjamin Poirier |
2c7d8e |
needs_rebuild = True
|
|
Benjamin Poirier |
15bd1c |
except CNeedsRebuild:
|
|
Benjamin Poirier |
2c7d8e |
needs_rebuild = True
|
|
Benjamin Poirier |
2c7d8e |
except CError as err:
|
|
Benjamin Poirier |
2c7d8e |
print("Error: %s" % (err,), file=sys.stderr)
|
|
Benjamin Poirier |
2c7d8e |
sys.exit(1)
|
|
Benjamin Poirier |
76bf0c |
|
|
Benjamin Poirier |
2c7d8e |
try:
|
|
Benjamin Poirier |
2c7d8e |
repo_heads = get_heads(repo)
|
|
Benjamin Poirier |
2c7d8e |
except GSError as err:
|
|
Benjamin Poirier |
2c7d8e |
print("Error: %s" % (err,), file=sys.stderr)
|
|
Benjamin Poirier |
2c7d8e |
sys.exit(1)
|
|
Benjamin Poirier |
76bf0c |
|
|
Benjamin Poirier |
600ead |
if needs_rebuild or list(history.keys()) != list(repo_heads.items()):
|
|
Benjamin Poirier |
2c7d8e |
try:
|
|
Benjamin Poirier |
2c7d8e |
history = get_history(repo, repo_heads)
|
|
Benjamin Poirier |
2c7d8e |
except GSError as err:
|
|
Benjamin Poirier |
2c7d8e |
print("Error: %s" % (err,), file=sys.stderr)
|
|
Benjamin Poirier |
2c7d8e |
sys.exit(1)
|
|
Benjamin Poirier |
2c7d8e |
try:
|
|
Benjamin Poirier |
2c7d8e |
with Cache(write_enable=True) as cache:
|
|
Benjamin Poirier |
2c7d8e |
cache["history"] = collections.OrderedDict(
|
|
Benjamin Poirier |
2c7d8e |
[((head, repo_heads[head],), log,)
|
|
Benjamin Poirier |
2c7d8e |
for head, log in history.items()])
|
|
Benjamin Poirier |
2c7d8e |
except CError as err:
|
|
Benjamin Poirier |
2c7d8e |
print("Error: %s" % (err,), file=sys.stderr)
|
|
Benjamin Poirier |
2c7d8e |
sys.exit(1)
|
|
Benjamin Poirier |
2c7d8e |
self.history = history
|
|
Benjamin Poirier |
76bf0c |
else:
|
|
Benjamin Poirier |
2c7d8e |
# no more need for the head sha1
|
|
Benjamin Poirier |
2c7d8e |
self.history = collections.OrderedDict(
|
|
Benjamin Poirier |
2c7d8e |
[(key[0], log,) for key, log in history.items()])
|
|
Benjamin Poirier |
2c7d8e |
self.version_indexes = None
|
|
Benjamin Poirier |
6a71e7 |
self.repo_heads = repo_heads
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
544f5d |
def lookup(self, commit):
|
|
Benjamin Poirier |
544f5d |
for head, log in self.history.items():
|
|
Benjamin Poirier |
544f5d |
try:
|
|
Benjamin Poirier |
544f5d |
index = log[commit]
|
|
Benjamin Poirier |
544f5d |
except KeyError:
|
|
Benjamin Poirier |
544f5d |
continue
|
|
Benjamin Poirier |
544f5d |
else:
|
|
Benjamin Poirier |
395993 |
return IndexedCommit(head, index)
|
|
Benjamin Poirier |
544f5d |
|
|
Benjamin Poirier |
544f5d |
raise GSKeyError
|
|
Benjamin Poirier |
544f5d |
|
|
Benjamin Poirier |
544f5d |
|
|
Benjamin Poirier |
0abe03 |
def describe(self, index):
|
|
Benjamin Poirier |
0abe03 |
"""
|
|
Benjamin Poirier |
0abe03 |
index must come from the mainline head (remotes[0]).
|
|
Benjamin Poirier |
0abe03 |
"""
|
|
Benjamin Poirier |
0abe03 |
if self.version_indexes is None:
|
|
Benjamin Poirier |
0abe03 |
history = self.history[remotes[0]]
|
|
Benjamin Poirier |
cf4f00 |
# Remove "refs/tags/"
|
|
Benjamin Poirier |
cf4f00 |
# Mainline release tags are annotated tag objects attached to a
|
|
Benjamin Poirier |
cf4f00 |
# commit object; do not consider other kinds of tags.
|
|
Benjamin Poirier |
cf4f00 |
objects = [(obj_tag.get_object(), tag,)
|
|
Benjamin Poirier |
cf4f00 |
for obj_tag, tag in [
|
|
Benjamin Poirier |
cf4f00 |
(self.repo.revparse_single(tag), tag[10:],)
|
|
Benjamin Poirier |
cf4f00 |
for tag in self.repo.listall_references()
|
|
Benjamin Poirier |
cf4f00 |
if self.version_match.match(tag)
|
|
Benjamin Poirier |
cf4f00 |
] if obj_tag.type == pygit2.GIT_OBJ_TAG]
|
|
Benjamin Poirier |
0abe03 |
revs = [(history[str(obj.id)], tag,)
|
|
Benjamin Poirier |
0abe03 |
for obj, tag in objects
|
|
Benjamin Poirier |
0abe03 |
if obj.type == pygit2.GIT_OBJ_COMMIT]
|
|
Benjamin Poirier |
0abe03 |
revs.sort(key=operator.itemgetter(0))
|
|
Benjamin Poirier |
600ead |
self.version_indexes = list(zip(*revs))
|
|
Benjamin Poirier |
0abe03 |
|
|
Benjamin Poirier |
535548 |
if not self.version_indexes:
|
|
Benjamin Poirier |
535548 |
raise GSError("Cannot describe commit, did not find any mainline "
|
|
Benjamin Poirier |
535548 |
"release tags in repository.")
|
|
Benjamin Poirier |
535548 |
|
|
Benjamin Poirier |
0abe03 |
indexes, tags = self.version_indexes
|
|
Benjamin Poirier |
0abe03 |
i = bisect.bisect_left(indexes, index)
|
|
Benjamin Poirier |
0abe03 |
if i == len(tags):
|
|
Benjamin Poirier |
0abe03 |
# not yet part of a tagged release
|
|
Michal Suchanek |
7dce3d |
m = re.search("v([0-9]+)\.([0-9]+)(|-rc([0-9]+))$", tags[-1])
|
|
Michal Suchanek |
7dce3d |
if m:
|
|
Michal Suchanek |
7dce3d |
# Post-release commit with no rc, it'll be rc1
|
|
Michal Suchanek |
7dce3d |
if m.group(3) == "":
|
|
Michal Suchanek |
7dce3d |
nexttag = "v%s.%d-rc1" % (m.group(1), int(m.group(2)) + 1)
|
|
Michal Suchanek |
7dce3d |
else:
|
|
Michal Suchanek |
7dce3d |
nexttag = "v%s.%d or v%s.%s-rc%d (next release)" % \
|
|
Michal Kubecek |
4f0865 |
(m.group(1), int(m.group(2)), m.group(1),
|
|
Michal Suchanek |
7dce3d |
m.group(2), int(m.group(4)) + 1)
|
|
Michal Suchanek |
7dce3d |
return nexttag
|
|
Benjamin Poirier |
0abe03 |
else:
|
|
Benjamin Poirier |
0abe03 |
return tags[i]
|
|
Benjamin Poirier |
0abe03 |
|
|
Benjamin Poirier |
0abe03 |
|
|
Benjamin Poirier |
0aaea3 |
if __name__ == "__main__":
|
|
Benjamin Poirier |
0aaea3 |
parser = argparse.ArgumentParser(
|
|
Benjamin Poirier |
0aaea3 |
description="Sort input lines according to the upstream order of "
|
|
Benjamin Poirier |
0aaea3 |
"commits that each line represents, with the first word on the line "
|
|
Benjamin Poirier |
0aaea3 |
"taken to be a commit id.")
|
|
Benjamin Poirier |
0aaea3 |
parser.add_argument("-d", "--dump-heads", action="store_true",
|
|
Benjamin Poirier |
0aaea3 |
help="Print the branch heads used for sorting "
|
|
Benjamin Poirier |
0aaea3 |
"(debugging).")
|
|
Benjamin Poirier |
0aaea3 |
args = parser.parse_args()
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
0aaea3 |
try:
|
|
Benjamin Poirier |
0aaea3 |
path = os.environ["GIT_DIR"]
|
|
Benjamin Poirier |
0aaea3 |
except KeyError:
|
|
Benjamin Poirier |
4f8279 |
try:
|
|
Benjamin Poirier |
9ae282 |
# depending on the pygit2 version, discover_repository() will either
|
|
Benjamin Poirier |
9ae282 |
# raise KeyError or return None if a repository is not found.
|
|
Benjamin Poirier |
4f8279 |
path = pygit2.discover_repository(os.getcwd())
|
|
Benjamin Poirier |
4f8279 |
except KeyError:
|
|
Benjamin Poirier |
9ae282 |
path = None
|
|
Benjamin Poirier |
9ae282 |
if path is None:
|
|
Benjamin Poirier |
9ae282 |
print("Error: Not a git repository", file=sys.stderr)
|
|
Benjamin Poirier |
9ae282 |
sys.exit(1)
|
|
Benjamin Poirier |
0aaea3 |
repo = pygit2.Repository(path)
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
0aaea3 |
if args.dump_heads:
|
|
Benjamin Poirier |
2c7d8e |
needs_rebuild = False
|
|
Benjamin Poirier |
0aaea3 |
try:
|
|
Benjamin Poirier |
2c7d8e |
with Cache() as cache:
|
|
Benjamin Poirier |
2c7d8e |
try:
|
|
Benjamin Poirier |
2c7d8e |
print("Cached heads (version %d):" % cache["version"])
|
|
Benjamin Poirier |
2c7d8e |
except CKeyError:
|
|
Benjamin Poirier |
2c7d8e |
print("No usable cache")
|
|
Benjamin Poirier |
2c7d8e |
needs_rebuild = True
|
|
Benjamin Poirier |
2c7d8e |
else:
|
|
Benjamin Poirier |
2c7d8e |
try:
|
|
Benjamin Poirier |
2c7d8e |
history = cache["history"]
|
|
Benjamin Poirier |
2c7d8e |
except CUnsupported:
|
|
Benjamin Poirier |
2c7d8e |
print("Unsupported cache version")
|
|
Benjamin Poirier |
2c7d8e |
needs_rebuild = True
|
|
Benjamin Poirier |
2c7d8e |
except CInconsistent:
|
|
Benjamin Poirier |
2c7d8e |
print("Inconsistent cache content")
|
|
Benjamin Poirier |
2c7d8e |
needs_rebuild = True
|
|
Benjamin Poirier |
2c7d8e |
else:
|
|
Benjamin Poirier |
600ead |
pprint.pprint(list(history.keys()))
|
|
Benjamin Poirier |
600ead |
except CAbsent:
|
|
Benjamin Poirier |
4f1bbb |
print("No usable cache")
|
|
Benjamin Poirier |
2c7d8e |
needs_rebuild = True
|
|
Benjamin Poirier |
600ead |
except CNeedsRebuild:
|
|
Benjamin Poirier |
600ead |
needs_rebuild = True
|
|
Benjamin Poirier |
2c7d8e |
except CError as err:
|
|
Benjamin Poirier |
2c7d8e |
print("Error: %s" % (err,), file=sys.stderr)
|
|
Benjamin Poirier |
2c7d8e |
sys.exit(1)
|
|
Benjamin Poirier |
2c7d8e |
|
|
Benjamin Poirier |
2c7d8e |
try:
|
|
Benjamin Poirier |
2c7d8e |
repo_heads = get_heads(repo)
|
|
Benjamin Poirier |
2c7d8e |
except GSError as err:
|
|
Benjamin Poirier |
2c7d8e |
print("Error: %s" % (err,), file=sys.stderr)
|
|
Benjamin Poirier |
2c7d8e |
sys.exit(1)
|
|
Benjamin Poirier |
600ead |
if not needs_rebuild and list(history.keys()) != list(repo_heads.items()):
|
|
Benjamin Poirier |
2c7d8e |
needs_rebuild = True
|
|
Benjamin Poirier |
2c7d8e |
print("Current heads (version %d):" % Cache.version)
|
|
Benjamin Poirier |
600ead |
pprint.pprint(list(repo_heads.items()))
|
|
Benjamin Poirier |
2c7d8e |
if needs_rebuild:
|
|
Benjamin Poirier |
2c7d8e |
action = "Will"
|
|
Benjamin Poirier |
4f1bbb |
else:
|
|
Benjamin Poirier |
0aaea3 |
action = "Will not"
|
|
Benjamin Poirier |
0aaea3 |
print("%s rebuild history" % (action,))
|
|
Benjamin Poirier |
0aaea3 |
sys.exit(0)
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
2c7d8e |
index = SortIndex(repo)
|
|
Benjamin Poirier |
395993 |
dest = {}
|
|
Benjamin Poirier |
395993 |
oot = []
|
|
Benjamin Poirier |
0aaea3 |
num = 0
|
|
Benjamin Poirier |
0aaea3 |
for line in sys.stdin.readlines():
|
|
Benjamin Poirier |
0aaea3 |
num = num + 1
|
|
Benjamin Poirier |
51f0b8 |
tokens = line.strip().split(None, 1)
|
|
Benjamin Poirier |
51f0b8 |
if not tokens:
|
|
Benjamin Poirier |
51f0b8 |
continue
|
|
Benjamin Poirier |
0aaea3 |
try:
|
|
Benjamin Poirier |
51f0b8 |
commit = repo.revparse_single(tokens[0])
|
|
Benjamin Poirier |
0aaea3 |
except ValueError:
|
|
Benjamin Poirier |
0aaea3 |
print("Error: did not find a commit hash on line %d:\n%s" %
|
|
Benjamin Poirier |
0aaea3 |
(num, line.strip(),), file=sys.stderr)
|
|
Benjamin Poirier |
0aaea3 |
sys.exit(1)
|
|
Benjamin Poirier |
0aaea3 |
except KeyError:
|
|
Benjamin Poirier |
0aaea3 |
print("Error: commit hash on line %d not found in the repository:\n%s" %
|
|
Benjamin Poirier |
0aaea3 |
(num, line.strip(),), file=sys.stderr)
|
|
Benjamin Poirier |
0aaea3 |
sys.exit(1)
|
|
Benjamin Poirier |
0aaea3 |
h = str(commit.id)
|
|
Benjamin Poirier |
395993 |
if h in dest:
|
|
Benjamin Poirier |
395993 |
dest[h][1].append(line)
|
|
Benjamin Poirier |
0aaea3 |
else:
|
|
Benjamin Poirier |
395993 |
try:
|
|
Benjamin Poirier |
395993 |
ic = index.lookup(h)
|
|
Benjamin Poirier |
395993 |
except GSKeyError:
|
|
Benjamin Poirier |
395993 |
oot.append(line)
|
|
Benjamin Poirier |
395993 |
else:
|
|
Benjamin Poirier |
395993 |
dest[h] = (ic, [line],)
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
e8d72d |
print("".join([line
|
|
Benjamin Poirier |
395993 |
for ic, lines in sorted(dest.values(),
|
|
Benjamin Poirier |
395993 |
key=operator.itemgetter(0))
|
|
Benjamin Poirier |
395993 |
for line in lines
|
|
Benjamin Poirier |
e8d72d |
]), end="")
|
|
Benjamin Poirier |
0aaea3 |
|
|
Benjamin Poirier |
395993 |
if oot:
|
|
Benjamin Poirier |
0aaea3 |
print("Error: the following entries were not found in the indexed heads:",
|
|
Benjamin Poirier |
0aaea3 |
file=sys.stderr)
|
|
Benjamin Poirier |
395993 |
print("".join(oot), end="")
|
|
Benjamin Poirier |
0aaea3 |
sys.exit(1)
|