1
1
mirror of https://github.com/go-gitea/gitea synced 2025-07-22 10:18:38 +00:00

New UI merge in progress

This commit is contained in:
Unknwon
2014-07-26 00:24:27 -04:00
parent 0a739cf9ac
commit 8dd07c0ddd
199 changed files with 15030 additions and 9325 deletions

26
modules/git/blob.go Normal file
View File

@@ -0,0 +1,26 @@
// 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
}

78
modules/git/commit.go Normal file
View File

@@ -0,0 +1,78 @@
// 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 (
"container/list"
"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
}
// 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) GetCommitOfRelPath(relPath string) (*Commit, error) {
return c.repo.getCommitOfRelPath(c.Id, relPath)
}

View File

@@ -0,0 +1,36 @@
// 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
}

27
modules/git/repo.go Normal file
View File

@@ -0,0 +1,27 @@
// 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 (
"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
}
return &Repository{Path: repoPath}, nil
}

View File

@@ -0,0 +1,38 @@
// 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 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, errors.New(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
}

234
modules/git/repo_commit.go Normal file
View File

@@ -0,0 +1,234 @@
// 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"
"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)
}
// 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, bytErr, err := com.ExecCmdDirBytes(repo.Path, "git", "cat-file", "-p", id.String())
if err != nil {
return nil, errors.New(string(bytErr))
}
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) {
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()
}
// 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 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) getCommitsBefore(id sha1) (*list.List, error) {
l := list.New()
lock := new(sync.Mutex)
err := repo.commitsBefore(lock, l, nil, id, 0)
return l, err
}
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)
}

View File

@@ -0,0 +1,14 @@
// 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"
)

96
modules/git/repo_tag.go Normal file
View File

@@ -0,0 +1,96 @@
// 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)
}
// GetTags returns all tags of given repository.
func (repo *Repository) GetTags() ([]string, error) {
stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", "-l")
if err != nil {
return nil, errors.New(stderr)
}
tags := strings.Split(stdout, "\n")
return tags[:len(tags)-1], 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)
}
// 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
}

32
modules/git/repo_tree.go Normal file
View File

@@ -0,0 +1,32 @@
// 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
}

87
modules/git/sha1.go Normal file
View File

@@ -0,0 +1,87 @@
// 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 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)
}

40
modules/git/signature.go Normal file
View File

@@ -0,0 +1,40 @@
// 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 this:
// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
// but without the "author " at the beginning (this method should)
// be used for author and committer.
//
// FIXME: include timezone!
func newSignatureFromCommitline(line []byte) (*Signature, error) {
sig := new(Signature)
emailstart := bytes.IndexByte(line, '<')
sig.Name = string(line[:emailstart-1])
emailstop := bytes.IndexByte(line, '>')
sig.Email = string(line[emailstart+1 : emailstop])
timestop := bytes.IndexByte(line[emailstop+2:], ' ')
timestring := string(line[emailstop+2 : emailstop+2+timestop])
seconds, err := strconv.ParseInt(timestring, 10, 64)
if err != nil {
return nil, err
}
sig.When = time.Unix(seconds, 0)
return sig, nil
}

67
modules/git/tag.go Normal file
View File

@@ -0,0 +1,67 @@
// 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
}

124
modules/git/tree.go Normal file
View File

@@ -0,0 +1,124 @@
// 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
}
// 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
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')
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, _, err := com.ExecCmdDirBytes(t.repo.Path,
"git", "ls-tree", t.Id.String())
if err != nil {
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
}

46
modules/git/tree_blob.go Normal file
View File

@@ -0,0 +1,46 @@
// 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)
}

109
modules/git/tree_entry.go Normal file
View File

@@ -0,0 +1,109 @@
// 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) 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() && !t2.IsDir()
},
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)
}

27
modules/git/utils.go Normal file
View File

@@ -0,0 +1,27 @@
// 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 (
"path/filepath"
"strings"
)
const prettyLogFormat = `--pretty=format:%H`
func RefEndName(refStr string) string {
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:])
}

43
modules/git/version.go Normal file
View File

@@ -0,0 +1,43 @@
// 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"
)
// Version represents version of Git.
type Version struct {
Major, Minor, Patch int
}
// GetVersion returns current Git version installed.
func GetVersion() (Version, error) {
stdout, stderr, err := com.ExecCmd("git", "version")
if err != nil {
return Version{}, errors.New(stderr)
}
infos := strings.Split(stdout, " ")
if len(infos) < 3 {
return Version{}, errors.New("not enough output")
}
v := Version{}
for i, s := range strings.Split(strings.TrimSpace(infos[2]), ".") {
switch i {
case 0:
v.Major, _ = com.StrTo(s).Int()
case 1:
v.Minor, _ = com.StrTo(s).Int()
case 2:
v.Patch, _ = com.StrTo(s).Int()
}
}
return v, nil
}