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