Skip to content

Commit c66dcde

Browse files
committed
feat: support for reading gzip,bzip2 and xz files
1 parent fcaea05 commit c66dcde

File tree

4 files changed

+142
-3
lines changed

4 files changed

+142
-3
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
github.com/dgraph-io/badger/v3 v3.2103.2
77
github.com/fatih/color v1.16.0
88
github.com/gdamore/tcell/v2 v2.7.1
9+
github.com/h2non/filetype v1.1.3
910
github.com/maruel/natural v1.1.0
1011
github.com/mattn/go-isatty v0.0.20
1112
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
@@ -14,6 +15,7 @@ require (
1415
github.com/sirupsen/logrus v1.9.3
1516
github.com/spf13/cobra v1.8.0
1617
github.com/stretchr/testify v1.9.0
18+
github.com/ulikunitz/xz v0.5.12
1719
golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3
1820
golang.org/x/sys v0.20.0
1921
gopkg.in/yaml.v3 v3.0.1

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6
4848
github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
4949
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
5050
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
51+
github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
52+
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
5153
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
5254
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
5355
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@@ -116,6 +118,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
116118
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
117119
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
118120
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
121+
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
122+
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
119123
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
120124
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
121125
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=

tui/show_file.go

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,18 @@ package tui
22

33
import (
44
"bufio"
5+
"compress/bzip2"
6+
"compress/gzip"
7+
"io"
58
"os"
69
"strings"
710

811
"github.com/gdamore/tcell/v2"
12+
"github.com/h2non/filetype"
13+
"github.com/h2non/filetype/matchers"
14+
"github.com/pkg/errors"
915
"github.com/rivo/tview"
16+
"github.com/ulikunitz/xz"
1017

1118
"github.com/dundee/gdu/v5/build"
1219
"github.com/dundee/gdu/v5/pkg/fs"
@@ -23,18 +30,23 @@ func (ui *UI) showFile() *tview.TextView {
2330
return nil
2431
}
2532

26-
f, err := os.Open(selectedFile.GetPath())
33+
path := selectedFile.GetPath()
34+
f, err := os.Open(path)
2735
if err != nil {
2836
ui.showErr("Error opening file", err)
2937
return nil
3038
}
39+
scanner, err := getScanner(f)
40+
if err != nil {
41+
ui.showErr("Error reading file", err)
42+
return nil
43+
}
3144

3245
totalLines := 0
33-
scanner := bufio.NewScanner(f)
3446

3547
file := tview.NewTextView()
3648
ui.currentDirLabel.SetText("[::b] --- " +
37-
strings.TrimPrefix(selectedFile.GetPath(), build.RootPathPrefix) +
49+
strings.TrimPrefix(path, build.RootPathPrefix) +
3850
" ---").SetDynamicColors(true)
3951

4052
readNextPart := func(linesCount int) int {
@@ -94,3 +106,41 @@ func (ui *UI) showFile() *tview.TextView {
94106

95107
return file
96108
}
109+
110+
func getScanner(f io.ReadSeeker) (scanner *bufio.Scanner, err error) {
111+
// We only have to pass the file header = first 261 bytes
112+
head := make([]byte, 261)
113+
if _, err = f.Read(head); err != nil {
114+
return nil, errors.Wrap(err, "error reading file header")
115+
}
116+
117+
if pos, err := f.Seek(0, 0); pos != 0 || err != nil {
118+
return nil, errors.Wrap(err, "error seeking file")
119+
}
120+
scanner = bufio.NewScanner(f)
121+
122+
typ, err := filetype.Match(head)
123+
if err != nil {
124+
return nil, errors.Wrap(err, "error matching file type")
125+
}
126+
127+
switch typ.MIME.Value {
128+
case matchers.TypeGz.MIME.Value:
129+
r, err := gzip.NewReader(f)
130+
if err != nil {
131+
return nil, errors.Wrap(err, "error creating gzip reader")
132+
}
133+
scanner = bufio.NewScanner(r)
134+
case matchers.TypeBz2.MIME.Value:
135+
r := bzip2.NewReader(f)
136+
scanner = bufio.NewScanner(r)
137+
case matchers.TypeXz.MIME.Value:
138+
r, err := xz.NewReader(f)
139+
if err != nil {
140+
return nil, errors.Wrap(err, "error creating xz reader")
141+
}
142+
scanner = bufio.NewScanner(r)
143+
}
144+
145+
return scanner, nil
146+
}

tui/show_file_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package tui
2+
3+
import (
4+
"bytes"
5+
"compress/gzip"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
"github.com/ulikunitz/xz"
10+
)
11+
12+
func TestGetScannerForPlainString(t *testing.T) {
13+
r := bytes.NewReader([]byte("hello"))
14+
s, err := getScanner(r)
15+
assert.Nil(t, err)
16+
17+
assert.Equal(t, true, s.Scan())
18+
assert.Equal(t, "hello", s.Text())
19+
assert.Equal(t, nil, s.Err())
20+
}
21+
22+
func TestGetScannerForGzipped(t *testing.T) {
23+
b := bytes.NewBuffer([]byte{})
24+
w := gzip.NewWriter(b)
25+
26+
_, err := w.Write([]byte("hello world"))
27+
assert.Nil(t, err)
28+
29+
err = w.Close()
30+
assert.Nil(t, err)
31+
32+
r := bytes.NewReader(b.Bytes())
33+
s, err := getScanner(r)
34+
assert.Nil(t, err)
35+
36+
assert.Equal(t, true, s.Scan())
37+
assert.Equal(t, "hello world", s.Text())
38+
assert.Equal(t, nil, s.Err())
39+
}
40+
41+
func TestGetScannerForBzipped(t *testing.T) {
42+
r := bytes.NewReader([]byte{
43+
// bzip2 header
44+
0x42, 0x5A, 0x68, 0x39,
45+
// bzip2 compressed data: "hello"
46+
0x31, 0x41, 0x59, 0x26,
47+
0x53, 0x59, 0xC1, 0xC0,
48+
0x80, 0xE2, 0x00, 0x00,
49+
0x01, 0x41, 0x00, 0x00,
50+
0x10, 0x02, 0x44, 0xA0,
51+
0x00, 0x30, 0xCD, 0x00,
52+
0xC3, 0x46, 0x29, 0x97,
53+
0x17, 0x72, 0x45, 0x38,
54+
0x50, 0x90, 0xC1, 0xC0,
55+
0x80, 0xE2,
56+
})
57+
s, err := getScanner(r)
58+
assert.Nil(t, err)
59+
60+
assert.Equal(t, true, s.Scan())
61+
assert.Equal(t, "hello", s.Text())
62+
assert.Equal(t, nil, s.Err())
63+
}
64+
65+
func TestGetScannerForXzipped(t *testing.T) {
66+
b := bytes.NewBuffer([]byte{})
67+
w, err := xz.NewWriter(b)
68+
assert.Nil(t, err)
69+
70+
_, err = w.Write([]byte("hello world"))
71+
assert.Nil(t, err)
72+
73+
err = w.Close()
74+
assert.Nil(t, err)
75+
76+
r := bytes.NewReader(b.Bytes())
77+
s, err := getScanner(r)
78+
assert.Nil(t, err)
79+
80+
assert.Equal(t, true, s.Scan())
81+
assert.Equal(t, "hello world", s.Text())
82+
assert.Equal(t, nil, s.Err())
83+
}

0 commit comments

Comments
 (0)