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