seafile_recovery/commit.go

179 lines
4.3 KiB
Go
Raw Normal View History

2021-04-21 12:44:49 +00:00
package main
import (
2021-04-21 14:49:12 +00:00
"encoding/json"
2021-04-21 20:29:17 +00:00
"fmt"
2021-04-21 12:44:49 +00:00
"log"
2021-04-21 20:29:17 +00:00
"time"
2021-04-21 13:54:50 +00:00
"io/ioutil"
"path/filepath"
2021-04-21 12:44:49 +00:00
)
2021-04-21 20:29:17 +00:00
type Empty struct{}
var empty Empty
2021-04-21 13:54:50 +00:00
type RepoCommits struct {
2021-04-23 14:44:42 +00:00
Config *configCollect
2021-04-21 13:54:50 +00:00
CommitDesc map[string]string
2021-04-21 20:29:17 +00:00
CommitContent map[string]*CommitNode
2021-04-22 10:38:52 +00:00
Root map[*CommitNode]Empty
2021-04-22 09:20:52 +00:00
Leafs map[*CommitNode]Empty
Head *CommitNode
2021-04-21 14:49:12 +00:00
}
type CommitNode struct {
2021-04-22 14:15:54 +00:00
Id string
2021-04-21 20:29:17 +00:00
Parents map[*CommitNode]Empty
Children map[*CommitNode]Empty
2021-04-21 14:49:12 +00:00
Content Commit
2021-04-21 13:54:50 +00:00
}
2021-04-21 12:44:49 +00:00
type Commit struct {
2021-04-21 20:29:17 +00:00
CommitId *string `json:"commit_id"`
RootId *string `json:"root_id"`
RepoId *string `json:"repo_id"`
CreatorName *string `json:"creator_name"`
Creator *string `json:"creator"`
Description *string `json:"description"`
Ctime int64 `json:"ctime"`
ParentId *string `json:"parent_id"`
SecondParentId *string `json:"second_parent_id"`
RepoName *string `json:"repo_name"`
RepoDesc *string `json:"repo_desc"`
RepoCategory *string `json:"repo_category"`
2021-04-21 12:44:49 +00:00
NoLocalHistory int `json:"no_local_history"`
Version int `json:"version"`
}
2021-04-22 14:15:54 +00:00
func nilable(s *string) string {
if s == nil {
return "<nil>"
} else {
return *s
}
}
2021-04-21 20:29:17 +00:00
func (c* Commit) String() string {
2021-04-22 14:15:54 +00:00
return fmt.Sprintf(`RootId: %v
CreatorName: %v
Creator: %v
Description: %v
Ctime: %v
RepoName: %v
RepoDesc: %v
`, nilable(c.RootId), nilable(c.CreatorName), nilable(c.Creator), nilable(c.Description), time.Unix(c.Ctime, 0), nilable(c.RepoName), nilable(c.RepoDesc))
2021-04-21 20:29:17 +00:00
}
2021-04-23 14:44:42 +00:00
func NewRepoCommits (config *configCollect) *RepoCommits {
2021-04-21 13:54:50 +00:00
rc := new(RepoCommits)
rc.Config = config
rc.CommitDesc = make(map[string]string)
2021-04-21 20:29:17 +00:00
rc.CommitContent = make(map[string]*CommitNode)
2021-04-22 10:38:52 +00:00
rc.Root = make(map[*CommitNode]Empty)
2021-04-22 09:20:52 +00:00
rc.Leafs = make(map[*CommitNode]Empty)
2021-04-21 13:54:50 +00:00
return rc
}
func (rc* RepoCommits) CollectDescs() {
baseFolder := filepath.Join(rc.Config.Storage, "commits", rc.Config.RepoId)
layer1, err := ioutil.ReadDir(baseFolder)
if err != nil { log.Fatal(err) }
for _, l1 := range layer1 {
intFolder := filepath.Join(baseFolder, l1.Name())
layer2, err := ioutil.ReadDir(intFolder)
if err != nil { log.Fatal(err) }
for _, l2 := range layer2 {
commitId := l1.Name() + l2.Name()
commitPath := filepath.Join(intFolder, l2.Name())
rc.CommitDesc[commitId] = commitPath
}
}
}
2021-04-22 14:15:54 +00:00
func NewCommitNode(c Commit, id string) *CommitNode {
2021-04-21 20:29:17 +00:00
cn := new(CommitNode)
cn.Content = c
2021-04-22 14:15:54 +00:00
cn.Id = id
2021-04-21 20:29:17 +00:00
cn.Parents = make(map[*CommitNode]Empty)
cn.Children = make(map[*CommitNode]Empty)
return cn
}
2021-04-21 14:49:12 +00:00
func (rc* RepoCommits) CollectContent() {
for id, path := range rc.CommitDesc {
data, err := ioutil.ReadFile(path)
if err != nil { log.Fatal(err) }
2021-04-21 20:29:17 +00:00
var c Commit;
2021-04-22 20:43:44 +00:00
err = json.Unmarshal(data, &c)
2021-04-22 14:15:54 +00:00
if err != nil {
log.Fatal(err)
}
rc.CommitContent[id] = NewCommitNode(c,id)
2021-04-21 14:49:12 +00:00
}
}
2021-04-21 20:29:17 +00:00
2021-04-22 10:38:52 +00:00
func (rc* RepoCommits) BuildGraph() map[*CommitNode]Empty {
2021-04-21 20:29:17 +00:00
for _, cn := range rc.CommitContent {
if cn.Content.ParentId == nil && cn.Content.SecondParentId == nil {
2021-04-22 10:38:52 +00:00
rc.Root[cn] = empty
2021-04-21 20:29:17 +00:00
}
if cn.Content.ParentId != nil {
parentCn := rc.CommitContent[*cn.Content.ParentId]
cn.Parents[parentCn] = empty
parentCn.Children[cn] = empty
}
if cn.Content.SecondParentId != nil {
parentCn := rc.CommitContent[*cn.Content.SecondParentId]
cn.Parents[parentCn] = empty
parentCn.Children[cn] = empty
}
}
2021-04-22 10:38:52 +00:00
if len(rc.Root) == 0 {
2021-04-21 20:29:17 +00:00
log.Fatal("Root commit has not been found")
}
return rc.Root
}
2021-04-22 09:20:52 +00:00
func (rc* RepoCommits) FindLeafs() map[*CommitNode]Empty {
2021-04-21 20:29:17 +00:00
toProcess := make(map[*CommitNode]Empty)
2021-04-22 10:38:52 +00:00
for cn, _ := range rc.Root {
toProcess[cn] = empty
}
2021-04-21 20:29:17 +00:00
for i := 0; i < len(rc.CommitContent) && len(toProcess) > 0; i++ {
nextToProcess := make(map[*CommitNode]Empty)
for cn, _ := range toProcess {
for ccn, _ := range cn.Children {
nextToProcess[ccn] = empty
}
if len(cn.Children) == 0 {
2021-04-22 09:20:52 +00:00
rc.Leafs[cn] = empty
2021-04-21 20:29:17 +00:00
}
}
toProcess = nextToProcess
}
2021-04-22 09:20:52 +00:00
if len(rc.Leafs) == 0 { log.Fatal("No leafs have been found") }
return rc.Leafs
2021-04-21 20:29:17 +00:00
}
2021-04-22 09:20:52 +00:00
func (rc* RepoCommits) ChooseHead() *CommitNode {
for cn, _ := range rc.Leafs {
if rc.Head == nil {
rc.Head = cn
} else if rc.Head.Content.Ctime < cn.Content.Ctime {
rc.Head = cn
}
}
if rc.Head == nil { log.Fatal("No HEAD has been found") }
return rc.Head
2021-04-21 20:29:17 +00:00
}