Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tidy up #25

Merged
merged 4 commits into from
May 2, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
move index.Write, rename Object type constants to include Type and mi…
…grate Object tree to objects package
richardjennings committed Apr 12, 2024
commit e5fd33faeb4d518b1d3721736950c9b65fdc683c
49 changes: 49 additions & 0 deletions internal/mygit/index/index.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package index

import (
"crypto/sha1"
"encoding/binary"
"errors"
"fmt"
"github.com/richardjennings/mygit/internal/mygit/config"
"github.com/richardjennings/mygit/internal/mygit/gfs"
"io"
"os"
"path/filepath"
"runtime"
@@ -118,6 +121,52 @@ func (idx *Index) Add(f *gfs.File) error {
return nil
}

// Write writes an Index struct to the Git Index
func (idx *Index) Write() error {
if idx.header.NumEntries != uint32(len(idx.items)) {
return errors.New("index numEntries and length of items inconsistent")
}
path := config.IndexFilePath()
f, err := os.OpenFile(path, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0644)
if err != nil {
return err
}
defer func() { _ = f.Close() }()
// use a multi-writer to allow both writing the the file whilst incrementally generating
// a Sha hash of the content as it is written
h := sha1.New()
mw := io.MultiWriter(f, h)

// write header
if err := binary.Write(mw, binary.BigEndian, idx.header); err != nil {
return err
}
// write each item fixed size entry
for _, item := range idx.items {
if err := binary.Write(mw, binary.BigEndian, item.indexItemP); err != nil {
return err
}
// write name
if _, err := mw.Write(item.Name); err != nil {
return err
}
// write padding
padding := make([]byte, 8-(62+len(item.Name))%8)
if _, err := mw.Write(padding); err != nil {
return err
}
}
// use the generated hash
sha := h.Sum(nil)
copy(idx.sig[:], sha)
// write Sha hash of Index
if err := binary.Write(f, binary.BigEndian, &sha); err != nil {
return err
}

return f.Close()
}

func item(f *gfs.File) (*indexItem, error) {
if f.Sha == nil {
return nil, errors.New("missing Sha from working directory file toIndexItem")
46 changes: 0 additions & 46 deletions internal/mygit/index/tree.go

This file was deleted.

56 changes: 0 additions & 56 deletions internal/mygit/index/writer.go

This file was deleted.

2 changes: 1 addition & 1 deletion internal/mygit/mygit.go
Original file line number Diff line number Diff line change
@@ -144,7 +144,7 @@ func Commit(message []byte) ([]byte, error) {
if err != nil {
return nil, err
}
root := index.ObjectTree(idx.Files())
root := objects.ObjectTree(idx.Files())
tree, err := root.WriteTree()
if err != nil {
return nil, err
49 changes: 45 additions & 4 deletions internal/mygit/objects/object.go
Original file line number Diff line number Diff line change
@@ -2,7 +2,11 @@ package objects

import (
"fmt"
"github.com/richardjennings/mygit/internal/mygit/config"
"github.com/richardjennings/mygit/internal/mygit/gfs"
"io"
"path/filepath"
"strings"
"time"
)

@@ -45,10 +49,10 @@ type (
)

const (
ObjectInvalid objectType = iota
ObjectBlob
ObjectTree
ObjectCommit
ObjectTypeInvalid objectType = iota
ObjectTypeBlob
ObjectTypeTree
ObjectTypeCommit
)

func (c Commit) String() string {
@@ -63,3 +67,40 @@ func (c Commit) String() string {
o += fmt.Sprintf("message: \n%s\n", c.Message)
return o
}

// ObjectTree creates a Tree Object with child Objects representing the files and
// paths in the provided files.
func ObjectTree(files []*gfs.File) *Object {
root := &Object{}
var n *Object // current node
var pn *Object // previous node
// mp holds a cache of file paths to objectTree nodes
mp := make(map[string]*Object)
for _, v := range files {
parts := strings.Split(strings.TrimPrefix(v.Path, config.WorkingDirectory()), string(filepath.Separator))
if len(parts) == 1 {
root.Objects = append(root.Objects, &Object{Typ: ObjectTypeBlob, Path: v.Path, Sha: v.Sha.AsBytes()})
continue // top level file
}
pn = root
for i, p := range parts {
if i == len(parts)-1 {
pn.Objects = append(pn.Objects, &Object{Typ: ObjectTypeBlob, Path: v.Path, Sha: v.Sha.AsBytes()})
continue // leaf
}
// key for cached nodes
key := strings.Join(parts[0:i+1], string(filepath.Separator))
cached, ok := mp[key]
if ok {
n = cached
} else {
n = &Object{Typ: ObjectTypeTree, Path: p}
pn.Objects = append(pn.Objects, n)
mp[key] = n
}
pn = n
}
}

return root
}
18 changes: 9 additions & 9 deletions internal/mygit/objects/reader.go
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ import (
// FlattenTree turns a TreeObject structure into a flat list of file paths
func (o *Object) FlattenTree() []*gfs.File {
var objFiles []*gfs.File
if o.Typ == ObjectBlob {
if o.Typ == ObjectTypeBlob {
s, _ := gfs.NewSha(o.Sha)
f := []*gfs.File{{Path: o.Path, Sha: s}}
return f
@@ -54,11 +54,11 @@ func ReadObject(sha []byte) (*Object, error) {

switch string(header[0]) {
case "commit":
o.Typ = ObjectCommit
o.Typ = ObjectTypeCommit
case "tree":
o.Typ = ObjectTree
o.Typ = ObjectTypeTree
case "blob":
o.Typ = ObjectBlob
o.Typ = ObjectTypeBlob
default:
return nil, fmt.Errorf("unknown %s", string(header[0]))
}
@@ -85,7 +85,7 @@ func ReadObjectTree(sha []byte) (*Object, error) {
return nil, err
}
switch obj.Typ {
case ObjectCommit:
case ObjectTypeCommit:
commit, err := readCommit(obj)
if err != nil {
return obj, err
@@ -96,7 +96,7 @@ func ReadObjectTree(sha []byte) (*Object, error) {
}
obj.Objects = append(obj.Objects, co)
return obj, nil
case ObjectTree:
case ObjectTypeTree:
tree, err := ReadTree(obj)
if err != nil {
return nil, err
@@ -113,7 +113,7 @@ func ReadObjectTree(sha []byte) (*Object, error) {
obj.Objects = append(obj.Objects, o)
}
return obj, nil
case ObjectBlob:
case ObjectTypeBlob:
// lets not read the whole blob
return obj, nil
}
@@ -158,12 +158,12 @@ func ReadTree(obj *Object) (*Tree, error) {
item := bytes.Fields(p)
itm.Sha = []byte(hex.EncodeToString(sha))
if string(item[0]) == "40000" {
itm.Typ = ObjectTree
itm.Typ = ObjectTypeTree
if err != nil {
return nil, err
}
} else {
itm.Typ = ObjectBlob
itm.Typ = ObjectTypeBlob
}
itm.Path = string(item[1][:len(item[1])-1])

4 changes: 2 additions & 2 deletions internal/mygit/objects/writer.go
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ import (
func (o *Object) WriteTree() ([]byte, error) {
// resolve child tree Objects
for i, v := range o.Objects {
if v.Typ == ObjectTree {
if v.Typ == ObjectTypeTree {
// if the tree only has blobs, write them and then
// add the corresponding tree returning the Sha
sha, err := v.WriteTree()
@@ -38,7 +38,7 @@ func (o *Object) writeTree() ([]byte, error) {
var mode string
for _, fo := range o.Objects {
// @todo add executable support
if fo.Typ == ObjectTree {
if fo.Typ == ObjectTypeTree {
mode = "40000"
} else {
mode = "100644"