From 52b1d99d0d65cfea9622b23c0d547971eb12e2c4 Mon Sep 17 00:00:00 2001 From: Joe Mou Date: Fri, 19 Apr 2019 01:28:00 -0400 Subject: [PATCH] checkout: checkout-index, improve rev-parse, symbolic-ref --- checkout | 15 +++++++++++++++ checkout-index | 33 +++++++++++++++++++++++++++++++++ get-sha1-basic | 11 +++++++++++ rev-parse | 45 ++++++++++++++++++++++++++++++++++++--------- symbolic-ref | 17 +++++++++++------ 5 files changed, 106 insertions(+), 15 deletions(-) create mode 100755 checkout create mode 100755 checkout-index create mode 100755 get-sha1-basic diff --git a/checkout b/checkout new file mode 100755 index 0000000..cfe6f3c --- /dev/null +++ b/checkout @@ -0,0 +1,15 @@ +#!/bin/bash -e + +if [[ $1 == -b ]]; then + ./branch $2 + shift +fi +revision=$1 +tree=$(./rev-parse $revision^{tree}) +./read-tree $tree +./checkout-index +if [[ -f .zit/refs/heads/$revision ]]; then + ./symbolic-ref HEAD refs/heads/$revision +else + echo "You are in 'detached HEAD' state." >&2 +fi diff --git a/checkout-index b/checkout-index new file mode 100755 index 0000000..edd4fb6 --- /dev/null +++ b/checkout-index @@ -0,0 +1,33 @@ +#!/usr/bin/python + +import os +import struct +import subprocess + +# TODO dedup w/ write-tree +index = open('.zit/index').read() +assert index[0:4] == 'DIRC' +assert struct.unpack('>I', index[4:8]) == (2,) +num_entries, = struct.unpack('>I', index[8:12]) +entries = [] +i = 12 +for _ in range(num_entries): + # ignore inode heuristics, file/symlink bit, permissions + i += 40 + sha1 = index[i:i+20].encode('hex') + # just use NUL-terminated? + name_length = struct.unpack('>H', index[i+20:i+22])[0] & 0xfff + name = index[i+22:i+22+name_length] + i += (22 + name_length + 8) / 8 * 8 + entries.append((name, sha1)) + +# entry.c:checkout_entry +for filename, sha1 in entries: + assert not filename.startswith('/') + assert '..' not in filename + # TODO unlink directories? + if os.path.exists(filename): + os.unlink(filename) + subprocess.check_call(['mkdir', '-p', './' + os.path.dirname(filename)]) + # TODO git 1.0 doesn't seem to unlink deleted files + subprocess.check_call(['./cat-file', 'blob', sha1], stdout=open(filename, 'w')) diff --git a/get-sha1-basic b/get-sha1-basic new file mode 100755 index 0000000..901c84d --- /dev/null +++ b/get-sha1-basic @@ -0,0 +1,11 @@ +#!/bin/bash -e + +# sha1_name.c:get_sha1_basic +if [[ ${#1} -eq 40 ]]; then + echo $1 +else + cat .zit/$(./symbolic-ref $1) 2> /dev/null || \ + cat .zit/$(./symbolic-ref refs/$1) 2> /dev/null || \ + cat .zit/$(./symbolic-ref refs/tags/$1) 2> /dev/null || \ + cat .zit/$(./symbolic-ref refs/heads/$1) +fi diff --git a/rev-parse b/rev-parse index 11ff61f..3f72497 100755 --- a/rev-parse +++ b/rev-parse @@ -1,13 +1,40 @@ -#!/bin/bash -e +#!/usr/bin/python # only implements --verify +import subprocess +import sys + # sha1_name.c:get_sha1 +def get_sha1(name): + # TODO ^ and ~? + # TODO specialize for tree? + if '^' in name: + name, type = name.rsplit('^', 1) + assert type[0] == '{' and type[-1] == '}' + type = type[1:-1] + while True: + sha1 = get_sha1(name) + + # TODO dedup w/ cat-file + import zlib + # sha1_file.c:sha1_file_name + filename = '.zit/objects/{}/{}'.format(sha1[:2], sha1[2:]) + decompressed = zlib.decompress(open(filename).read()) + header, contents = decompressed.split('\0', 1) + actual_type, length = header.split(' ') + + if actual_type == type: + return sha1 + elif actual_type == 'commit': + assert int(length) == len(contents) + tree = next(line for line in contents.split('\n') + if line.startswith('tree ')) + name = tree.split(' ')[1] + # TODO deref tags? + else: + raise Exception('wrong type') + else: + return subprocess.check_output(['./get-sha1-basic', name])[:-1] -if [[ ${#1} -eq 40 ]]; then - echo $1 -else - cat .zit/$(./symbolic-ref $1) 2> /dev/null || \ - cat .zit/$(./symbolic-ref refs/$1) 2> /dev/null || \ - cat .zit/$(./symbolic-ref refs/tags/$1) 2> /dev/null || \ - cat .zit/$(./symbolic-ref refs/heads/$1) -fi +_, name = sys.argv +print get_sha1(name) diff --git a/symbolic-ref b/symbolic-ref index 9a72285..907e613 100755 --- a/symbolic-ref +++ b/symbolic-ref @@ -1,8 +1,13 @@ #!/bin/bash -e -# refs.c:resolve_ref -path=.zit/$1 -while grep -q '^ref: ' $path 2> /dev/null; do - path=.zit/$(cut -d' ' -f2 < $path) -done -echo $path | cut -d/ -f2- +if [[ $# == 2 ]]; then + # refs.c:create_symref + echo "ref: $2" > .zit/$1 +elif [[ $# == 1 ]]; then + # refs.c:resolve_ref + path=.zit/$1 + while grep -q '^ref: ' $path 2> /dev/null; do + path=.zit/$(cut -d' ' -f2 < $path) + done + echo $path | cut -d/ -f2- +fi