create single dpkg bufio reader

This commit is contained in:
Alex Goodman 2020-05-16 07:59:34 -04:00 committed by Alfredo Deza
parent 09cf5b9862
commit d56d157e90
2 changed files with 61 additions and 48 deletions

View file

@ -10,7 +10,7 @@ import (
)
// TODO: consider keeping the remaining values as an embedded map
type DpkgEntry struct {
type Entry struct {
Package string `mapstructure:"Package"`
Architecture string `mapstructure:"Architecture"`
DependsPkgs string `mapstructure:"Depends"`
@ -60,29 +60,49 @@ type DpkgEntry struct {
// Triggers-Awaited (internal)
// Triggers-Pending (internal)
// Version
//
var EndOfPackages = fmt.Errorf("no more packages to read")
var endOfPackages = fmt.Errorf("no more packages to read")
func Read(reader io.Reader) (entry DpkgEntry, err error) {
buff := bufio.NewReader(reader)
func ParseEntries(reader io.Reader) ([]Entry, error) {
buffedReader := bufio.NewReader(reader)
var entries = make([]Entry, 0)
for {
entry, err := parseEntry(buffedReader)
if err != nil {
if err == endOfPackages {
break
}
return nil, err
}
entries = append(entries, entry)
}
return entries, nil
}
func parseEntry(reader *bufio.Reader) (entry Entry, err error) {
dpkgFields := make(map[string]string)
var key string
for {
line, ioerr := buff.ReadString('\n')
fmt.Printf("line:'%+v' err:'%+v'\n", line, ioerr)
if ioerr != nil {
if ioerr == io.EOF {
return DpkgEntry{}, EndOfPackages
line, err := reader.ReadString('\n')
if err != nil {
if err == io.EOF {
return Entry{}, endOfPackages
}
return DpkgEntry{}, ioerr
return Entry{}, err
}
line = strings.TrimRight(line, "\n")
// stop if there is no contents in line
// empty line indicates end of entry
if len(line) == 0 {
// if the entry has not started, keep parsing lines
if len(dpkgFields) == 0{
continue
}
break
}
@ -90,12 +110,12 @@ func Read(reader io.Reader) (entry DpkgEntry, err error) {
case strings.HasPrefix(line, " "):
// a field-body continuation
if len(key) == 0 {
return DpkgEntry{}, fmt.Errorf("no match for continuation: line: '%s'", line)
return Entry{}, fmt.Errorf("no match for continuation: line: '%s'", line)
}
val, ok := dpkgFields[key]
if !ok {
return DpkgEntry{}, fmt.Errorf("no previous key exists, expecting: %s", key)
return Entry{}, fmt.Errorf("no previous key exists, expecting: %s", key)
}
// concatenate onto previous value
val = fmt.Sprintf("%s\n %s", val, strings.TrimSpace(line))
@ -107,42 +127,21 @@ func Read(reader io.Reader) (entry DpkgEntry, err error) {
val := strings.TrimSpace(line[i+1:])
if _, ok := dpkgFields[key]; ok {
return DpkgEntry{}, fmt.Errorf("duplicate key discovered: %s", key)
return Entry{}, fmt.Errorf("duplicate key discovered: %s", key)
}
dpkgFields[key] = val
} else {
return DpkgEntry{}, fmt.Errorf("cannot parse field from line: '%s'", line)
return Entry{}, fmt.Errorf("cannot parse field from line: '%s'", line)
}
}
}
fmt.Println("OUTOFLOOP")
// map -> struct
err = mapstructure.Decode(dpkgFields, &entry)
if err != nil {
return DpkgEntry{}, err
return Entry{}, err
}
return entry, nil
}
func ReadAllDpkgEntries(reader io.Reader) ([]DpkgEntry, error) {
var entries = make([]DpkgEntry, 0)
for {
// Read() until error
entry, err := Read(reader)
fmt.Printf("entry:'%+v'\n\terr:%+v\n", entry, err)
if err != nil {
if err == EndOfPackages {
break
}
return nil, err
}
entries = append(entries, entry)
}
return entries, nil
}

View file

@ -1,13 +1,14 @@
package dpkg
import (
"bufio"
"os"
"testing"
"github.com/go-test/deep"
)
func compareEntries(t *testing.T, left, right DpkgEntry) {
func compareEntries(t *testing.T, left, right Entry) {
t.Helper()
if diff := deep.Equal(left, right); diff != nil {
t.Error(diff)
@ -17,11 +18,11 @@ func compareEntries(t *testing.T, left, right DpkgEntry) {
func TestSinglePackage(t *testing.T) {
tests := []struct {
name string
expected DpkgEntry
expected Entry
}{
{
name: "Test Single Package",
expected: DpkgEntry{
expected: Entry{
Package: "apt",
Status: "install ok installed",
Priority: "required",
@ -49,8 +50,16 @@ func TestSinglePackage(t *testing.T) {
if err != nil {
t.Fatal("Unable to read test_fixtures/single: ", err)
}
defer func() {
err := file.Close()
if err != nil {
panic(err)
}
}()
entry, err := Read(file)
reader := bufio.NewReader(file)
entry, err := parseEntry(reader)
if err != nil {
t.Fatal("Unable to read file contents: ", err)
}
@ -61,14 +70,14 @@ func TestSinglePackage(t *testing.T) {
}
}
func TestMultiplePackage(t *testing.T) {
func TestMultiplePackages(t *testing.T) {
tests := []struct {
name string
expected []DpkgEntry
expected []Entry
}{
{
name: "Test Multiple Package",
expected: []DpkgEntry{
expected: []Entry{
{
Package: "tzdata",
Status: "install ok installed",
@ -110,9 +119,14 @@ func TestMultiplePackage(t *testing.T) {
if err != nil {
t.Fatal("Unable to read: ", err)
}
defer file.Close()
defer func() {
err := file.Close()
if err != nil {
panic(err)
}
}()
entries, err := ReadAllDpkgEntries(file)
entries, err := ParseEntries(file)
if err != nil {
t.Fatal("Unable to read file contents: ", err)
}