-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcmd_commit.go
137 lines (107 loc) · 3.12 KB
/
cmd_commit.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"gitlab.com/nlulic/lit/cad"
. "gitlab.com/nlulic/lit/objects"
"gitlab.com/nlulic/lit/util"
)
func (lit *Lit) Commit(message string) {
r, err := lit.Root()
if err != nil {
lit.logger.Fatal(err)
}
objectsDir := lit.objectsDir()
db := cad.New(objectsDir)
var headSnapshot Tree
// initialize the HEAD snapshot only if a head exists (has commits)
if head, err := lit.GetHead(); err == nil {
headSnapshot = snapshotHead(head, r, db)
}
workingTree := lit.Snapshot(r)
// used later for STDOUT
var createdBlobs []Blob
// write all the trees and files to the objects storage
for _, tree := range trees(workingTree) {
mustCreate(db, []byte(tree.Value()), TreeType, tree.Hash())
lit.logger.Debug(fmt.Sprintf("created %s object %s", TreeType, tree.Hash()))
for _, blob := range tree.Blobs {
b, err := ioutil.ReadFile(blob.Path)
if err != nil {
panic(err)
}
mustCreate(db, b, BlobType, blob.Hash)
createdBlobs = append(createdBlobs, blob)
lit.logger.Debug(fmt.Sprintf("created %s object %s", BlobType, blob.Hash))
}
}
ref, err := lit.GetRef()
if err != nil {
panic(err)
}
// exit if no objects have been added to the cad
if headSnapshot.Hash() == workingTree.Hash() {
lit.logger.Info("On branch '" + filepath.Base(ref) + "' nothing to commit, working tree clean")
return
}
head, err := lit.GetHead()
if err != nil {
if os.IsNotExist(err) {
lit.logger.Debug("HEAD currently doesn't exist")
} else {
panic(err)
}
}
commit := NewCommit(message, &workingTree, head)
hash, _ := mustCreate(db, []byte(commit.Value()), CommitType, commit.Hash())
lit.logger.Debug(fmt.Sprintf("created %s object %s", CommitType, commit.Hash()))
mustWriteToFile(ref, hash)
// output
lit.logger.Info(fmt.Sprintf("[%s (commit %s)] %s", filepath.Base(ref), hash, message))
lit.logger.Info(len(createdBlobs), "files changed:")
for _, blob := range createdBlobs {
lit.logger.Info("created/updated", blob.Name)
}
}
// tree traverses a base tree and returns the base and all of its subtrees
func trees(tree Tree) (trees []Tree) {
if tree.IsEmpty() {
return nil
}
stack := util.Stack()
stack.Push(tree)
for !stack.IsEmpty() {
next := stack.Pop().(Tree)
trees = append(trees, next)
for _, t := range next.Trees {
stack.Push(t)
}
}
return
}
// mustCreate creates object to the cad. If any errors occur or the snpashot hash
// doesn't match the created hashed object it panics
func mustCreate(db *cad.Cad, b []byte, objectType string, snapshotHash string) (hash string, exists bool) {
hash, err := db.Write(b, objectType)
if err != nil {
// ignore if the object already exists in the cad
if err == cad.ObjectAlreadyExists {
return hash, true
}
panic(err)
}
if hash != snapshotHash {
panic(fmt.Sprintf("created %s hash %s doesn't match snapshot hash %s", objectType, hash, snapshotHash))
}
return hash, false
}
func mustWriteToFile(path, value string) {
if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil {
panic(err)
}
if err := ioutil.WriteFile(path, []byte(value), 0777); err != nil {
panic(err)
}
}