Skip to content

Commit fc8dd28

Browse files
committed
Fixes go-gitea#16558 CSV delimiter determiner
1 parent 07c7100 commit fc8dd28

4 files changed

Lines changed: 38 additions & 13 deletions

File tree

‎modules/csv/csv.go‎

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ import (
99
stdcsv "encoding/csv"
1010
"errors"
1111
"io"
12+
"path/filepath"
1213
"regexp"
1314
"strings"
1415

16+
"code.gitea.io/gitea/modules/markup"
1517
"code.gitea.io/gitea/modules/translation"
1618
"code.gitea.io/gitea/modules/util"
1719
)
@@ -26,8 +28,8 @@ func CreateReader(input io.Reader, delimiter rune) *stdcsv.Reader {
2628
return rd
2729
}
2830

29-
// CreateReaderAndGuessDelimiter tries to guess the field delimiter from the content and creates a csv.Reader.
30-
func CreateReaderAndGuessDelimiter(rd io.Reader) (*stdcsv.Reader, error) {
31+
// CreateReaderAndDetermineDelimiter tries to guess the field delimiter from the content and creates a csv.Reader.
32+
func CreateReaderAndDetermineDelimiter(ctx *markup.RenderContext, rd io.Reader) (*stdcsv.Reader, error) {
3133
var data = make([]byte, 1e4)
3234
size, err := rd.Read(data)
3335
if err != nil {
@@ -37,7 +39,7 @@ func CreateReaderAndGuessDelimiter(rd io.Reader) (*stdcsv.Reader, error) {
3739
return nil, err
3840
}
3941

40-
delimiter := guessDelimiter(data[:size])
42+
delimiter := determineDelimiter(ctx, data[:size])
4143

4244
var newInput io.Reader
4345
if size < 1e4 {
@@ -49,6 +51,27 @@ func CreateReaderAndGuessDelimiter(rd io.Reader) (*stdcsv.Reader, error) {
4951
return CreateReader(newInput, delimiter), nil
5052
}
5153

54+
// determineDelimiter takes a RenderContext and if it isn't nil and the Filename has an extension that specifies the delimiter,
55+
// it is used as the delimiter. Otherwise we call guessDelimiter with the data passed
56+
func determineDelimiter(ctx *markup.RenderContext, data []byte) rune {
57+
extension := ".csv"
58+
if ctx != nil {
59+
extension = strings.ToLower(filepath.Ext(ctx.Filename))
60+
}
61+
62+
var delimiter rune
63+
switch extension {
64+
case ".tsv":
65+
delimiter = '\t'
66+
case ".psv":
67+
delimiter = '|'
68+
default:
69+
delimiter = guessDelimiter(data)
70+
}
71+
72+
return delimiter
73+
}
74+
5275
// guessDelimiter scores the input CSV data against delimiters, and returns the best match.
5376
// Reads at most 10k bytes & 10 lines.
5477
func guessDelimiter(data []byte) rune {

‎modules/csv/csv_test.go‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ func TestCreateReader(t *testing.T) {
1717
assert.Equal(t, ',', rd.Comma)
1818
}
1919

20-
func TestCreateReaderAndGuessDelimiter(t *testing.T) {
20+
func TestCreateReaderAndDetermineDelimiter(t *testing.T) {
2121
input := "a;b;c\n1;2;3\n4;5;6"
2222

23-
rd, err := CreateReaderAndGuessDelimiter(strings.NewReader(input))
23+
rd, err := CreateReaderAndDetermineDelimiter(nil, strings.NewReader(input))
2424
assert.NoError(t, err)
2525
assert.Equal(t, ';', rd.Comma)
2626
}
@@ -35,6 +35,7 @@ func TestGuessDelimiter(t *testing.T) {
3535
"1,2,3;4,5,6;7,8,9\na;b;c": ';',
3636
"\"1,2,3,4\";\"a\nb\"\nc;d": ';',
3737
"<br/>": ',',
38+
"name\temail\tnote\nJohn Doe\tjohn@doe.com\tThis,note,had,a,lot,of,commas,to,test,delimters": '\t',
3839
}
3940

4041
for k, v := range kases {

‎routers/web/repo/compare.go‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
csv_module "code.gitea.io/gitea/modules/csv"
2323
"code.gitea.io/gitea/modules/git"
2424
"code.gitea.io/gitea/modules/log"
25+
"code.gitea.io/gitea/modules/markup"
2526
"code.gitea.io/gitea/modules/setting"
2627
"code.gitea.io/gitea/modules/upload"
2728
"code.gitea.io/gitea/modules/util"
@@ -105,7 +106,7 @@ func setCsvCompareContext(ctx *context.Context) {
105106

106107
errTooLarge := errors.New(ctx.Locale.Tr("repo.error.csv.too_large"))
107108

108-
csvReaderFromCommit := func(c *git.Commit) (*csv.Reader, error) {
109+
csvReaderFromCommit := func(ctx *markup.RenderContext, c *git.Commit) (*csv.Reader, error) {
109110
blob, err := c.GetBlobByPath(diffFile.Name)
110111
if err != nil {
111112
return nil, err
@@ -121,14 +122,14 @@ func setCsvCompareContext(ctx *context.Context) {
121122
}
122123
defer reader.Close()
123124

124-
return csv_module.CreateReaderAndGuessDelimiter(charset.ToUTF8WithFallbackReader(reader))
125+
return csv_module.CreateReaderAndGuessDelimiter(ctx, charset.ToUTF8WithFallbackReader(reader))
125126
}
126127

127-
baseReader, err := csvReaderFromCommit(baseCommit)
128+
baseReader, err := csvReaderFromCommit(&markup.RenderContext{Filename: diffFile.OldName}, baseCommit)
128129
if err == errTooLarge {
129130
return CsvDiffResult{nil, err.Error()}
130131
}
131-
headReader, err := csvReaderFromCommit(headCommit)
132+
headReader, err := csvReaderFromCommit(&markup.RenderContext{Filename: diffFile.Name}, headCommit)
132133
if err == errTooLarge {
133134
return CsvDiffResult{nil, err.Error()}
134135
}

‎services/gitdiff/csv_test.go‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,16 +194,16 @@ c,d,e`,
194194

195195
var baseReader *csv.Reader
196196
if len(c.base) > 0 {
197-
baseReader, err = csv_module.CreateReaderAndGuessDelimiter(strings.NewReader(c.base))
197+
baseReader, err = csv_module.CreateReaderAndDetermineDelimiter(nil, strings.NewReader(c.base))
198198
if err != nil {
199-
t.Errorf("CreateReaderAndGuessDelimiter failed: %s", err)
199+
t.Errorf("CreateReaderAndDetermineDelimiter failed: %s", err)
200200
}
201201
}
202202
var headReader *csv.Reader
203203
if len(c.head) > 0 {
204-
headReader, err = csv_module.CreateReaderAndGuessDelimiter(strings.NewReader(c.head))
204+
headReader, err = csv_module.CreateReaderAndDetermineDelimiter(nil, strings.NewReader(c.head))
205205
if err != nil {
206-
t.Errorf("CreateReaderAndGuessDelimiter failed: %s", err)
206+
t.Errorf("CreateReaderAndDetermineDelimiter failed: %s", err)
207207
}
208208
}
209209

0 commit comments

Comments
 (0)