1275 lines
35 KiB
Go
1275 lines
35 KiB
Go
package viewfile
|
||
|
||
import (
|
||
"bytes"
|
||
"encoding/base64"
|
||
"fmt"
|
||
gotemplate "html/template"
|
||
"io/ioutil"
|
||
"net/http"
|
||
"net/url"
|
||
"path"
|
||
"path/filepath"
|
||
"strconv"
|
||
"strings"
|
||
|
||
"code.gitea.io/gitea/models"
|
||
"code.gitea.io/gitea/modules/base"
|
||
"code.gitea.io/gitea/modules/charset"
|
||
"code.gitea.io/gitea/modules/context"
|
||
"code.gitea.io/gitea/modules/git"
|
||
"code.gitea.io/gitea/modules/lfs"
|
||
"code.gitea.io/gitea/modules/log"
|
||
"code.gitea.io/gitea/modules/markup"
|
||
"code.gitea.io/gitea/modules/repofiles"
|
||
repo_module "code.gitea.io/gitea/modules/repository"
|
||
"code.gitea.io/gitea/modules/setting"
|
||
"gitea.com/macaron/macaron"
|
||
)
|
||
|
||
func Map2DTO(ctx *context.APIContext) (dto *ReadmeDTO) {
|
||
dto = &ReadmeDTO{}
|
||
dto.Type = "file"
|
||
dto.Encoding = ctx.Data["Encoding"].(string)
|
||
dto.Size = ctx.Data["FileSize"].(int64)
|
||
dto.Name = ctx.Repo.TreePath
|
||
dto.Path = ctx.Repo.TreePath
|
||
dto.Content = ctx.Data["FileContent"].(string)
|
||
dto.Sha = ctx.Repo.CommitID
|
||
return
|
||
}
|
||
|
||
// RepoRefByType handles repository reference name for a specific type
|
||
// of repository reference
|
||
func RepoRefByType(refType context.RepoRefType) macaron.Handler {
|
||
return func(ctx *context.APIContext) {
|
||
// Empty repository does not have reference information.
|
||
if ctx.Repo.Repository.IsEmpty {
|
||
return
|
||
}
|
||
|
||
var (
|
||
refName string
|
||
err error
|
||
)
|
||
|
||
// For API calls.
|
||
if ctx.Repo.GitRepo == nil {
|
||
fmt.Println("*******ctx.Repo.GitRepo is nil recreated")
|
||
repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
|
||
ctx.Repo.GitRepo, err = git.OpenRepository(repoPath)
|
||
if err != nil {
|
||
ctx.ServerError("RepoRef Invalid repo "+repoPath, err)
|
||
return
|
||
}
|
||
// We opened it, we should close it
|
||
defer func() {
|
||
// If it's been set to nil then assume someone else has closed it.
|
||
if ctx.Repo.GitRepo != nil {
|
||
ctx.Repo.GitRepo.Close()
|
||
}
|
||
}()
|
||
}
|
||
|
||
// Get default branch.
|
||
if len(ctx.Params("*")) == 0 {
|
||
refName = ctx.Repo.Repository.DefaultBranch
|
||
ctx.Repo.BranchName = refName
|
||
if !ctx.Repo.GitRepo.IsBranchExist(refName) {
|
||
brs, err := ctx.Repo.GitRepo.GetBranches()
|
||
if err != nil {
|
||
ctx.ServerError("GetBranches", err)
|
||
return
|
||
} else if len(brs) == 0 {
|
||
err = fmt.Errorf("No branches in non-empty repository %s",
|
||
ctx.Repo.GitRepo.Path)
|
||
ctx.ServerError("GetBranches", err)
|
||
return
|
||
}
|
||
refName = brs[0]
|
||
}
|
||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
|
||
if err != nil {
|
||
ctx.ServerError("GetBranchCommit", err)
|
||
return
|
||
}
|
||
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
|
||
ctx.Repo.IsViewBranch = true
|
||
|
||
} else {
|
||
refName = getRefName(ctx, refType)
|
||
ctx.Repo.BranchName = refName
|
||
if refType.RefTypeIncludesBranches() && ctx.Repo.GitRepo.IsBranchExist(refName) {
|
||
ctx.Repo.IsViewBranch = true
|
||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
|
||
//fmt.Println("****:GetBranchCommit:",ctx.Repo.Commit, err)
|
||
if err != nil {
|
||
ctx.ServerError("GetBranchCommit", err)
|
||
return
|
||
}
|
||
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
|
||
|
||
} else if refType.RefTypeIncludesTags() && ctx.Repo.GitRepo.IsTagExist(refName) {
|
||
ctx.Repo.IsViewTag = true
|
||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetTagCommit(refName)
|
||
if err != nil {
|
||
ctx.ServerError("GetTagCommit", err)
|
||
return
|
||
}
|
||
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
|
||
} else if len(refName) == 40 {
|
||
ctx.Repo.IsViewCommit = true
|
||
ctx.Repo.CommitID = refName
|
||
|
||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
|
||
if err != nil {
|
||
ctx.NotFound("GetCommit", nil)
|
||
return
|
||
}
|
||
} else {
|
||
ctx.NotFound("RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
|
||
return
|
||
}
|
||
|
||
if refType == context.RepoRefLegacy {
|
||
// redirect from old URL scheme to new URL scheme
|
||
ctx.Redirect(path.Join(
|
||
setting.AppSubURL,
|
||
strings.TrimSuffix(ctx.Req.URL.Path, ctx.Params("*")),
|
||
ctx.Repo.BranchNameSubURL(),
|
||
ctx.Repo.TreePath))
|
||
return
|
||
}
|
||
}
|
||
|
||
ctx.Data["BranchName"] = ctx.Repo.BranchName
|
||
ctx.Data["BranchNameSubURL"] = ctx.Repo.BranchNameSubURL()
|
||
ctx.Data["CommitID"] = ctx.Repo.CommitID
|
||
ctx.Data["TreePath"] = ctx.Repo.TreePath
|
||
ctx.Data["IsViewBranch"] = ctx.Repo.IsViewBranch
|
||
ctx.Data["IsViewTag"] = ctx.Repo.IsViewTag
|
||
ctx.Data["IsViewCommit"] = ctx.Repo.IsViewCommit
|
||
ctx.Data["CanCreateBranch"] = ctx.Repo.CanCreateBranch()
|
||
|
||
ctx.Repo.CommitsCount, err = ctx.Repo.GetCommitsCount()
|
||
if err != nil {
|
||
ctx.ServerError("GetCommitsCount", err)
|
||
return
|
||
}
|
||
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
|
||
|
||
ctx.Next()
|
||
}
|
||
}
|
||
|
||
func getRefName(ctx *context.APIContext, pathType context.RepoRefType) string {
|
||
path := ctx.Params("*")
|
||
switch pathType {
|
||
case context.RepoRefLegacy, context.RepoRefAny:
|
||
if refName := getRefName(ctx, context.RepoRefBranch); len(refName) > 0 {
|
||
return refName
|
||
}
|
||
if refName := getRefName(ctx, context.RepoRefTag); len(refName) > 0 {
|
||
return refName
|
||
}
|
||
if refName := getRefName(ctx, context.RepoRefCommit); len(refName) > 0 {
|
||
return refName
|
||
}
|
||
if refName := getRefName(ctx, context.RepoRefBlob); len(refName) > 0 {
|
||
return refName
|
||
}
|
||
ctx.Repo.TreePath = path
|
||
return ctx.Repo.Repository.DefaultBranch
|
||
case context.RepoRefBranch:
|
||
return getRefNameFromPath(ctx, path, ctx.Repo.GitRepo.IsBranchExist)
|
||
case context.RepoRefTag:
|
||
return getRefNameFromPath(ctx, path, ctx.Repo.GitRepo.IsTagExist)
|
||
case context.RepoRefCommit:
|
||
parts := strings.Split(path, "/")
|
||
if len(parts) > 0 && len(parts[0]) == 40 {
|
||
ctx.Repo.TreePath = strings.Join(parts[1:], "/")
|
||
return parts[0]
|
||
}
|
||
case context.RepoRefBlob:
|
||
_, err := ctx.Repo.GitRepo.GetBlob(path)
|
||
if err != nil {
|
||
return ""
|
||
}
|
||
return path
|
||
default:
|
||
ctx.Error(http.StatusBadRequest, "Unrecognized path type: %v", path)
|
||
}
|
||
return ""
|
||
}
|
||
|
||
func getRefNameFromPath(ctx *context.APIContext, path string, isExist func(string) bool) string {
|
||
refName := ""
|
||
parts := strings.Split(path, "/")
|
||
for i, part := range parts {
|
||
refName = strings.TrimPrefix(refName+"/"+part, "/")
|
||
if isExist(refName) {
|
||
ctx.Repo.TreePath = strings.Join(parts[i+1:], "/")
|
||
return refName
|
||
}
|
||
}
|
||
return ""
|
||
}
|
||
|
||
func GetRefType() macaron.Handler {
|
||
return func(ctx *context.APIContext) {
|
||
ref := ctx.ParamsInt64(":ref")
|
||
fmt.Println("ref:", ref)
|
||
}
|
||
}
|
||
|
||
func CommitCount(ctx *context.APIContext) {
|
||
// swagger:operation GET /repos/{owner}/{repo}/count repository Count
|
||
// ---
|
||
// summary: Get commit quantity by branch which is a custom interface ****
|
||
// produces:
|
||
// - application/json
|
||
// parameters:
|
||
// - name: owner
|
||
// in: path
|
||
// description: owner of the repo
|
||
// type: string
|
||
// required: true
|
||
// - name: repo
|
||
// in: path
|
||
// description: name of the repo
|
||
// type: string
|
||
// required: true
|
||
// - name: ref
|
||
// in: query
|
||
// description: "The name of the commit/branch/tag. Default the repository’s default branch (usually master)"
|
||
// type: string
|
||
// required: false
|
||
// responses:
|
||
// "200":
|
||
// "$ref": "#/responses/CountDTO"
|
||
// "404":
|
||
// "$ref": "#/responses/notFound"
|
||
|
||
ref := ctx.QueryTrim("ref")
|
||
if ref == "" {
|
||
ref = ctx.Params(":ref")
|
||
if ref == "" {
|
||
ref = ctx.Repo.Repository.DefaultBranch
|
||
}
|
||
}
|
||
|
||
//log.Info("********CommitCount:ref:%s", ref)
|
||
var err error
|
||
if ctx.Repo.GitRepo == nil {
|
||
fmt.Println("*****ctx.Repo.GitRepo is nil ")
|
||
repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
|
||
ctx.Repo.GitRepo, err = git.OpenRepository(repoPath)
|
||
if err != nil {
|
||
ctx.ServerError("RepoRef Invalid repo "+repoPath, err)
|
||
return
|
||
}
|
||
// We opened it, we should close it
|
||
defer func() {
|
||
// If it's been set to nil then assume someone else has closed it.
|
||
if ctx.Repo.GitRepo != nil {
|
||
ctx.Repo.GitRepo.Close()
|
||
}
|
||
}()
|
||
}
|
||
|
||
// Get the commit object for the ref
|
||
commit, err := ctx.Repo.GitRepo.GetCommit(ref)
|
||
if err != nil || commit == nil {
|
||
ctx.Error(http.StatusInternalServerError, "ctx.Repo.GitRepo.GetCommit", err)
|
||
return
|
||
}
|
||
ctx.Repo.Commit = commit
|
||
|
||
CommitCount, err := ctx.Repo.Commit.CommitsCount()
|
||
if err != nil {
|
||
ctx.Error(http.StatusInternalServerError, "ctx.Repo.Commit.CommitsCount", err)
|
||
return
|
||
}
|
||
opts := models.FindReleasesOptions{
|
||
ListOptions: models.ListOptions{
|
||
Page: 1,
|
||
PageSize: 1000,
|
||
},
|
||
IncludeDrafts: true,
|
||
IncludeTags: true,
|
||
}
|
||
|
||
//fmt.Println("*****************ctx.Repo.Repository.ID:",ctx.Repo.Repository.ID)
|
||
ReleaseCount, err := models.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, opts)
|
||
if err != nil {
|
||
ctx.ServerError("GetReleaseCountByRepoID", err)
|
||
return
|
||
}
|
||
branches, err := repo_module.GetBranches(ctx.Repo.Repository)
|
||
if err != nil {
|
||
ctx.Error(http.StatusInternalServerError, "GetBranches", err)
|
||
return
|
||
}
|
||
|
||
tags, err := ctx.Repo.GitRepo.GetTags()
|
||
if err != nil {
|
||
ctx.Error(http.StatusInternalServerError, "ctx.Repo.GitRepo.GetTags", err)
|
||
return
|
||
}
|
||
|
||
dto := &CountDTO{}
|
||
dto.Branch.CommitCount = CommitCount
|
||
dto.Branch.BranchName = ref
|
||
dto.BranchCount = int64(len(branches))
|
||
dto.TagCount = int64(len(tags))
|
||
dto.ReleaseCount = ReleaseCount
|
||
ctx.JSON(http.StatusOK, dto)
|
||
}
|
||
|
||
type CountDTO struct {
|
||
Branch struct {
|
||
CommitCount int64 `json:"commit_count"`
|
||
BranchName string `json:"branch_name"`
|
||
} `json:"branch"`
|
||
ReleaseCount int64 `json:"release_count"`
|
||
TagCount int64 `json:"tag_count"`
|
||
BranchCount int64 `json:"branch_count"`
|
||
}
|
||
|
||
// LatestRelease redirects to the latest release
|
||
func LatestRelease(ctx *context.APIContext) {
|
||
// swagger:operation GET /repos/{owner}/{repo}/releases/latest repository latest
|
||
// ---
|
||
// summary: Get the last updated Release version of the repository., which is a custom interface ****
|
||
// produces:
|
||
// - application/json
|
||
// parameters:
|
||
// - name: owner
|
||
// in: path
|
||
// description: owner of the repo
|
||
// type: string
|
||
// required: true
|
||
// - name: repo
|
||
// in: path
|
||
// description: name of the repo
|
||
// type: string
|
||
// required: true
|
||
// responses:
|
||
// "200":
|
||
// "$ref": "#/responses/release"
|
||
// "404":
|
||
// "$ref": "#/responses/notFound"
|
||
var err error
|
||
if ctx.Repo.GitRepo == nil {
|
||
fmt.Println("*****ctx.Repo.GitRepo is nil ")
|
||
repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
|
||
ctx.Repo.GitRepo, err = git.OpenRepository(repoPath)
|
||
if err != nil {
|
||
ctx.ServerError("RepoRef Invalid repo "+repoPath, err)
|
||
return
|
||
}
|
||
// We opened it, we should close it
|
||
defer func() {
|
||
// If it's been set to nil then assume someone else has closed it.
|
||
if ctx.Repo.GitRepo != nil {
|
||
ctx.Repo.GitRepo.Close()
|
||
}
|
||
}()
|
||
}
|
||
|
||
release, err := models.GetLatestReleaseByRepoIDExt(ctx.Repo.Repository.ID)
|
||
//fmt.Println("****************ctx.Repo.Repository.ID:",ctx.Repo.Repository.ID," ",release," ",err)
|
||
if err != nil {
|
||
if models.IsErrReleaseNotExist(err) {
|
||
ctx.NotFound("LatestRelease", err)
|
||
return
|
||
}
|
||
ctx.ServerError("GetLatestReleaseByRepoID", err)
|
||
return
|
||
}
|
||
|
||
if err := release.LoadAttributes(); err != nil {
|
||
ctx.ServerError("LoadAttributes", err)
|
||
return
|
||
}
|
||
|
||
release.Publisher.Passwd = ""
|
||
ctx.JSON(http.StatusOK, release)
|
||
}
|
||
|
||
func Readme(ctx *context.APIContext) {
|
||
// swagger:operation GET /repos/{owner}/{repo}/readme repository readme
|
||
// ---
|
||
// summary: Get the content of the readme.* file, which is a custom interface *****
|
||
// produces:
|
||
// - application/json
|
||
// parameters:
|
||
// - name: owner
|
||
// in: path
|
||
// description: owner of the repo
|
||
// type: string
|
||
// required: true
|
||
// - name: repo
|
||
// in: path
|
||
// description: name of the repo
|
||
// type: string
|
||
// required: true
|
||
// - name: ref
|
||
// in: query
|
||
// description: "The name of the commit/branch/tag. Default the repository’s default branch (usually master)"
|
||
// type: string
|
||
// required: false
|
||
// responses:
|
||
// "200":
|
||
// "$ref": "#/responses/ReadmeDTO"
|
||
// "404":
|
||
// "$ref": "#/responses/notFound"
|
||
|
||
ctx.Data["Encoding"] = "base64"
|
||
treePath := ctx.Repo.TreePath
|
||
|
||
ref := ctx.QueryTrim("ref")
|
||
if ref == "" {
|
||
ref = ctx.Params(":ref")
|
||
if ref == "" {
|
||
ref = ctx.Repo.Repository.DefaultBranch
|
||
}
|
||
}
|
||
fmt.Println("***ref:", ref)
|
||
|
||
namedBlob, err := getReadmeFileFromPathExt(ctx, treePath, ref)
|
||
if err != nil || namedBlob == nil {
|
||
ctx.NotFound("getReadmeFileFromPath", err)
|
||
return
|
||
}
|
||
//fmt.Println("********getReadmeFileFromPathExt:",err," ",namedBlob)
|
||
FoundFileItem := namedBlob.name
|
||
ctx.Repo.TreePath = FoundFileItem //找到指定文件;
|
||
|
||
//fmt.Println("**** reqRepoReader(models.UnitTypeCode):",FoundFileItem)
|
||
ctx.Data["PageIsViewCode"] = true
|
||
if ctx.Repo.Repository.IsEmpty {
|
||
ctx.NotFound("Home", fmt.Errorf(ctx.Tr("Repository is empty")))
|
||
return
|
||
}
|
||
|
||
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
|
||
|
||
ctx.Repo.RepoLink = `/` + ctx.Repo.Owner.Name + `/` + ctx.Repo.Repository.Name
|
||
|
||
ctx.Repo.IsViewCommit = true //此处无实际意义;加上为了编译
|
||
|
||
branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
|
||
treeLink := branchLink
|
||
rawLink := ctx.Repo.RepoLink + "/raw/" + ctx.Repo.BranchNameSubURL()
|
||
//fmt.Println("******rawLink:",rawLink)
|
||
if len(ctx.Repo.TreePath) > 0 {
|
||
treeLink += "/" + ctx.Repo.TreePath
|
||
treeLink = strings.ReplaceAll(treeLink, "//", "/")
|
||
}
|
||
|
||
// Get current entry user currently looking at.
|
||
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath)
|
||
//fmt.Println("*********GetTreeEntryByPath:",entry," ",err)
|
||
if err != nil {
|
||
ctx.NotFound("Repo.Commit.GetTreeEntryByPath", err)
|
||
return
|
||
}
|
||
if entry == nil {
|
||
ctx.NotFound("Repo.Commit.GetTreeEntryByPath", err)
|
||
return
|
||
}
|
||
renderFile(ctx, entry, treeLink, rawLink)
|
||
//if ctx.Written() {
|
||
// return
|
||
//}
|
||
|
||
var treeNames []string
|
||
paths := make([]string, 0, 5)
|
||
if len(ctx.Repo.TreePath) > 0 {
|
||
treeNames = strings.Split(ctx.Repo.TreePath, "/")
|
||
fmt.Println("***treeNames:", treeNames)
|
||
for i := range treeNames {
|
||
paths = append(paths, strings.Join(treeNames[:i+1], "/"))
|
||
fmt.Println("***paths:", paths)
|
||
|
||
}
|
||
ctx.Data["HasParentPath"] = true
|
||
if len(paths)-2 >= 0 {
|
||
ctx.Data["ParentPath"] = "/" + paths[len(paths)-2]
|
||
}
|
||
}
|
||
|
||
ctx.Data["Paths"] = paths
|
||
ctx.Data["TreeLink"] = treeLink
|
||
ctx.Data["TreeNames"] = treeNames
|
||
ctx.Data["BranchLink"] = branchLink
|
||
|
||
fmt.Println("***rawLink:", rawLink)
|
||
fmt.Println("***paths:", paths)
|
||
fmt.Println("***treeLink:", treeLink)
|
||
fmt.Println("***treeNames:", treeNames)
|
||
fmt.Println("***branchLink:", branchLink)
|
||
|
||
ctx.JSON(http.StatusOK, Map2DTO(ctx))
|
||
|
||
}
|
||
|
||
/////////////
|
||
func ReadmeByPath(ctx *context.APIContext) {
|
||
// swagger:operation GET /repos/{owner}/{repo}/readme/{dir} repository readmePathContents
|
||
// ---
|
||
// summary: Gets the metadata and contents (if a file) of an entry in a repository, or a list of entries if a dir
|
||
// produces:
|
||
// - application/json
|
||
// parameters:
|
||
// - name: owner
|
||
// in: path
|
||
// description: owner of the repo
|
||
// type: string
|
||
// required: true
|
||
// - name: repo
|
||
// in: path
|
||
// description: name of the repo
|
||
// type: string
|
||
// required: true
|
||
// - name: dir
|
||
// in: path
|
||
// description: name of the path
|
||
// type: string
|
||
// required: true
|
||
// - name: ref
|
||
// in: query
|
||
// description: "The name of the commit/branch/tag. Default the repository’s default branch (usually master)"
|
||
// type: string
|
||
// required: false
|
||
// responses:
|
||
// "200":
|
||
// "$ref": "#/responses/ContentsResponse"
|
||
// "404":
|
||
// "$ref": "#/responses/notFound"
|
||
|
||
treePath := ctx.Params("*")
|
||
ref := ctx.QueryTrim("ref")
|
||
if ref == "" {
|
||
ref = ctx.Params(":ref")
|
||
if ref == "" {
|
||
ref = ctx.Repo.Repository.DefaultBranch
|
||
}
|
||
}
|
||
namedBlob, err := getReadmeFileFromPathExt(ctx, treePath, ref)
|
||
if err != nil || namedBlob == nil {
|
||
// ctx.NotFound("getReadmeFileFromPath", err)
|
||
fileList, err1 := repofiles.GetContentsOrList(ctx.Repo.Repository, treePath, ref)
|
||
if err1 != nil {
|
||
if git.IsErrNotExist(err1) {
|
||
ctx.NotFound("fileList", err1)
|
||
return
|
||
}
|
||
ctx.Error(http.StatusInternalServerError, "GetFileListByPath", err)
|
||
} else {
|
||
ctx.JSON(http.StatusOK, fileList)
|
||
}
|
||
} else {
|
||
FoundFileItem := namedBlob.name
|
||
newTreePath := treePath + "/" + FoundFileItem
|
||
|
||
contents, err2 := repofiles.GetContents(ctx.Repo.Repository, newTreePath, ref, false)
|
||
if err2 != nil {
|
||
if git.IsErrNotExist(err2) {
|
||
ctx.NotFound("GetReadmeContentByPath", err2)
|
||
return
|
||
}
|
||
ctx.Error(http.StatusInternalServerError, "GetReadmeContentByPath", err)
|
||
} else {
|
||
ctx.JSON(http.StatusOK, contents)
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
func ViewFile(ctx *context.APIContext) {
|
||
ctx.Data["Encoding"] = "base64"
|
||
|
||
fmt.Println("*********viewFile.ctx.Repo.TreePath:", ctx.Repo.TreePath)
|
||
namedBlob, err := getReadmeFileFromPath(ctx.Repo.Commit, ctx.Repo.TreePath)
|
||
if err != nil || namedBlob == nil {
|
||
ctx.NotFound("getReadmeFileFromPath", err)
|
||
return
|
||
}
|
||
FoundFileItem := namedBlob.name
|
||
ctx.Repo.TreePath = FoundFileItem //找到指定文件;
|
||
|
||
fmt.Println("****getReadmeFileFromPath:", FoundFileItem)
|
||
ctx.Data["PageIsViewCode"] = true
|
||
if ctx.Repo.Repository.IsEmpty {
|
||
ctx.NotFound("Home", fmt.Errorf(ctx.Tr("Repository is empty")))
|
||
return
|
||
}
|
||
|
||
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
|
||
|
||
ctx.Repo.RepoLink = `/` + ctx.Repo.Owner.Name + `/` + ctx.Repo.Repository.Name
|
||
|
||
branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
|
||
//fmt.Println("******branchLink:",branchLink)
|
||
treeLink := branchLink
|
||
rawLink := ctx.Repo.RepoLink + "/raw/" + ctx.Repo.BranchNameSubURL()
|
||
//fmt.Println("******rawLink:",rawLink)
|
||
if len(ctx.Repo.TreePath) > 0 {
|
||
treeLink += "/" + ctx.Repo.TreePath
|
||
}
|
||
//fmt.Println("******treeLink:",treeLink)
|
||
//fmt.Println("******ctx.Repo.TreePath111:",ctx.Repo.TreePath)
|
||
//fmt.Println("******ctx.Repo.BranchName:",ctx.Repo.BranchName)
|
||
|
||
//isExists,err:=ctx.Repo.FileExists(ctx.Repo.TreePath,ctx.Repo.BranchName)
|
||
//if !isExists || err != nil {
|
||
// ctx.NotFound("Repo.Commit.FileExists", err)
|
||
// return
|
||
//}
|
||
|
||
// Get current entry user currently looking at.
|
||
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath)
|
||
fmt.Println("*********GetTreeEntryByPath:", entry, " ", err)
|
||
if err != nil {
|
||
ctx.NotFound("Repo.Commit.GetTreeEntryByPath", err)
|
||
return
|
||
}
|
||
if entry == nil {
|
||
ctx.NotFound("Repo.Commit.GetTreeEntryByPath", err)
|
||
return
|
||
}
|
||
renderFile(ctx, entry, treeLink, rawLink)
|
||
//if ctx.Written() {
|
||
// return
|
||
//}
|
||
|
||
var treeNames []string
|
||
paths := make([]string, 0, 5)
|
||
if len(ctx.Repo.TreePath) > 0 {
|
||
treeNames = strings.Split(ctx.Repo.TreePath, "/")
|
||
fmt.Println("***treeNames:", treeNames)
|
||
for i := range treeNames {
|
||
paths = append(paths, strings.Join(treeNames[:i+1], "/"))
|
||
fmt.Println("***paths:", paths)
|
||
|
||
}
|
||
ctx.Data["HasParentPath"] = true
|
||
if len(paths)-2 >= 0 {
|
||
ctx.Data["ParentPath"] = "/" + paths[len(paths)-2]
|
||
}
|
||
}
|
||
|
||
ctx.Data["Paths"] = paths
|
||
ctx.Data["TreeLink"] = treeLink
|
||
ctx.Data["TreeNames"] = treeNames
|
||
ctx.Data["BranchLink"] = branchLink
|
||
|
||
fmt.Println("***rawLink:", rawLink)
|
||
fmt.Println("***paths:", paths)
|
||
fmt.Println("***treeLink:", treeLink)
|
||
fmt.Println("***treeNames:", treeNames)
|
||
fmt.Println("***branchLink:", branchLink)
|
||
|
||
ctx.JSON(http.StatusOK, Map2DTO(ctx))
|
||
|
||
}
|
||
|
||
func renderFile(ctx *context.APIContext, entry *git.TreeEntry, treeLink, rawLink string) {
|
||
ctx.Data["IsViewFile"] = true
|
||
blob := entry.Blob()
|
||
dataRc, err := blob.DataAsync()
|
||
if err != nil {
|
||
ctx.Error(http.StatusInternalServerError, "DataAsync", err)
|
||
return
|
||
}
|
||
defer dataRc.Close()
|
||
|
||
ctx.Data["Title"] = ctx.Data["Title"].(string) + " - " + ctx.Repo.TreePath + " at " + ctx.Repo.BranchName
|
||
|
||
fileSize := blob.Size()
|
||
ctx.Data["FileIsSymlink"] = entry.IsLink()
|
||
ctx.Data["FileSize"] = fileSize
|
||
ctx.Data["FileName"] = blob.Name()
|
||
ctx.Data["RawFileLink"] = rawLink + "/" + ctx.Repo.TreePath
|
||
|
||
Base64Encoding := base64.StdEncoding
|
||
if ctx.Data["Encoding"] == "base64url" {
|
||
Base64Encoding = base64.RawURLEncoding
|
||
}
|
||
buf := make([]byte, 1024)
|
||
n, _ := dataRc.Read(buf)
|
||
buf = buf[:n]
|
||
|
||
isTextFile := base.IsTextFile(buf)
|
||
isLFSFile := false
|
||
ctx.Data["IsTextFile"] = isTextFile
|
||
//Check for LFS meta file
|
||
if isTextFile && setting.LFS.StartServer {
|
||
meta := lfs.IsPointerFile(&buf)
|
||
if meta != nil {
|
||
meta, err = ctx.Repo.Repository.GetLFSMetaObjectByOid(meta.Oid)
|
||
if err != nil && err != models.ErrLFSObjectNotExist {
|
||
ctx.Error(http.StatusInternalServerError, "GetLFSMetaObject", err)
|
||
return
|
||
}
|
||
}
|
||
fmt.Println("***setting.LFS.StartServer:", meta)
|
||
if meta != nil {
|
||
ctx.Data["IsLFSFile"] = true
|
||
isLFSFile = true
|
||
|
||
// OK read the lfs object
|
||
var err error
|
||
dataRc, err = lfs.ReadMetaObject(meta)
|
||
if err != nil {
|
||
ctx.Error(http.StatusInternalServerError, "ReadMetaObject", err)
|
||
return
|
||
}
|
||
defer dataRc.Close()
|
||
|
||
buf = make([]byte, 1024)
|
||
n, err = dataRc.Read(buf)
|
||
if err != nil {
|
||
ctx.Error(http.StatusInternalServerError, "Data", err)
|
||
return
|
||
}
|
||
buf = buf[:n]
|
||
|
||
isTextFile = base.IsTextFile(buf)
|
||
ctx.Data["IsTextFile"] = isTextFile
|
||
|
||
fileSize = meta.Size
|
||
ctx.Data["FileSize"] = meta.Size
|
||
filenameBase64 := base64.RawURLEncoding.EncodeToString([]byte(blob.Name()))
|
||
ctx.Data["RawFileLink"] = fmt.Sprintf("%s%s.git/info/lfs/objects/%s/%s", setting.AppURL, ctx.Repo.Repository.FullName(), meta.Oid, filenameBase64)
|
||
}
|
||
}
|
||
// Check LFS Lock
|
||
lfsLock, err := ctx.Repo.Repository.GetTreePathLock(ctx.Repo.TreePath)
|
||
ctx.Data["LFSLock"] = lfsLock
|
||
if err != nil {
|
||
ctx.Error(http.StatusInternalServerError, "GetTreePathLock", err)
|
||
return
|
||
}
|
||
if lfsLock != nil {
|
||
ctx.Data["LFSLockOwner"] = lfsLock.Owner.DisplayName()
|
||
ctx.Data["LFSLockHint"] = ctx.Tr("repo.editor.this_file_locked")
|
||
}
|
||
|
||
// Assume file is not editable first.
|
||
if isLFSFile {
|
||
ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.cannot_edit_lfs_files")
|
||
} else if !isTextFile {
|
||
ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.cannot_edit_non_text_files")
|
||
}
|
||
|
||
switch {
|
||
case isTextFile:
|
||
if fileSize >= setting.UI.MaxDisplayFileSize {
|
||
ctx.Data["IsFileTooLarge"] = true
|
||
break
|
||
}
|
||
|
||
d, _ := ioutil.ReadAll(dataRc)
|
||
buf = charset.ToUTF8WithFallback(append(buf, d...))
|
||
readmeExist := markup.IsReadmeFile(blob.Name())
|
||
ctx.Data["ReadmeExist"] = readmeExist
|
||
if markupType := markup.Type(blob.Name()); markupType != "" {
|
||
ctx.Data["IsMarkup"] = true
|
||
ctx.Data["MarkupType"] = markupType
|
||
//ctx.Data["FileContent"] = string(markup.Render(blob.Name(), buf, path.Dir(treeLink), ctx.Repo.Repository.ComposeDocumentMetas()))
|
||
filenameBase64 := Base64Encoding.EncodeToString(buf)
|
||
ctx.Data["FileContent"] = filenameBase64
|
||
//fmt.Println("************FileContent1:",ctx.Data["FileContent"].(string))
|
||
} else if readmeExist {
|
||
ctx.Data["IsRenderedHTML"] = true
|
||
ctx.Data["FileContent"] = strings.Replace(
|
||
gotemplate.HTMLEscapeString(string(buf)), "\n", `<br>`, -1,
|
||
)
|
||
} else {
|
||
buf = charset.ToUTF8WithFallback(buf)
|
||
lineNums := linesBytesCount(buf)
|
||
ctx.Data["NumLines"] = strconv.Itoa(lineNums)
|
||
ctx.Data["NumLinesSet"] = true
|
||
//ctx.Data["FileContent"] = highlight.File(lineNums, blob.Name(), buf)
|
||
|
||
filenameBase64 := Base64Encoding.EncodeToString(buf)
|
||
ctx.Data["FileContent"] = filenameBase64
|
||
//fmt.Println("************FileContent2:",ctx.Data["FileContent"].(string))
|
||
}
|
||
if !isLFSFile {
|
||
if ctx.Repo.CanEnableEditor() {
|
||
if lfsLock != nil && lfsLock.OwnerID != ctx.User.ID {
|
||
ctx.Data["CanEditFile"] = false
|
||
ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.this_file_locked")
|
||
} else {
|
||
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.CanWrite(models.UnitTypeCode) {
|
||
ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.fork_before_edit")
|
||
}
|
||
}
|
||
|
||
case base.IsPDFFile(buf):
|
||
ctx.Data["IsPDFFile"] = true
|
||
case base.IsVideoFile(buf):
|
||
ctx.Data["IsVideoFile"] = true
|
||
case base.IsAudioFile(buf):
|
||
ctx.Data["IsAudioFile"] = true
|
||
case base.IsImageFile(buf):
|
||
ctx.Data["IsImageFile"] = true
|
||
default:
|
||
if fileSize >= setting.UI.MaxDisplayFileSize {
|
||
ctx.Data["IsFileTooLarge"] = true
|
||
break
|
||
}
|
||
|
||
if markupType := markup.Type(blob.Name()); markupType != "" {
|
||
d, _ := ioutil.ReadAll(dataRc)
|
||
buf = append(buf, d...)
|
||
ctx.Data["IsMarkup"] = true
|
||
ctx.Data["MarkupType"] = markupType
|
||
//ctx.Data["FileContent"] = string(markup.Render(blob.Name(), buf, path.Dir(treeLink), ctx.Repo.Repository.ComposeDocumentMetas()))
|
||
|
||
filenameBase64 := Base64Encoding.EncodeToString(buf)
|
||
ctx.Data["FileContent"] = filenameBase64
|
||
fmt.Println("************FileContent3:", ctx.Data["FileContent"].(string))
|
||
}
|
||
|
||
}
|
||
}
|
||
func safeURL(address string) string {
|
||
u, err := url.Parse(address)
|
||
if err != nil {
|
||
return address
|
||
}
|
||
u.User = nil
|
||
return u.String()
|
||
}
|
||
|
||
func linesBytesCount(s []byte) int {
|
||
nl := []byte{'\n'}
|
||
n := bytes.Count(s, nl)
|
||
if len(s) > 0 && !bytes.HasSuffix(s, nl) {
|
||
n++
|
||
}
|
||
return n
|
||
}
|
||
|
||
/*
|
||
{
|
||
"type": "file",
|
||
"encoding": "base64",
|
||
"size": 5362,
|
||
"name": "README.md",
|
||
"path": "README.md",
|
||
"content": "encoded content ...",
|
||
"sha": "3d21ec53a331a6f037a91c368710b99387d012c1",
|
||
}
|
||
*/
|
||
|
||
// FIXME: There has to be a more efficient way of doing this
|
||
func getReadmeFileFromPath(commit *git.Commit, treePath string) (*namedBlob, error) {
|
||
|
||
tree, err := commit.SubTree(treePath)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
entries, err := tree.ListEntries()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var readmeFiles [4]*namedBlob
|
||
var exts = []string{".md", ".txt", ""} // sorted by priority
|
||
for _, entry := range entries {
|
||
if entry.IsDir() {
|
||
continue
|
||
}
|
||
for i, ext := range exts {
|
||
if markup.IsReadmeFile(entry.Name(), ext) || IsReadmeFileExt(entry.Name(), ext) {
|
||
if readmeFiles[i] == nil || base.NaturalSortLess(readmeFiles[i].name, entry.Blob().Name()) {
|
||
name := entry.Name()
|
||
isSymlink := entry.IsLink()
|
||
target := entry
|
||
if isSymlink {
|
||
target, err = entry.FollowLinks()
|
||
if err != nil && !git.IsErrBadLink(err) {
|
||
return nil, err
|
||
}
|
||
}
|
||
if target != nil && (target.IsExecutable() || target.IsRegular()) {
|
||
readmeFiles[i] = &namedBlob{
|
||
name,
|
||
isSymlink,
|
||
target.Blob(),
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if markup.IsReadmeFile(entry.Name()) {
|
||
if readmeFiles[3] == nil || base.NaturalSortLess(readmeFiles[3].name, entry.Blob().Name()) {
|
||
name := entry.Name()
|
||
isSymlink := entry.IsLink()
|
||
if isSymlink {
|
||
entry, err = entry.FollowLinks()
|
||
if err != nil && !git.IsErrBadLink(err) {
|
||
return nil, err
|
||
}
|
||
}
|
||
if entry != nil && (entry.IsExecutable() || entry.IsRegular()) {
|
||
readmeFiles[3] = &namedBlob{
|
||
name,
|
||
isSymlink,
|
||
entry.Blob(),
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
var readmeFile *namedBlob
|
||
for _, f := range readmeFiles {
|
||
if f != nil {
|
||
readmeFile = f
|
||
break
|
||
}
|
||
}
|
||
return readmeFile, nil
|
||
}
|
||
|
||
// FIXME: There has to be a more efficient way of doing this
|
||
func getReadmeFileFromPathExt(ctx *context.APIContext, treePath, ref string) (*namedBlob, error) {
|
||
log.Info("*****************getReadmeFileFromPathExt.GetCommit:ref:%s treepath:%s", ref, treePath)
|
||
var err error
|
||
if ctx.Repo.GitRepo == nil {
|
||
repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
|
||
ctx.Repo.GitRepo, err = git.OpenRepository(repoPath)
|
||
if err != nil {
|
||
ctx.ServerError("RepoRef Invalid repo "+repoPath, err)
|
||
return nil, err
|
||
}
|
||
// We opened it, we should close it
|
||
defer func() {
|
||
// If it's been set to nil then assume someone else has closed it.
|
||
if ctx.Repo.GitRepo != nil {
|
||
ctx.Repo.GitRepo.Close()
|
||
}
|
||
}()
|
||
}
|
||
|
||
// Get the commit object for the ref
|
||
commit, err := ctx.Repo.GitRepo.GetCommit(ref)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
//log.Info("********GetCommit:%v",commit)
|
||
|
||
ctx.Repo.Commit = commit
|
||
|
||
tree, err := commit.SubTree(treePath)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
//log.Info("********SubTree:%v",tree)
|
||
|
||
entries, err := tree.ListEntries()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
//log.Info("********ListEntries:%v, %v",err,entries)
|
||
var readmeFiles [4]*namedBlob
|
||
var exts = []string{".md", ".txt", ""} // sorted by priority
|
||
for _, entry := range entries {
|
||
if entry.IsDir() {
|
||
continue
|
||
}
|
||
for i, ext := range exts {
|
||
if markup.IsReadmeFile(entry.Name(), ext) || IsReadmeFileExt(entry.Name(), ext) {
|
||
if readmeFiles[i] == nil || base.NaturalSortLess(readmeFiles[i].name, entry.Blob().Name()) {
|
||
name := entry.Name()
|
||
isSymlink := entry.IsLink()
|
||
target := entry
|
||
if isSymlink {
|
||
target, err = entry.FollowLinks()
|
||
if err != nil && !git.IsErrBadLink(err) {
|
||
return nil, err
|
||
}
|
||
}
|
||
if target != nil && (target.IsExecutable() || target.IsRegular()) {
|
||
readmeFiles[i] = &namedBlob{
|
||
name,
|
||
isSymlink,
|
||
target.Blob(),
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if markup.IsReadmeFile(entry.Name()) {
|
||
if readmeFiles[3] == nil || base.NaturalSortLess(readmeFiles[3].name, entry.Blob().Name()) {
|
||
name := entry.Name()
|
||
isSymlink := entry.IsLink()
|
||
if isSymlink {
|
||
entry, err = entry.FollowLinks()
|
||
if err != nil && !git.IsErrBadLink(err) {
|
||
return nil, err
|
||
}
|
||
}
|
||
if entry != nil && (entry.IsExecutable() || entry.IsRegular()) {
|
||
readmeFiles[3] = &namedBlob{
|
||
name,
|
||
isSymlink,
|
||
entry.Blob(),
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
var readmeFile *namedBlob
|
||
for _, f := range readmeFiles {
|
||
if f != nil {
|
||
readmeFile = f
|
||
break
|
||
}
|
||
}
|
||
return readmeFile, nil
|
||
}
|
||
|
||
func FindFiles(ctx *context.APIContext) {
|
||
// swagger:operation GET /repos/{owner}/{repo}/find repository find
|
||
// ---
|
||
// summary: The search file contains subdirectories, which is a custom interface *****
|
||
// produces:
|
||
// - application/json
|
||
// parameters:
|
||
// - name: owner
|
||
// in: path
|
||
// description: owner of the repo
|
||
// type: string
|
||
// required: true
|
||
// - name: repo
|
||
// in: path
|
||
// description: name of the repo
|
||
// type: string
|
||
// required: true
|
||
// - name: ref
|
||
// in: query
|
||
// description: "The name of the commit/branch/tag. Default the repository’s default branch (usually master)"
|
||
// type: string
|
||
// required: false
|
||
// - name: q
|
||
// in: query
|
||
// description: "Search keywords"
|
||
// type: string
|
||
// required: false
|
||
// responses:
|
||
// "200":
|
||
// "$ref": "#/responses/[]*SearchFileItem"
|
||
// "404":
|
||
// "$ref": "#/responses/notFound"
|
||
|
||
treePath := ctx.Repo.TreePath
|
||
ref := ctx.QueryTrim("ref")
|
||
if ref == "" {
|
||
ref = ctx.Repo.Repository.DefaultBranch
|
||
}
|
||
fmt.Println("***ref:", ref)
|
||
keyword := ctx.QueryTrim("q")
|
||
if keyword == "" {
|
||
//keyword="README" //test
|
||
}
|
||
|
||
FindList, err := FindFileFromPathExt(ctx, treePath, ref, keyword)
|
||
if err != nil {
|
||
ctx.NotFound("FindFiles", err)
|
||
return
|
||
}
|
||
|
||
ctx.JSON(http.StatusOK, FindList)
|
||
}
|
||
|
||
// TO DO
|
||
func FindFileFromPathExt(ctx *context.APIContext, treePath, ref, key string) (fileList []*SearchFileItem, err error) {
|
||
if ctx.Repo.GitRepo == nil {
|
||
repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
|
||
ctx.Repo.GitRepo, err = git.OpenRepository(repoPath)
|
||
if err != nil {
|
||
ctx.ServerError("RepoRef Invalid repo "+repoPath, err)
|
||
return nil, err
|
||
}
|
||
// We opened it, we should close it
|
||
defer func() {
|
||
// If it's been set to nil then assume someone else has closed it.
|
||
if ctx.Repo.GitRepo != nil {
|
||
ctx.Repo.GitRepo.Close()
|
||
}
|
||
}()
|
||
}
|
||
|
||
// Get the commit object for the ref
|
||
commit, err := ctx.Repo.GitRepo.GetCommit(ref)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
tree, err := commit.SubTree(treePath)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
//entries, err := tree.ListEntries()
|
||
//if err != nil {
|
||
// return nil, err
|
||
//}
|
||
entries, err := tree.ListEntriesRecursive()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
fileList = make([]*SearchFileItem, 0, 0)
|
||
|
||
for _, entry := range entries {
|
||
if entry.IsDir() {
|
||
continue
|
||
}
|
||
|
||
fileName := filepath.Base(entry.Name())
|
||
|
||
if strings.Contains(strings.ToLower(fileName), strings.ToLower(key)) || key == "" {
|
||
name := entry.Name()
|
||
//isSymlink := entry.IsLink()
|
||
//target := entry
|
||
//_=target
|
||
//
|
||
//if isSymlink {
|
||
// target, err = entry.FollowLinks()
|
||
// if err != nil && !git.IsErrBadLink(err) {
|
||
// return nil, err
|
||
// }
|
||
//}
|
||
treePath = name
|
||
selfURL, err := url.Parse(fmt.Sprintf("%s/contents/%s?ref=%s", ctx.Repo.Repository.APIURL(), treePath, ref))
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
selfURLString := selfURL.String()
|
||
|
||
refType := ctx.Repo.GitRepo.GetRefType(ref)
|
||
if refType == "invalid" {
|
||
return nil, fmt.Errorf("no commit found for the ref [ref: %s]", ref)
|
||
}
|
||
|
||
htmlURL, err := url.Parse(fmt.Sprintf("%s/src/%s/%s/%s", ctx.Repo.Repository.HTMLURL(), refType, ref, treePath))
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
htmlURLString := htmlURL.String()
|
||
|
||
Item := &SearchFileItem{
|
||
Name: fileName,
|
||
Path: treePath,
|
||
SHA: entry.ID.String(),
|
||
Type: entry.Type(),
|
||
Size: entry.Size(),
|
||
URL: &selfURLString,
|
||
HTMLURL: &htmlURLString,
|
||
}
|
||
|
||
// Now populate the rest of the ContentsResponse based on entry type
|
||
if entry.IsRegular() || entry.IsExecutable() {
|
||
Item.Type = string(repofiles.ContentTypeRegular)
|
||
|
||
} else if entry.IsDir() {
|
||
Item.Type = string(repofiles.ContentTypeDir)
|
||
} else if entry.IsLink() {
|
||
Item.Type = string(repofiles.ContentTypeLink)
|
||
|
||
} else if entry.IsSubModule() {
|
||
Item.Type = string(repofiles.ContentTypeSubmodule)
|
||
}
|
||
fileList = append(fileList, Item)
|
||
}
|
||
|
||
}
|
||
return
|
||
}
|
||
|
||
type SearchFileItem struct {
|
||
Name string `json:"name"`
|
||
Path string `json:"path"`
|
||
SHA string `json:"sha"`
|
||
// `type` will be `file`, `dir`, `symlink`, or `submodule`
|
||
Type string `json:"type"`
|
||
Size int64 `json:"size"`
|
||
URL *string `json:"url"`
|
||
HTMLURL *string `json:"html_url"`
|
||
// GitURL *string `json:"git_url"`
|
||
// DownloadURL *string `json:"download_url"`
|
||
// // `submodule_git_url` is populated when `type` is `submodule`, otherwise null
|
||
// SubmoduleGitURL *string `json:"submodule_git_url"`
|
||
// Links *api.FileLinksResponse `json:"_links"`
|
||
}
|
||
|
||
func IsReadmeFileExt(name string, ext ...string) bool {
|
||
name = strings.ToLower(name)
|
||
if len(ext) > 0 {
|
||
return name == "readme_zh"+ext[0]
|
||
}
|
||
if len(name) < 6 {
|
||
return false
|
||
} else if len(name) == 6 {
|
||
return name == "readme_zh"
|
||
}
|
||
return name[:7] == "readme_zh."
|
||
}
|
||
|
||
type namedBlob struct {
|
||
name string
|
||
isSymlink bool
|
||
blob *git.Blob
|
||
}
|
||
|
||
type ReadmeDTO struct {
|
||
Type string `json:"type"`
|
||
Encoding string `json:"encoding"`
|
||
Size int64 `json:"size"`
|
||
Name string `json:"name"`
|
||
Path string `json:"path"`
|
||
Content string `json:"content"`
|
||
Sha string `json:"sha"`
|
||
//URL string `json:"url"`
|
||
//GitURL string `json:"git_url"`
|
||
//HTMLURL string `json:"html_url"`
|
||
//DownloadURL string `json:"download_url"`
|
||
//Links struct {
|
||
// Git string `json:"git"`
|
||
// Self string `json:"self"`
|
||
// HTML string `json:"html"`
|
||
//} `json:"_links"`
|
||
}
|
||
|
||
type ReadmeResponeDTO struct {
|
||
Msg string
|
||
Code int
|
||
ReadmeDTO *ReadmeDTO
|
||
}
|