diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2022-12-26 22:02:13 -0700 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2022-12-26 23:55:42 -0700 |
commit | d5737a0e71b17a97b82ae68e49acc41a08fcc0ad (patch) | |
tree | 7378523c12afd0636b78c08a1bfbd5d26bc97087 /cmd/btrfs-rec/util.go | |
parent | 0bbcd2cadf8a6e1a277a68653ac2f7f95c63ba01 (diff) |
cmd/btrfs-rec: Add a utility function for reading JSON files with progress
Diffstat (limited to 'cmd/btrfs-rec/util.go')
-rw-r--r-- | cmd/btrfs-rec/util.go | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/cmd/btrfs-rec/util.go b/cmd/btrfs-rec/util.go new file mode 100644 index 0000000..adfe97e --- /dev/null +++ b/cmd/btrfs-rec/util.go @@ -0,0 +1,83 @@ +// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com> +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package main + +import ( + "bufio" + "context" + "io" + "os" + "time" + + "git.lukeshu.com/go/lowmemjson" + "github.com/datawire/dlib/dlog" + + "git.lukeshu.com/btrfs-progs-ng/lib/textui" +) + +type runeScanner struct { + progress textui.Portion[int64] + progressWriter *textui.Progress[textui.Portion[int64]] + unreadCnt uint64 + reader *bufio.Reader + closer io.Closer +} + +func newRuneScanner(ctx context.Context, fh *os.File) (*runeScanner, error) { + fi, err := fh.Stat() + if err != nil { + return nil, err + } + ret := &runeScanner{ + progress: textui.Portion[int64]{ + D: fi.Size(), + }, + progressWriter: textui.NewProgress[textui.Portion[int64]](ctx, dlog.LogLevelInfo, 1*time.Second), + reader: bufio.NewReader(fh), + closer: fh, + } + return ret, nil +} + +func (rs *runeScanner) ReadRune() (r rune, size int, err error) { + r, size, err = rs.reader.ReadRune() + if rs.unreadCnt > 0 { + rs.unreadCnt-- + } else { + rs.progress.N += int64(size) + rs.progressWriter.Set(rs.progress) + } + return +} + +func (rs *runeScanner) UnreadRune() error { + rs.unreadCnt++ + return rs.reader.UnreadRune() +} + +func (rs *runeScanner) Close() error { + rs.progressWriter.Done() + return rs.closer.Close() +} + +func readJSONFile[T any](ctx context.Context, filename string) (T, error) { + fh, err := os.Open(filename) + if err != nil { + var zero T + return zero, err + } + buf, err := newRuneScanner(dlog.WithField(ctx, "btrfs.read-json-file", filename), fh) + if err != nil { + var zero T + return zero, err + } + var ret T + if err := lowmemjson.DecodeThenEOF(buf, &ret); err != nil { + var zero T + return zero, err + } + _ = buf.Close() + return ret, nil +} |