Allow space and/or percent in file and directory namestags/v1.21.12.1
| @@ -87,7 +87,7 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff | |||||
| leftLine, rightLine int | leftLine, rightLine int | ||||
| isTooLong bool | isTooLong bool | ||||
| // FIXME: use first 30 lines to detect file encoding. Should use cache in the future. | |||||
| // FIXME: Should use cache in the future. | |||||
| buf bytes.Buffer | buf bytes.Buffer | ||||
| ) | ) | ||||
| @@ -106,16 +106,10 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff | |||||
| i = i + 1 | i = i + 1 | ||||
| // FIXME: use first 30 lines to detect file encoding. | |||||
| if i <= 30 { | |||||
| buf.WriteString(line) | |||||
| } | |||||
| // Diff data too large, we only show the first about maxlines lines | // Diff data too large, we only show the first about maxlines lines | ||||
| if i == maxlines { | if i == maxlines { | ||||
| isTooLong = true | isTooLong = true | ||||
| log.Warn("Diff data too large") | log.Warn("Diff data too large") | ||||
| //return &Diff{}, nil | |||||
| } | } | ||||
| switch { | switch { | ||||
| @@ -127,7 +121,7 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff | |||||
| continue | continue | ||||
| case line[0] == '@': | case line[0] == '@': | ||||
| if isTooLong { | if isTooLong { | ||||
| return diff, nil | |||||
| break | |||||
| } | } | ||||
| curSection = &DiffSection{} | curSection = &DiffSection{} | ||||
| @@ -137,9 +131,14 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff | |||||
| curSection.Lines = append(curSection.Lines, diffLine) | curSection.Lines = append(curSection.Lines, diffLine) | ||||
| // Parse line number. | // Parse line number. | ||||
| ranges := strings.Split(ss[len(ss)-2][1:], " ") | |||||
| ranges := strings.Split(ss[1][1:], " ") | |||||
| leftLine, _ = com.StrTo(strings.Split(ranges[0], ",")[0][1:]).Int() | leftLine, _ = com.StrTo(strings.Split(ranges[0], ",")[0][1:]).Int() | ||||
| rightLine, _ = com.StrTo(strings.Split(ranges[1], ",")[0]).Int() | |||||
| if len(ranges) > 1 { | |||||
| rightLine, _ = com.StrTo(strings.Split(ranges[1], ",")[0]).Int() | |||||
| } else { | |||||
| log.Warn("Parse line number failed: %v", line) | |||||
| rightLine = leftLine | |||||
| } | |||||
| continue | continue | ||||
| case line[0] == '+': | case line[0] == '+': | ||||
| curFile.Addition++ | curFile.Addition++ | ||||
| @@ -164,11 +163,11 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff | |||||
| // Get new file. | // Get new file. | ||||
| if strings.HasPrefix(line, DIFF_HEAD) { | if strings.HasPrefix(line, DIFF_HEAD) { | ||||
| if isTooLong { | if isTooLong { | ||||
| return diff, nil | |||||
| break | |||||
| } | } | ||||
| fs := strings.Split(line[len(DIFF_HEAD):], " ") | |||||
| a := fs[0] | |||||
| beg := len(DIFF_HEAD) | |||||
| a := line[beg : (len(line)-beg)/2+beg] | |||||
| curFile = &DiffFile{ | curFile = &DiffFile{ | ||||
| Name: a[strings.Index(a, "/")+1:], | Name: a[strings.Index(a, "/")+1:], | ||||
| @@ -201,14 +200,19 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff | |||||
| } | } | ||||
| } | } | ||||
| // FIXME: use first 30 lines to detect file encoding. | |||||
| charsetLabel, err := base.DetectEncoding(buf.Bytes()) | |||||
| if charsetLabel != "utf8" && err == nil { | |||||
| encoding, _ := charset.Lookup(charsetLabel) | |||||
| if encoding != nil { | |||||
| d := encoding.NewDecoder() | |||||
| for _, f := range diff.Files { | |||||
| for _, f := range diff.Files { | |||||
| buf.Reset() | |||||
| for _, sec := range f.Sections { | |||||
| for _, l := range sec.Lines { | |||||
| buf.WriteString(l.Content) | |||||
| buf.WriteString("\n") | |||||
| } | |||||
| } | |||||
| charsetLabel, err := base.DetectEncoding(buf.Bytes()) | |||||
| if charsetLabel != "UTF-8" && err == nil { | |||||
| encoding, _ := charset.Lookup(charsetLabel) | |||||
| if encoding != nil { | |||||
| d := encoding.NewDecoder() | |||||
| for _, sec := range f.Sections { | for _, sec := range f.Sections { | ||||
| for _, l := range sec.Lines { | for _, l := range sec.Lines { | ||||
| if c, _, err := transform.String(d, l.Content); err == nil { | if c, _, err := transform.String(d, l.Content); err == nil { | ||||
| @@ -219,7 +223,6 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return diff, nil | return diff, nil | ||||
| } | } | ||||
| @@ -55,7 +55,7 @@ func ShortSha(sha1 string) string { | |||||
| func DetectEncoding(content []byte) (string, error) { | func DetectEncoding(content []byte) (string, error) { | ||||
| detector := chardet.NewTextDetector() | detector := chardet.NewTextDetector() | ||||
| result, err := detector.DetectBest(content) | result, err := detector.DetectBest(content) | ||||
| if result.Charset == "ISO-8859-1" { | |||||
| if result.Charset != "UTF-8" && len(setting.AnsiCharset) > 0 { | |||||
| return setting.AnsiCharset, err | return setting.AnsiCharset, err | ||||
| } | } | ||||
| return result.Charset, err | return result.Charset, err | ||||
| @@ -67,7 +67,7 @@ func ToUtf8WithErr(content []byte) (error, string) { | |||||
| return err, "" | return err, "" | ||||
| } | } | ||||
| if charsetLabel == "utf8" { | |||||
| if charsetLabel == "UTF-8" { | |||||
| return nil, string(content) | return nil, string(content) | ||||
| } | } | ||||
| @@ -313,7 +313,7 @@ func NewConfigContext() { | |||||
| RepoRootPath = path.Clean(RepoRootPath) | RepoRootPath = path.Clean(RepoRootPath) | ||||
| } | } | ||||
| ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash") | ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash") | ||||
| AnsiCharset = sec.Key("ANSI_CHARSET").MustString("ISO-8859-1") | |||||
| AnsiCharset = sec.Key("ANSI_CHARSET").MustString("") | |||||
| // UI settings. | // UI settings. | ||||
| IssuePagingNum = Cfg.Section("ui").Key("ISSUE_PAGING_NUM").MustInt(10) | IssuePagingNum = Cfg.Section("ui").Key("ISSUE_PAGING_NUM").MustInt(10) | ||||
| @@ -26,10 +26,17 @@ func ServeBlob(ctx *middleware.Context, blob *git.Blob) error { | |||||
| } | } | ||||
| _, isTextFile := base.IsTextFile(buf) | _, isTextFile := base.IsTextFile(buf) | ||||
| _, isImageFile := base.IsImageFile(buf) | |||||
| if !isTextFile && !isImageFile { | |||||
| ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+path.Base(ctx.Repo.TreeName)) | |||||
| ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary") | |||||
| if isTextFile { | |||||
| charset, _ := base.DetectEncoding(buf) | |||||
| if charset != "UTF-8" { | |||||
| ctx.Resp.Header().Set("Content-Type", "text/plain; charset="+charset) | |||||
| } | |||||
| } else { | |||||
| _, isImageFile := base.IsImageFile(buf) | |||||
| if !isImageFile { | |||||
| ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+path.Base(ctx.Repo.TreeName)) | |||||
| ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary") | |||||
| } | |||||
| } | } | ||||
| ctx.Resp.Write(buf) | ctx.Resp.Write(buf) | ||||
| _, err = io.Copy(ctx.Resp, dataRc) | _, err = io.Copy(ctx.Resp, dataRc) | ||||
| @@ -6,7 +6,7 @@ | |||||
| {{if .IsDiffCompare }} | {{if .IsDiffCompare }} | ||||
| <div class="panel panel-info panel-radius compare-head-box"> | <div class="panel panel-info panel-radius compare-head-box"> | ||||
| <div class="panel-header"> | <div class="panel-header"> | ||||
| <a class="pull-right btn btn-blue btn-header btn-medium btn-radius" rel="nofollow" href="{{.SourcePath}}">{{.i18n.Tr "repo.diff.browse_source"}}</a> | |||||
| <a class="pull-right btn btn-blue btn-header btn-medium btn-radius" rel="nofollow" href="{{EscapePound .SourcePath}}">{{.i18n.Tr "repo.diff.browse_source"}}</a> | |||||
| <h4><a href="{{$.RepoLink}}/commit/{{.BeforeCommitId}}" class="label label-green">{{ShortSha .BeforeCommitId}}</a> ... <a href="{{$.RepoLink}}/commit/{{.AfterCommitId}}" class="label label-green">{{ShortSha .AfterCommitId}}</a></h4> | <h4><a href="{{$.RepoLink}}/commit/{{.BeforeCommitId}}" class="label label-green">{{ShortSha .BeforeCommitId}}</a> ... <a href="{{$.RepoLink}}/commit/{{.AfterCommitId}}" class="label label-green">{{ShortSha .AfterCommitId}}</a></h4> | ||||
| </div> | </div> | ||||
| <div class="panel-body compare"> | <div class="panel-body compare"> | ||||
| @@ -16,7 +16,7 @@ | |||||
| {{else}} | {{else}} | ||||
| <div class="panel panel-info panel-radius diff-head-box"> | <div class="panel panel-info panel-radius diff-head-box"> | ||||
| <div class="panel-header"> | <div class="panel-header"> | ||||
| <a class="pull-right btn btn-blue btn-header btn-medium btn-radius" rel="nofollow" href="{{.SourcePath}}">{{.i18n.Tr "repo.diff.browse_source"}}</a> | |||||
| <a class="pull-right btn btn-blue btn-header btn-medium btn-radius" rel="nofollow" href="{{EscapePound .SourcePath}}">{{.i18n.Tr "repo.diff.browse_source"}}</a> | |||||
| <h4 class="commit-message">{{RenderCommitMessage .Commit.Message $.RepoLink}}</h4> | <h4 class="commit-message">{{RenderCommitMessage .Commit.Message $.RepoLink}}</h4> | ||||
| </div> | </div> | ||||
| <div class="panel-body"> | <div class="panel-body"> | ||||
| @@ -37,7 +37,7 @@ | |||||
| <img class="avatar-30" src="{{AvatarLink .Commit.Author.Email}}" /> | <img class="avatar-30" src="{{AvatarLink .Commit.Author.Email}}" /> | ||||
| <strong>{{.Commit.Author.Name}}</strong> | <strong>{{.Commit.Author.Name}}</strong> | ||||
| {{end}} | {{end}} | ||||
| <span class="text-grey" id="authored-time">{{TimeSince .Commit.Author.When $.Lang}}</span> | |||||
| <span class="text-grey" id="authored-time">{{TimeSince .Commit.Author.When $.Lang}}</span> | |||||
| </p> | </p> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| @@ -90,9 +90,9 @@ | |||||
| {{end}} | {{end}} | ||||
| </div> | </div> | ||||
| {{if $file.IsDeleted}} | {{if $file.IsDeleted}} | ||||
| <a class="btn btn-gray btn-header btn-radius text-black pull-right" rel="nofollow" href="{{$.BeforeSourcePath}}/{{.Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a> | |||||
| <a class="btn btn-gray btn-header btn-radius text-black pull-right" rel="nofollow" href="{{EscapePound $.BeforeSourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a> | |||||
| {{else}} | {{else}} | ||||
| <a class="btn btn-gray btn-header btn-radius text-black pull-right" rel="nofollow" href="{{$.SourcePath}}/{{.Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a> | |||||
| <a class="btn btn-gray btn-header btn-radius text-black pull-right" rel="nofollow" href="{{EscapePound $.SourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a> | |||||
| {{end}} | {{end}} | ||||
| <span class="file">{{$file.Name}}</span> | <span class="file">{{$file.Name}}</span> | ||||
| </div> | </div> | ||||
| @@ -100,7 +100,7 @@ | |||||
| <div class="panel-body file-body file-code code-view code-diff"> | <div class="panel-body file-body file-code code-view code-diff"> | ||||
| {{if $isImage}} | {{if $isImage}} | ||||
| <div class="text-center"> | <div class="text-center"> | ||||
| <img src="{{$.RawPath}}/{{.Name}}"> | |||||
| <img src="{{$.RawPath}}/{{EscapePound .Name}}"> | |||||
| </div> | </div> | ||||
| {{else}} | {{else}} | ||||
| <table> | <table> | ||||
| @@ -114,7 +114,7 @@ | |||||
| <td class="lines-num lines-num-new"> | <td class="lines-num lines-num-new"> | ||||
| <span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}">{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}</span> | <span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}">{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}</span> | ||||
| </td> | </td> | ||||
| <td class="lines-code"> | <td class="lines-code"> | ||||
| <pre>{{$line.Content}}</pre> | <pre>{{$line.Content}}</pre> | ||||
| </td> | </td> | ||||
| @@ -126,7 +126,7 @@ | |||||
| {{end}} | {{end}} | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <br> | |||||
| <br> | |||||
| {{end}} | {{end}} | ||||
| {{end}} | {{end}} | ||||
| </div> | </div> | ||||
| @@ -50,7 +50,8 @@ | |||||
| {{if eq $i $l}} | {{if eq $i $l}} | ||||
| <span class="bread">{{$v}}</span> | <span class="bread">{{$v}}</span> | ||||
| {{else}} | {{else}} | ||||
| <span class="bread"><a href="{{EscapePound $.BranchLink}}/{{index $.Paths $i}}">{{$v}}</a></span> | |||||
| {{ $p := index $.Paths $i}} | |||||
| <span class="bread"><a href="{{EscapePound $.BranchLink}}/{{EscapePound $p}}">{{$v}}</a></span> | |||||
| {{end}} | {{end}} | ||||
| {{end}} | {{end}} | ||||
| </li> | </li> | ||||
| @@ -13,11 +13,11 @@ | |||||
| {{end}} | {{end}} | ||||
| {{if not .ReadmeInList}} | {{if not .ReadmeInList}} | ||||
| {{if not .IsCommit}} | {{if not .IsCommit}} | ||||
| <a class="right" href="{{.RepoLink}}/src/{{.CommitId}}/{{.TreeName}}"> | |||||
| <a class="right" href="{{.RepoLink}}/src/{{.CommitId}}/{{EscapePound .TreeName}}"> | |||||
| <button class="btn btn-medium btn-gray btn-right-radius btn-comb">{{.i18n.Tr "repo.file_permalink"}}</button> | <button class="btn btn-medium btn-gray btn-right-radius btn-comb">{{.i18n.Tr "repo.file_permalink"}}</button> | ||||
| </a> | </a> | ||||
| {{end}} | {{end}} | ||||
| <a class="right" href="{{.RepoLink}}/commits/{{EscapePound .BranchName}}/{{.TreeName}}"> | |||||
| <a class="right" href="{{.RepoLink}}/commits/{{EscapePound .BranchName}}/{{EscapePound .TreeName}}"> | |||||
| <button class="btn btn-medium btn-gray btn-right-radius btn-comb">{{.i18n.Tr "repo.file_history"}}</button> | <button class="btn btn-medium btn-gray btn-right-radius btn-comb">{{.i18n.Tr "repo.file_history"}}</button> | ||||
| </a> | </a> | ||||
| <a class="right" href="{{EscapePound .FileLink}}"> | <a class="right" href="{{EscapePound .FileLink}}"> | ||||
| @@ -47,4 +47,4 @@ | |||||
| </table> | </table> | ||||
| {{end}} | {{end}} | ||||
| </div> | </div> | ||||
| </div> | |||||
| </div> | |||||