All checks were successful
Golang test / go-test (push) Successful in 23s
Signed-off-by: Matheus Sampaio Queiroga <srherobrine20@gmail.com>
172 lines
4.4 KiB
Go
172 lines
4.4 KiB
Go
package apt
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"iter"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"sirherobrine23.com.br/sirherobrine23/go-dpkg/deb822"
|
|
"sirherobrine23.com.br/sirherobrine23/go-dpkg/internal/scanner"
|
|
)
|
|
|
|
// Extends response error
|
|
type HttpError http.Response
|
|
|
|
func (errHttp HttpError) Error() string {
|
|
return fmt.Sprintf("(%s) http client return %d", errHttp.Request.URL.String(), errHttp.StatusCode)
|
|
}
|
|
|
|
// APT repository source from sources.list(5) or deb822 file
|
|
type AptSource struct {
|
|
Enabled bool `json:"enabled"` // Repository is enabled
|
|
Types []string `json:"source_type"` // Files origem, example: deb, deb-src
|
|
URIs []*url.URL `json:"uris"` // Repository Root URL
|
|
Suites []string `json:"suites"` // Repository suite or dist name
|
|
Components []string `json:"components"` // Repository Components
|
|
SignedBy string `json:"signed_by,omitempty"` // GPG Key path
|
|
Arch string `json:"arch,omitempty"` // Arch to get Packages
|
|
Extra map[string]string `json:"extra"` // Other options
|
|
}
|
|
|
|
// Process Debian sources in one line or deb822 styles
|
|
func ParseSourcelist(body string) (sources []*AptSource, err error) {
|
|
sourceType := "deb822"
|
|
for line := range strings.SplitSeq(body, "\n") {
|
|
line = strings.TrimSpace(line)
|
|
if strings.HasPrefix(line, "#") {
|
|
continue
|
|
} else if sourceType == "deb822" && (strings.HasPrefix(line, "deb") || strings.HasPrefix(line, "deb-src")) {
|
|
sourceType = "apt"
|
|
}
|
|
}
|
|
|
|
switch sourceType {
|
|
case "deb822":
|
|
return ParseDeb822(strings.NewReader(body))
|
|
default:
|
|
return ParseOneLine(strings.NewReader(body))
|
|
}
|
|
}
|
|
|
|
// Return source list from one line style
|
|
func ParseOneLine(r io.Reader) (sources []*AptSource, err error) {
|
|
for line := range splitSeq(r, "\n") {
|
|
line = strings.TrimSpace(line)
|
|
if line == "" || line[0] == '#' {
|
|
continue
|
|
}
|
|
|
|
config := ""
|
|
if i := strings.Index(line, "["); i > 0 {
|
|
j := strings.Index(line, "]")
|
|
config = strings.TrimSpace(line[i+1 : j])
|
|
line = strings.TrimSpace(line[:i]) + " " + strings.TrimSpace(line[j+1:])
|
|
}
|
|
|
|
fields := strings.Fields(line)
|
|
if len(fields) < 3 || !(fields[0] == "deb" || fields[0] == "deb-src") {
|
|
continue
|
|
}
|
|
source := &AptSource{Enabled: true, Types: []string{fields[0]}, Extra: map[string]string{}}
|
|
fields = fields[1:]
|
|
|
|
if config != "" {
|
|
config := strings.Fields(strings.Trim(config, "[]"))
|
|
for _, c := range config {
|
|
values := strings.SplitN(c, "=", 2)
|
|
switch values[0] {
|
|
case "signed-by":
|
|
source.SignedBy = values[1]
|
|
case "arch":
|
|
source.Arch = values[1]
|
|
default:
|
|
source.Extra[values[0]] = values[1]
|
|
}
|
|
}
|
|
}
|
|
|
|
uriRepository, err := url.Parse(fields[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
source.URIs = append(source.URIs, uriRepository)
|
|
source.Suites = append(source.Suites, fields[1])
|
|
source.Components = fields[2:]
|
|
sources = append(sources, source)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Return source list in deb822 file format
|
|
func ParseDeb822(r io.Reader) (sources []*AptSource, err error) {
|
|
reader := deb822.NewReader(r)
|
|
var previusSource *AptSource
|
|
for {
|
|
var key, value string
|
|
key, value, err = reader.Next()
|
|
switch err {
|
|
default:
|
|
return
|
|
case nil:
|
|
case io.EOF:
|
|
err = nil
|
|
return
|
|
case deb822.ErrNextDeb822:
|
|
previusSource = nil
|
|
if key == "" {
|
|
continue
|
|
}
|
|
}
|
|
|
|
if previusSource == nil {
|
|
previusSource = &AptSource{Enabled: true, Extra: map[string]string{}}
|
|
sources = append(sources, previusSource)
|
|
}
|
|
|
|
switch key {
|
|
case "Enabled":
|
|
if value == "no" {
|
|
previusSource.Enabled = false
|
|
}
|
|
case "Types":
|
|
previusSource.Types = strings.Fields(value)
|
|
case "URIs":
|
|
for _, uri := range strings.Fields(value) {
|
|
uriRepository, err := url.Parse(uri)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
previusSource.URIs = append(previusSource.URIs, uriRepository)
|
|
}
|
|
case "Suites":
|
|
previusSource.Suites = strings.Fields(value)
|
|
case "Components":
|
|
previusSource.Components = strings.Fields(value)
|
|
case "Signed-By":
|
|
previusSource.SignedBy = value
|
|
default:
|
|
if key != "" {
|
|
previusSource.Extra[key] = value
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func splitSeq(r io.Reader, sep string) iter.Seq[string] {
|
|
return func(yield func(string) bool) {
|
|
sc := scanner.NewScannerSplit(r, scanner.SplitSep(sep))
|
|
for sc.Scan() {
|
|
t := sc.Text()
|
|
if !yield(t[:len(t)-len(sep)]) {
|
|
break
|
|
}
|
|
}
|
|
if err := sc.Err(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
}
|