Something went wrong. Try again.
Maps Linux distribution source packages to their upstream repositories, and through them to each other
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102package arch
import ( "archive/tar" "bytes" "compress/gzip" "context" "fmt" "io" "sort" "strings" "time"
"tangled.org/odd.computer/isomorph/internal/fetch")
// Arch's packaging "state" repository records, per repository and architecture directory// (core-x86_64, extra-any, ...), one file per pkgbase holding// "<pkgbase> <version> <version> <packaging commit>". It enumerates the whole distribution in// one download and pins each pkgbase to the packaging commit that was released.
// statePath is the GitLab project of the state repository.const statePath = "archlinux/packaging/state"
// StableRepos are the state directories that make up the released distribution; testing,// staging and *-unstable directories are left out.var StableRepos = []string{"core-x86_64", "core-any", "extra-x86_64", "extra-any", "multilib-x86_64"}
// StateEntry is one released pkgbase.type StateEntry struct { // Repo is core, extra or multilib. Repo string PkgBase string Version string // Commit is the packaging repository commit the release was built from. Commit string}
// State downloads the state repository and returns the pkgbases of dirs (StableRepos when// nil), sorted by repository and pkgbase. A pkgbase listed under both -x86_64 and -any// directories of one repository appears once.func (r *Resolver) State(ctx context.Context, dirs []string) ([]StateEntry, error) { if dirs == nil { dirs = StableRepos } u := r.GitLabBase + "/" + statePath + "/-/archive/main/state-main.tar.gz" b, err := r.c.Get(ctx, u, fetch.WithTTL(6*time.Hour)) if err != nil { return nil, fmt.Errorf("arch: state: %w", err) } return ParseState(b, dirs)}
// ParseState reads a state-main.tar.gz archive.func ParseState(archive []byte, dirs []string) ([]StateEntry, error) { want := map[string]bool{} for _, d := range dirs { want[d] = true } zr, err := gzip.NewReader(bytes.NewReader(archive)) if err != nil { return nil, fmt.Errorf("arch: state: %w", err) } tr := tar.NewReader(zr) seen := map[string]bool{} var out []StateEntry for { h, err := tr.Next() if err == io.EOF { break } if err != nil { return nil, fmt.Errorf("arch: state: %w", err) } parts := strings.Split(h.Name, "/") if h.Typeflag != tar.TypeReg || len(parts) != 3 || !want[parts[1]] { continue } b, err := io.ReadAll(io.LimitReader(tr, 1<<16)) if err != nil { return nil, err } f := strings.Fields(string(b)) if len(f) < 4 { continue } repo, _, _ := strings.Cut(parts[1], "-") if seen[repo+"/"+f[0]] { continue } seen[repo+"/"+f[0]] = true out = append(out, StateEntry{Repo: repo, PkgBase: f[0], Version: f[1], Commit: f[3]}) } sort.Slice(out, func(i, j int) bool { if out[i].Repo != out[j].Repo { return out[i].Repo < out[j].Repo } return out[i].PkgBase < out[j].PkgBase }) return out, nil}