Add ref handling and ref-parse command
This commit is contained in:
parent
9365c473fd
commit
3a7bad0e47
149
libwyag.py
149
libwyag.py
@ -634,3 +634,152 @@ def tree_checkout(repo, tree, path):
|
||||
# TODO: Support symlinks (identified by mode 12*****)
|
||||
with open(dest, 'wb') as f:
|
||||
f.write(obj.blobdata)
|
||||
|
||||
def ref_resolve(repo, ref):
|
||||
path = GitRepository.repo_file(repo, ref)
|
||||
|
||||
# Sometimes, an indirect reference may be broken. This is normal
|
||||
# in one specific case: we're looking for HEAD on a new repository
|
||||
# with no commits. In that case, .git/HEAD points to "ref:
|
||||
# refs/heads/master", but .git/refs/heads/master doesn't exist yet
|
||||
# (since there's no commit for it to refer to).
|
||||
if not os.path.isfile(path):
|
||||
return None
|
||||
|
||||
with open(path, "r") as fp:
|
||||
data = fp.read()[:-1] # Drop final "\n"
|
||||
|
||||
if data.startswith("ref: "):
|
||||
return ref_resolve(repo, data[len("ref: "):])
|
||||
else:
|
||||
return data
|
||||
|
||||
def ref_list(repo, path=None):
|
||||
if not path:
|
||||
path = repo_dir(repo, "refs")
|
||||
|
||||
ret = collections.OrderedDict()
|
||||
|
||||
for f in sorted(os.listdir(path)):
|
||||
can = os.path.join(path, f)
|
||||
if os.path.isdir(can):
|
||||
ret[f] = ref_list(repo, can)
|
||||
else:
|
||||
ret[f] = ref_resolve(repo, can)
|
||||
|
||||
return ret
|
||||
|
||||
argsp = argsubparsers.add_parser(
|
||||
"tag",
|
||||
help="List and create tags")
|
||||
|
||||
argsp.add_argument("-a",
|
||||
action="store_true",
|
||||
dest="create_tag_object",
|
||||
help="Whether to create a tag object")
|
||||
|
||||
argsp.add_argument("name",
|
||||
nargs="?",
|
||||
help="The new tag's name")
|
||||
|
||||
argsp.add_argument("object",
|
||||
default="HEAD",
|
||||
nargs="?",
|
||||
help="The object the new tag will point to")
|
||||
|
||||
def cmd_tag(args):
|
||||
repo = repo_find()
|
||||
|
||||
if args.name:
|
||||
tag_create(repo,
|
||||
args.name,
|
||||
args.object,
|
||||
type="object" if args.create_tag_object else "ref")
|
||||
else:
|
||||
refs = ref_list(repo)
|
||||
show_ref(repo, refs["tags"], with_hash=False)
|
||||
|
||||
def tag_create(repo, name, ref, create_tag_object=False):
|
||||
sha = object_find(repo, ref)
|
||||
|
||||
if create_tag_object:
|
||||
tag = GitTag(repo)
|
||||
tag.kvlm = collections.OrderedDict()
|
||||
tag.kvlm[b'object'] = sha.encode()
|
||||
tag.kvlm[b'type'] = b'commit'
|
||||
tag.kvlm[b'tag'] = name.encode()
|
||||
tag.kvlm[b'tagger'] = b'Wyag <wyag@example.com>'
|
||||
tag.kvlm[None] = b'Tag generated by wyag'
|
||||
tag_sha = object_write(tag)
|
||||
ref_create(repo, "tags/" + name, tag_sha)
|
||||
else:
|
||||
ref_create(repo, "tags/" + name, sha)
|
||||
|
||||
def ref_create(repo, ref_name, sha):
|
||||
with open(repo_file(repo, "refs/" + ref_name), "w") as fp:
|
||||
fp.write(sha + "\n")
|
||||
|
||||
def object_resolve(repo, name):
|
||||
"""Resolve a name to an object hash in repo.
|
||||
|
||||
This function is aware of:
|
||||
|
||||
- the HEAD literal
|
||||
- short and long hashes
|
||||
- tags
|
||||
- branches
|
||||
- remote branches"""
|
||||
candidates = list()
|
||||
hashRE = re.compile(r"[0-9A-Fa-f]{4,40}$")
|
||||
|
||||
# Abort on empty string
|
||||
if not name.strip():
|
||||
return None
|
||||
|
||||
if name == "HEAD":
|
||||
return [ref_resolve(repo, "HEAD")]
|
||||
|
||||
if hashRE.match(name):
|
||||
name = name.lower()
|
||||
prefix = name[0:2]
|
||||
path = GitRepository.repo_dir(repo, "objects", prefix, mkdir=False)
|
||||
if path:
|
||||
rem = name[2:]
|
||||
for f in os.listdir(path):
|
||||
if f.startswith(rem):
|
||||
candidates.append(prefix + f)
|
||||
|
||||
# Try for references
|
||||
as_tag = ref_resolve(repo, "refs/tags/" + name)
|
||||
if as_tag:
|
||||
candidates.append(as_tag)
|
||||
|
||||
as_branch = ref_resolve(repo, "refs/heads/" + name)
|
||||
if as_branch:
|
||||
candidates.append(as_branch)
|
||||
|
||||
return candidates
|
||||
|
||||
argsp = argsubparsers.add_parser(
|
||||
"rev-parse",
|
||||
help="Parse revision (or other objects) identifiers")
|
||||
|
||||
argsp.add_argument("--wyag-type",
|
||||
metavar="type",
|
||||
dest="type",
|
||||
choices=["blob", "commit", "tag", "tree"],
|
||||
default=None,
|
||||
help="Specify the expected type")
|
||||
|
||||
argsp.add_argument("name",
|
||||
help="The name to parse")
|
||||
|
||||
def cmd_rev_parse(args):
|
||||
if args.type:
|
||||
fmt = args.type.encode()
|
||||
else:
|
||||
fmt = None
|
||||
|
||||
repo = repo_find()
|
||||
|
||||
print(object_find(repo, args.name, fmt, follow=True))
|
||||
|
Loading…
Reference in New Issue
Block a user