Signed-off-by: Matheus Sampaio Queiroga <srherobrine20@gmail.com>
160 lines
4.3 KiB
Go
160 lines
4.3 KiB
Go
package deb822
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"slices"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"sirherobrine23.com.br/sirherobrine23/go-dpkg/internal/scanner"
|
|
)
|
|
|
|
type Source interface {
|
|
IsMultiline() bool
|
|
IsBool() bool
|
|
IsInt() bool
|
|
|
|
Len() int
|
|
Line(int) string
|
|
|
|
String() string
|
|
ToSlice() []string
|
|
ToBool() bool
|
|
ToInt() int
|
|
}
|
|
|
|
var (
|
|
_ Source = SingleLine("")
|
|
_ Source = NumberLine(0)
|
|
_ Source = Multiline{}
|
|
)
|
|
|
|
type SingleLine string
|
|
|
|
func (SingleLine) IsInt() bool { return false }
|
|
func (SingleLine) ToInt() int { return 0 }
|
|
func (s SingleLine) IsMultiline() bool { return false }
|
|
func (s SingleLine) IsBool() bool { return slices.Contains([]string{"yes", "no"}, string(s)) }
|
|
func (s SingleLine) ToBool() bool { return s.IsBool() && s.String() == "yes" }
|
|
func (s SingleLine) String() string { return string(s) }
|
|
func (s SingleLine) Line(int) string { return string(s) }
|
|
func (s SingleLine) Len() int { return len(s) }
|
|
func (s SingleLine) ToSlice() []string {
|
|
if s == "" {
|
|
return nil
|
|
}
|
|
return []string{string(s)}
|
|
}
|
|
|
|
type NumberLine int
|
|
|
|
func (s NumberLine) IsMultiline() bool { return false }
|
|
func (s NumberLine) IsBool() bool { return false }
|
|
func (s NumberLine) IsInt() bool { return true }
|
|
func (s NumberLine) String() string { return strconv.Itoa(int(s)) }
|
|
func (s NumberLine) Line(int) string { return s.String() }
|
|
func (s NumberLine) Len() int { return len(s.String()) }
|
|
func (s NumberLine) ToSlice() []string { return []string{s.String()} }
|
|
func (s NumberLine) ToInt() int { return int(s) }
|
|
func (s NumberLine) ToBool() bool { return s == 1 }
|
|
|
|
type Multiline []string
|
|
|
|
func (m Multiline) IsMultiline() bool { return len(m) > 1 }
|
|
func (m Multiline) IsBool() bool { return slices.Contains([]string{"yes", "no"}, m.String()) }
|
|
func (m Multiline) ToBool() bool { return m.IsBool() && m.String() == "yes" }
|
|
func (m Multiline) String() string { return strings.Join(m, "\n") }
|
|
func (m Multiline) Len() int { return len(m) }
|
|
func (m Multiline) ToSlice() []string { return m }
|
|
func (Multiline) IsInt() bool { return true }
|
|
func (Multiline) ToInt() int { return 0 }
|
|
func (m Multiline) Line(i int) string {
|
|
if i < 0 || i >= len(m) {
|
|
return ""
|
|
}
|
|
return m[i]
|
|
}
|
|
|
|
// Debian control file
|
|
type Deb822 map[string]Source
|
|
|
|
// Parse control file
|
|
func Parse(body []byte) (Deb822, error) {
|
|
deb822Map := Deb822{}
|
|
if err := deb822Map.UnmarshalBinary(body); err != nil {
|
|
return nil, err
|
|
}
|
|
return deb822Map, nil
|
|
}
|
|
|
|
// Get key, if not exists return SingleLine
|
|
func (deb822Map Deb822) Get(key string) Source {
|
|
if value, ok := deb822Map[key]; ok {
|
|
return value
|
|
}
|
|
return SingleLine("")
|
|
}
|
|
|
|
// Unmarshall Debian822
|
|
func (deb822Map *Deb822) UnmarshalBinary(body []byte) error {
|
|
if err := newParse(deb822Map, strings.NewReader(strings.TrimSpace(string(body)))); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Parse Debian822 with stream file
|
|
func NewParse(r io.Reader) (Deb822, error) {
|
|
deb822Map := Deb822{}
|
|
if err := newParse(&deb822Map, r); err != nil {
|
|
return nil, err
|
|
}
|
|
return deb822Map, nil
|
|
}
|
|
|
|
// parse Debian822 file
|
|
func newParse(deb822Map *Deb822, r io.Reader) error {
|
|
multilineKey, scann := "", scanner.NewScanner(r)
|
|
for scann.Scan() {
|
|
line := scann.Text()
|
|
if line == "" {
|
|
break // New deb822 ignore
|
|
} else if strings.HasPrefix(line, "#") || strings.HasPrefix(line, "-") {
|
|
continue // Ignore line
|
|
} else if line[0] == ' ' || line[0] == '\t' {
|
|
if multilineKey == "" {
|
|
return fmt.Errorf("invalid control file, line: %s", line)
|
|
} else if line = strings.TrimLeft(line, " \t"); line == "." {
|
|
line = "" // Replace . with empty line
|
|
}
|
|
|
|
(*deb822Map)[multilineKey] = append(Multiline((*deb822Map)[multilineKey].ToSlice()), line)
|
|
continue
|
|
}
|
|
|
|
keys := strings.SplitN(line, ":", 2)
|
|
if len(keys) != 2 {
|
|
return fmt.Errorf("invalid line: %s", line)
|
|
}
|
|
|
|
multilineKey, line = keys[0], keys[1]
|
|
if line == "" {
|
|
(*deb822Map)[multilineKey] = Multiline{}
|
|
continue
|
|
} else if line[0] == ' ' || line[0] == '\t' {
|
|
line = line[1:]
|
|
}
|
|
|
|
if _, ok := (*deb822Map)[multilineKey]; !ok {
|
|
(*deb822Map)[multilineKey] = SingleLine(line)
|
|
if nu, err := strconv.Atoi(line); err == nil {
|
|
(*deb822Map)[multilineKey] = NumberLine(nu)
|
|
}
|
|
continue
|
|
}
|
|
(*deb822Map)[multilineKey] = append(Multiline((*deb822Map)[multilineKey].ToSlice()), line)
|
|
}
|
|
return scann.Err()
|
|
}
|