1package git
2
3import (
4 "path/filepath"
5
6 "github.com/gogs/git-module"
7)
8
9var (
10 // DiffMaxFile is the maximum number of files to show in a diff.
11 DiffMaxFiles = 1000
12 // DiffMaxFileLines is the maximum number of lines to show in a file diff.
13 DiffMaxFileLines = 1000
14 // DiffMaxLineChars is the maximum number of characters to show in a line diff.
15 DiffMaxLineChars = 1000
16)
17
18// Repository is a wrapper around git.Repository with helper methods.
19type Repository struct {
20 *git.Repository
21 Path string
22}
23
24// Clone clones a repository.
25func Clone(src, dst string, opts ...git.CloneOptions) error {
26 return git.Clone(src, dst, opts...)
27}
28
29// Init initializes and opens a new git repository.
30func Init(path string, bare bool) (*Repository, error) {
31 err := git.Init(path, git.InitOptions{Bare: bare})
32 if err != nil {
33 return nil, err
34 }
35 return Open(path)
36}
37
38// Open opens a git repository at the given path.
39func Open(path string) (*Repository, error) {
40 repo, err := git.Open(path)
41 if err != nil {
42 return nil, err
43 }
44 return &Repository{
45 Repository: repo,
46 Path: path,
47 }, nil
48}
49
50// Name returns the name of the repository.
51func (r *Repository) Name() string {
52 return filepath.Base(r.Path)
53}
54
55// HEAD returns the HEAD reference for a repository.
56func (r *Repository) HEAD() (*Reference, error) {
57 rn, err := r.SymbolicRef()
58 if err != nil {
59 return nil, err
60 }
61 hash, err := r.ShowRefVerify(rn)
62 if err != nil {
63 return nil, err
64 }
65 return &Reference{
66 Reference: &git.Reference{
67 ID: hash,
68 Refspec: rn,
69 },
70 Hash: Hash(hash),
71 path: r.Path,
72 }, nil
73}
74
75// References returns the references for a repository.
76func (r *Repository) References() ([]*Reference, error) {
77 refs, err := r.ShowRef()
78 if err != nil {
79 return nil, err
80 }
81 rrefs := make([]*Reference, 0, len(refs))
82 for _, ref := range refs {
83 rrefs = append(rrefs, &Reference{
84 Reference: ref,
85 Hash: Hash(ref.ID),
86 path: r.Path,
87 })
88 }
89 return rrefs, nil
90}
91
92// Tree returns the tree for the given reference.
93func (r *Repository) Tree(ref *Reference) (*Tree, error) {
94 if ref == nil {
95 rref, err := r.HEAD()
96 if err != nil {
97 return nil, err
98 }
99 ref = rref
100 }
101 tree, err := r.LsTree(ref.Hash.String())
102 if err != nil {
103 return nil, err
104 }
105 return &Tree{
106 Tree: tree,
107 Path: "",
108 Repository: r,
109 }, nil
110}
111
112// TreePath returns the tree for the given path.
113func (r *Repository) TreePath(ref *Reference, path string) (*Tree, error) {
114 path = filepath.Clean(path)
115 if path == "." {
116 path = ""
117 }
118 if path == "" {
119 return r.Tree(ref)
120 }
121 t, err := r.Tree(ref)
122 if err != nil {
123 return nil, err
124 }
125 return t.SubTree(path)
126}
127
128// Diff returns the diff for the given commit.
129func (r *Repository) Diff(commit *Commit) (*Diff, error) {
130 ddiff, err := r.Repository.Diff(commit.Hash.String(), DiffMaxFiles, DiffMaxFileLines, DiffMaxLineChars)
131 if err != nil {
132 return nil, err
133 }
134 files := make([]*DiffFile, 0, len(ddiff.Files))
135 for _, df := range ddiff.Files {
136 sections := make([]*DiffSection, 0, len(df.Sections))
137 for _, ds := range df.Sections {
138 sections = append(sections, &DiffSection{
139 DiffSection: ds,
140 })
141 }
142 files = append(files, &DiffFile{
143 DiffFile: df,
144 Sections: sections,
145 })
146 }
147 diff := &Diff{
148 Diff: ddiff,
149 Files: files,
150 }
151 return diff, nil
152}
153
154// Patch returns the patch for the given reference.
155func (r *Repository) Patch(commit *Commit) (string, error) {
156 diff, err := r.Diff(commit)
157 if err != nil {
158 return "", err
159 }
160 return diff.Patch(), err
161}
162
163// CountCommits returns the number of commits in the repository.
164func (r *Repository) CountCommits(ref *Reference) (int64, error) {
165 return r.Repository.RevListCount([]string{ref.Name().String()})
166}
167
168// CommitsByPage returns the commits for a given page and size.
169func (r *Repository) CommitsByPage(ref *Reference, page, size int) (Commits, error) {
170 cs, err := r.Repository.CommitsByPage(ref.Name().String(), page, size)
171 if err != nil {
172 return nil, err
173 }
174 commits := make(Commits, len(cs))
175 for i, c := range cs {
176 commits[i] = &Commit{
177 Commit: c,
178 Hash: Hash(c.ID.String()),
179 }
180 }
181 return commits, nil
182}
183
184// UpdateServerInfo updates the repository server info.
185func (r *Repository) UpdateServerInfo() error {
186 cmd := git.NewCommand("update-server-info")
187 _, err := cmd.RunInDir(r.Path)
188 return err
189}