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