read single file
This commit is contained in:
parent
805732fdc7
commit
24678d73f5
7 changed files with 226 additions and 119 deletions
|
@ -81,6 +81,7 @@ var (
|
|||
var (
|
||||
ErrRepoAlreadyExist = errors.New("Repository already exist")
|
||||
ErrRepoNotExist = errors.New("Repository does not exist")
|
||||
ErrRepoFileNotExist = errors.New("Target Repo file does not exist")
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -463,6 +464,51 @@ func GetBranches(userName, reposName string) ([]string, error) {
|
|||
return brs, nil
|
||||
}
|
||||
|
||||
func GetTargetFile(userName, reposName, branchName, commitId, rpath string) (*RepoFile, error) {
|
||||
repo, err := git.OpenRepository(RepoPath(userName, reposName))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
commit, err := repo.GetCommit(branchName, commitId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parts := strings.Split(path.Clean(rpath), "/")
|
||||
|
||||
var entry *git.TreeEntry
|
||||
tree := commit.Tree
|
||||
for i, part := range parts {
|
||||
if i == len(parts)-1 {
|
||||
entry = tree.EntryByName(part)
|
||||
if entry == nil {
|
||||
return nil, ErrRepoFileNotExist
|
||||
}
|
||||
} else {
|
||||
tree, err = repo.SubTree(tree, part)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size, err := repo.ObjectSize(entry.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repoFile := &RepoFile{
|
||||
entry,
|
||||
rpath,
|
||||
size,
|
||||
repo,
|
||||
commit,
|
||||
}
|
||||
|
||||
return repoFile, nil
|
||||
}
|
||||
|
||||
// GetReposFiles returns a list of file object in given directory of repository.
|
||||
func GetReposFiles(userName, reposName, branchName, commitId, rpath string) ([]*RepoFile, error) {
|
||||
repo, err := git.OpenRepository(RepoPath(userName, reposName))
|
||||
|
|
|
@ -7,6 +7,8 @@ package base
|
|||
import (
|
||||
"bytes"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gogits/gfm"
|
||||
)
|
||||
|
@ -31,6 +33,26 @@ func isLink(link []byte) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func IsMarkdownFile(name string) bool {
|
||||
name = strings.ToLower(name)
|
||||
switch filepath.Ext(name) {
|
||||
case "md", "markdown":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func IsReadmeFile(name string) bool {
|
||||
name = strings.ToLower(name)
|
||||
if len(name) < 6 {
|
||||
return false
|
||||
}
|
||||
if name[:6] == "readme" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type CustomRender struct {
|
||||
gfm.Renderer
|
||||
urlPrefix string
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/codegangsta/martini"
|
||||
|
@ -47,7 +46,7 @@ func Single(ctx *middleware.Context, params martini.Params) {
|
|||
return
|
||||
}
|
||||
|
||||
if params["branchname"] == "" {
|
||||
if len(params["branchname"]) == 0 {
|
||||
params["branchname"] = "master"
|
||||
}
|
||||
|
||||
|
@ -56,7 +55,7 @@ func Single(ctx *middleware.Context, params martini.Params) {
|
|||
|
||||
if len(treename) > 0 && treename[len(treename)-1] == '/' {
|
||||
ctx.Redirect("/"+ctx.Repo.Owner.LowerName+"/"+
|
||||
ctx.Repo.Repository.Name+"/tree/"+params["branchname"]+"/"+treename[:len(treename)-1], 302)
|
||||
ctx.Repo.Repository.Name+"/src/"+params["branchname"]+"/"+treename[:len(treename)-1], 302)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -74,14 +73,78 @@ func Single(ctx *middleware.Context, params martini.Params) {
|
|||
|
||||
ctx.Data["Branches"] = brs
|
||||
|
||||
// Directory and file list.
|
||||
files, err := models.GetReposFiles(params["username"], params["reponame"],
|
||||
repoFile, err := models.GetTargetFile(params["username"], params["reponame"],
|
||||
params["branchname"], params["commitid"], treename)
|
||||
if err != nil {
|
||||
log.Error("repo.Single(GetReposFiles): %v", err)
|
||||
|
||||
if err != nil && err != models.ErrRepoFileNotExist {
|
||||
log.Error("repo.Single(GetTargetFile): %v", err)
|
||||
ctx.Error(404)
|
||||
return
|
||||
}
|
||||
|
||||
branchLink := "/" + ctx.Repo.Owner.LowerName + "/" + ctx.Repo.Repository.Name + "/src/" + params["branchname"]
|
||||
|
||||
if repoFile != nil && repoFile.IsFile() {
|
||||
if repoFile.Size > 1024*1024 || repoFile.Filemode != git.FileModeBlob {
|
||||
ctx.Data["FileIsLarge"] = true
|
||||
} else if blob, err := repoFile.LookupBlob(); err != nil {
|
||||
log.Error("repo.Single(repoFile.LookupBlob): %v", err)
|
||||
ctx.Error(404)
|
||||
} else {
|
||||
ctx.Data["IsFile"] = true
|
||||
ctx.Data["FileName"] = repoFile.Name
|
||||
|
||||
readmeExist := base.IsMarkdownFile(repoFile.Name) || base.IsReadmeFile(repoFile.Name)
|
||||
ctx.Data["ReadmeExist"] = readmeExist
|
||||
if readmeExist {
|
||||
ctx.Data["FileContent"] = string(base.RenderMarkdown(blob.Contents(), ""))
|
||||
} else {
|
||||
ctx.Data["FileContent"] = string(blob.Contents())
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Directory and file list.
|
||||
files, err := models.GetReposFiles(params["username"], params["reponame"],
|
||||
params["branchname"], params["commitid"], treename)
|
||||
if err != nil {
|
||||
log.Error("repo.Single(GetReposFiles): %v", err)
|
||||
ctx.Error(404)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Files"] = files
|
||||
|
||||
var readmeFile *models.RepoFile
|
||||
|
||||
for _, f := range files {
|
||||
if !f.IsFile() || !base.IsReadmeFile(f.Name) {
|
||||
continue
|
||||
} else {
|
||||
readmeFile = f
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if readmeFile != nil {
|
||||
ctx.Data["ReadmeExist"] = true
|
||||
// if file large than 1M not show it
|
||||
if readmeFile.Size > 1024*1024 || readmeFile.Filemode != git.FileModeBlob {
|
||||
ctx.Data["FileIsLarge"] = true
|
||||
} else if blob, err := readmeFile.LookupBlob(); err != nil {
|
||||
log.Error("repo.Single(readmeFile.LookupBlob): %v", err)
|
||||
ctx.Error(404)
|
||||
return
|
||||
} else {
|
||||
// current repo branch link
|
||||
urlPrefix := "http://" + base.Domain + branchLink
|
||||
|
||||
ctx.Data["FileName"] = readmeFile.Name
|
||||
ctx.Data["FileContent"] = string(base.RenderMarkdown(blob.Contents(), urlPrefix))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Data["Username"] = params["username"]
|
||||
ctx.Data["Reponame"] = params["reponame"]
|
||||
ctx.Data["Branchname"] = params["branchname"]
|
||||
|
@ -111,39 +174,10 @@ func Single(ctx *middleware.Context, params martini.Params) {
|
|||
}
|
||||
ctx.Data["LastCommit"] = commit
|
||||
|
||||
var readmeFile *models.RepoFile
|
||||
|
||||
for _, f := range files {
|
||||
if !f.IsFile() || len(f.Name) < 6 {
|
||||
continue
|
||||
} else if strings.ToLower(f.Name[:6]) == "readme" {
|
||||
readmeFile = f
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if readmeFile != nil {
|
||||
ctx.Data["ReadmeExist"] = true
|
||||
// if file large than 1M not show it
|
||||
if readmeFile.Size > 1024*1024 || readmeFile.Filemode != git.FileModeBlob {
|
||||
ctx.Data["FileIsLarge"] = true
|
||||
} else if blob, err := readmeFile.LookupBlob(); err != nil {
|
||||
ctx.Data["ReadmeExist"] = false
|
||||
} else {
|
||||
// current repo branch link
|
||||
urlPrefix := "http://" + base.Domain + "/" + ctx.Repo.Owner.LowerName + "/" +
|
||||
ctx.Repo.Repository.Name + "/tree/" + params["branchname"]
|
||||
|
||||
ctx.Data["ReadmeContent"] = string(base.RenderMarkdown(blob.Contents(), urlPrefix))
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println(Paths)
|
||||
|
||||
ctx.Data["Paths"] = Paths
|
||||
ctx.Data["Treenames"] = treenames
|
||||
ctx.Data["IsRepoToolbarSource"] = true
|
||||
ctx.Data["Files"] = files
|
||||
ctx.Data["BranchLink"] = branchLink
|
||||
ctx.HTML(200, "repo/single", ctx.Data)
|
||||
}
|
||||
|
||||
|
|
|
@ -8,104 +8,35 @@
|
|||
Need to fill in some guide.
|
||||
{{else}}
|
||||
<div class="source-toolbar">
|
||||
{{ $username := .Username}}
|
||||
{{ $reponame := .Reponame}}
|
||||
{{ $branchname := .Branchname}}
|
||||
{{ $treenames := .Treenames}}
|
||||
{{ $repoLink := .RepositoryLink}}
|
||||
{{ $n := len $treenames}}
|
||||
<button class="btn btn-default pull-right"><i class="fa fa-plus-square"></i>Add File</button>
|
||||
{{ $n := len .Treenames}}
|
||||
{{if not .IsFile}}<button class="btn btn-default pull-right"><i class="fa fa-plus-square"></i>Add File</button>{{end}}
|
||||
<div class="dropdown branch-switch">
|
||||
<a href="#" class="btn btn-success dropdown-toggle" data-toggle="dropdown"><i class="fa fa-chain"></i>{{$branchname}}
|
||||
<a href="#" class="btn btn-success dropdown-toggle" data-toggle="dropdown"><i class="fa fa-chain"></i>{{.Branchname}}
|
||||
<b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
{{range .Branches}}
|
||||
<li><a {{if eq . $branchname}}class="current" {{end}}href="/{{$repoLink}}/tree/{{.}}">{{.}}</a></li>
|
||||
<li><a {{if eq . $.Branchname}}class="current" {{end}}href="{{$.BranchLink}}">{{.}}</a></li>
|
||||
{{end}}
|
||||
</ul>
|
||||
</div>
|
||||
{{$paths := .Paths}}
|
||||
{{ $l := Subtract $n 1}}
|
||||
<ol class="breadcrumb">
|
||||
<li class="root dir">
|
||||
<a href="/{{$username}}/{{$reponame}}/tree/{{$branchname}}">{{.Repository.Name}}</a></li>
|
||||
{{range $i, $v := $treenames}}
|
||||
<a href="{{.BranchLink}}">{{.Repository.Name}}</a></li>
|
||||
{{range $i, $v := .Treenames}}
|
||||
<li class="dir">
|
||||
{{if eq $i $l}}{{$v}}
|
||||
{{else}}
|
||||
<a href="/{{$username}}/{{$reponame}}/tree/{{$branchname}}/{{index $paths $i}}">{{$v}}</a>
|
||||
<a href="{{$.BranchLink}}/{{index $.Paths $i}}">{{$v}}</a>
|
||||
{{end}}
|
||||
</li>
|
||||
{{end}}
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default info-box">
|
||||
<div class="panel-heading info-head">
|
||||
<a href="/{{$username}}/{{$reponame}}/commit/{{.LastCommit.Oid.String}}">{{.LastCommit.Message}}</a>
|
||||
</div>
|
||||
<div class="panel-body info-content">
|
||||
<a href="/user/{{.LastCommit.Author.Name}}">{{.LastCommit.Author.Name}}</a> <span class="text-muted">{{TimeSince .LastCommit.Author.When}}</span>
|
||||
</div>
|
||||
<table class="panel-footer table file-list">
|
||||
<thead class="hidden">
|
||||
<tr>
|
||||
<th class="icon"></th>
|
||||
<th class="name">Filename</th>
|
||||
<th class="text">Message</th>
|
||||
<th class="date">Date modified</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{if .HasParentPath}}
|
||||
<tr class="has-parent">
|
||||
<td class="icon"><a href="/{{$username}}/{{$reponame}}/tree/{{$branchname}}{{.ParentPath}}"><i class="fa fa-reply"></i></a></td>
|
||||
<td class="name"><a href="/{{$username}}/{{$reponame}}/tree/{{$branchname}}{{.ParentPath}}">..</a></td>
|
||||
<td class="text"></td>
|
||||
<td class="date"></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
{{range .Files}}
|
||||
<tr
|
||||
{{if .IsDir}}class="is-dir"{{end}}>
|
||||
<td class="icon">
|
||||
<i class="fa {{if .IsDir}}fa-folder{{else}}fa-file-text-o{{end}}"></i>
|
||||
</td>
|
||||
<td class="name">
|
||||
<span class="wrap">
|
||||
{{if .IsDir}}
|
||||
<a href="/{{$username}}/{{$reponame}}/tree/{{$branchname}}/{{.Path}}">{{.Name}}</a>
|
||||
{{else}}
|
||||
<a href="/{{$username}}/{{$reponame}}/blob/{{$branchname}}/{{.Name}}">{{.Name}}</a>
|
||||
{{end}}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text">
|
||||
<span class="wrap"><a href="/{{$username}}/{{$reponame}}/commit/{{.Commit.Oid}}">{{.Commit.Message}}</a></span>
|
||||
</td>
|
||||
<td class="date">
|
||||
<span class="wrap">{{TimeSince .Commit.Committer.When}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{if .ReadmeExist}}
|
||||
<div class="panel panel-default file-content">
|
||||
<div class="panel-heading file-head">
|
||||
<i class="icon fa fa-book"></i> README.md
|
||||
</div>
|
||||
{{if .FileIsLarge}}
|
||||
<div class="panel-footer">
|
||||
Large file size 1000kb
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="panel-body file-body markdown">
|
||||
{{.ReadmeContent|str2html}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{if .IsFile}}
|
||||
{{template "repo/single_file" .}}
|
||||
{{else}}
|
||||
{{template "repo/single_list" .}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
|
|
20
templates/repo/single_file.tmpl
Normal file
20
templates/repo/single_file.tmpl
Normal file
|
@ -0,0 +1,20 @@
|
|||
<div class="panel panel-default file-content">
|
||||
<div class="panel-heading file-head">
|
||||
<i class="icon fa fa-book"></i> {{.FileName}}
|
||||
</div>
|
||||
{{if .FileIsLarge}}
|
||||
<div class="panel-footer">
|
||||
Large file size 1000kb
|
||||
</div>
|
||||
{{else}}
|
||||
{{if .ReadmeExist}}
|
||||
<div class="panel-body file-body markdown">
|
||||
{{.FileContent|str2html}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="panel-body file-body markdown">
|
||||
<pre><code>{{.FileContent|str2html}}</code></pre>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
54
templates/repo/single_list.tmpl
Normal file
54
templates/repo/single_list.tmpl
Normal file
|
@ -0,0 +1,54 @@
|
|||
<div class="panel panel-default info-box">
|
||||
<div class="panel-heading info-head">
|
||||
<a href="/{{.Username}}/{{.Reponame}}/commit/{{.LastCommit.Oid.String}}">{{.LastCommit.Message}}</a>
|
||||
</div>
|
||||
<div class="panel-body info-content">
|
||||
<a href="/user/{{.LastCommit.Author.Name}}">{{.LastCommit.Author.Name}}</a> <span class="text-muted">{{TimeSince .LastCommit.Author.When}}</span>
|
||||
</div>
|
||||
<table class="panel-footer table file-list">
|
||||
<thead class="hidden">
|
||||
<tr>
|
||||
<th class="icon"></th>
|
||||
<th class="name">Filename</th>
|
||||
<th class="text">Message</th>
|
||||
<th class="date">Date modified</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{if .HasParentPath}}
|
||||
<tr class="has-parent">
|
||||
<td class="icon"><a href="{{.BranchLink}}{{.ParentPath}}"><i class="fa fa-reply"></i></a></td>
|
||||
<td class="name"><a href="{{.BranchLink}}{{.ParentPath}}">..</a></td>
|
||||
<td class="text"></td>
|
||||
<td class="date"></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
{{range .Files}}
|
||||
<tr
|
||||
{{if .IsDir}}class="is-dir"{{end}}>
|
||||
<td class="icon">
|
||||
<i class="fa {{if .IsDir}}fa-folder{{else}}fa-file-text-o{{end}}"></i>
|
||||
</td>
|
||||
<td class="name">
|
||||
<span class="wrap">
|
||||
{{if .IsDir}}
|
||||
<a href="{{$.BranchLink}}/{{.Path}}">{{.Name}}</a>
|
||||
{{else}}
|
||||
<a href="{{$.BranchLink}}/{{.Path}}">{{.Name}}</a>
|
||||
{{end}}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text">
|
||||
<span class="wrap"><a href="/{{$.Username}}/{{$.Reponame}}/commit/{{.Commit.Oid}}">{{.Commit.Message}}</a></span>
|
||||
</td>
|
||||
<td class="date">
|
||||
<span class="wrap">{{TimeSince .Commit.Committer.When}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{if .ReadmeExist}}
|
||||
{{template "repo/single_file" .}}
|
||||
{{end}}
|
4
web.go
4
web.go
|
@ -107,9 +107,9 @@ func runWeb(*cli.Context) {
|
|||
m.Get("/:username/:reponame/pulls", ignSignIn, middleware.RepoAssignment(true), repo.Pulls)
|
||||
m.Get("/:username/:reponame/branches", ignSignIn, middleware.RepoAssignment(true), repo.Branches)
|
||||
m.Get("/:username/:reponame/action/:action", reqSignIn, middleware.RepoAssignment(true), repo.Action)
|
||||
m.Get("/:username/:reponame/tree/:branchname/**",
|
||||
m.Get("/:username/:reponame/src/:branchname/**",
|
||||
ignSignIn, middleware.RepoAssignment(true), repo.Single)
|
||||
m.Get("/:username/:reponame/tree/:branchname",
|
||||
m.Get("/:username/:reponame/src/:branchname",
|
||||
ignSignIn, middleware.RepoAssignment(true), repo.Single)
|
||||
m.Get("/:username/:reponame/commit/:commitid/**", ignSignIn, middleware.RepoAssignment(true), repo.Single)
|
||||
m.Get("/:username/:reponame/commit/:commitid", ignSignIn, middleware.RepoAssignment(true), repo.Single)
|
||||
|
|
Loading…
Reference in a new issue