2014-02-15 03:16:54 +04:00
// 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.
2014-02-14 18:20:57 +04:00
package models
import (
2014-03-19 10:39:07 +04:00
"container/list"
2014-03-10 04:06:29 +04:00
"errors"
2014-03-11 04:48:58 +04:00
"fmt"
2014-03-11 08:18:44 +04:00
"io/ioutil"
2014-02-14 18:20:57 +04:00
"os"
2014-03-23 15:53:50 +04:00
"os/exec"
2014-03-17 22:03:58 +04:00
"path"
2014-02-14 18:20:57 +04:00
"path/filepath"
2014-03-20 19:41:24 +04:00
"regexp"
2014-02-14 18:20:57 +04:00
"strings"
2014-03-17 19:56:50 +04:00
"sync"
2014-02-14 18:20:57 +04:00
"time"
2014-03-11 08:53:53 +04:00
"unicode/utf8"
2014-02-14 18:20:57 +04:00
2014-03-17 19:56:50 +04:00
"github.com/Unknwon/cae/zip"
2014-03-11 09:32:36 +04:00
"github.com/Unknwon/com"
2014-03-17 19:56:50 +04:00
"github.com/gogits/git"
2014-03-08 02:22:15 +04:00
2014-03-11 09:32:36 +04:00
"github.com/gogits/gogs/modules/base"
2014-03-08 02:22:15 +04:00
"github.com/gogits/gogs/modules/log"
2014-02-14 18:20:57 +04:00
)
2014-03-11 09:32:36 +04:00
var (
2014-03-21 00:04:56 +04:00
ErrRepoAlreadyExist = errors . New ( "Repository already exist" )
ErrRepoNotExist = errors . New ( "Repository does not exist" )
ErrRepoFileNotExist = errors . New ( "Target Repo file does not exist" )
ErrRepoNameIllegal = errors . New ( "Repository name contains illegal characters" )
ErrRepoFileNotLoaded = fmt . Errorf ( "repo file not loaded" )
2014-03-11 09:32:36 +04:00
)
2014-03-21 00:04:56 +04:00
var gitInitLocker = sync . Mutex { }
2014-03-10 04:06:29 +04:00
var (
2014-03-21 00:04:56 +04:00
LanguageIgns , Licenses [ ] string
2014-03-10 04:06:29 +04:00
)
2014-03-21 09:48:10 +04:00
func LoadRepoConfig ( ) {
2014-03-11 09:32:36 +04:00
LanguageIgns = strings . Split ( base . Cfg . MustValue ( "repository" , "LANG_IGNS" ) , "|" )
Licenses = strings . Split ( base . Cfg . MustValue ( "repository" , "LICENSES" ) , "|" )
2014-03-21 09:48:10 +04:00
}
2014-03-17 19:56:50 +04:00
2014-03-21 09:48:10 +04:00
func NewRepoContext ( ) {
2014-03-17 19:56:50 +04:00
zip . Verbose = false
2014-03-17 23:58:32 +04:00
// Check if server has basic git setting.
stdout , _ , err := com . ExecCmd ( "git" , "config" , "--get" , "user.name" )
if err != nil {
fmt . Printf ( "repo.init(fail to get git user.name): %v" , err )
os . Exit ( 2 )
} else if len ( stdout ) == 0 {
if _ , _ , err = com . ExecCmd ( "git" , "config" , "--global" , "user.email" , "gogitservice@gmail.com" ) ; err != nil {
fmt . Printf ( "repo.init(fail to set git user.email): %v" , err )
os . Exit ( 2 )
} else if _ , _ , err = com . ExecCmd ( "git" , "config" , "--global" , "user.name" , "Gogs" ) ; err != nil {
fmt . Printf ( "repo.init(fail to set git user.name): %v" , err )
os . Exit ( 2 )
}
}
2014-03-20 19:41:24 +04:00
// Initialize illegal patterns.
for i := range illegalPatterns [ 1 : ] {
pattern := ""
for j := range illegalPatterns [ i + 1 ] {
pattern += "[" + string ( illegalPatterns [ i + 1 ] [ j ] - 32 ) + string ( illegalPatterns [ i + 1 ] [ j ] ) + "]"
}
illegalPatterns [ i + 1 ] = pattern
}
2014-03-11 09:32:36 +04:00
}
2014-03-21 00:04:56 +04:00
// Repository represents a git repository.
type Repository struct {
Id int64
OwnerId int64 ` xorm:"unique(s)" `
ForkId int64
LowerName string ` xorm:"unique(s) index not null" `
Name string ` xorm:"index not null" `
Description string
Website string
NumWatches int
NumStars int
NumForks int
2014-03-22 19:59:14 +04:00
IsPrivate bool
IsBare bool
2014-03-21 00:04:56 +04:00
Created time . Time ` xorm:"created" `
Updated time . Time ` xorm:"updated" `
}
2014-03-17 22:03:58 +04:00
// IsRepositoryExist returns true if the repository with given name under user has already existed.
2014-03-10 04:06:29 +04:00
func IsRepositoryExist ( user * User , repoName string ) ( bool , error ) {
repo := Repository { OwnerId : user . Id }
has , err := orm . Where ( "lower_name = ?" , strings . ToLower ( repoName ) ) . Get ( & repo )
2014-02-19 13:50:53 +04:00
if err != nil {
return has , err
}
2014-03-10 04:06:29 +04:00
s , err := os . Stat ( RepoPath ( user . Name , repoName ) )
2014-02-19 13:50:53 +04:00
if err != nil {
2014-03-17 19:56:50 +04:00
return false , nil // Error simply means does not exist, but we don't want to show up.
2014-02-19 13:50:53 +04:00
}
return s . IsDir ( ) , nil
2014-02-14 18:20:57 +04:00
}
2014-03-20 19:41:24 +04:00
var (
// Define as all lower case!!
2014-03-24 19:44:47 +04:00
illegalPatterns = [ ] string { "[.][Gg][Ii][Tt]" , "raw" , "user" , "help" , "stars" , "issues" , "pulls" , "commits" , "admin" , "repo" , "template" , "admin" }
2014-03-20 19:41:24 +04:00
)
// IsLegalName returns false if name contains illegal characters.
func IsLegalName ( repoName string ) bool {
for _ , pattern := range illegalPatterns {
has , _ := regexp . MatchString ( pattern , repoName )
if has {
return false
}
}
return true
}
2014-03-08 02:08:21 +04:00
// CreateRepository creates a repository for given user or orgnaziation.
2014-03-11 09:32:36 +04:00
func CreateRepository ( user * User , repoName , desc , repoLang , license string , private bool , initReadme bool ) ( * Repository , error ) {
2014-03-20 19:41:24 +04:00
if ! IsLegalName ( repoName ) {
return nil , ErrRepoNameIllegal
}
2014-03-10 04:06:29 +04:00
isExist , err := IsRepositoryExist ( user , repoName )
2014-02-14 18:20:57 +04:00
if err != nil {
return nil , err
2014-03-10 04:06:29 +04:00
} else if isExist {
return nil , ErrRepoAlreadyExist
}
repo := & Repository {
OwnerId : user . Id ,
Name : repoName ,
LowerName : strings . ToLower ( repoName ) ,
Description : desc ,
2014-03-22 19:59:14 +04:00
IsPrivate : private ,
IsBare : repoLang == "" && license == "" && ! initReadme ,
2014-03-10 04:06:29 +04:00
}
2014-03-11 08:53:53 +04:00
2014-03-17 22:03:58 +04:00
repoPath := RepoPath ( user . Name , repoName )
if err = initRepository ( repoPath , user , repo , initReadme , repoLang , license ) ; err != nil {
2014-03-11 08:53:53 +04:00
return nil , err
}
2014-02-14 18:20:57 +04:00
session := orm . NewSession ( )
defer session . Close ( )
session . Begin ( )
2014-03-10 04:06:29 +04:00
if _ , err = session . Insert ( repo ) ; err != nil {
2014-03-17 22:03:58 +04:00
if err2 := os . RemoveAll ( repoPath ) ; err2 != nil {
log . Error ( "repo.CreateRepository(repo): %v" , err )
2014-03-11 04:48:58 +04:00
return nil , errors . New ( fmt . Sprintf (
2014-03-17 22:03:58 +04:00
"delete repo directory %s/%s failed(1): %v" , user . Name , repoName , err2 ) )
2014-02-20 10:53:56 +04:00
}
2014-02-14 18:20:57 +04:00
session . Rollback ( )
return nil , err
}
2014-03-10 04:06:29 +04:00
access := Access {
UserName : user . Name ,
2014-02-25 11:11:54 +04:00
RepoName : repo . Name ,
Mode : AU_WRITABLE ,
}
2014-03-10 04:06:29 +04:00
if _ , err = session . Insert ( & access ) ; err != nil {
2014-03-11 08:18:44 +04:00
session . Rollback ( )
2014-03-17 22:03:58 +04:00
if err2 := os . RemoveAll ( repoPath ) ; err2 != nil {
log . Error ( "repo.CreateRepository(access): %v" , err )
2014-03-11 04:48:58 +04:00
return nil , errors . New ( fmt . Sprintf (
2014-03-17 22:03:58 +04:00
"delete repo directory %s/%s failed(2): %v" , user . Name , repoName , err2 ) )
2014-02-25 11:11:54 +04:00
}
return nil , err
}
2014-03-10 04:06:29 +04:00
2014-03-19 11:46:16 +04:00
rawSql := "UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?"
2014-03-17 22:03:58 +04:00
if _ , err = session . Exec ( rawSql , user . Id ) ; err != nil {
2014-03-11 08:18:44 +04:00
session . Rollback ( )
2014-03-17 22:03:58 +04:00
if err2 := os . RemoveAll ( repoPath ) ; err2 != nil {
log . Error ( "repo.CreateRepository(repo count): %v" , err )
2014-03-11 04:48:58 +04:00
return nil , errors . New ( fmt . Sprintf (
2014-03-17 22:03:58 +04:00
"delete repo directory %s/%s failed(3): %v" , user . Name , repoName , err2 ) )
2014-02-20 10:53:56 +04:00
}
2014-02-14 18:20:57 +04:00
return nil , err
}
2014-03-10 04:06:29 +04:00
if err = session . Commit ( ) ; err != nil {
2014-03-11 08:18:44 +04:00
session . Rollback ( )
2014-03-17 22:03:58 +04:00
if err2 := os . RemoveAll ( repoPath ) ; err2 != nil {
log . Error ( "repo.CreateRepository(commit): %v" , err )
2014-03-11 04:48:58 +04:00
return nil , errors . New ( fmt . Sprintf (
2014-03-17 22:03:58 +04:00
"delete repo directory %s/%s failed(3): %v" , user . Name , repoName , err2 ) )
2014-02-20 10:53:56 +04:00
}
2014-02-14 18:20:57 +04:00
return nil , err
}
2014-03-13 09:14:43 +04:00
2014-03-23 15:53:50 +04:00
c := exec . Command ( "git" , "update-server-info" )
2014-03-23 16:04:26 +04:00
c . Dir = repoPath
2014-03-23 15:53:50 +04:00
err = c . Run ( )
if err != nil {
log . Error ( "repo.CreateRepository(exec update-server-info): %v" , err )
}
2014-03-13 09:14:43 +04:00
return repo , NewRepoAction ( user , repo )
2014-03-17 19:56:50 +04:00
}
// extractGitBareZip extracts git-bare.zip to repository path.
func extractGitBareZip ( repoPath string ) error {
z , err := zip . Open ( "conf/content/git-bare.zip" )
if err != nil {
fmt . Println ( "shi?" )
return err
}
defer z . Close ( )
return z . ExtractTo ( repoPath )
}
// initRepoCommit temporarily changes with work directory.
func initRepoCommit ( tmpPath string , sig * git . Signature ) error {
gitInitLocker . Lock ( )
defer gitInitLocker . Unlock ( )
// Change work directory.
curPath , err := os . Getwd ( )
if err != nil {
return err
} else if err = os . Chdir ( tmpPath ) ; err != nil {
return err
}
defer os . Chdir ( curPath )
2014-03-17 23:58:32 +04:00
var stderr string
if _ , stderr , err = com . ExecCmd ( "git" , "add" , "--all" ) ; err != nil {
2014-03-17 19:56:50 +04:00
return err
}
2014-03-18 00:03:40 +04:00
log . Info ( "stderr(1): %s" , stderr )
2014-03-17 23:58:32 +04:00
if _ , stderr , err = com . ExecCmd ( "git" , "commit" , fmt . Sprintf ( "--author='%s <%s>'" , sig . Name , sig . Email ) ,
2014-03-17 19:56:50 +04:00
"-m" , "Init commit" ) ; err != nil {
return err
}
2014-03-18 00:03:40 +04:00
log . Info ( "stderr(2): %s" , stderr )
2014-03-17 23:58:32 +04:00
if _ , stderr , err = com . ExecCmd ( "git" , "push" , "origin" , "master" ) ; err != nil {
2014-03-17 19:56:50 +04:00
return err
}
2014-03-18 00:03:40 +04:00
log . Info ( "stderr(3): %s" , stderr )
2014-03-17 19:56:50 +04:00
return nil
2014-02-14 18:20:57 +04:00
}
2014-03-11 04:48:58 +04:00
// InitRepository initializes README and .gitignore if needed.
2014-03-11 09:32:36 +04:00
func initRepository ( f string , user * User , repo * Repository , initReadme bool , repoLang , license string ) error {
2014-03-17 19:56:50 +04:00
repoPath := RepoPath ( user . Name , repo . Name )
2014-03-11 14:10:19 +04:00
2014-03-17 19:56:50 +04:00
// Create bare new repository.
if err := extractGitBareZip ( repoPath ) ; err != nil {
return err
}
2014-03-24 18:26:05 +04:00
/ *
2014-03-18 01:00:35 +04:00
// hook/post-update
pu , err := os . OpenFile ( filepath . Join ( repoPath , "hooks" , "post-update" ) , os . O_CREATE | os . O_WRONLY , 0777 )
if err != nil {
return err
}
defer pu . Close ( )
// TODO: Windows .bat
if _ , err = pu . WriteString ( fmt . Sprintf ( "#!/usr/bin/env bash\n%s update\n" , appPath ) ) ; err != nil {
return err
}
2014-03-21 20:48:26 +04:00
// hook/post-update
pu2 , err := os . OpenFile ( filepath . Join ( repoPath , "hooks" , "post-receive" ) , os . O_CREATE | os . O_WRONLY , 0777 )
if err != nil {
return err
}
defer pu2 . Close ( )
// TODO: Windows .bat
if _ , err = pu2 . WriteString ( "#!/usr/bin/env bash\ngit update-server-info\n" ) ; err != nil {
return err
}
2014-03-24 18:26:05 +04:00
* /
2014-03-21 20:48:26 +04:00
2014-03-17 19:56:50 +04:00
// Initialize repository according to user's choice.
fileName := map [ string ] string { }
2014-03-11 14:10:19 +04:00
if initReadme {
fileName [ "readme" ] = "README.md"
}
if repoLang != "" {
fileName [ "gitign" ] = ".gitignore"
2014-03-11 08:53:53 +04:00
}
2014-03-11 14:10:19 +04:00
if license != "" {
fileName [ "license" ] = "LICENSE"
}
2014-03-17 19:56:50 +04:00
// Clone to temprory path and do the init commit.
tmpDir := filepath . Join ( os . TempDir ( ) , fmt . Sprintf ( "%d" , time . Now ( ) . Nanosecond ( ) ) )
os . MkdirAll ( tmpDir , os . ModePerm )
2014-03-11 08:18:44 +04:00
2014-03-17 19:56:50 +04:00
if _ , _ , err := com . ExecCmd ( "git" , "clone" , repoPath , tmpDir ) ; err != nil {
return err
}
2014-03-11 08:18:44 +04:00
// README
2014-03-11 14:10:19 +04:00
if initReadme {
defaultReadme := repo . Name + "\n" + strings . Repeat ( "=" ,
utf8 . RuneCountInString ( repo . Name ) ) + "\n\n" + repo . Description
2014-03-17 19:56:50 +04:00
if err := ioutil . WriteFile ( filepath . Join ( tmpDir , fileName [ "readme" ] ) ,
2014-03-11 14:10:19 +04:00
[ ] byte ( defaultReadme ) , 0644 ) ; err != nil {
return err
}
2014-03-11 08:18:44 +04:00
}
2014-03-11 04:48:58 +04:00
2014-03-17 19:56:50 +04:00
// .gitignore
2014-03-11 14:10:19 +04:00
if repoLang != "" {
filePath := "conf/gitignore/" + repoLang
if com . IsFile ( filePath ) {
if _ , err := com . Copy ( filePath ,
2014-03-17 19:56:50 +04:00
filepath . Join ( tmpDir , fileName [ "gitign" ] ) ) ; err != nil {
2014-03-11 14:10:19 +04:00
return err
}
2014-03-11 09:32:36 +04:00
}
}
2014-03-11 08:53:53 +04:00
2014-03-17 19:56:50 +04:00
// LICENSE
2014-03-11 14:10:19 +04:00
if license != "" {
filePath := "conf/license/" + license
if com . IsFile ( filePath ) {
if _ , err := com . Copy ( filePath ,
2014-03-17 19:56:50 +04:00
filepath . Join ( tmpDir , fileName [ "license" ] ) ) ; err != nil {
2014-03-11 14:10:19 +04:00
return err
}
2014-03-11 09:32:36 +04:00
}
}
2014-03-11 08:18:44 +04:00
2014-03-18 01:00:35 +04:00
if len ( fileName ) == 0 {
return nil
}
2014-03-17 19:56:50 +04:00
// Apply changes and commit.
if err := initRepoCommit ( tmpDir , user . NewGitSig ( ) ) ; err != nil {
2014-03-16 18:32:33 +04:00
return err
}
2014-03-17 19:56:50 +04:00
return nil
2014-03-11 04:48:58 +04:00
}
2014-03-21 09:09:22 +04:00
// UserRepo reporesents a repository with user name.
type UserRepo struct {
* Repository
UserName string
}
2014-03-21 00:04:56 +04:00
// GetRepos returns given number of repository objects with offset.
2014-03-21 09:09:22 +04:00
func GetRepos ( num , offset int ) ( [ ] UserRepo , error ) {
2014-03-21 00:04:56 +04:00
repos := make ( [ ] Repository , 0 , num )
2014-03-21 09:09:22 +04:00
if err := orm . Limit ( num , offset ) . Asc ( "id" ) . Find ( & repos ) ; err != nil {
return nil , err
}
urepos := make ( [ ] UserRepo , len ( repos ) )
for i := range repos {
urepos [ i ] . Repository = & repos [ i ]
u := new ( User )
has , err := orm . Id ( urepos [ i ] . Repository . OwnerId ) . Get ( u )
if err != nil {
return nil , err
} else if ! has {
return nil , ErrUserNotExist
}
urepos [ i ] . UserName = u . Name
}
return urepos , nil
2014-03-21 00:04:56 +04:00
}
func RepoPath ( userName , repoName string ) string {
return filepath . Join ( UserPath ( userName ) , repoName + ".git" )
}
2014-03-22 12:44:57 +04:00
func UpdateRepository ( repo * Repository ) error {
2014-03-23 00:00:46 +04:00
if len ( repo . Description ) > 255 {
repo . Description = repo . Description [ : 255 ]
}
if len ( repo . Website ) > 255 {
repo . Website = repo . Website [ : 255 ]
}
2014-03-24 17:01:25 +04:00
_ , err := orm . Id ( repo . Id ) . AllCols ( ) . Update ( repo )
2014-03-22 12:44:57 +04:00
return err
}
2014-03-21 00:04:56 +04:00
// DeleteRepository deletes a repository for a user or orgnaztion.
func DeleteRepository ( userId , repoId int64 , userName string ) ( err error ) {
repo := & Repository { Id : repoId , OwnerId : userId }
has , err := orm . Get ( repo )
if err != nil {
return err
} else if ! has {
return ErrRepoNotExist
}
session := orm . NewSession ( )
if err = session . Begin ( ) ; err != nil {
return err
}
if _ , err = session . Delete ( & Repository { Id : repoId } ) ; err != nil {
session . Rollback ( )
return err
}
if _ , err := session . Delete ( & Access { UserName : userName , RepoName : repo . Name } ) ; err != nil {
session . Rollback ( )
return err
}
rawSql := "UPDATE `user` SET num_repos = num_repos - 1 WHERE id = ?"
if _ , err = session . Exec ( rawSql , userId ) ; err != nil {
session . Rollback ( )
return err
}
if _ , err = session . Delete ( & Watch { RepoId : repoId } ) ; err != nil {
session . Rollback ( )
return err
}
if err = session . Commit ( ) ; err != nil {
session . Rollback ( )
return err
}
if err = os . RemoveAll ( RepoPath ( userName , repo . Name ) ) ; err != nil {
// TODO: log and delete manully
log . Error ( "delete repo %s/%s failed: %v" , userName , repo . Name , err )
return err
}
return nil
}
2014-03-17 22:03:58 +04:00
// GetRepositoryByName returns the repository by given name under user if exists.
2014-03-22 12:44:57 +04:00
func GetRepositoryByName ( userId int64 , repoName string ) ( * Repository , error ) {
2014-03-13 06:27:11 +04:00
repo := & Repository {
2014-03-22 12:44:57 +04:00
OwnerId : userId ,
2014-03-13 06:27:11 +04:00
LowerName : strings . ToLower ( repoName ) ,
}
has , err := orm . Get ( repo )
if err != nil {
return nil , err
} else if ! has {
return nil , ErrRepoNotExist
}
return repo , err
}
2014-03-17 22:03:58 +04:00
// GetRepositoryById returns the repository by given id if exists.
2014-03-13 06:27:11 +04:00
func GetRepositoryById ( id int64 ) ( repo * Repository , err error ) {
has , err := orm . Id ( id ) . Get ( repo )
if err != nil {
return nil , err
} else if ! has {
return nil , ErrRepoNotExist
}
return repo , err
}
2014-02-19 22:04:31 +04:00
// GetRepositories returns the list of repositories of given user.
2014-03-10 04:06:29 +04:00
func GetRepositories ( user * User ) ( [ ] Repository , error ) {
repos := make ( [ ] Repository , 0 , 10 )
2014-03-16 10:28:24 +04:00
err := orm . Desc ( "updated" ) . Find ( & repos , & Repository { OwnerId : user . Id } )
2014-02-14 18:20:57 +04:00
return repos , err
}
2014-03-11 10:17:05 +04:00
func GetRepositoryCount ( user * User ) ( int64 , error ) {
return orm . Count ( & Repository { OwnerId : user . Id } )
}
2014-03-21 00:04:56 +04:00
// Watch is connection request for receiving repository notifycation.
type Watch struct {
Id int64
RepoId int64 ` xorm:"UNIQUE(watch)" `
UserId int64 ` xorm:"UNIQUE(watch)" `
}
// Watch or unwatch repository.
func WatchRepo ( userId , repoId int64 , watch bool ) ( err error ) {
if watch {
2014-03-21 00:14:50 +04:00
if _ , err = orm . Insert ( & Watch { RepoId : repoId , UserId : userId } ) ; err != nil {
return err
}
rawSql := "UPDATE `repository` SET num_watches = num_watches + 1 WHERE id = ?"
_ , err = orm . Exec ( rawSql , repoId )
2014-03-21 00:04:56 +04:00
} else {
2014-03-21 00:14:50 +04:00
if _ , err = orm . Delete ( & Watch { 0 , repoId , userId } ) ; err != nil {
return err
}
rawSql := "UPDATE `repository` SET num_watches = num_watches - 1 WHERE id = ?"
_ , err = orm . Exec ( rawSql , repoId )
2014-03-21 00:04:56 +04:00
}
return err
}
// GetWatches returns all watches of given repository.
func GetWatches ( repoId int64 ) ( [ ] Watch , error ) {
watches := make ( [ ] Watch , 0 , 10 )
err := orm . Find ( & watches , & Watch { RepoId : repoId } )
return watches , err
}
// IsWatching checks if user has watched given repository.
func IsWatching ( userId , repoId int64 ) bool {
has , _ := orm . Get ( & Watch { 0 , repoId , userId } )
return has
}
2014-02-14 18:20:57 +04:00
func StarReposiory ( user * User , repoName string ) error {
return nil
}
func UnStarRepository ( ) {
}
func WatchRepository ( ) {
}
func UnWatchRepository ( ) {
}
2014-03-02 17:58:20 +04:00
func ForkRepository ( reposName string , userId int64 ) {
}
2014-03-17 22:03:58 +04:00
// RepoFile represents a file object in git repository.
type RepoFile struct {
* git . TreeEntry
2014-03-18 07:22:19 +04:00
Path string
Size int64
Repo * git . Repository
Commit * git . Commit
2014-03-17 22:03:58 +04:00
}
// LookupBlob returns the content of an object.
func ( file * RepoFile ) LookupBlob ( ) ( * git . Blob , error ) {
if file . Repo == nil {
return nil , ErrRepoFileNotLoaded
}
return file . Repo . LookupBlob ( file . Id )
}
// GetBranches returns all branches of given repository.
func GetBranches ( userName , reposName string ) ( [ ] string , error ) {
repo , err := git . OpenRepository ( RepoPath ( userName , reposName ) )
if err != nil {
return nil , err
}
refs , err := repo . AllReferences ( )
if err != nil {
return nil , err
}
brs := make ( [ ] string , len ( refs ) )
for i , ref := range refs {
brs [ i ] = ref . Name
}
return brs , nil
}
2014-03-20 09:31:24 +04:00
func GetTargetFile ( userName , reposName , branchName , commitId , rpath string ) ( * RepoFile , error ) {
repo , err := git . OpenRepository ( RepoPath ( userName , reposName ) )
if err != nil {
return nil , err
}
commit , err := repo . GetCommit ( branchName , commitId )
if err != nil {
return nil , err
}
parts := strings . Split ( path . Clean ( rpath ) , "/" )
var entry * git . TreeEntry
tree := commit . Tree
for i , part := range parts {
if i == len ( parts ) - 1 {
entry = tree . EntryByName ( part )
if entry == nil {
return nil , ErrRepoFileNotExist
}
} else {
tree , err = repo . SubTree ( tree , part )
if err != nil {
return nil , err
}
}
}
size , err := repo . ObjectSize ( entry . Id )
if err != nil {
return nil , err
}
repoFile := & RepoFile {
entry ,
rpath ,
size ,
repo ,
commit ,
}
return repoFile , nil
}
2014-03-17 22:03:58 +04:00
// GetReposFiles returns a list of file object in given directory of repository.
2014-03-18 07:22:19 +04:00
func GetReposFiles ( userName , reposName , branchName , commitId , rpath string ) ( [ ] * RepoFile , error ) {
2014-03-17 22:03:58 +04:00
repo , err := git . OpenRepository ( RepoPath ( userName , reposName ) )
if err != nil {
return nil , err
}
2014-03-19 12:42:50 +04:00
commit , err := repo . GetCommit ( branchName , commitId )
2014-03-17 22:03:58 +04:00
if err != nil {
return nil , err
}
var repodirs [ ] * RepoFile
var repofiles [ ] * RepoFile
2014-03-18 07:22:19 +04:00
commit . Tree . Walk ( func ( dirname string , entry * git . TreeEntry ) int {
2014-03-17 22:03:58 +04:00
if dirname == rpath {
2014-03-18 07:22:19 +04:00
// TODO: size get method shoule be improved
2014-03-17 22:03:58 +04:00
size , err := repo . ObjectSize ( entry . Id )
if err != nil {
return 0
}
2014-03-18 07:22:19 +04:00
var cm = commit
2014-03-19 12:42:50 +04:00
var i int
2014-03-17 22:03:58 +04:00
for {
2014-03-19 12:42:50 +04:00
i = i + 1
//fmt.Println(".....", i, cm.Id(), cm.ParentCount())
2014-03-17 22:03:58 +04:00
if cm . ParentCount ( ) == 0 {
break
} else if cm . ParentCount ( ) == 1 {
pt , _ := repo . SubTree ( cm . Parent ( 0 ) . Tree , dirname )
if pt == nil {
break
}
pEntry := pt . EntryByName ( entry . Name )
if pEntry == nil || ! pEntry . Id . Equal ( entry . Id ) {
break
} else {
cm = cm . Parent ( 0 )
}
} else {
var emptyCnt = 0
var sameIdcnt = 0
2014-03-19 12:42:50 +04:00
var lastSameCm * git . Commit
//fmt.Println(".....", cm.ParentCount())
2014-03-17 22:03:58 +04:00
for i := 0 ; i < cm . ParentCount ( ) ; i ++ {
2014-03-19 12:42:50 +04:00
//fmt.Println("parent", i, cm.Parent(i).Id())
2014-03-17 22:03:58 +04:00
p := cm . Parent ( i )
pt , _ := repo . SubTree ( p . Tree , dirname )
var pEntry * git . TreeEntry
if pt != nil {
pEntry = pt . EntryByName ( entry . Name )
}
2014-03-19 12:42:50 +04:00
//fmt.Println("pEntry", pEntry)
2014-03-17 22:03:58 +04:00
if pEntry == nil {
2014-03-19 12:42:50 +04:00
emptyCnt = emptyCnt + 1
if emptyCnt + sameIdcnt == cm . ParentCount ( ) {
if lastSameCm == nil {
goto loop
} else {
cm = lastSameCm
break
}
2014-03-17 22:03:58 +04:00
}
} else {
2014-03-19 12:42:50 +04:00
//fmt.Println(i, "pEntry", pEntry.Id, "entry", entry.Id)
2014-03-17 22:03:58 +04:00
if ! pEntry . Id . Equal ( entry . Id ) {
goto loop
} else {
2014-03-19 12:42:50 +04:00
lastSameCm = cm . Parent ( i )
sameIdcnt = sameIdcnt + 1
if emptyCnt + sameIdcnt == cm . ParentCount ( ) {
2014-03-17 22:03:58 +04:00
// TODO: now follow the first parent commit?
2014-03-19 12:42:50 +04:00
cm = lastSameCm
//fmt.Println("sameId...")
2014-03-17 22:03:58 +04:00
break
}
}
}
}
}
}
loop :
rp := & RepoFile {
entry ,
path . Join ( dirname , entry . Name ) ,
size ,
repo ,
2014-03-18 07:22:19 +04:00
cm ,
2014-03-17 22:03:58 +04:00
}
if entry . IsFile ( ) {
repofiles = append ( repofiles , rp )
} else if entry . IsDir ( ) {
repodirs = append ( repodirs , rp )
}
}
return 0
} )
return append ( repodirs , repofiles ... ) , nil
}
2014-03-18 07:22:19 +04:00
func GetCommit ( userName , repoName , branchname , commitid string ) ( * git . Commit , error ) {
repo , err := git . OpenRepository ( RepoPath ( userName , repoName ) )
if err != nil {
return nil , err
}
2014-03-19 12:42:50 +04:00
return repo . GetCommit ( branchname , commitid )
2014-03-18 07:22:19 +04:00
}
2014-03-17 22:03:58 +04:00
// GetCommits returns all commits of given branch of repository.
2014-03-19 10:39:07 +04:00
func GetCommits ( userName , reposName , branchname string ) ( * list . List , error ) {
2014-03-17 22:03:58 +04:00
repo , err := git . OpenRepository ( RepoPath ( userName , reposName ) )
if err != nil {
return nil , err
}
r , err := repo . LookupReference ( fmt . Sprintf ( "refs/heads/%s" , branchname ) )
if err != nil {
return nil , err
}
return r . AllCommits ( )
}