2019-04-17 19:06:35 +03:00
// Copyright 2019 The Gitea 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 repofiles
import (
2019-06-29 23:51:10 +03:00
"fmt"
2019-04-17 19:06:35 +03:00
"net/url"
2019-06-29 23:51:10 +03:00
"path"
"strings"
2019-04-17 19:06:35 +03:00
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git"
2019-05-11 13:21:34 +03:00
api "code.gitea.io/gitea/modules/structs"
2019-04-17 19:06:35 +03:00
)
2019-06-29 23:51:10 +03:00
// ContentType repo content type
type ContentType string
// The string representations of different content types
const (
// ContentTypeRegular regular content type (file)
ContentTypeRegular ContentType = "file"
// ContentTypeDir dir content type (dir)
ContentTypeDir ContentType = "dir"
// ContentLink link content type (symlink)
ContentTypeLink ContentType = "symlink"
// ContentTag submodule content type (submodule)
ContentTypeSubmodule ContentType = "submodule"
)
// String gets the string of ContentType
func ( ct * ContentType ) String ( ) string {
return string ( * ct )
}
// GetContentsOrList gets the meta data of a file's contents (*ContentsResponse) if treePath not a tree
// directory, otherwise a listing of file contents ([]*ContentsResponse). Ref can be a branch, commit or tag
func GetContentsOrList ( repo * models . Repository , treePath , ref string ) ( interface { } , error ) {
2019-10-19 18:38:49 +03:00
if repo . IsEmpty {
return make ( [ ] interface { } , 0 ) , nil
}
2019-04-17 19:06:35 +03:00
if ref == "" {
ref = repo . DefaultBranch
}
2019-06-29 23:51:10 +03:00
origRef := ref
2019-04-17 19:06:35 +03:00
// Check that the path given in opts.treePath is valid (not a git path)
2019-06-29 23:51:10 +03:00
cleanTreePath := CleanUploadFileName ( treePath )
if cleanTreePath == "" && treePath != "" {
2019-04-17 19:06:35 +03:00
return nil , models . ErrFilenameInvalid {
Path : treePath ,
}
}
2019-06-29 23:51:10 +03:00
treePath = cleanTreePath
2019-04-17 19:06:35 +03:00
gitRepo , err := git . OpenRepository ( repo . RepoPath ( ) )
if err != nil {
return nil , err
}
2019-11-13 10:01:19 +03:00
defer gitRepo . Close ( )
2019-04-17 19:06:35 +03:00
// Get the commit object for the ref
commit , err := gitRepo . GetCommit ( ref )
if err != nil {
return nil , err
}
entry , err := commit . GetTreeEntryByPath ( treePath )
if err != nil {
return nil , err
}
2019-06-29 23:51:10 +03:00
if entry . Type ( ) != "tree" {
return GetContents ( repo , treePath , origRef , false )
}
// We are in a directory, so we return a list of FileContentResponse objects
var fileList [ ] * api . ContentsResponse
gitTree , err := commit . SubTree ( treePath )
if err != nil {
return nil , err
}
entries , err := gitTree . ListEntries ( )
if err != nil {
return nil , err
}
for _ , e := range entries {
subTreePath := path . Join ( treePath , e . Name ( ) )
fileContentResponse , err := GetContents ( repo , subTreePath , origRef , true )
if err != nil {
return nil , err
}
fileList = append ( fileList , fileContentResponse )
}
return fileList , nil
}
// GetContents gets the meta data on a file's contents. Ref can be a branch, commit or tag
func GetContents ( repo * models . Repository , treePath , ref string , forList bool ) ( * api . ContentsResponse , error ) {
if ref == "" {
ref = repo . DefaultBranch
2019-04-17 19:06:35 +03:00
}
2019-06-29 23:51:10 +03:00
origRef := ref
2019-04-17 19:06:35 +03:00
2019-06-29 23:51:10 +03:00
// Check that the path given in opts.treePath is valid (not a git path)
cleanTreePath := CleanUploadFileName ( treePath )
if cleanTreePath == "" && treePath != "" {
return nil , models . ErrFilenameInvalid {
Path : treePath ,
}
}
treePath = cleanTreePath
gitRepo , err := git . OpenRepository ( repo . RepoPath ( ) )
if err != nil {
return nil , err
}
2019-11-13 10:01:19 +03:00
defer gitRepo . Close ( )
2019-04-17 19:06:35 +03:00
2019-06-29 23:51:10 +03:00
// Get the commit object for the ref
commit , err := gitRepo . GetCommit ( ref )
if err != nil {
return nil , err
}
commitID := commit . ID . String ( )
if len ( ref ) >= 4 && strings . HasPrefix ( commitID , ref ) {
ref = commit . ID . String ( )
}
entry , err := commit . GetTreeEntryByPath ( treePath )
if err != nil {
return nil , err
}
refType := gitRepo . GetRefType ( ref )
if refType == "invalid" {
return nil , fmt . Errorf ( "no commit found for the ref [ref: %s]" , ref )
}
selfURL , err := url . Parse ( fmt . Sprintf ( "%s/contents/%s?ref=%s" , repo . APIURL ( ) , treePath , origRef ) )
if err != nil {
return nil , err
}
selfURLString := selfURL . String ( )
// All content types have these fields in populated
contentsResponse := & api . ContentsResponse {
Name : entry . Name ( ) ,
Path : treePath ,
SHA : entry . ID . String ( ) ,
Size : entry . Size ( ) ,
URL : & selfURLString ,
2019-04-17 19:06:35 +03:00
Links : & api . FileLinksResponse {
2019-06-29 23:51:10 +03:00
Self : & selfURLString ,
2019-04-17 19:06:35 +03:00
} ,
}
2019-06-29 23:51:10 +03:00
// Now populate the rest of the ContentsResponse based on entry type
2020-04-24 19:20:22 +03:00
if entry . IsRegular ( ) || entry . IsExecutable ( ) {
2019-06-29 23:51:10 +03:00
contentsResponse . Type = string ( ContentTypeRegular )
if blobResponse , err := GetBlobBySHA ( repo , entry . ID . String ( ) ) ; err != nil {
return nil , err
} else if ! forList {
// We don't show the content if we are getting a list of FileContentResponses
contentsResponse . Encoding = & blobResponse . Encoding
contentsResponse . Content = & blobResponse . Content
}
} else if entry . IsDir ( ) {
contentsResponse . Type = string ( ContentTypeDir )
} else if entry . IsLink ( ) {
contentsResponse . Type = string ( ContentTypeLink )
// The target of a symlink file is the content of the file
targetFromContent , err := entry . Blob ( ) . GetBlobContent ( )
if err != nil {
return nil , err
}
contentsResponse . Target = & targetFromContent
} else if entry . IsSubModule ( ) {
contentsResponse . Type = string ( ContentTypeSubmodule )
submodule , err := commit . GetSubModule ( treePath )
if err != nil {
return nil , err
}
contentsResponse . SubmoduleGitURL = & submodule . URL
}
// Handle links
if entry . IsRegular ( ) || entry . IsLink ( ) {
downloadURL , err := url . Parse ( fmt . Sprintf ( "%s/raw/%s/%s/%s" , repo . HTMLURL ( ) , refType , ref , treePath ) )
if err != nil {
return nil , err
}
downloadURLString := downloadURL . String ( )
contentsResponse . DownloadURL = & downloadURLString
}
if ! entry . IsSubModule ( ) {
htmlURL , err := url . Parse ( fmt . Sprintf ( "%s/src/%s/%s/%s" , repo . HTMLURL ( ) , refType , ref , treePath ) )
if err != nil {
return nil , err
}
htmlURLString := htmlURL . String ( )
contentsResponse . HTMLURL = & htmlURLString
contentsResponse . Links . HTMLURL = & htmlURLString
gitURL , err := url . Parse ( fmt . Sprintf ( "%s/git/blobs/%s" , repo . APIURL ( ) , entry . ID . String ( ) ) )
if err != nil {
return nil , err
}
gitURLString := gitURL . String ( )
contentsResponse . GitURL = & gitURLString
contentsResponse . Links . GitURL = & gitURLString
}
return contentsResponse , nil
2019-04-17 19:06:35 +03:00
}