Files
go-dpkg/apt/apt.go
Matheus Sampaio Queiroga 8498030b4f
All checks were successful
Golang test / go-test (push) Successful in 23s
Update Packege http error message
Signed-off-by: Matheus Sampaio Queiroga <srherobrine20@gmail.com>
2025-06-22 22:28:16 -03:00

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)
}
}
}