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.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124package opensuse
import ( "context" "encoding/xml" "errors" "fmt" "sort" "strings" "time"
"tangled.org/odd.computer/isomorph/internal/fetch")
// Tumbleweed's repository metadata carries only each spec's Url:. What the packaging itself// says about its upstream (SourceN, Git-Clone, a _service source-control URL) is read per// package from the anonymous OBS API: the package directory, then the spec and _service// pinned to the directory's source revision, so a cached copy never goes stale.
// OBSFiles are the files of the OBS package that builds one source package.type OBSFiles struct { // Package is the OBS package and Rev its source revision (srcmd5, links expanded). Package, Rev string // SpecName and Spec are the source package's spec file. SpecName string Spec []byte // Service is the package's _service file, if it has one. Service []byte}
// ErrNotCached is returned by OBSFiles when network use is off and a file is not cached.var ErrNotCached = errors.New("opensuse: not cached")
const ( // obsDirTTL keeps a crawl's directory listings for a month, so it stays resumable. obsDirTTL = 30 * 24 * time.Hour // obsFileTTL applies to files pinned to a revision, which never change. obsFileTTL = 10 * 365 * 24 * time.Hour)
// OBSPackageCandidates returns the OBS packages that may build source package src: src// itself, then up to two listed packages whose names are dash-separated prefixes of it,// longest first (the adios2 package builds adios2-openmpi4 as a multibuild flavour).func OBSPackageCandidates(src string, pkgs map[string]bool) []string { var out []string if pkgs[src] { out = append(out, src) } for s := src; len(out) < 3; { i := strings.LastIndexByte(s, '-') if i <= 0 { break } s = s[:i] if pkgs[s] { out = append(out, s) } } return out}
// OBSFiles returns the spec and _service of the OBS package building src, trying candidates// in order. With network false it reads only the cache and returns ErrNotCached when a file is// missing. It returns nil, nil when no candidate package holds src's spec.func (r *Resolver) OBSFiles(ctx context.Context, src string, candidates []string, network bool) (*OBSFiles, error) { for _, pkg := range candidates { b, err := r.obsGet(ctx, r.pkgURL(pkg)+"?expand=1", obsDirTTL, network) if fetch.IsNotFound(err) { continue } if err != nil { return nil, err } var d obsDirectory if err := xml.Unmarshal(b, &d); err != nil { return nil, fmt.Errorf("opensuse: %s/%s: parse directory: %w", r.Project, pkg, err) } spec := specFor(&d, src, pkg) if spec == "" { continue } f := &OBSFiles{Package: pkg, Rev: d.SrcMD5, SpecName: spec} if f.Spec, err = r.obsGet(ctx, r.fileURL(pkg, spec)+"?rev="+d.SrcMD5, obsFileTTL, network); err != nil { return nil, err } if d.has("_service") { if f.Service, err = r.obsGet(ctx, r.fileURL(pkg, "_service")+"?rev="+d.SrcMD5, obsFileTTL, network); err != nil { return nil, err } } return f, nil } return nil, nil}
// specFor picks src's spec in the directory of OBS package pkg: <src>.spec; else, in src's// own package, its only spec; else, in a multibuild package, the package's own spec.func specFor(d *obsDirectory, src, pkg string) string { if d.has(src + ".spec") { return src + ".spec" } var specs []string for _, e := range d.Entries { if strings.HasSuffix(e.Name, ".spec") { specs = append(specs, e.Name) } } sort.Strings(specs) switch { case src == pkg && len(specs) == 1: return specs[0] case d.has("_multibuild") && d.has(pkg+".spec"): return pkg + ".spec" } return ""}
func (r *Resolver) obsGet(ctx context.Context, u string, ttl time.Duration, network bool) ([]byte, error) { if !network && !r.c.Cached(u, fetch.WithTTL(ttl)) { return nil, ErrNotCached } return r.c.Get(ctx, u, fetch.WithTTL(ttl))}