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}