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-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"
"path/filepath"
"strings"
"time"
2014-03-11 08:53:53 +04:00
"unicode/utf8"
2014-02-14 18:20:57 +04:00
git "github.com/libgit2/git2go"
2014-03-08 02:22:15 +04:00
"github.com/gogits/gogs/modules/log"
2014-02-14 18:20:57 +04:00
)
2014-03-10 04:06:29 +04:00
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
Private bool
NumWatchs int
NumStars int
NumForks int
Created time . Time ` xorm:"created" `
Updated time . Time ` xorm:"updated" `
2014-02-14 18:20:57 +04:00
}
2014-03-02 17:58:20 +04:00
type Star struct {
Id int64
RepoId int64
UserId int64
Created time . Time ` xorm:"created" `
}
2014-03-10 04:06:29 +04:00
var (
ErrRepoAlreadyExist = errors . New ( "Repository already exist" )
)
2014-02-14 18:20:57 +04:00
// check if repository is exist
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-02-20 10:53:56 +04:00
return false , nil
2014-02-19 13:50:53 +04:00
}
return s . IsDir ( ) , nil
2014-02-14 18:20:57 +04:00
}
2014-03-08 02:08:21 +04:00
// CreateRepository creates a repository for given user or orgnaziation.
2014-03-11 08:53:53 +04:00
func CreateRepository ( user * User , repoName , desc , repoLang string , private bool , initReadme bool ) ( * Repository , error ) {
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 ,
Private : private ,
}
2014-03-11 08:53:53 +04:00
f := RepoPath ( user . Name , repoName )
if err = initRepository ( f , user , repo , initReadme , repoLang ) ; err != nil {
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 {
if err2 := os . RemoveAll ( f ) ; err2 != nil {
2014-03-11 04:48:58 +04:00
return nil , errors . New ( fmt . Sprintf (
"delete repo directory %s/%s failed" , user . Name , repoName ) )
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
// TODO: RemoveAll may fail due to not root access.
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-10 04:06:29 +04:00
if err2 := os . RemoveAll ( f ) ; err2 != nil {
2014-03-11 04:48:58 +04:00
return nil , errors . New ( fmt . Sprintf (
"delete repo directory %s/%s failed" , user . Name , repoName ) )
2014-02-25 11:11:54 +04:00
}
return nil , err
}
2014-03-10 04:06:29 +04:00
if _ , err = session . Exec ( "update user set num_repos = num_repos + 1 where id = ?" , user . Id ) ; err != nil {
2014-03-11 08:18:44 +04:00
session . Rollback ( )
2014-03-10 04:06:29 +04:00
if err2 := os . RemoveAll ( f ) ; err2 != nil {
2014-03-11 04:48:58 +04:00
return nil , errors . New ( fmt . Sprintf (
"delete repo directory %s/%s failed" , user . Name , repoName ) )
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-10 04:06:29 +04:00
if err2 := os . RemoveAll ( f ) ; err2 != nil {
2014-03-11 04:48:58 +04:00
return nil , errors . New ( fmt . Sprintf (
"delete repo directory %s/%s failed" , user . Name , repoName ) )
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
return repo , 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 08:53:53 +04:00
func initRepository ( f string , user * User , repo * Repository , initReadme bool , repoLang string ) error {
fileName := map [ string ] string {
"readme" : "README.md" ,
"gitign" : ".gitignore" ,
}
workdir := os . TempDir ( ) + fmt . Sprintf ( "%d" , time . Now ( ) . Nanosecond ( ) )
2014-03-11 08:18:44 +04:00
sig := & git . Signature {
2014-03-11 08:53:53 +04:00
Name : user . Name ,
Email : user . Email ,
2014-03-11 08:18:44 +04:00
When : time . Now ( ) ,
}
// README
2014-03-11 08:53:53 +04:00
defaultReadme := repo . Name + "\n" + strings . Repeat ( "=" ,
utf8 . RuneCountInString ( repo . Name ) ) + "\n\n" + repo . Description
if err := ioutil . WriteFile ( filepath . Join ( workdir , fileName [ "readme" ] ) ,
[ ] byte ( defaultReadme ) , 0644 ) ; err != nil {
2014-03-11 08:18:44 +04:00
return err
}
2014-03-11 04:48:58 +04:00
// .gitignore
2014-03-11 08:53:53 +04:00
// if err := ioutil.WriteFile(filepath.Join(workdir, gitIgn),
// []byte(defaultREADME), 0644); err != nil {
// return err
// }
// LICENSE
2014-03-11 08:18:44 +04:00
rp , err := git . InitRepository ( f , true )
if err != nil {
return err
}
rp . SetWorkdir ( workdir , false )
idx , err := rp . Index ( )
if err != nil {
return err
}
2014-03-11 08:53:53 +04:00
if err = idx . AddByPath ( fileName [ "readme" ] ) ; err != nil {
2014-03-11 08:18:44 +04:00
return err
}
treeId , err := idx . WriteTree ( )
if err != nil {
return err
}
2014-03-11 08:53:53 +04:00
message := "Init commit"
2014-03-11 08:18:44 +04:00
tree , err := rp . LookupTree ( treeId )
if err != nil {
return err
}
2014-03-11 08:53:53 +04:00
if _ , err = rp . CreateCommit ( "HEAD" , sig , sig , message , tree ) ; err != nil {
2014-03-11 08:18:44 +04:00
return err
}
2014-03-11 04:48:58 +04:00
return nil
}
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 )
err := orm . Find ( & repos , & Repository { OwnerId : user . Id } )
2014-02-14 18:20:57 +04:00
return repos , err
}
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-02-20 10:53:56 +04:00
func RepoPath ( userName , repoName string ) string {
return filepath . Join ( UserPath ( userName ) , repoName + ".git" )
}
2014-02-15 03:16:54 +04:00
// DeleteRepository deletes a repository for a user or orgnaztion.
func DeleteRepository ( user * User , reposName string ) ( err error ) {
2014-02-14 18:20:57 +04:00
session := orm . NewSession ( )
2014-03-10 04:06:29 +04:00
if _ , err = session . Delete ( & Repository { OwnerId : user . Id , Name : reposName } ) ; err != nil {
2014-02-14 18:20:57 +04:00
session . Rollback ( )
return err
}
2014-02-15 03:16:54 +04:00
if _ , err = session . Exec ( "update user set num_repos = num_repos - 1 where id = ?" , user . Id ) ; err != nil {
2014-02-14 18:20:57 +04:00
session . Rollback ( )
return err
}
2014-02-15 03:16:54 +04:00
if err = session . Commit ( ) ; err != nil {
2014-02-14 18:20:57 +04:00
session . Rollback ( )
return err
}
2014-02-20 10:53:56 +04:00
if err = os . RemoveAll ( RepoPath ( user . Name , reposName ) ) ; err != nil {
2014-02-14 18:20:57 +04:00
// TODO: log and delete manully
2014-02-20 10:53:56 +04:00
log . Error ( "delete repo %s/%s failed" , user . Name , reposName )
2014-02-14 18:20:57 +04:00
return err
}
return nil
}