Commit cbfa78d2 authored by Kirill Smelkov's avatar Kirill Smelkov

*: Handle Git object types as git.ObjectType instead of string

parent 7f349cd9
......@@ -184,20 +184,22 @@ func blob_to_file(g *git.Repository, blob_sha1 Sha1, mode uint32, path string) {
// another, so that on backup restore we only have to recreate original tag
// object and tagged object is kept there in repo thanks to it being reachable
// through created commit.
var tag_tree_blob = StrSet{"tag": {}, "tree": {}, "blob": {}}
func obj_represent_as_commit(g *git.Repository, sha1 Sha1, obj_type string) Sha1 {
if !tag_tree_blob.Contains(obj_type) {
func obj_represent_as_commit(g *git.Repository, sha1 Sha1, obj_type git.ObjectType) Sha1 {
switch obj_type {
case git.ObjectTag, git.ObjectTree, git.ObjectBlob:
// ok
default:
exc.Raisef("%s (%s): cannot encode as commit", sha1, obj_type)
}
// first line in commit msg = object type
obj_encoded := obj_type + "\n"
var tagged_type string
obj_encoded := gittypestr(obj_type) + "\n"
var tagged_type git.ObjectType
var tagged_sha1 Sha1
// below the code layout is mainly for tag type, and we hook tree and blob
// types handling into that layout
if obj_type == "tag" {
if obj_type == git.ObjectTag {
tag, tag_obj := xload_tag(g, sha1)
tagged_type = tag.tagged_type
tagged_sha1 = tag.tagged_sha1
......@@ -219,7 +221,7 @@ func obj_represent_as_commit(g *git.Repository, sha1 Sha1, obj_type string) Sha1
// | .msg: Tag
// v .tree -> ø
// Commit .parent -> Commit
if tagged_type == "commit" {
if tagged_type == git.ObjectCommit {
return zcommit_tree(mktree_empty(), []Sha1{tagged_sha1}, obj_encoded)
}
......@@ -227,7 +229,7 @@ func obj_represent_as_commit(g *git.Repository, sha1 Sha1, obj_type string) Sha1
// | .msg: Tag
// v .tree -> Tree
// Tree .parent -> ø
if tagged_type == "tree" {
if tagged_type == git.ObjectTree {
return zcommit_tree(tagged_sha1, []Sha1{}, obj_encoded)
}
......@@ -235,7 +237,7 @@ func obj_represent_as_commit(g *git.Repository, sha1 Sha1, obj_type string) Sha1
// | .msg: Tag
// v .tree -> Tree* "tagged" -> Blob
// Blob .parent -> ø
if tagged_type == "blob" {
if tagged_type == git.ObjectBlob {
tree_for_blob := xgitSha1("mktree", RunWith{stdin: fmt.Sprintf("100644 blob %s\ttagged\n", tagged_sha1)})
return zcommit_tree(tree_for_blob, []Sha1{}, obj_encoded)
}
......@@ -244,7 +246,7 @@ func obj_represent_as_commit(g *git.Repository, sha1 Sha1, obj_type string) Sha1
// | .msg: Tag₂
// v .tree -> ø
// Tag₁ .parent -> Commit₁*
if tagged_type == "tag" {
if tagged_type == git.ObjectTag {
commit1 := obj_represent_as_commit(g, tagged_sha1, tagged_type)
return zcommit_tree(mktree_empty(), []Sha1{commit1}, obj_encoded)
}
......@@ -274,7 +276,10 @@ func obj_recreate_from_commit(g *git.Repository, commit_sha1 Sha1) Sha1 {
if err != nil {
xraise("invalid encoded format")
}
if !tag_tree_blob.Contains(obj_type) {
switch obj_type {
case "tag", "tree", "blob":
// ok
default:
xraisef("unexpected encoded object type %q", obj_type)
}
......@@ -295,7 +300,7 @@ func obj_recreate_from_commit(g *git.Repository, commit_sha1 Sha1) Sha1 {
if err != nil {
xraisef("encoded tag: %s", err)
}
if tag.tagged_type == "tag" {
if tag.tagged_type == git.ObjectTag {
if commit.ParentCount() == 0 {
xraise("encoded tag corrupt (tagged is tag but []parent is empty)")
}
......@@ -494,7 +499,11 @@ func cmd_pull_(gb *git.Repository, pullspecv []PullSpec) {
var seen bool
sha1_, seen = noncommit_seen[sha1]
if !seen {
sha1_ = obj_represent_as_commit(gb, sha1, type_)
obj_type, ok := gittype(type_)
if !ok {
exc.Raisef("%s: invalid git type in entry %q", backup_refs_work, __)
}
sha1_ = obj_represent_as_commit(gb, sha1, obj_type)
noncommit_seen[sha1] = sha1_
}
......
......@@ -60,6 +60,15 @@ func XSha1(s string) Sha1 {
return sha1
}
func xgittype(s string) git.ObjectType {
type_, ok := gittype(s)
if !ok {
exc.Raisef("unknown git type %q", s)
}
return type_
}
// verify end-to-end pull-restore
func TestPullRestore(t *testing.T) {
// if something raises -> don't let testing panic - report it as proper error with context.
......@@ -145,7 +154,7 @@ func TestPullRestore(t *testing.T) {
// encoding original object should give sha1_
obj_type := xgit("cat-file", "-t", nc.sha1)
sha1_ := obj_represent_as_commit(gb, nc.sha1, obj_type)
sha1_ := obj_represent_as_commit(gb, nc.sha1, xgittype(obj_type))
if sha1_ != nc.sha1_ {
t.Fatalf("encode %s -> %s ; want %s", sha1, sha1_, nc.sha1_)
}
......
......@@ -91,9 +91,8 @@ func (e *UnexpectedObjType) Error() string {
}
type Tag struct {
tagged_type string
tagged_type git.ObjectType
tagged_sha1 Sha1
// TODO msg
}
......@@ -127,10 +126,16 @@ func (e *TagLoadError) Error() string {
func tag_parse(tag_raw string) (*Tag, error) {
t := Tag{}
_, err := fmt.Sscanf(tag_raw, "object %s\ntype %s\n", &t.tagged_sha1, &t.tagged_type)
tagged_type := ""
_, err := fmt.Sscanf(tag_raw, "object %s\ntype %s\n", &t.tagged_sha1, &tagged_type)
if err != nil {
return nil, errors.New("invalid header")
}
var ok bool
t.tagged_type, ok = gittype(tagged_type)
if !ok {
return nil, fmt.Errorf("invalid tagged type %q", tagged_type)
}
return &t, nil
}
......@@ -244,3 +249,37 @@ func xcommit_tree2(g *git.Repository, tree Sha1, parents []Sha1, msg string, aut
func xcommit_tree(g *git.Repository, tree Sha1, parents []Sha1, msg string) Sha1 {
return xcommit_tree2(g, tree, parents, msg, AuthorInfo{}, AuthorInfo{})
}
// gittype converts string to git.ObjectType.
//
// Only valid concrete git types are converted successfully.
func gittype(typ string) (git.ObjectType, bool) {
switch typ {
case "commit": return git.ObjectCommit, true
case "tree": return git.ObjectTree, true
case "blob": return git.ObjectBlob, true
case "tag": return git.ObjectTag, true
}
return git.ObjectBad, false
}
// gittypestr converts git.ObjectType to string.
//
// We depend on this conversion being exact and matching how Git encodes it in
// objects. git.ObjectType.String() is different (e.g. "Blob" instead of
// "blob"), and can potentially change over time.
//
// gittypestr expects the type to be valid and concrete - else it panics.
func gittypestr(typ git.ObjectType) string {
switch typ {
case git.ObjectCommit: return "commit"
case git.ObjectTree: return "tree"
case git.ObjectBlob: return "blob"
case git.ObjectTag: return "tag"
}
panic(fmt.Sprintf("git type %#v invalid", typ))
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment