mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	move out git module and #1573 send push hook
This commit is contained in:
		@@ -1,26 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/com"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Blob struct {
 | 
			
		||||
	repo *Repository
 | 
			
		||||
	*TreeEntry
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Blob) Data() (io.Reader, error) {
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDirBytes(b.repo.Path, "git", "show", b.ID.String())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New(string(stderr))
 | 
			
		||||
	}
 | 
			
		||||
	return bytes.NewBuffer(stdout), nil
 | 
			
		||||
}
 | 
			
		||||
@@ -1,162 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"container/list"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Commit represents a git commit.
 | 
			
		||||
type Commit struct {
 | 
			
		||||
	Tree
 | 
			
		||||
	ID            sha1 // The id of this commit object
 | 
			
		||||
	Author        *Signature
 | 
			
		||||
	Committer     *Signature
 | 
			
		||||
	CommitMessage string
 | 
			
		||||
 | 
			
		||||
	parents    []sha1 // sha1 strings
 | 
			
		||||
	submodules map[string]*SubModule
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Return the commit message. Same as retrieving CommitMessage directly.
 | 
			
		||||
func (c *Commit) Message() string {
 | 
			
		||||
	return c.CommitMessage
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Commit) Summary() string {
 | 
			
		||||
	return strings.Split(c.CommitMessage, "\n")[0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Return oid of the parent number n (0-based index). Return nil if no such parent exists.
 | 
			
		||||
func (c *Commit) ParentId(n int) (id sha1, err error) {
 | 
			
		||||
	if n >= len(c.parents) {
 | 
			
		||||
		err = IDNotExist
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return c.parents[n], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Return parent number n (0-based index)
 | 
			
		||||
func (c *Commit) Parent(n int) (*Commit, error) {
 | 
			
		||||
	id, err := c.ParentId(n)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	parent, err := c.repo.getCommit(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return parent, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Return the number of parents of the commit. 0 if this is the
 | 
			
		||||
// root commit, otherwise 1,2,...
 | 
			
		||||
func (c *Commit) ParentCount() int {
 | 
			
		||||
	return len(c.parents)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Commit) CommitsBefore() (*list.List, error) {
 | 
			
		||||
	return c.repo.getCommitsBefore(c.ID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Commit) CommitsBeforeUntil(commitId string) (*list.List, error) {
 | 
			
		||||
	ec, err := c.repo.GetCommit(commitId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return c.repo.CommitsBetween(c, ec)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Commit) CommitsCount() (int, error) {
 | 
			
		||||
	return c.repo.commitsCount(c.ID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Commit) SearchCommits(keyword string) (*list.List, error) {
 | 
			
		||||
	return c.repo.searchCommits(c.ID, keyword)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Commit) CommitsByRange(page int) (*list.List, error) {
 | 
			
		||||
	return c.repo.commitsByRange(c.ID, page)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Commit) GetCommitOfRelPath(relPath string) (*Commit, error) {
 | 
			
		||||
	return c.repo.getCommitOfRelPath(c.ID, relPath)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Commit) GetSubModule(entryname string) (*SubModule, error) {
 | 
			
		||||
	modules, err := c.GetSubModules()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return modules[entryname], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Commit) GetSubModules() (map[string]*SubModule, error) {
 | 
			
		||||
	if c.submodules != nil {
 | 
			
		||||
		return c.submodules, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	entry, err := c.GetTreeEntryByPath(".gitmodules")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	rd, err := entry.Blob().Data()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scanner := bufio.NewScanner(rd)
 | 
			
		||||
	c.submodules = make(map[string]*SubModule)
 | 
			
		||||
	var ismodule bool
 | 
			
		||||
	var path string
 | 
			
		||||
	for scanner.Scan() {
 | 
			
		||||
		if strings.HasPrefix(scanner.Text(), "[submodule") {
 | 
			
		||||
			ismodule = true
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if ismodule {
 | 
			
		||||
			fields := strings.Split(scanner.Text(), "=")
 | 
			
		||||
			k := strings.TrimSpace(fields[0])
 | 
			
		||||
			if k == "path" {
 | 
			
		||||
				path = strings.TrimSpace(fields[1])
 | 
			
		||||
			} else if k == "url" {
 | 
			
		||||
				c.submodules[path] = &SubModule{path, strings.TrimSpace(fields[1])}
 | 
			
		||||
				ismodule = false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c.submodules, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isImageFile(data []byte) (string, bool) {
 | 
			
		||||
	contentType := http.DetectContentType(data)
 | 
			
		||||
	if strings.Index(contentType, "image/") != -1 {
 | 
			
		||||
		return contentType, true
 | 
			
		||||
	}
 | 
			
		||||
	return contentType, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Commit) IsImageFile(name string) bool {
 | 
			
		||||
	blob, err := c.GetBlobByPath(name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dataRc, err := blob.Data()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	buf := make([]byte, 1024)
 | 
			
		||||
	n, _ := dataRc.Read(buf)
 | 
			
		||||
	if n > 0 {
 | 
			
		||||
		buf = buf[:n]
 | 
			
		||||
	}
 | 
			
		||||
	_, isImage := isImageFile(buf)
 | 
			
		||||
	return isImage
 | 
			
		||||
}
 | 
			
		||||
@@ -1,36 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/com"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ArchiveType int
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	ZIP ArchiveType = iota + 1
 | 
			
		||||
	TARGZ
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (c *Commit) CreateArchive(path string, archiveType ArchiveType) error {
 | 
			
		||||
	var format string
 | 
			
		||||
	switch archiveType {
 | 
			
		||||
	case ZIP:
 | 
			
		||||
		format = "zip"
 | 
			
		||||
	case TARGZ:
 | 
			
		||||
		format = "tar.gz"
 | 
			
		||||
	default:
 | 
			
		||||
		return fmt.Errorf("unknown format: %v", archiveType)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, stderr, err := com.ExecCmdDir(c.repo.Path, "git", "archive", "--format="+format, "-o", path, c.ID.String())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("%s", stderr)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@@ -1,22 +0,0 @@
 | 
			
		||||
// Copyright 2015 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ErrUnsupportedVersion struct {
 | 
			
		||||
	Required string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func IsErrUnsupportedVersion(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrUnsupportedVersion)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrUnsupportedVersion) Error() string {
 | 
			
		||||
	return fmt.Sprintf("Operation requires higher version [required: %s]", err.Required)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,125 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/com"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// hookNames is a list of Git hooks' name that are supported.
 | 
			
		||||
var hookNames = []string{
 | 
			
		||||
	"applypatch-msg",
 | 
			
		||||
	"pre-applypatch",
 | 
			
		||||
	"post-applypatch",
 | 
			
		||||
	"pre-commit",
 | 
			
		||||
	"prepare-commit-msg",
 | 
			
		||||
	"commit-msg",
 | 
			
		||||
	"post-commit",
 | 
			
		||||
	"pre-rebase",
 | 
			
		||||
	"post-checkout",
 | 
			
		||||
	"post-merge",
 | 
			
		||||
	"pre-push",
 | 
			
		||||
	"pre-receive",
 | 
			
		||||
	// "update",
 | 
			
		||||
	"post-receive",
 | 
			
		||||
	"post-update",
 | 
			
		||||
	"push-to-checkout",
 | 
			
		||||
	"pre-auto-gc",
 | 
			
		||||
	"post-rewrite",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ErrNotValidHook = errors.New("not a valid Git hook")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// IsValidHookName returns true if given name is a valid Git hook.
 | 
			
		||||
func IsValidHookName(name string) bool {
 | 
			
		||||
	for _, hn := range hookNames {
 | 
			
		||||
		if hn == name {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Hook represents a Git hook.
 | 
			
		||||
type Hook struct {
 | 
			
		||||
	name     string
 | 
			
		||||
	IsActive bool   // Indicates whether repository has this hook.
 | 
			
		||||
	Content  string // Content of hook if it's active.
 | 
			
		||||
	Sample   string // Sample content from Git.
 | 
			
		||||
	path     string // Hook file path.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetHook returns a Git hook by given name and repository.
 | 
			
		||||
func GetHook(repoPath, name string) (*Hook, error) {
 | 
			
		||||
	if !IsValidHookName(name) {
 | 
			
		||||
		return nil, ErrNotValidHook
 | 
			
		||||
	}
 | 
			
		||||
	h := &Hook{
 | 
			
		||||
		name: name,
 | 
			
		||||
		path: path.Join(repoPath, "hooks", name),
 | 
			
		||||
	}
 | 
			
		||||
	if isFile(h.path) {
 | 
			
		||||
		data, err := ioutil.ReadFile(h.path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		h.IsActive = true
 | 
			
		||||
		h.Content = string(data)
 | 
			
		||||
	} else if isFile(h.path + ".sample") {
 | 
			
		||||
		data, err := ioutil.ReadFile(h.path + ".sample")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		h.Sample = string(data)
 | 
			
		||||
	}
 | 
			
		||||
	return h, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *Hook) Name() string {
 | 
			
		||||
	return h.name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Update updates hook settings.
 | 
			
		||||
func (h *Hook) Update() error {
 | 
			
		||||
	if len(strings.TrimSpace(h.Content)) == 0 {
 | 
			
		||||
		if com.IsExist(h.path) {
 | 
			
		||||
			return os.Remove(h.path)
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return ioutil.WriteFile(h.path, []byte(strings.Replace(h.Content, "\r", "", -1)), os.ModePerm)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ListHooks returns a list of Git hooks of given repository.
 | 
			
		||||
func ListHooks(repoPath string) (_ []*Hook, err error) {
 | 
			
		||||
	if !isDir(path.Join(repoPath, "hooks")) {
 | 
			
		||||
		return nil, errors.New("hooks path does not exist")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hooks := make([]*Hook, len(hookNames))
 | 
			
		||||
	for i, name := range hookNames {
 | 
			
		||||
		hooks[i], err = GetHook(repoPath, name)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return hooks, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) GetHook(name string) (*Hook, error) {
 | 
			
		||||
	return GetHook(repo.Path, name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) Hooks() ([]*Hook, error) {
 | 
			
		||||
	return ListHooks(repo.Path)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,30 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Repository represents a Git repository.
 | 
			
		||||
type Repository struct {
 | 
			
		||||
	Path string
 | 
			
		||||
 | 
			
		||||
	commitCache map[sha1]*Commit
 | 
			
		||||
	tagCache    map[sha1]*Tag
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OpenRepository opens the repository at the given path.
 | 
			
		||||
func OpenRepository(repoPath string) (*Repository, error) {
 | 
			
		||||
	repoPath, err := filepath.Abs(repoPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if !isDir(repoPath) {
 | 
			
		||||
		return nil, errors.New("no such file or directory")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &Repository{Path: repoPath}, nil
 | 
			
		||||
}
 | 
			
		||||
@@ -1,50 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/com"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func IsBranchExist(repoPath, branchName string) bool {
 | 
			
		||||
	_, _, err := com.ExecCmdDir(repoPath, "git", "show-ref", "--verify", "refs/heads/"+branchName)
 | 
			
		||||
	return err == nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) IsBranchExist(branchName string) bool {
 | 
			
		||||
	return IsBranchExist(repo.Path, branchName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) GetBranches() ([]string, error) {
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "show-ref", "--heads")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, concatenateError(err, stderr)
 | 
			
		||||
	}
 | 
			
		||||
	infos := strings.Split(stdout, "\n")
 | 
			
		||||
	branches := make([]string, len(infos)-1)
 | 
			
		||||
	for i, info := range infos[:len(infos)-1] {
 | 
			
		||||
		parts := strings.Split(info, " ")
 | 
			
		||||
		if len(parts) != 2 {
 | 
			
		||||
			continue // NOTE: I should believe git will not give me wrong string.
 | 
			
		||||
		}
 | 
			
		||||
		branches[i] = strings.TrimPrefix(parts[1], "refs/heads/")
 | 
			
		||||
	}
 | 
			
		||||
	return branches, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetDefaultBranch sets default branch of repository.
 | 
			
		||||
func (repo *Repository) SetDefaultBranch(branchName string) error {
 | 
			
		||||
	if gitVer.LessThan(MustParseVersion("1.7.10")) {
 | 
			
		||||
		return ErrUnsupportedVersion{"1.7.10"}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, stderr, err := com.ExecCmdDir(repo.Path, "git", "symbolic-ref", "HEAD", "refs/heads/"+branchName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return concatenateError(err, stderr)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@@ -1,341 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"container/list"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/com"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) getCommitIdOfRef(refpath string) (string, error) {
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "show-ref", "--verify", refpath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", errors.New(stderr)
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Split(stdout, " ")[0], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) GetCommitIdOfBranch(branchName string) (string, error) {
 | 
			
		||||
	return repo.getCommitIdOfRef("refs/heads/" + branchName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// get branch's last commit or a special commit by id string
 | 
			
		||||
func (repo *Repository) GetCommitOfBranch(branchName string) (*Commit, error) {
 | 
			
		||||
	commitId, err := repo.GetCommitIdOfBranch(branchName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return repo.GetCommit(commitId)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) GetCommitIdOfTag(tagName string) (string, error) {
 | 
			
		||||
	return repo.getCommitIdOfRef("refs/tags/" + tagName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) GetCommitOfTag(tagName string) (*Commit, error) {
 | 
			
		||||
	tag, err := repo.GetTag(tagName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return tag.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Parse commit information from the (uncompressed) raw
 | 
			
		||||
// data from the commit object.
 | 
			
		||||
// \n\n separate headers from message
 | 
			
		||||
func parseCommitData(data []byte) (*Commit, error) {
 | 
			
		||||
	commit := new(Commit)
 | 
			
		||||
	commit.parents = make([]sha1, 0, 1)
 | 
			
		||||
	// we now have the contents of the commit object. Let's investigate...
 | 
			
		||||
	nextline := 0
 | 
			
		||||
l:
 | 
			
		||||
	for {
 | 
			
		||||
		eol := bytes.IndexByte(data[nextline:], '\n')
 | 
			
		||||
		switch {
 | 
			
		||||
		case eol > 0:
 | 
			
		||||
			line := data[nextline : nextline+eol]
 | 
			
		||||
			spacepos := bytes.IndexByte(line, ' ')
 | 
			
		||||
			reftype := line[:spacepos]
 | 
			
		||||
			switch string(reftype) {
 | 
			
		||||
			case "tree":
 | 
			
		||||
				id, err := NewIdFromString(string(line[spacepos+1:]))
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
				commit.Tree.ID = id
 | 
			
		||||
			case "parent":
 | 
			
		||||
				// A commit can have one or more parents
 | 
			
		||||
				oid, err := NewIdFromString(string(line[spacepos+1:]))
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
				commit.parents = append(commit.parents, oid)
 | 
			
		||||
			case "author":
 | 
			
		||||
				sig, err := newSignatureFromCommitline(line[spacepos+1:])
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
				commit.Author = sig
 | 
			
		||||
			case "committer":
 | 
			
		||||
				sig, err := newSignatureFromCommitline(line[spacepos+1:])
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
				commit.Committer = sig
 | 
			
		||||
			}
 | 
			
		||||
			nextline += eol + 1
 | 
			
		||||
		case eol == 0:
 | 
			
		||||
			commit.CommitMessage = string(data[nextline+1:])
 | 
			
		||||
			break l
 | 
			
		||||
		default:
 | 
			
		||||
			break l
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return commit, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) getCommit(id sha1) (*Commit, error) {
 | 
			
		||||
	if repo.commitCache != nil {
 | 
			
		||||
		if c, ok := repo.commitCache[id]; ok {
 | 
			
		||||
			return c, nil
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		repo.commitCache = make(map[sha1]*Commit, 10)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data, stderr, err := com.ExecCmdDirBytes(repo.Path, "git", "cat-file", "-p", id.String())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, concatenateError(err, string(stderr))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	commit, err := parseCommitData(data)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	commit.repo = repo
 | 
			
		||||
	commit.ID = id
 | 
			
		||||
 | 
			
		||||
	repo.commitCache[id] = commit
 | 
			
		||||
	return commit, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Find the commit object in the repository.
 | 
			
		||||
func (repo *Repository) GetCommit(commitId string) (*Commit, error) {
 | 
			
		||||
	id, err := NewIdFromString(commitId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return repo.getCommit(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) commitsCount(id sha1) (int, error) {
 | 
			
		||||
	if gitVer.LessThan(MustParseVersion("1.8.0")) {
 | 
			
		||||
		stdout, stderr, err := com.ExecCmdDirBytes(repo.Path, "git", "log",
 | 
			
		||||
			"--pretty=format:''", id.String())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, errors.New(string(stderr))
 | 
			
		||||
		}
 | 
			
		||||
		return len(bytes.Split(stdout, []byte("\n"))), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "rev-list", "--count", id.String())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, errors.New(stderr)
 | 
			
		||||
	}
 | 
			
		||||
	return com.StrTo(strings.TrimSpace(stdout)).Int()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) CommitsCount(commitId string) (int, error) {
 | 
			
		||||
	id, err := NewIdFromString(commitId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return repo.commitsCount(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) commitsCountBetween(start, end sha1) (int, error) {
 | 
			
		||||
	if gitVer.LessThan(MustParseVersion("1.8.0")) {
 | 
			
		||||
		stdout, stderr, err := com.ExecCmdDirBytes(repo.Path, "git", "log",
 | 
			
		||||
			"--pretty=format:''", start.String()+"..."+end.String())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, errors.New(string(stderr))
 | 
			
		||||
		}
 | 
			
		||||
		return len(bytes.Split(stdout, []byte("\n"))), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "rev-list", "--count",
 | 
			
		||||
		start.String()+"..."+end.String())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, errors.New(stderr)
 | 
			
		||||
	}
 | 
			
		||||
	return com.StrTo(strings.TrimSpace(stdout)).Int()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) CommitsCountBetween(startCommitID, endCommitID string) (int, error) {
 | 
			
		||||
	start, err := NewIdFromString(startCommitID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	end, err := NewIdFromString(endCommitID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return repo.commitsCountBetween(start, end)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) {
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "diff", "--name-only",
 | 
			
		||||
		startCommitID+"..."+endCommitID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, fmt.Errorf("list changed files: %v", concatenateError(err, stderr))
 | 
			
		||||
	}
 | 
			
		||||
	return len(strings.Split(stdout, "\n")) - 1, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// used only for single tree, (]
 | 
			
		||||
func (repo *Repository) CommitsBetween(last *Commit, before *Commit) (*list.List, error) {
 | 
			
		||||
	l := list.New()
 | 
			
		||||
	if last == nil || last.ParentCount() == 0 {
 | 
			
		||||
		return l, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	cur := last
 | 
			
		||||
	for {
 | 
			
		||||
		if cur.ID.Equal(before.ID) {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		l.PushBack(cur)
 | 
			
		||||
		if cur.ParentCount() == 0 {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		cur, err = cur.Parent(0)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return l, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) commitsBefore(lock *sync.Mutex, l *list.List, parent *list.Element, id sha1, limit int) error {
 | 
			
		||||
	commit, err := repo.getCommit(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("getCommit: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var e *list.Element
 | 
			
		||||
	if parent == nil {
 | 
			
		||||
		e = l.PushBack(commit)
 | 
			
		||||
	} else {
 | 
			
		||||
		var in = parent
 | 
			
		||||
		for {
 | 
			
		||||
			if in == nil {
 | 
			
		||||
				break
 | 
			
		||||
			} else if in.Value.(*Commit).ID.Equal(commit.ID) {
 | 
			
		||||
				return nil
 | 
			
		||||
			} else {
 | 
			
		||||
				if in.Next() == nil {
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
				if in.Value.(*Commit).Committer.When.Equal(commit.Committer.When) {
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if in.Value.(*Commit).Committer.When.After(commit.Committer.When) &&
 | 
			
		||||
					in.Next().Value.(*Commit).Committer.When.Before(commit.Committer.When) {
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			in = in.Next()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		e = l.InsertAfter(commit, in)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var pr = parent
 | 
			
		||||
	if commit.ParentCount() > 1 {
 | 
			
		||||
		pr = e
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < commit.ParentCount(); i++ {
 | 
			
		||||
		id, err := commit.ParentId(i)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		err = repo.commitsBefore(lock, l, pr, id, 0)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) FileCommitsCount(branch, file string) (int, error) {
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "rev-list", "--count",
 | 
			
		||||
		branch, "--", file)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, errors.New(stderr)
 | 
			
		||||
	}
 | 
			
		||||
	return com.StrTo(strings.TrimSpace(stdout)).Int()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) CommitsByFileAndRange(branch, file string, page int) (*list.List, error) {
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDirBytes(repo.Path, "git", "log", branch,
 | 
			
		||||
		"--skip="+com.ToStr((page-1)*50), "--max-count=50", prettyLogFormat, "--", file)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New(string(stderr))
 | 
			
		||||
	}
 | 
			
		||||
	return parsePrettyFormatLog(repo, stdout)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) getCommitsBefore(id sha1) (*list.List, error) {
 | 
			
		||||
	l := list.New()
 | 
			
		||||
	lock := new(sync.Mutex)
 | 
			
		||||
	return l, repo.commitsBefore(lock, l, nil, id, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) searchCommits(id sha1, keyword string) (*list.List, error) {
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDirBytes(repo.Path, "git", "log", id.String(), "-100",
 | 
			
		||||
		"-i", "--grep="+keyword, prettyLogFormat)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else if len(stderr) > 0 {
 | 
			
		||||
		return nil, errors.New(string(stderr))
 | 
			
		||||
	}
 | 
			
		||||
	return parsePrettyFormatLog(repo, stdout)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var CommitsRangeSize = 50
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) commitsByRange(id sha1, page int) (*list.List, error) {
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDirBytes(repo.Path, "git", "log", id.String(),
 | 
			
		||||
		"--skip="+com.ToStr((page-1)*CommitsRangeSize), "--max-count="+com.ToStr(CommitsRangeSize), prettyLogFormat)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New(string(stderr))
 | 
			
		||||
	}
 | 
			
		||||
	return parsePrettyFormatLog(repo, stdout)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) getCommitOfRelPath(id sha1, relPath string) (*Commit, error) {
 | 
			
		||||
	stdout, _, err := com.ExecCmdDir(repo.Path, "git", "log", "-1", prettyLogFormat, id.String(), "--", relPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	id, err = NewIdFromString(string(stdout))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return repo.getCommit(id)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,14 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
type ObjectType string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	COMMIT ObjectType = "commit"
 | 
			
		||||
	TREE   ObjectType = "tree"
 | 
			
		||||
	BLOB   ObjectType = "blob"
 | 
			
		||||
	TAG    ObjectType = "tag"
 | 
			
		||||
)
 | 
			
		||||
@@ -1,104 +0,0 @@
 | 
			
		||||
// Copyright 2015 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"container/list"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/com"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type PullRequestInfo struct {
 | 
			
		||||
	MergeBase string
 | 
			
		||||
	Commits   *list.List
 | 
			
		||||
	// Diff      *Diff
 | 
			
		||||
	NumFiles int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetMergeBase checks and returns merge base of two branches.
 | 
			
		||||
func (repo *Repository) GetMergeBase(remoteBranch, headBranch string) (string, error) {
 | 
			
		||||
	// Get merge base commit.
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "merge-base", remoteBranch, headBranch)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", fmt.Errorf("get merge base: %v", concatenateError(err, stderr))
 | 
			
		||||
	}
 | 
			
		||||
	return strings.TrimSpace(stdout), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddRemote adds a remote to repository.
 | 
			
		||||
func (repo *Repository) AddRemote(name, path string) error {
 | 
			
		||||
	_, stderr, err := com.ExecCmdDir(repo.Path, "git", "remote", "add", "-f", name, path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("add remote(%s - %s): %v", name, path, concatenateError(err, stderr))
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoveRemote removes a remote from repository.
 | 
			
		||||
func (repo *Repository) RemoveRemote(name string) error {
 | 
			
		||||
	_, stderr, err := com.ExecCmdDir(repo.Path, "git", "remote", "remove", name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("remove remote(%s): %v", name, concatenateError(err, stderr))
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetPullRequestInfo generates and returns pull request information
 | 
			
		||||
// between base and head branches of repositories.
 | 
			
		||||
func (repo *Repository) GetPullRequestInfo(basePath, baseBranch, headBranch string) (_ *PullRequestInfo, err error) {
 | 
			
		||||
	// Add a temporary remote.
 | 
			
		||||
	tmpRemote := com.ToStr(time.Now().UnixNano())
 | 
			
		||||
	if err = repo.AddRemote(tmpRemote, basePath); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("AddRemote: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		repo.RemoveRemote(tmpRemote)
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	remoteBranch := "remotes/" + tmpRemote + "/" + baseBranch
 | 
			
		||||
 | 
			
		||||
	prInfo := new(PullRequestInfo)
 | 
			
		||||
	prInfo.MergeBase, err = repo.GetMergeBase(remoteBranch, headBranch)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("GetMergeBase: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "log", prInfo.MergeBase+"..."+headBranch, prettyLogFormat)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("list diff logs: %v", concatenateError(err, stderr))
 | 
			
		||||
	}
 | 
			
		||||
	prInfo.Commits, err = parsePrettyFormatLog(repo, []byte(stdout))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("parsePrettyFormatLog: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Count number of changed files.
 | 
			
		||||
	stdout, stderr, err = com.ExecCmdDir(repo.Path, "git", "diff", "--name-only", remoteBranch+"..."+headBranch)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("list changed files: %v", concatenateError(err, stderr))
 | 
			
		||||
	}
 | 
			
		||||
	prInfo.NumFiles = len(strings.Split(stdout, "\n")) - 1
 | 
			
		||||
 | 
			
		||||
	return prInfo, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetPatch generates and returns patch data between given branches.
 | 
			
		||||
func (repo *Repository) GetPatch(mergeBase, headBranch string) ([]byte, error) {
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDirBytes(repo.Path, "git", "diff", "-p", "--binary", mergeBase, headBranch)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, concatenateError(err, string(stderr))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return stdout, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Merge merges pull request from head repository and branch.
 | 
			
		||||
func (repo *Repository) Merge(headRepoPath string, baseBranch, headBranch string) error {
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@@ -1,117 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/com"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func IsTagExist(repoPath, tagName string) bool {
 | 
			
		||||
	_, _, err := com.ExecCmdDir(repoPath, "git", "show-ref", "--verify", "refs/tags/"+tagName)
 | 
			
		||||
	return err == nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) IsTagExist(tagName string) bool {
 | 
			
		||||
	return IsTagExist(repo.Path, tagName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) getTagsReversed() ([]string, error) {
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", "-l", "--sort=-v:refname")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, concatenateError(err, stderr)
 | 
			
		||||
	}
 | 
			
		||||
	tags := strings.Split(stdout, "\n")
 | 
			
		||||
	return tags[:len(tags)-1], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTags returns all tags of given repository.
 | 
			
		||||
func (repo *Repository) GetTags() ([]string, error) {
 | 
			
		||||
	if gitVer.AtLeast(MustParseVersion("2.0.0")) {
 | 
			
		||||
		return repo.getTagsReversed()
 | 
			
		||||
	}
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", "-l")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, concatenateError(err, stderr)
 | 
			
		||||
	}
 | 
			
		||||
	tags := strings.Split(stdout, "\n")
 | 
			
		||||
	return tags[:len(tags)-1], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) CreateTag(tagName, idStr string) error {
 | 
			
		||||
	_, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", tagName, idStr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.New(stderr)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) getTag(id sha1) (*Tag, error) {
 | 
			
		||||
	if repo.tagCache != nil {
 | 
			
		||||
		if t, ok := repo.tagCache[id]; ok {
 | 
			
		||||
			return t, nil
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		repo.tagCache = make(map[sha1]*Tag, 10)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get tag type.
 | 
			
		||||
	tp, stderr, err := com.ExecCmdDir(repo.Path, "git", "cat-file", "-t", id.String())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New(stderr)
 | 
			
		||||
	}
 | 
			
		||||
	tp = strings.TrimSpace(tp)
 | 
			
		||||
 | 
			
		||||
	// Tag is a commit.
 | 
			
		||||
	if ObjectType(tp) == COMMIT {
 | 
			
		||||
		tag := &Tag{
 | 
			
		||||
			ID:     id,
 | 
			
		||||
			Object: id,
 | 
			
		||||
			Type:   string(COMMIT),
 | 
			
		||||
			repo:   repo,
 | 
			
		||||
		}
 | 
			
		||||
		repo.tagCache[id] = tag
 | 
			
		||||
		return tag, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Tag with message.
 | 
			
		||||
	data, bytErr, err := com.ExecCmdDirBytes(repo.Path, "git", "cat-file", "-p", id.String())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New(string(bytErr))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tag, err := parseTagData(data)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tag.ID = id
 | 
			
		||||
	tag.repo = repo
 | 
			
		||||
 | 
			
		||||
	repo.tagCache[id] = tag
 | 
			
		||||
	return tag, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTag returns a Git tag by given name.
 | 
			
		||||
func (repo *Repository) GetTag(tagName string) (*Tag, error) {
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "show-ref", "--tags", tagName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New(stderr)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	id, err := NewIdFromString(strings.Split(stdout, " ")[0])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tag, err := repo.getTag(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	tag.Name = tagName
 | 
			
		||||
	return tag, nil
 | 
			
		||||
}
 | 
			
		||||
@@ -1,32 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/com"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Find the tree object in the repository.
 | 
			
		||||
func (repo *Repository) GetTree(idStr string) (*Tree, error) {
 | 
			
		||||
	id, err := NewIdFromString(idStr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return repo.getTree(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (repo *Repository) getTree(id sha1) (*Tree, error) {
 | 
			
		||||
	treePath := filepathFromSHA1(repo.Path, id.String())
 | 
			
		||||
	if !com.IsFile(treePath) {
 | 
			
		||||
		_, _, err := com.ExecCmdDir(repo.Path, "git", "ls-tree", id.String())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("repo.getTree: %v", ErrNotExist)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NewTree(repo, id), nil
 | 
			
		||||
}
 | 
			
		||||
@@ -1,87 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	IDNotExist = errors.New("sha1 ID does not exist")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type sha1 [20]byte
 | 
			
		||||
 | 
			
		||||
// Return true if s has the same sha1 as caller.
 | 
			
		||||
// Support 40-length-string, []byte, sha1
 | 
			
		||||
func (id sha1) Equal(s2 interface{}) bool {
 | 
			
		||||
	switch v := s2.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		if len(v) != 40 {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		return v == id.String()
 | 
			
		||||
	case []byte:
 | 
			
		||||
		if len(v) != 20 {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		for i, v := range v {
 | 
			
		||||
			if id[i] != v {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	case sha1:
 | 
			
		||||
		for i, v := range v {
 | 
			
		||||
			if id[i] != v {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Return string (hex) representation of the Oid
 | 
			
		||||
func (s sha1) String() string {
 | 
			
		||||
	result := make([]byte, 0, 40)
 | 
			
		||||
	hexvalues := []byte("0123456789abcdef")
 | 
			
		||||
	for i := 0; i < 20; i++ {
 | 
			
		||||
		result = append(result, hexvalues[s[i]>>4])
 | 
			
		||||
		result = append(result, hexvalues[s[i]&0xf])
 | 
			
		||||
	}
 | 
			
		||||
	return string(result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create a new sha1 from a 20 byte slice.
 | 
			
		||||
func NewId(b []byte) (sha1, error) {
 | 
			
		||||
	var id sha1
 | 
			
		||||
	if len(b) != 20 {
 | 
			
		||||
		return id, errors.New("Length must be 20")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < 20; i++ {
 | 
			
		||||
		id[i] = b[i]
 | 
			
		||||
	}
 | 
			
		||||
	return id, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create a new sha1 from a Sha1 string of length 40.
 | 
			
		||||
func NewIdFromString(s string) (sha1, error) {
 | 
			
		||||
	s = strings.TrimSpace(s)
 | 
			
		||||
	var id sha1
 | 
			
		||||
	if len(s) != 40 {
 | 
			
		||||
		return id, fmt.Errorf("Length must be 40")
 | 
			
		||||
	}
 | 
			
		||||
	b, err := hex.DecodeString(s)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return id, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NewId(b)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,51 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Author and Committer information
 | 
			
		||||
type Signature struct {
 | 
			
		||||
	Email string
 | 
			
		||||
	Name  string
 | 
			
		||||
	When  time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Helper to get a signature from the commit line, which looks like these:
 | 
			
		||||
//     author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
 | 
			
		||||
//     author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200
 | 
			
		||||
// but without the "author " at the beginning (this method should)
 | 
			
		||||
// be used for author and committer.
 | 
			
		||||
//
 | 
			
		||||
// FIXME: include timezone for timestamp!
 | 
			
		||||
func newSignatureFromCommitline(line []byte) (_ *Signature, err error) {
 | 
			
		||||
	sig := new(Signature)
 | 
			
		||||
	emailStart := bytes.IndexByte(line, '<')
 | 
			
		||||
	sig.Name = string(line[:emailStart-1])
 | 
			
		||||
	emailEnd := bytes.IndexByte(line, '>')
 | 
			
		||||
	sig.Email = string(line[emailStart+1 : emailEnd])
 | 
			
		||||
 | 
			
		||||
	// Check date format.
 | 
			
		||||
	firstChar := line[emailEnd+2]
 | 
			
		||||
	if firstChar >= 48 && firstChar <= 57 {
 | 
			
		||||
		timestop := bytes.IndexByte(line[emailEnd+2:], ' ')
 | 
			
		||||
		timestring := string(line[emailEnd+2 : emailEnd+2+timestop])
 | 
			
		||||
		seconds, err := strconv.ParseInt(timestring, 10, 64)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		sig.When = time.Unix(seconds, 0)
 | 
			
		||||
	} else {
 | 
			
		||||
		sig.When, err = time.Parse("Mon Jan _2 15:04:05 2006 -0700", string(line[emailEnd+2:]))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return sig, nil
 | 
			
		||||
}
 | 
			
		||||
@@ -1,20 +0,0 @@
 | 
			
		||||
// Copyright 2015 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	. "github.com/smartystreets/goconvey/convey"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Test_newSignatureFromCommitline(t *testing.T) {
 | 
			
		||||
	Convey("Parse signature from commit line", t, func() {
 | 
			
		||||
		line := "Intern <intern@macbook-intern.(none)> 1445412825 +0200"
 | 
			
		||||
		sig, err := newSignatureFromCommitline([]byte(line))
 | 
			
		||||
		So(err, ShouldBeNil)
 | 
			
		||||
		So(sig, ShouldNotBeNil)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
@@ -1,70 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/gogits/gogs/modules/setting"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SubModule struct {
 | 
			
		||||
	Name string
 | 
			
		||||
	Url  string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SubModuleFile represents a file with submodule type.
 | 
			
		||||
type SubModuleFile struct {
 | 
			
		||||
	*Commit
 | 
			
		||||
 | 
			
		||||
	refUrl string
 | 
			
		||||
	refId  string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewSubModuleFile(c *Commit, refUrl, refId string) *SubModuleFile {
 | 
			
		||||
	return &SubModuleFile{
 | 
			
		||||
		Commit: c,
 | 
			
		||||
		refUrl: refUrl,
 | 
			
		||||
		refId:  refId,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RefUrl guesses and returns reference URL.
 | 
			
		||||
func (sf *SubModuleFile) RefUrl() string {
 | 
			
		||||
	if sf.refUrl == "" {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	url := strings.TrimSuffix(sf.refUrl, ".git")
 | 
			
		||||
 | 
			
		||||
	// git://xxx/user/repo
 | 
			
		||||
	if strings.HasPrefix(url, "git://") {
 | 
			
		||||
		return "http://" + strings.TrimPrefix(url, "git://")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// http[s]://xxx/user/repo
 | 
			
		||||
	if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") {
 | 
			
		||||
		return url
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// sysuser@xxx:user/repo
 | 
			
		||||
	i := strings.Index(url, "@")
 | 
			
		||||
	j := strings.LastIndex(url, ":")
 | 
			
		||||
	if i > -1 && j > -1 {
 | 
			
		||||
		// fix problem with reverse proxy works only with local server
 | 
			
		||||
		if strings.Contains(setting.AppUrl, url[i+1:j]) {
 | 
			
		||||
			return setting.AppUrl + url[j+1:]
 | 
			
		||||
		} else {
 | 
			
		||||
			return "http://" + url[i+1:j] + "/" + url[j+1:]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return url
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RefId returns reference ID.
 | 
			
		||||
func (sf *SubModuleFile) RefId() string {
 | 
			
		||||
	return sf.refId
 | 
			
		||||
}
 | 
			
		||||
@@ -1,67 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Tag represents a Git tag.
 | 
			
		||||
type Tag struct {
 | 
			
		||||
	Name       string
 | 
			
		||||
	ID         sha1
 | 
			
		||||
	repo       *Repository
 | 
			
		||||
	Object     sha1 // The id of this commit object
 | 
			
		||||
	Type       string
 | 
			
		||||
	Tagger     *Signature
 | 
			
		||||
	TagMessage string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tag *Tag) Commit() (*Commit, error) {
 | 
			
		||||
	return tag.repo.getCommit(tag.Object)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Parse commit information from the (uncompressed) raw
 | 
			
		||||
// data from the commit object.
 | 
			
		||||
// \n\n separate headers from message
 | 
			
		||||
func parseTagData(data []byte) (*Tag, error) {
 | 
			
		||||
	tag := new(Tag)
 | 
			
		||||
	// we now have the contents of the commit object. Let's investigate...
 | 
			
		||||
	nextline := 0
 | 
			
		||||
l:
 | 
			
		||||
	for {
 | 
			
		||||
		eol := bytes.IndexByte(data[nextline:], '\n')
 | 
			
		||||
		switch {
 | 
			
		||||
		case eol > 0:
 | 
			
		||||
			line := data[nextline : nextline+eol]
 | 
			
		||||
			spacepos := bytes.IndexByte(line, ' ')
 | 
			
		||||
			reftype := line[:spacepos]
 | 
			
		||||
			switch string(reftype) {
 | 
			
		||||
			case "object":
 | 
			
		||||
				id, err := NewIdFromString(string(line[spacepos+1:]))
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
				tag.Object = id
 | 
			
		||||
			case "type":
 | 
			
		||||
				// A commit can have one or more parents
 | 
			
		||||
				tag.Type = string(line[spacepos+1:])
 | 
			
		||||
			case "tagger":
 | 
			
		||||
				sig, err := newSignatureFromCommitline(line[spacepos+1:])
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
				tag.Tagger = sig
 | 
			
		||||
			}
 | 
			
		||||
			nextline += eol + 1
 | 
			
		||||
		case eol == 0:
 | 
			
		||||
			tag.TagMessage = string(data[nextline+1:])
 | 
			
		||||
			break l
 | 
			
		||||
		default:
 | 
			
		||||
			break l
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return tag, nil
 | 
			
		||||
}
 | 
			
		||||
@@ -1,157 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/com"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ErrNotExist = errors.New("error not exist")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A tree is a flat directory listing.
 | 
			
		||||
type Tree struct {
 | 
			
		||||
	ID   sha1
 | 
			
		||||
	repo *Repository
 | 
			
		||||
 | 
			
		||||
	// parent tree
 | 
			
		||||
	ptree *Tree
 | 
			
		||||
 | 
			
		||||
	entries       Entries
 | 
			
		||||
	entriesParsed bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var escapeChar = []byte("\\")
 | 
			
		||||
 | 
			
		||||
func UnescapeChars(in []byte) []byte {
 | 
			
		||||
	if bytes.Index(in, escapeChar) == -1 {
 | 
			
		||||
		return in
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	endIdx := len(in) - 1
 | 
			
		||||
	isEscape := false
 | 
			
		||||
	out := make([]byte, 0, endIdx+1)
 | 
			
		||||
	for i := range in {
 | 
			
		||||
		if in[i] == '\\' && !isEscape {
 | 
			
		||||
			isEscape = true
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		isEscape = false
 | 
			
		||||
		out = append(out, in[i])
 | 
			
		||||
	}
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Parse tree information from the (uncompressed) raw
 | 
			
		||||
// data from the tree object.
 | 
			
		||||
func parseTreeData(tree *Tree, data []byte) ([]*TreeEntry, error) {
 | 
			
		||||
	entries := make([]*TreeEntry, 0, 10)
 | 
			
		||||
	l := len(data)
 | 
			
		||||
	pos := 0
 | 
			
		||||
	for pos < l {
 | 
			
		||||
		entry := new(TreeEntry)
 | 
			
		||||
		entry.ptree = tree
 | 
			
		||||
		step := 6
 | 
			
		||||
		switch string(data[pos : pos+step]) {
 | 
			
		||||
		case "100644":
 | 
			
		||||
			entry.mode = ModeBlob
 | 
			
		||||
			entry.Type = BLOB
 | 
			
		||||
		case "100755":
 | 
			
		||||
			entry.mode = ModeExec
 | 
			
		||||
			entry.Type = BLOB
 | 
			
		||||
		case "120000":
 | 
			
		||||
			entry.mode = ModeSymlink
 | 
			
		||||
			entry.Type = BLOB
 | 
			
		||||
		case "160000":
 | 
			
		||||
			entry.mode = ModeCommit
 | 
			
		||||
			entry.Type = COMMIT
 | 
			
		||||
 | 
			
		||||
			step = 8
 | 
			
		||||
		case "040000":
 | 
			
		||||
			entry.mode = ModeTree
 | 
			
		||||
			entry.Type = TREE
 | 
			
		||||
		default:
 | 
			
		||||
			return nil, errors.New("unknown type: " + string(data[pos:pos+step]))
 | 
			
		||||
		}
 | 
			
		||||
		pos += step + 6 // Skip string type of entry type.
 | 
			
		||||
 | 
			
		||||
		step = 40
 | 
			
		||||
		id, err := NewIdFromString(string(data[pos : pos+step]))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		entry.ID = id
 | 
			
		||||
		pos += step + 1 // Skip half of sha1.
 | 
			
		||||
 | 
			
		||||
		step = bytes.IndexByte(data[pos:], '\n')
 | 
			
		||||
 | 
			
		||||
		// In case entry name is surrounded by double quotes(it happens only in git-shell).
 | 
			
		||||
		if data[pos] == '"' {
 | 
			
		||||
			entry.name = string(UnescapeChars(data[pos+1 : pos+step-1]))
 | 
			
		||||
		} else {
 | 
			
		||||
			entry.name = string(data[pos : pos+step])
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pos += step + 1
 | 
			
		||||
		entries = append(entries, entry)
 | 
			
		||||
	}
 | 
			
		||||
	return entries, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Tree) SubTree(rpath string) (*Tree, error) {
 | 
			
		||||
	if len(rpath) == 0 {
 | 
			
		||||
		return t, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	paths := strings.Split(rpath, "/")
 | 
			
		||||
	var err error
 | 
			
		||||
	var g = t
 | 
			
		||||
	var p = t
 | 
			
		||||
	var te *TreeEntry
 | 
			
		||||
	for _, name := range paths {
 | 
			
		||||
		te, err = p.GetTreeEntryByPath(name)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		g, err = t.repo.getTree(te.ID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		g.ptree = p
 | 
			
		||||
		p = g
 | 
			
		||||
	}
 | 
			
		||||
	return g, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Tree) ListEntries(relpath string) (Entries, error) {
 | 
			
		||||
	if t.entriesParsed {
 | 
			
		||||
		return t.entries, nil
 | 
			
		||||
	}
 | 
			
		||||
	t.entriesParsed = true
 | 
			
		||||
 | 
			
		||||
	stdout, stderr, err := com.ExecCmdDirBytes(t.repo.Path,
 | 
			
		||||
		"git", "ls-tree", t.ID.String())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if strings.Contains(err.Error(), "exit status 128") {
 | 
			
		||||
			return nil, errors.New(strings.TrimSpace(string(stderr)))
 | 
			
		||||
		}
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	t.entries, err = parseTreeData(t, stdout)
 | 
			
		||||
	return t.entries, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewTree(repo *Repository, id sha1) *Tree {
 | 
			
		||||
	tree := new(Tree)
 | 
			
		||||
	tree.ID = id
 | 
			
		||||
	tree.repo = repo
 | 
			
		||||
	return tree
 | 
			
		||||
}
 | 
			
		||||
@@ -1,59 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) {
 | 
			
		||||
	if len(relpath) == 0 {
 | 
			
		||||
		return &TreeEntry{
 | 
			
		||||
			ID:   t.ID,
 | 
			
		||||
			Type: TREE,
 | 
			
		||||
			mode: ModeTree,
 | 
			
		||||
		}, nil
 | 
			
		||||
		// return nil, fmt.Errorf("GetTreeEntryByPath(empty relpath): %v", ErrNotExist)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	relpath = path.Clean(relpath)
 | 
			
		||||
	parts := strings.Split(relpath, "/")
 | 
			
		||||
	var err error
 | 
			
		||||
	tree := t
 | 
			
		||||
	for i, name := range parts {
 | 
			
		||||
		if i == len(parts)-1 {
 | 
			
		||||
			entries, err := tree.ListEntries(path.Dir(relpath))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			for _, v := range entries {
 | 
			
		||||
				if v.name == name {
 | 
			
		||||
					return v, nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			tree, err = tree.SubTree(name)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil, fmt.Errorf("GetTreeEntryByPath: %v", ErrNotExist)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Tree) GetBlobByPath(rpath string) (*Blob, error) {
 | 
			
		||||
	entry, err := t.GetTreeEntryByPath(rpath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !entry.IsDir() {
 | 
			
		||||
		return entry.Blob(), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, ErrNotExist
 | 
			
		||||
}
 | 
			
		||||
@@ -1,113 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/com"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type EntryMode int
 | 
			
		||||
 | 
			
		||||
// There are only a few file modes in Git. They look like unix file modes, but they can only be
 | 
			
		||||
// one of these.
 | 
			
		||||
const (
 | 
			
		||||
	ModeBlob    EntryMode = 0100644
 | 
			
		||||
	ModeExec    EntryMode = 0100755
 | 
			
		||||
	ModeSymlink EntryMode = 0120000
 | 
			
		||||
	ModeCommit  EntryMode = 0160000
 | 
			
		||||
	ModeTree    EntryMode = 0040000
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type TreeEntry struct {
 | 
			
		||||
	ID   sha1
 | 
			
		||||
	Type ObjectType
 | 
			
		||||
 | 
			
		||||
	mode EntryMode
 | 
			
		||||
	name string
 | 
			
		||||
 | 
			
		||||
	ptree *Tree
 | 
			
		||||
 | 
			
		||||
	commited bool
 | 
			
		||||
 | 
			
		||||
	size  int64
 | 
			
		||||
	sized bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (te *TreeEntry) Name() string {
 | 
			
		||||
	return te.name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (te *TreeEntry) Size() int64 {
 | 
			
		||||
	if te.IsDir() {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if te.sized {
 | 
			
		||||
		return te.size
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stdout, _, err := com.ExecCmdDir(te.ptree.repo.Path, "git", "cat-file", "-s", te.ID.String())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	te.sized = true
 | 
			
		||||
	te.size = com.StrTo(strings.TrimSpace(stdout)).MustInt64()
 | 
			
		||||
	return te.size
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (te *TreeEntry) IsSubModule() bool {
 | 
			
		||||
	return te.mode == ModeCommit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (te *TreeEntry) IsDir() bool {
 | 
			
		||||
	return te.mode == ModeTree
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (te *TreeEntry) EntryMode() EntryMode {
 | 
			
		||||
	return te.mode
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (te *TreeEntry) Blob() *Blob {
 | 
			
		||||
	return &Blob{
 | 
			
		||||
		repo:      te.ptree.repo,
 | 
			
		||||
		TreeEntry: te,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Entries []*TreeEntry
 | 
			
		||||
 | 
			
		||||
var sorter = []func(t1, t2 *TreeEntry) bool{
 | 
			
		||||
	func(t1, t2 *TreeEntry) bool {
 | 
			
		||||
		return (t1.IsDir() || t1.IsSubModule()) && !t2.IsDir() && !t2.IsSubModule()
 | 
			
		||||
	},
 | 
			
		||||
	func(t1, t2 *TreeEntry) bool {
 | 
			
		||||
		return t1.name < t2.name
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (bs Entries) Len() int      { return len(bs) }
 | 
			
		||||
func (bs Entries) Swap(i, j int) { bs[i], bs[j] = bs[j], bs[i] }
 | 
			
		||||
func (bs Entries) Less(i, j int) bool {
 | 
			
		||||
	t1, t2 := bs[i], bs[j]
 | 
			
		||||
	var k int
 | 
			
		||||
	for k = 0; k < len(sorter)-1; k++ {
 | 
			
		||||
		sort := sorter[k]
 | 
			
		||||
		switch {
 | 
			
		||||
		case sort(t1, t2):
 | 
			
		||||
			return true
 | 
			
		||||
		case sort(t2, t1):
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return sorter[k](t1, t2)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (bs Entries) Sort() {
 | 
			
		||||
	sort.Sort(bs)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,82 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"container/list"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const prettyLogFormat = `--pretty=format:%H`
 | 
			
		||||
 | 
			
		||||
func parsePrettyFormatLog(repo *Repository, logByts []byte) (*list.List, error) {
 | 
			
		||||
	l := list.New()
 | 
			
		||||
	if len(logByts) == 0 {
 | 
			
		||||
		return l, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	parts := bytes.Split(logByts, []byte{'\n'})
 | 
			
		||||
 | 
			
		||||
	for _, commitId := range parts {
 | 
			
		||||
		commit, err := repo.GetCommit(string(commitId))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		l.PushBack(commit)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return l, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RefEndName(refStr string) string {
 | 
			
		||||
	if strings.HasPrefix(refStr, "refs/heads/") {
 | 
			
		||||
		// trim the "refs/heads/"
 | 
			
		||||
		return refStr[len("refs/heads/"):]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	index := strings.LastIndex(refStr, "/")
 | 
			
		||||
	if index != -1 {
 | 
			
		||||
		return refStr[index+1:]
 | 
			
		||||
	}
 | 
			
		||||
	return refStr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// If the object is stored in its own file (i.e not in a pack file),
 | 
			
		||||
// this function returns the full path to the object file.
 | 
			
		||||
// It does not test if the file exists.
 | 
			
		||||
func filepathFromSHA1(rootdir, sha1 string) string {
 | 
			
		||||
	return filepath.Join(rootdir, "objects", sha1[:2], sha1[2:])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isDir returns true if given path is a directory,
 | 
			
		||||
// or returns false when it's a file or does not exist.
 | 
			
		||||
func isDir(dir string) bool {
 | 
			
		||||
	f, e := os.Stat(dir)
 | 
			
		||||
	if e != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return f.IsDir()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isFile returns true if given path is a file,
 | 
			
		||||
// or returns false when it's a directory or does not exist.
 | 
			
		||||
func isFile(filePath string) bool {
 | 
			
		||||
	f, e := os.Stat(filePath)
 | 
			
		||||
	if e != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return !f.IsDir()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func concatenateError(err error, stderr string) error {
 | 
			
		||||
	if len(stderr) == 0 {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Errorf("%v: %s", err, stderr)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,104 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/com"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// Cached Git version.
 | 
			
		||||
	gitVer *Version
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Version represents version of Git.
 | 
			
		||||
type Version struct {
 | 
			
		||||
	Major, Minor, Patch int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ParseVersion(verStr string) (*Version, error) {
 | 
			
		||||
	infos := strings.Split(verStr, ".")
 | 
			
		||||
	if len(infos) < 3 {
 | 
			
		||||
		return nil, errors.New("incorrect version input")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	v := &Version{}
 | 
			
		||||
	for i, s := range infos {
 | 
			
		||||
		switch i {
 | 
			
		||||
		case 0:
 | 
			
		||||
			v.Major, _ = com.StrTo(s).Int()
 | 
			
		||||
		case 1:
 | 
			
		||||
			v.Minor, _ = com.StrTo(s).Int()
 | 
			
		||||
		case 2:
 | 
			
		||||
			v.Patch, _ = com.StrTo(strings.TrimSpace(s)).Int()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return v, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func MustParseVersion(verStr string) *Version {
 | 
			
		||||
	v, _ := ParseVersion(verStr)
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Compare compares two versions,
 | 
			
		||||
// it returns 1 if original is greater, -1 if original is smaller, 0 if equal.
 | 
			
		||||
func (v *Version) Compare(that *Version) int {
 | 
			
		||||
	if v.Major > that.Major {
 | 
			
		||||
		return 1
 | 
			
		||||
	} else if v.Major < that.Major {
 | 
			
		||||
		return -1
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if v.Minor > that.Minor {
 | 
			
		||||
		return 1
 | 
			
		||||
	} else if v.Minor < that.Minor {
 | 
			
		||||
		return -1
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if v.Patch > that.Patch {
 | 
			
		||||
		return 1
 | 
			
		||||
	} else if v.Patch < that.Patch {
 | 
			
		||||
		return -1
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *Version) LessThan(that *Version) bool {
 | 
			
		||||
	return v.Compare(that) < 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *Version) AtLeast(that *Version) bool {
 | 
			
		||||
	return v.Compare(that) >= 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *Version) String() string {
 | 
			
		||||
	return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetVersion returns current Git version installed.
 | 
			
		||||
func GetVersion() (*Version, error) {
 | 
			
		||||
	if gitVer != nil {
 | 
			
		||||
		return gitVer, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stdout, stderr, err := com.ExecCmd("git", "version")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New(stderr)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	infos := strings.Split(stdout, " ")
 | 
			
		||||
	if len(infos) < 3 {
 | 
			
		||||
		return nil, errors.New("not enough output")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gitVer, err = ParseVersion(infos[2])
 | 
			
		||||
	return gitVer, err
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user