-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(write-tree): initial draft of write-tree
Works for directories containing just files. When we run on a directory containing subdirs it writes the correct file but the hash for the root tree is incorrect. Needs further investigating.
- Loading branch information
Showing
5 changed files
with
229 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
) | ||
|
||
func TestTree_Encode(t *testing.T) { | ||
type fields struct { | ||
} | ||
tests := []struct { | ||
name string | ||
Size int | ||
Children []*Child | ||
fields fields | ||
want string | ||
}{ | ||
{ | ||
name: "Test 1", | ||
want: "tree 59\x00100644 file1.txt\x003b18e512dba79e4c8300dd08aeb3yi7f8e728b8dad", | ||
Children: []*Child{ | ||
{ | ||
mode: "100644", | ||
name: "file1.txt", | ||
sha: []byte("3b18e512dba79e4c8300dd08aeb3yi7f8e728b8dad"), | ||
typ: "blob", | ||
}, | ||
}, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
tr := &Tree{ | ||
Size: tt.Size, | ||
Children: tt.Children, | ||
} | ||
if got := tr.Encode(); got != tt.want { | ||
t.Errorf("Tree.Encode() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestTree_GetSHA(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
Size int | ||
Children []*Child | ||
want string | ||
}{ | ||
{ | ||
name: "Test 1", | ||
want: "cc518e1c8b5356ef4f448ef6725fb4fbe6871509", | ||
Children: []*Child{ | ||
{ | ||
mode: "100644", | ||
name: "file1.txt", | ||
sha: []byte{59, 24, 229, 18, 219, 167, 158, 76, 131, 0, 221, 8, 174, 179, 127, 142, 114, 139, 141, 173}, | ||
typ: "blob", | ||
}, | ||
{ | ||
mode: "100644", | ||
name: "file2.txt", | ||
sha: []byte{208, 225, 233, 84, 85, 117, 75, 211, 29, 86, 38, 13, 25, 167, 119, 79, 215, 174, 190, 93}, | ||
typ: "blob", | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "Test 2", | ||
want: "b67fea69b76b86cf0843c69bdc954366598175e0", | ||
Children: []*Child{ | ||
{ | ||
mode: "100644", | ||
name: "file1.txt", | ||
sha: []byte{59, 24, 229, 18, 219, 167, 158, 76, 131, 0, 221, 8, 174, 179, 127, 142, 114, 139, 141, 173}, | ||
typ: "blob", | ||
}, | ||
{ | ||
mode: "100644", | ||
name: "file2.txt", | ||
sha: []byte{208, 225, 233, 84, 85, 117, 75, 211, 29, 86, 38, 13, 25, 167, 119, 79, 215, 174, 190, 93}, | ||
typ: "blob", | ||
}, | ||
{ | ||
mode: "040000", | ||
name: "foo", | ||
sha: []byte{128, 147, 227, 82, 216, 203, 25, 44, 44, 86, 143, 233, 208, 135, 40, 228, 201, 173, 40, 230}, | ||
typ: "tree", | ||
}, | ||
}, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
tr := &Tree{ | ||
Children: tt.Children, | ||
} | ||
if got := fmt.Sprintf("%s", tr.GetSHA()); got != tt.want { | ||
t.Errorf("Tree.GetSHA() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"compress/zlib" | ||
"crypto/sha1" | ||
"encoding/hex" | ||
"fmt" | ||
"os" | ||
"strings" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
var writeTreeCmd = &cobra.Command{ | ||
Use: "write-tree", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
workDir, err := os.Getwd() | ||
cobra.CheckErr(err) | ||
root := buildDirectoryTree(workDir) | ||
fmt.Println(fmt.Sprintf("%s", root.GetSHA())) | ||
}, | ||
} | ||
|
||
func init() { | ||
rootcmd.AddCommand(writeTreeCmd) | ||
} | ||
|
||
func writeObjectToDisk(sha string, data []byte) { | ||
path := blobNameToPath(sha) | ||
dirs := strings.Split(path, "/") | ||
dir := strings.Join(dirs[:len(dirs)-1], "/") | ||
if _, err := os.Stat(dir); os.IsNotExist(err) { | ||
os.Mkdir(dir, 0755) | ||
} | ||
if _, err := os.Stat(path); err == nil { | ||
os.Remove(path) | ||
} | ||
cobra.CheckErr(os.WriteFile(path, data, 0644)) | ||
} | ||
|
||
func buildDirectoryTree(dirname string) *Tree { | ||
entries, err := os.ReadDir(dirname) | ||
cobra.CheckErr(err) | ||
|
||
var children []*Child | ||
|
||
for _, file := range entries { | ||
if file.Name() == ".git" { | ||
continue | ||
} | ||
if file.IsDir() { | ||
subTree := buildDirectoryTree(dirname + "/" + file.Name()) | ||
encoded := subTree.Encode() | ||
hasher := sha1.New() | ||
hasher.Write([]byte(encoded)) | ||
treeSha := hasher.Sum(nil) | ||
children = append(children, &Child{ | ||
mode: "040000", | ||
sha: []byte(fmt.Sprintf("%s", treeSha)), | ||
name: file.Name(), | ||
typ: "tree", | ||
}) | ||
continue | ||
} | ||
contents, err := os.ReadFile(dirname + "/" + file.Name()) | ||
cobra.CheckErr(err) | ||
|
||
content := string(contents) | ||
g := GitObject{Size: len(bytes.Runes([]byte(content))), Content: content} | ||
a := g.ToBlob() | ||
|
||
var compressed bytes.Buffer | ||
w := zlib.NewWriter(&compressed) | ||
w.Write(a) | ||
cobra.CheckErr(w.Close()) | ||
|
||
hasher := sha1.New() | ||
hasher.Write(a) | ||
hash := hasher.Sum(nil) | ||
sha := hex.EncodeToString(hash) | ||
children = append(children, &Child{ | ||
mode: "100644", | ||
sha: hash, | ||
name: file.Name(), | ||
typ: "blob", | ||
}) | ||
|
||
writeObjectToDisk(sha, compressed.Bytes()) | ||
} | ||
tree := Tree{ | ||
Children: children, | ||
} | ||
encoded := tree.Encode() | ||
|
||
var compressed bytes.Buffer | ||
w := zlib.NewWriter(&compressed) | ||
w.Write([]byte(encoded)) | ||
cobra.CheckErr(w.Close()) | ||
|
||
writeObjectToDisk(tree.GetSHA(), compressed.Bytes()) | ||
return &tree | ||
} |
Empty file.