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*****)
|
# TODO: Support symlinks (identified by mode 12*****)
|
||||||
with open(dest, 'wb') as f:
|
with open(dest, 'wb') as f:
|
||||||
f.write(obj.blobdata)
|
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