diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 13 | ||||
-rw-r--r-- | go.mod | 3 | ||||
-rw-r--r-- | main.go | 75 | ||||
-rw-r--r-- | parser.go | 85 |
5 files changed, 178 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f331ccd --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +bin/ +vendor/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e3ed19e --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +BIN?=apkdoc +GO_RUN?= go run -v +GO_BUILD?= go build -v + +all: build + +run: + $(GO_RUN) . + +build: + $(GO_BUILD) \ + -o bin/$(BIN) \ + . @@ -0,0 +1,3 @@ +module git.sr.ht/~gabrielgio/apkdoc + +go 1.20 @@ -0,0 +1,75 @@ +package main + +import ( + "archive/tar" + "bufio" + "compress/gzip" + "errors" + "flag" + "fmt" + "io" + "net/http" +) + +func fechIndex(url string) (io.ReadCloser, error) { + resp, err := http.Get(url) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + return nil, errors.New("Invlid response") + } + + return resp.Body, nil +} + +func main() { + url := flag.String("url", "", "Url to the APKINDEX.tar.gz") + flag.Parse() + + tarStream, err := fechIndex(*url) + if err != nil { + panic("Error fecthing the index: " + err.Error()) + } + + defer tarStream.Close() + + archive, err := gzip.NewReader(tarStream) + if err != nil { + panic("Error creating gzip reader: " + err.Error()) + } + + tr := tar.NewReader(archive) + + for { + h, err := tr.Next() + if err != nil { + panic("Error reading next tar entry: " + err.Error()) + } + + if h.FileInfo().Name() == "APKINDEX" { + break + } + } + + s := bufio.NewScanner(tr) + + entries := make([]*Entry, 0) + lines := make([]string, 0) + + for s.Scan() { + l := s.Text() + if l == "" { + entry := Parse(lines) + entries = append(entries, entry) + lines = make([]string, 0) + } else { + lines = append(lines, l) + } + } + + for _, e := range entries { + fmt.Printf("%+v\n", e) + } +} diff --git a/parser.go b/parser.go new file mode 100644 index 0000000..998df91 --- /dev/null +++ b/parser.go @@ -0,0 +1,85 @@ +package main + +import ( + "strconv" + "strings" + "time" +) + +type ( + // https://wiki.alpinelinux.org/wiki/Apk_spec + Entry struct { + Checksum string // C + Name string // P + Architecture *string // A + PackageSize int // S + InstalledSize *int // I + Description string // T + Url string // U + License string // L + Origin *string // o + Maintainer *string // m + BuildTime *time.Time // t + Commit *string // c + ProviderPriority *int // k + Dependencies []string // D + Provides []string // p + InstallIf []string // i + } +) + +func ptr[T any](v T) *T { + return &v +} + +func split(line string) (string, string) { + parts := strings.SplitN(line, ":", 2) + return parts[0], parts[1] +} + +func toInt(v string) int { + i, _ := strconv.Atoi(v) + return i +} + +func Parse(lines []string) *Entry { + entry := &Entry{} + for _, line := range lines { + r, c := split(line) + switch r { + case "C": + entry.Checksum = c + case "P": + entry.Name = c + case "A": + entry.Architecture = &c + case "S": + entry.PackageSize = toInt(c) + case "I": + entry.InstalledSize = ptr(toInt(c)) + case "T": + entry.Description = c + case "U": + entry.Url = c + case "L": + entry.License = c + case "o": + entry.Origin = &c + case "m": + entry.Maintainer = &c + case "t": + entry.BuildTime = ptr(time.Unix(int64(toInt(c)), 0)) + case "c": + entry.Commit = &c + case "k": + entry.ProviderPriority = ptr(toInt(c)) + case "D": + entry.Dependencies = strings.Split(c, " ") + case "p": + entry.Dependencies = strings.Split(c, " ") + case "i": + entry.Dependencies = strings.Split(c, " ") + } + } + return entry +} |