1// Package repository contains helper methods for working with a Git repo.
2package repository
3
4import (
5 "bytes"
6 "errors"
7 "strings"
8
9 "github.com/MichaelMure/git-bug/util/git"
10 "github.com/MichaelMure/git-bug/util/lamport"
11)
12
13var ErrNoConfigEntry = errors.New("no config entry for the given key")
14var ErrMultipleConfigEntry = errors.New("multiple config entry for the given key")
15
16// RepoCommon represent the common function the we want all the repo to implement
17type RepoCommon interface {
18 // GetPath returns the path to the repo.
19 GetPath() string
20
21 // GetUserName returns the name the the user has used to configure git
22 GetUserName() (string, error)
23
24 // GetUserEmail returns the email address that the user has used to configure git.
25 GetUserEmail() (string, error)
26
27 // GetCoreEditor returns the name of the editor that the user has used to configure git.
28 GetCoreEditor() (string, error)
29
30 // StoreConfig store a single key/value pair in the config of the repo
31 StoreConfig(key string, value string) error
32
33 // ReadConfigs read all key/value pair matching the key prefix
34 ReadConfigs(keyPrefix string) (map[string]string, error)
35
36 // ReadConfigBool read a single boolean value from the config
37 // Return ErrNoConfigEntry or ErrMultipleConfigEntry if there is zero or more than one entry
38 // for this key
39 ReadConfigBool(key string) (bool, error)
40
41 // ReadConfigBool read a single string value from the config
42 // Return ErrNoConfigEntry or ErrMultipleConfigEntry if there is zero or more than one entry
43 // for this key
44 ReadConfigString(key string) (string, error)
45
46 // RmConfigs remove all key/value pair matching the key prefix
47 RmConfigs(keyPrefix string) error
48}
49
50// Repo represents a source code repository.
51type Repo interface {
52 RepoCommon
53
54 // FetchRefs fetch git refs from a remote
55 FetchRefs(remote string, refSpec string) (string, error)
56
57 // PushRefs push git refs to a remote
58 PushRefs(remote string, refSpec string) (string, error)
59
60 // StoreData will store arbitrary data and return the corresponding hash
61 StoreData(data []byte) (git.Hash, error)
62
63 // ReadData will attempt to read arbitrary data from the given hash
64 ReadData(hash git.Hash) ([]byte, error)
65
66 // StoreTree will store a mapping key-->Hash as a Git tree
67 StoreTree(mapping []TreeEntry) (git.Hash, error)
68
69 // StoreCommit will store a Git commit with the given Git tree
70 StoreCommit(treeHash git.Hash) (git.Hash, error)
71
72 // StoreCommit will store a Git commit with the given Git tree
73 StoreCommitWithParent(treeHash git.Hash, parent git.Hash) (git.Hash, error)
74
75 // UpdateRef will create or update a Git reference
76 UpdateRef(ref string, hash git.Hash) error
77
78 // ListRefs will return a list of Git ref matching the given refspec
79 ListRefs(refspec string) ([]string, error)
80
81 // RefExist will check if a reference exist in Git
82 RefExist(ref string) (bool, error)
83
84 // CopyRef will create a new reference with the same value as another one
85 CopyRef(source string, dest string) error
86
87 // ListCommits will return the list of tree hashes of a ref, in chronological order
88 ListCommits(ref string) ([]git.Hash, error)
89
90 // ListEntries will return the list of entries in a Git tree
91 ListEntries(hash git.Hash) ([]TreeEntry, error)
92
93 // FindCommonAncestor will return the last common ancestor of two chain of commit
94 FindCommonAncestor(hash1 git.Hash, hash2 git.Hash) (git.Hash, error)
95
96 // GetTreeHash return the git tree hash referenced in a commit
97 GetTreeHash(commit git.Hash) (git.Hash, error)
98}
99
100// ClockedRepo is a Repo that also has Lamport clocks
101type ClockedRepo interface {
102 Repo
103
104 // LoadClocks read the clocks values from the on-disk repo
105 LoadClocks() error
106
107 // WriteClocks write the clocks values into the repo
108 WriteClocks() error
109
110 // CreateTime return the current value of the creation clock
111 CreateTime() lamport.Time
112
113 // CreateTimeIncrement increment the creation clock and return the new value.
114 CreateTimeIncrement() (lamport.Time, error)
115
116 // EditTime return the current value of the edit clock
117 EditTime() lamport.Time
118
119 // EditTimeIncrement increment the edit clock and return the new value.
120 EditTimeIncrement() (lamport.Time, error)
121
122 // CreateWitness witness another create time and increment the corresponding
123 // clock if needed.
124 CreateWitness(time lamport.Time) error
125
126 // EditWitness witness another edition time and increment the corresponding
127 // clock if needed.
128 EditWitness(time lamport.Time) error
129}
130
131// Witnesser is a function that will initialize the clocks of a repo
132// from scratch
133type Witnesser func(repo ClockedRepo) error
134
135func prepareTreeEntries(entries []TreeEntry) bytes.Buffer {
136 var buffer bytes.Buffer
137
138 for _, entry := range entries {
139 buffer.WriteString(entry.Format())
140 }
141
142 return buffer
143}
144
145func readTreeEntries(s string) ([]TreeEntry, error) {
146 split := strings.Split(strings.TrimSpace(s), "\n")
147
148 casted := make([]TreeEntry, len(split))
149 for i, line := range split {
150 if line == "" {
151 continue
152 }
153
154 entry, err := ParseTreeEntry(line)
155
156 if err != nil {
157 return nil, err
158 }
159
160 casted[i] = entry
161 }
162
163 return casted, nil
164}