2014-07-26 08:24:27 +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 (
"bytes"
2016-08-09 22:56:00 +03:00
"fmt"
gotemplate "html/template"
2014-07-26 08:24:27 +04:00
"io/ioutil"
"path"
"strings"
2015-11-17 07:28:46 +03:00
"github.com/Unknwon/paginater"
2015-12-16 01:25:45 +03:00
"github.com/gogits/git-module"
2015-12-10 04:46:05 +03:00
2014-09-26 16:55:13 +04:00
"github.com/gogits/gogs/models"
2014-07-26 08:24:27 +04:00
"github.com/gogits/gogs/modules/base"
2016-03-11 19:56:52 +03:00
"github.com/gogits/gogs/modules/context"
2014-08-23 16:30:29 +04:00
"github.com/gogits/gogs/modules/log"
2016-02-21 01:10:05 +03:00
"github.com/gogits/gogs/modules/markdown"
2016-07-12 01:21:26 +03:00
"github.com/gogits/gogs/modules/setting"
2015-11-14 01:10:25 +03:00
"github.com/gogits/gogs/modules/template"
2016-01-31 19:19:02 +03:00
"github.com/gogits/gogs/modules/template/highlight"
2014-07-26 08:24:27 +04:00
)
const (
2015-11-17 07:28:46 +03:00
HOME base . TplName = "repo/home"
WATCHERS base . TplName = "repo/watchers"
2015-11-17 07:33:40 +03:00
FORKS base . TplName = "repo/forks"
2014-07-26 08:24:27 +04:00
)
2016-03-11 19:56:52 +03:00
func Home ( ctx * context . Context ) {
2016-06-27 11:38:35 +03:00
title := ctx . Repo . Repository . Owner . Name + "/" + ctx . Repo . Repository . Name
if len ( ctx . Repo . Repository . Description ) > 0 {
title += ": " + ctx . Repo . Repository . Description
}
ctx . Data [ "Title" ] = title
2015-11-26 04:10:25 +03:00
ctx . Data [ "PageIsViewCode" ] = true
2015-11-14 12:34:01 +03:00
ctx . Data [ "RequireHighlightJS" ] = true
2014-07-26 08:24:27 +04:00
branchName := ctx . Repo . BranchName
userName := ctx . Repo . Owner . Name
repoName := ctx . Repo . Repository . Name
branchLink := ctx . Repo . RepoLink + "/src/" + branchName
2015-11-09 10:13:25 +03:00
treeLink := branchLink
2014-07-26 08:24:27 +04:00
rawLink := ctx . Repo . RepoLink + "/raw/" + branchName
2016-08-28 01:25:01 +03:00
// newFileLink := ctx.Repo.RepoLink + "/_new/" + branchName
// uploadFileLink := ctx.Repo.RepoLink + "/upload/" + branchName
2014-07-26 08:24:27 +04:00
2016-08-28 01:25:01 +03:00
treePath := ctx . Repo . TreePath
if len ( treePath ) > 0 {
treeLink += "/" + treePath
2014-07-26 08:24:27 +04:00
}
2016-08-28 01:25:01 +03:00
entry , err := ctx . Repo . Commit . GetTreeEntryByPath ( treePath )
2016-08-15 09:02:14 +03:00
if err != nil {
if git . IsErrNotExist ( err ) {
ctx . Handle ( 404 , "GetTreeEntryByPath" , err )
} else {
ctx . Handle ( 500 , "GetTreeEntryByPath" , err )
}
2014-07-26 08:24:27 +04:00
return
}
2016-08-15 09:02:14 +03:00
if ! entry . IsDir ( ) {
2014-07-26 08:24:27 +04:00
blob := entry . Blob ( )
2016-08-15 09:02:14 +03:00
dataRc , err := blob . Data ( )
if err != nil {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 404 , "blob.Data" , err )
return
2016-08-15 09:02:14 +03:00
}
2014-07-26 08:24:27 +04:00
2016-08-15 09:02:14 +03:00
ctx . Data [ "FileSize" ] = blob . Size ( )
ctx . Data [ "IsFile" ] = true
ctx . Data [ "FileName" ] = blob . Name ( )
ctx . Data [ "HighlightClass" ] = highlight . FileNameToHighlightClass ( blob . Name ( ) )
2016-08-28 01:25:01 +03:00
ctx . Data [ "FileLink" ] = rawLink + "/" + treePath
2016-08-09 22:56:00 +03:00
2016-08-15 09:02:14 +03:00
buf := make ( [ ] byte , 1024 )
n , _ := dataRc . Read ( buf )
if n > 0 {
buf = buf [ : n ]
}
2016-08-09 22:35:20 +03:00
2016-08-15 09:02:14 +03:00
_ , isTextFile := base . IsTextFile ( buf )
_ , isImageFile := base . IsImageFile ( buf )
_ , isPDFFile := base . IsPDFFile ( buf )
ctx . Data [ "IsFileText" ] = isTextFile
2016-08-28 01:25:01 +03:00
// Assume file is not editable first.
if ! isTextFile {
ctx . Data [ "EditFileTooltip" ] = ctx . Tr ( "repo.editor.cannot_edit_non_text_files" )
}
2016-08-15 09:02:14 +03:00
switch {
case isPDFFile :
ctx . Data [ "IsPDFFile" ] = true
case isImageFile :
ctx . Data [ "IsImageFile" ] = true
case isTextFile :
if blob . Size ( ) >= setting . UI . MaxDisplayFileSize {
ctx . Data [ "IsFileTooLarge" ] = true
} else {
d , _ := ioutil . ReadAll ( dataRc )
buf = append ( buf , d ... )
2016-08-28 01:25:01 +03:00
isMarkdown := markdown . IsMarkdownFile ( blob . Name ( ) )
2016-08-15 09:02:14 +03:00
ctx . Data [ "IsMarkdown" ] = isMarkdown
2016-08-28 01:25:01 +03:00
readmeExist := isMarkdown || markdown . IsReadmeFile ( blob . Name ( ) )
ctx . Data [ "ReadmeExist" ] = readmeExist
if readmeExist {
// TODO: don't need to render if it's a README but not Markdown file.
2016-08-15 09:02:14 +03:00
ctx . Data [ "FileContent" ] = string ( markdown . Render ( buf , path . Dir ( treeLink ) , ctx . Repo . Repository . ComposeMetas ( ) ) )
} else {
// Building code view blocks with line number on server side.
var filecontent string
if err , content := template . ToUTF8WithErr ( buf ) ; err != nil {
if err != nil {
log . Error ( 4 , "ToUTF8WithErr: %s" , err )
2016-07-12 01:21:26 +03:00
}
2016-08-15 09:02:14 +03:00
filecontent = string ( buf )
} else {
filecontent = content
2014-08-20 12:34:48 +04:00
}
2016-08-15 09:02:14 +03:00
var output bytes . Buffer
lines := strings . Split ( filecontent , "\n" )
for index , line := range lines {
output . WriteString ( fmt . Sprintf ( ` <li class="L%d" rel="L%d">%s</li> ` , index + 1 , index + 1 , gotemplate . HTMLEscapeString ( line ) ) + "\n" )
2016-08-11 15:48:08 +03:00
}
2016-08-15 09:02:14 +03:00
ctx . Data [ "FileContent" ] = gotemplate . HTML ( output . String ( ) )
output . Reset ( )
for i := 0 ; i < len ( lines ) ; i ++ {
output . WriteString ( fmt . Sprintf ( ` <span id="L%d">%d</span> ` , i + 1 , i + 1 ) )
}
ctx . Data [ "LineNums" ] = gotemplate . HTML ( output . String ( ) )
2016-08-11 15:48:08 +03:00
}
}
2016-08-28 01:25:01 +03:00
2016-08-11 15:48:08 +03:00
if ctx . Repo . IsWriter ( ) && ctx . Repo . IsViewBranch {
2016-08-28 01:25:01 +03:00
ctx . Data [ "CanEditFile" ] = true
ctx . Data [ "EditFileTooltip" ] = ctx . Tr ( "repo.editor.edit_this_file" )
} else if ! ctx . Repo . IsViewBranch {
ctx . Data [ "EditFileTooltip" ] = ctx . Tr ( "repo.editor.must_be_on_a_branch" )
} else if ! ctx . Repo . IsWriter ( ) {
ctx . Data [ "EditFileTooltip" ] = ctx . Tr ( "repo.editor.fork_before_edit" )
2014-07-26 08:24:27 +04:00
}
2016-08-15 09:02:14 +03:00
}
if ctx . Repo . IsWriter ( ) && ctx . Repo . IsViewBranch {
2016-08-28 01:25:01 +03:00
ctx . Data [ "CanDeleteFile" ] = true
2016-08-15 09:02:14 +03:00
ctx . Data [ "FileDeleteLinkTooltip" ] = ctx . Tr ( "repo.delete_this_file" )
} else {
if ! ctx . Repo . IsViewBranch {
ctx . Data [ "FileDeleteLinkTooltip" ] = ctx . Tr ( "repo.must_be_on_branch" )
} else if ! ctx . Repo . IsWriter ( ) {
ctx . Data [ "FileDeleteLinkTooltip" ] = ctx . Tr ( "repo.must_be_writer" )
}
2014-07-26 08:24:27 +04:00
}
2016-08-15 09:02:14 +03:00
2014-07-26 08:24:27 +04:00
} else {
// Directory and file list.
2016-08-28 01:25:01 +03:00
tree , err := ctx . Repo . Commit . SubTree ( treePath )
2014-07-26 08:24:27 +04:00
if err != nil {
ctx . Handle ( 404 , "SubTree" , err )
return
}
2014-09-30 12:39:53 +04:00
2015-12-10 04:46:05 +03:00
entries , err := tree . ListEntries ( )
2014-07-26 08:24:27 +04:00
if err != nil {
ctx . Handle ( 500 , "ListEntries" , err )
return
}
entries . Sort ( )
2015-12-14 06:58:12 +03:00
ctx . Data [ "Files" ] , err = entries . GetCommitsInfo ( ctx . Repo . Commit , treePath )
if err != nil {
ctx . Handle ( 500 , "GetCommitsInfo" , err )
return
2014-07-26 08:24:27 +04:00
}
var readmeFile * git . Blob
for _ , f := range entries {
2016-02-21 01:10:05 +03:00
if f . IsDir ( ) || ! markdown . IsReadmeFile ( f . Name ( ) ) {
2014-07-26 08:24:27 +04:00
continue
} else {
readmeFile = f . Blob ( )
break
}
}
if readmeFile != nil {
2014-10-12 02:02:48 +04:00
ctx . Data [ "ReadmeInList" ] = true
2014-07-26 08:24:27 +04:00
ctx . Data [ "ReadmeExist" ] = true
if dataRc , err := readmeFile . Data ( ) ; err != nil {
2015-11-22 05:09:18 +03:00
ctx . Handle ( 404 , "repo.SinglereadmeFile.Data" , err )
2014-07-26 08:24:27 +04:00
return
} else {
buf := make ( [ ] byte , 1024 )
n , _ := dataRc . Read ( buf )
if n > 0 {
buf = buf [ : n ]
}
ctx . Data [ "FileSize" ] = readmeFile . Size ( )
2016-08-28 01:25:01 +03:00
ctx . Data [ "FileLink" ] = rawLink + "/" + treePath
2014-07-26 08:24:27 +04:00
_ , isTextFile := base . IsTextFile ( buf )
ctx . Data [ "FileIsText" ] = isTextFile
ctx . Data [ "FileName" ] = readmeFile . Name ( )
if isTextFile {
d , _ := ioutil . ReadAll ( dataRc )
buf = append ( buf , d ... )
switch {
2016-02-21 01:10:05 +03:00
case markdown . IsMarkdownFile ( readmeFile . Name ( ) ) :
2016-08-11 15:48:08 +03:00
ctx . Data [ "IsMarkdown" ] = true
2016-02-21 01:10:05 +03:00
buf = markdown . Render ( buf , treeLink , ctx . Repo . Repository . ComposeMetas ( ) )
2014-07-26 08:24:27 +04:00
default :
buf = bytes . Replace ( buf , [ ] byte ( "\n" ) , [ ] byte ( ` <br> ` ) , - 1 )
}
ctx . Data [ "FileContent" ] = string ( buf )
}
}
}
2014-09-26 16:55:13 +04:00
lastCommit := ctx . Repo . Commit
if len ( treePath ) > 0 {
2015-12-10 04:46:05 +03:00
c , err := ctx . Repo . Commit . GetCommitByPath ( treePath )
2014-09-26 16:55:13 +04:00
if err != nil {
2015-12-10 04:46:05 +03:00
ctx . Handle ( 500 , "GetCommitByPath" , err )
2014-09-26 16:55:13 +04:00
return
}
lastCommit = c
}
ctx . Data [ "LastCommit" ] = lastCommit
ctx . Data [ "LastCommitUser" ] = models . ValidateCommitWithEmail ( lastCommit )
2016-08-28 01:25:01 +03:00
// if ctx.Repo.IsWriter() && ctx.Repo.IsViewBranch {
// ctx.Data["NewFileLink"] = newFileLink + "/" + treePath
// if setting.Repository.Upload.Enabled {
// ctx.Data["UploadFileLink"] = uploadFileLink + "/" + treePath
// }
// }
2014-07-26 08:24:27 +04:00
}
ctx . Data [ "Username" ] = userName
ctx . Data [ "Reponame" ] = repoName
2016-08-12 03:07:09 +03:00
ec , err := ctx . Repo . GetEditorconfig ( )
if err != nil && ! git . IsErrNotExist ( err ) {
ctx . Handle ( 500 , "ErrGettingEditorconfig" , err )
return
}
ctx . Data [ "Editorconfig" ] = ec
2014-07-26 08:24:27 +04:00
var treenames [ ] string
2016-08-09 22:56:00 +03:00
paths := make ( [ ] string , 0 )
2014-07-26 08:24:27 +04:00
2016-08-28 01:25:01 +03:00
if len ( treePath ) > 0 {
treenames = strings . Split ( treePath , "/" )
2016-08-09 22:56:00 +03:00
for i := range treenames {
paths = append ( paths , strings . Join ( treenames [ 0 : i + 1 ] , "/" ) )
2014-07-26 08:24:27 +04:00
}
ctx . Data [ "HasParentPath" ] = true
2016-08-09 22:56:00 +03:00
if len ( paths ) - 2 >= 0 {
ctx . Data [ "ParentPath" ] = "/" + paths [ len ( paths ) - 2 ]
2014-07-26 08:24:27 +04:00
}
}
2016-08-09 22:56:00 +03:00
ctx . Data [ "Paths" ] = paths
2014-07-26 08:24:27 +04:00
ctx . Data [ "TreePath" ] = treePath
2016-08-28 01:25:01 +03:00
ctx . Data [ "TreeLink" ] = treeLink
ctx . Data [ "Treenames" ] = treenames
2014-07-26 08:24:27 +04:00
ctx . Data [ "BranchLink" ] = branchLink
ctx . HTML ( 200 , HOME )
}
2015-11-17 07:28:46 +03:00
2016-03-11 19:56:52 +03:00
func RenderUserCards ( ctx * context . Context , total int , getter func ( page int ) ( [ ] * models . User , error ) , tpl base . TplName ) {
2015-11-17 07:28:46 +03:00
page := ctx . QueryInt ( "page" )
if page <= 0 {
page = 1
}
pager := paginater . New ( total , models . ItemsPerPage , page , 5 )
ctx . Data [ "Page" ] = pager
items , err := getter ( pager . Current ( ) )
if err != nil {
ctx . Handle ( 500 , "getter" , err )
return
}
2015-12-21 15:24:11 +03:00
ctx . Data [ "Cards" ] = items
2015-11-17 07:28:46 +03:00
2015-12-21 15:24:11 +03:00
ctx . HTML ( 200 , tpl )
2015-11-17 07:28:46 +03:00
}
2016-03-11 19:56:52 +03:00
func Watchers ( ctx * context . Context ) {
2015-11-17 07:28:46 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.watchers" )
2015-12-21 15:24:11 +03:00
ctx . Data [ "CardsTitle" ] = ctx . Tr ( "repo.watchers" )
2015-11-17 07:28:46 +03:00
ctx . Data [ "PageIsWatchers" ] = true
2015-12-21 15:24:11 +03:00
RenderUserCards ( ctx , ctx . Repo . Repository . NumWatches , ctx . Repo . Repository . GetWatchers , WATCHERS )
2015-11-17 07:28:46 +03:00
}
2016-03-11 19:56:52 +03:00
func Stars ( ctx * context . Context ) {
2015-11-17 07:28:46 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.stargazers" )
2015-12-21 15:24:11 +03:00
ctx . Data [ "CardsTitle" ] = ctx . Tr ( "repo.stargazers" )
2015-11-17 07:28:46 +03:00
ctx . Data [ "PageIsStargazers" ] = true
2015-12-21 15:24:11 +03:00
RenderUserCards ( ctx , ctx . Repo . Repository . NumStars , ctx . Repo . Repository . GetStargazers , WATCHERS )
2015-11-17 07:28:46 +03:00
}
2015-11-17 07:33:40 +03:00
2016-03-11 19:56:52 +03:00
func Forks ( ctx * context . Context ) {
2015-11-17 07:33:40 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repos.forks" )
forks , err := ctx . Repo . Repository . GetForks ( )
if err != nil {
ctx . Handle ( 500 , "GetForks" , err )
return
}
for _ , fork := range forks {
if err = fork . GetOwner ( ) ; err != nil {
ctx . Handle ( 500 , "GetOwner" , err )
return
}
}
ctx . Data [ "Forks" ] = forks
ctx . HTML ( 200 , FORKS )
}