2014-02-20 06:45:43 +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.
package repo
import (
2014-04-05 11:17:57 +04:00
"encoding/base64"
"errors"
2014-04-03 23:50:55 +04:00
"fmt"
2014-03-22 21:50:50 +04:00
"path"
2014-03-24 19:56:32 +04:00
"path/filepath"
2014-03-22 21:50:50 +04:00
"strings"
2014-03-30 20:11:28 +04:00
"github.com/go-martini/martini"
2014-03-22 21:50:50 +04:00
2014-05-06 03:58:13 +04:00
"github.com/gogits/git"
2014-02-20 06:45:43 +04:00
"github.com/gogits/gogs/models"
2014-03-08 01:05:18 +04:00
"github.com/gogits/gogs/modules/auth"
2014-03-22 21:50:50 +04:00
"github.com/gogits/gogs/modules/base"
2014-03-19 12:48:45 +04:00
"github.com/gogits/gogs/modules/log"
2014-03-15 17:17:16 +04:00
"github.com/gogits/gogs/modules/middleware"
2014-02-20 06:45:43 +04:00
)
2014-04-11 02:09:57 +04:00
func Create ( ctx * middleware . Context ) {
2014-03-15 17:58:32 +04:00
ctx . Data [ "Title" ] = "Create repository"
2014-04-11 02:09:57 +04:00
ctx . Data [ "PageIsNewRepo" ] = true
2014-03-19 21:14:56 +04:00
ctx . Data [ "LanguageIgns" ] = models . LanguageIgns
ctx . Data [ "Licenses" ] = models . Licenses
2014-04-11 02:09:57 +04:00
ctx . HTML ( 200 , "repo/create" )
}
2014-03-08 01:05:18 +04:00
2014-04-11 02:09:57 +04:00
func CreatePost ( ctx * middleware . Context , form auth . CreateRepoForm ) {
ctx . Data [ "Title" ] = "Create repository"
ctx . Data [ "PageIsNewRepo" ] = true
ctx . Data [ "LanguageIgns" ] = models . LanguageIgns
ctx . Data [ "Licenses" ] = models . Licenses
2014-02-20 06:45:43 +04:00
2014-03-23 00:00:46 +04:00
if ctx . HasError ( ) {
ctx . HTML ( 200 , "repo/create" )
return
}
2014-04-13 04:35:35 +04:00
repo , err := models . CreateRepository ( ctx . User , form . RepoName , form . Description ,
form . Language , form . License , form . Private , false , form . InitReadme )
2014-03-17 19:56:50 +04:00
if err == nil {
2014-03-19 12:48:45 +04:00
log . Trace ( "%s Repository created: %s/%s" , ctx . Req . RequestURI , ctx . User . LowerName , form . RepoName )
2014-03-23 01:59:22 +04:00
ctx . Redirect ( "/" + ctx . User . Name + "/" + form . RepoName )
2014-03-09 06:25:38 +04:00
return
2014-03-17 10:36:28 +04:00
} else if err == models . ErrRepoAlreadyExist {
2014-03-15 18:52:14 +04:00
ctx . RenderWithErr ( "Repository name has already been used" , "repo/create" , & form )
2014-03-10 04:06:29 +04:00
return
2014-03-20 19:41:24 +04:00
} else if err == models . ErrRepoNameIllegal {
ctx . RenderWithErr ( models . ErrRepoNameIllegal . Error ( ) , "repo/create" , & form )
return
2014-03-10 04:06:29 +04:00
}
2014-04-13 04:35:35 +04:00
if repo != nil {
if errDelete := models . DeleteRepository ( ctx . User . Id , repo . Id , ctx . User . Name ) ; errDelete != nil {
log . Error ( "repo.MigratePost(CreatePost): %v" , errDelete )
}
}
2014-04-11 02:09:57 +04:00
ctx . Handle ( 500 , "repo.Create" , err )
2014-02-20 06:45:43 +04:00
}
2014-04-13 04:35:35 +04:00
func Migrate ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = "Migrate repository"
2014-04-11 02:09:57 +04:00
ctx . Data [ "PageIsNewRepo" ] = true
2014-04-13 04:35:35 +04:00
ctx . HTML ( 200 , "repo/migrate" )
2014-04-11 02:09:57 +04:00
}
2014-04-09 17:28:00 +04:00
2014-04-13 04:35:35 +04:00
func MigratePost ( ctx * middleware . Context , form auth . MigrateRepoForm ) {
ctx . Data [ "Title" ] = "Migrate repository"
2014-04-11 02:09:57 +04:00
ctx . Data [ "PageIsNewRepo" ] = true
2014-04-09 17:28:00 +04:00
if ctx . HasError ( ) {
2014-04-13 04:35:35 +04:00
ctx . HTML ( 200 , "repo/migrate" )
2014-04-09 17:28:00 +04:00
return
}
2014-04-13 04:35:35 +04:00
url := strings . Replace ( form . Url , "://" , fmt . Sprintf ( "://%s:%s@" , form . AuthUserName , form . AuthPasswd ) , 1 )
repo , err := models . MigrateRepository ( ctx . User , form . RepoName , form . Description , form . Private ,
form . Mirror , url )
2014-04-09 17:28:00 +04:00
if err == nil {
2014-04-13 04:35:35 +04:00
log . Trace ( "%s Repository migrated: %s/%s" , ctx . Req . RequestURI , ctx . User . LowerName , form . RepoName )
2014-04-09 17:28:00 +04:00
ctx . Redirect ( "/" + ctx . User . Name + "/" + form . RepoName )
return
} else if err == models . ErrRepoAlreadyExist {
2014-04-13 04:35:35 +04:00
ctx . RenderWithErr ( "Repository name has already been used" , "repo/migrate" , & form )
2014-04-09 17:28:00 +04:00
return
} else if err == models . ErrRepoNameIllegal {
2014-04-13 04:35:35 +04:00
ctx . RenderWithErr ( models . ErrRepoNameIllegal . Error ( ) , "repo/migrate" , & form )
return
}
if repo != nil {
if errDelete := models . DeleteRepository ( ctx . User . Id , repo . Id , ctx . User . Name ) ; errDelete != nil {
log . Error ( "repo.MigratePost(DeleteRepository): %v" , errDelete )
}
}
if strings . Contains ( err . Error ( ) , "Authentication failed" ) {
ctx . RenderWithErr ( err . Error ( ) , "repo/migrate" , & form )
2014-04-09 17:28:00 +04:00
return
}
2014-04-13 04:35:35 +04:00
ctx . Handle ( 500 , "repo.Migrate" , err )
2014-04-09 17:28:00 +04:00
}
2014-03-22 21:50:50 +04:00
func Single ( ctx * middleware . Context , params martini . Params ) {
2014-03-30 06:13:02 +04:00
branchName := ctx . Repo . BranchName
userName := ctx . Repo . Owner . Name
repoName := ctx . Repo . Repository . Name
2014-03-22 21:50:50 +04:00
2014-03-30 06:13:02 +04:00
repoLink := ctx . Repo . RepoLink
branchLink := ctx . Repo . RepoLink + "/src/" + branchName
rawLink := ctx . Repo . RepoLink + "/raw/" + branchName
2014-03-27 20:07:22 +04:00
2014-03-22 21:50:50 +04:00
// Get tree path
treename := params [ "_1" ]
if len ( treename ) > 0 && treename [ len ( treename ) - 1 ] == '/' {
2014-03-30 06:13:02 +04:00
ctx . Redirect ( repoLink + "/src/" + branchName + "/" + treename [ : len ( treename ) - 1 ] )
2014-03-22 21:50:50 +04:00
return
}
ctx . Data [ "IsRepoToolbarSource" ] = true
2014-03-30 06:13:02 +04:00
isViewBranch := ctx . Repo . IsBranch
2014-03-28 05:15:53 +04:00
ctx . Data [ "IsViewBranch" ] = isViewBranch
2014-03-27 20:07:22 +04:00
2014-04-13 05:35:36 +04:00
treePath := treename
if len ( treePath ) != 0 {
treePath = treePath + "/"
}
entry , err := ctx . Repo . Commit . GetTreeEntryByPath ( treename )
if err != nil && err != git . ErrNotExist {
ctx . Handle ( 404 , "repo.Single(GetTreeEntryByPath)" , err )
2014-03-22 21:50:50 +04:00
return
}
2014-04-13 05:35:36 +04:00
if len ( treename ) != 0 && entry == nil {
2014-03-23 09:12:55 +04:00
ctx . Handle ( 404 , "repo.Single" , nil )
2014-03-22 21:50:50 +04:00
return
}
2014-04-15 20:27:29 +04:00
if entry != nil && ! entry . IsDir ( ) {
2014-04-13 05:35:36 +04:00
blob := entry . Blob ( )
if data , err := blob . Data ( ) ; err != nil {
ctx . Handle ( 404 , "repo.Single(blob.Data)" , err )
2014-03-22 21:50:50 +04:00
} else {
2014-04-13 05:35:36 +04:00
ctx . Data [ "FileSize" ] = blob . Size ( )
2014-03-22 21:50:50 +04:00
ctx . Data [ "IsFile" ] = true
2014-04-16 04:01:20 +04:00
ctx . Data [ "FileName" ] = blob . Name ( )
2014-04-15 20:27:29 +04:00
ext := path . Ext ( blob . Name ( ) )
2014-03-22 21:50:50 +04:00
if len ( ext ) > 0 {
ext = ext [ 1 : ]
}
ctx . Data [ "FileExt" ] = ext
2014-03-24 19:56:32 +04:00
ctx . Data [ "FileLink" ] = rawLink + "/" + treename
_ , isTextFile := base . IsTextFile ( data )
2014-03-27 20:30:20 +04:00
_ , isImageFile := base . IsImageFile ( data )
2014-03-24 19:56:32 +04:00
ctx . Data [ "FileIsText" ] = isTextFile
2014-03-22 21:50:50 +04:00
2014-03-27 20:30:20 +04:00
if isImageFile {
ctx . Data [ "IsImageFile" ] = true
2014-03-22 21:50:50 +04:00
} else {
2014-04-15 20:27:29 +04:00
readmeExist := base . IsMarkdownFile ( blob . Name ( ) ) || base . IsReadmeFile ( blob . Name ( ) )
2014-03-27 20:30:20 +04:00
ctx . Data [ "ReadmeExist" ] = readmeExist
if readmeExist {
ctx . Data [ "FileContent" ] = string ( base . RenderMarkdown ( data , "" ) )
} else {
if isTextFile {
ctx . Data [ "FileContent" ] = string ( data )
}
2014-03-24 19:56:32 +04:00
}
2014-03-22 21:50:50 +04:00
}
}
} else {
// Directory and file list.
2014-04-13 05:35:36 +04:00
tree , err := ctx . Repo . Commit . SubTree ( treename )
2014-03-22 21:50:50 +04:00
if err != nil {
2014-04-13 05:35:36 +04:00
ctx . Handle ( 404 , "repo.Single(SubTree)" , err )
2014-03-22 21:50:50 +04:00
return
}
2014-04-13 05:35:36 +04:00
entries := tree . ListEntries ( )
entries . Sort ( )
files := make ( [ ] [ ] interface { } , 0 , len ( entries ) )
for _ , te := range entries {
2014-04-15 20:27:29 +04:00
c , err := ctx . Repo . Commit . GetCommitOfRelPath ( filepath . Join ( treePath , te . Name ( ) ) )
2014-04-13 05:35:36 +04:00
if err != nil {
ctx . Handle ( 404 , "repo.Single(SubTree)" , err )
return
}
files = append ( files , [ ] interface { } { te , c } )
}
2014-03-22 21:50:50 +04:00
ctx . Data [ "Files" ] = files
2014-04-13 05:35:36 +04:00
var readmeFile * git . Blob
2014-03-22 21:50:50 +04:00
2014-04-13 05:35:36 +04:00
for _ , f := range entries {
2014-04-15 20:27:29 +04:00
if f . IsDir ( ) || ! base . IsReadmeFile ( f . Name ( ) ) {
2014-03-22 21:50:50 +04:00
continue
} else {
2014-04-13 05:35:36 +04:00
readmeFile = f . Blob ( )
2014-03-22 21:50:50 +04:00
break
}
}
if readmeFile != nil {
2014-03-24 20:42:57 +04:00
ctx . Data [ "ReadmeInSingle" ] = true
2014-03-22 21:50:50 +04:00
ctx . Data [ "ReadmeExist" ] = true
2014-04-13 05:35:36 +04:00
if data , err := readmeFile . Data ( ) ; err != nil {
2014-03-23 09:12:55 +04:00
ctx . Handle ( 404 , "repo.Single(readmeFile.LookupBlob)" , err )
2014-03-22 21:50:50 +04:00
return
} else {
2014-03-24 19:56:32 +04:00
ctx . Data [ "FileSize" ] = readmeFile . Size
ctx . Data [ "FileLink" ] = rawLink + "/" + treename
_ , isTextFile := base . IsTextFile ( data )
ctx . Data [ "FileIsText" ] = isTextFile
2014-04-16 04:01:20 +04:00
ctx . Data [ "FileName" ] = readmeFile . Name ( )
2014-03-24 19:56:32 +04:00
if isTextFile {
ctx . Data [ "FileContent" ] = string ( base . RenderMarkdown ( data , branchLink ) )
}
2014-03-22 21:50:50 +04:00
}
}
}
2014-03-27 20:07:22 +04:00
ctx . Data [ "Username" ] = userName
ctx . Data [ "Reponame" ] = repoName
2014-03-22 21:50:50 +04:00
var treenames [ ] string
Paths := make ( [ ] string , 0 )
if len ( treename ) > 0 {
treenames = strings . Split ( treename , "/" )
for i , _ := range treenames {
Paths = append ( Paths , strings . Join ( treenames [ 0 : i + 1 ] , "/" ) )
}
ctx . Data [ "HasParentPath" ] = true
if len ( Paths ) - 2 >= 0 {
ctx . Data [ "ParentPath" ] = "/" + Paths [ len ( Paths ) - 2 ]
}
}
2014-03-30 06:13:02 +04:00
ctx . Data [ "LastCommit" ] = ctx . Repo . Commit
2014-03-22 21:50:50 +04:00
ctx . Data [ "Paths" ] = Paths
ctx . Data [ "Treenames" ] = treenames
2014-04-13 05:35:36 +04:00
ctx . Data [ "TreePath" ] = treePath
2014-03-22 21:50:50 +04:00
ctx . Data [ "BranchLink" ] = branchLink
ctx . HTML ( 200 , "repo/single" )
}
2014-04-05 11:17:57 +04:00
func basicEncode ( username , password string ) string {
auth := username + ":" + password
return base64 . StdEncoding . EncodeToString ( [ ] byte ( auth ) )
}
func basicDecode ( encoded string ) ( user string , name string , err error ) {
var s [ ] byte
s , err = base64 . StdEncoding . DecodeString ( encoded )
if err != nil {
return
}
a := strings . Split ( string ( s ) , ":" )
if len ( a ) == 2 {
user , name = a [ 0 ] , a [ 1 ]
} else {
err = errors . New ( "decode failed" )
}
return
}
func authRequired ( ctx * middleware . Context ) {
2014-04-05 18:24:10 +04:00
ctx . ResponseWriter . Header ( ) . Set ( "WWW-Authenticate" , "Basic realm=\".\"" )
2014-04-05 11:17:57 +04:00
ctx . Data [ "ErrorMsg" ] = "no basic auth and digit auth"
ctx . HTML ( 401 , fmt . Sprintf ( "status/401" ) )
}
2014-03-22 21:50:50 +04:00
func Action ( ctx * middleware . Context , params martini . Params ) {
var err error
switch params [ "action" ] {
case "watch" :
err = models . WatchRepo ( ctx . User . Id , ctx . Repo . Repository . Id , true )
case "unwatch" :
err = models . WatchRepo ( ctx . User . Id , ctx . Repo . Repository . Id , false )
case "desc" :
if ! ctx . Repo . IsOwner {
ctx . Error ( 404 )
return
}
ctx . Repo . Repository . Description = ctx . Query ( "desc" )
ctx . Repo . Repository . Website = ctx . Query ( "site" )
err = models . UpdateRepository ( ctx . Repo . Repository )
}
if err != nil {
log . Error ( "repo.Action(%s): %v" , params [ "action" ] , err )
ctx . JSON ( 200 , map [ string ] interface { } {
"ok" : false ,
"err" : err . Error ( ) ,
} )
return
}
ctx . JSON ( 200 , map [ string ] interface { } {
"ok" : true ,
} )
}