feat(classifypkg): add arch_map/os_map conf keys; use them for ffmpeg

Adds two new releases.conf keys:
  arch_map = x64:x86_64 ia32:x86   (upstream:canonical pairs)
  os_map   = win32:windows

The generic GitHub classifier now applies these after classify.Filename
so packages with non-standard naming don't need a custom classifier.

Also adds a .gz (single-file gunzip) branch to package-install.tpl.sh
so bare-binary-plus-.gz release patterns are fully handled.

Removes the ffmpegdist custom classifier — ffmpeg/releases.conf now
uses source = github with arch_map + os_map + version_prefix = b.
This commit is contained in:
AJ ONeal
2026-05-16 20:23:29 -06:00
parent 571a93cf06
commit 4d1fc7bb62
4 changed files with 51 additions and 86 deletions
+3
View File
@@ -226,6 +226,9 @@ __bootstrap_webi() {
elif test "$WEBI_EXT" = "git"; then
echo " Moving $(t_path "${my_dl_rel}")"
mv "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" .
elif test "$WEBI_EXT" = "gz"; then
echo " Inflating $(t_path "${my_dl_rel}")"
gunzip -c "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" > "$(basename "$WEBI_PKG_FILE" .gz)"
elif test "$WEBI_EXT" = "xz"; then
echo " Inflating $(t_path "${my_dl_rel}")"
unxz -c "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" > "$(basename "$WEBI_PKG_FILE")"
+3 -1
View File
@@ -1,4 +1,6 @@
source = ffmpegdist
source = github
github_releases = eugeneware/ffmpeg-static
asset_filter = ffmpeg
version_prefix = b
arch_map = x64:x86_64 ia32:x86 arm64:aarch64 arm:armv7
os_map = win32:windows
+13 -85
View File
@@ -166,8 +166,6 @@ func classifySource(pkg string, conf *installerconf.Conf, d *rawcache.Dir) ([]st
return classifyMariaDBDist(d)
case "zigdist":
return classifyZigDist(d)
case "ffmpegdist":
return classifyFFmpegDist(d)
default:
return nil, nil
}
@@ -428,6 +426,16 @@ func classifyGitHub(pkg string, conf *installerconf.Conf, d *rawcache.Dir) ([]st
r := classify.Filename(a.Name)
// Apply conf-level OS/arch overrides for non-standard naming.
osStr := string(r.OS)
if mapped, ok := conf.OSMap[osStr]; ok {
osStr = mapped
}
archStr := string(r.Arch)
if mapped, ok := conf.ArchMap[archStr]; ok {
archStr = mapped
}
// Normalize .tgz → .tar.gz in the display filename.
// The download URL still points to the real file.
name := a.Name
@@ -441,7 +449,7 @@ func classifyGitHub(pkg string, conf *installerconf.Conf, d *rawcache.Dir) ([]st
libc = buildmeta.LibcNone
}
// Windows gnu (MinGW) is self-contained — no runtime deps.
if r.OS == buildmeta.OSWindows && libc == buildmeta.LibcGNU {
if buildmeta.OS(osStr) == buildmeta.OSWindows && libc == buildmeta.LibcGNU {
libc = buildmeta.LibcNone
}
@@ -449,8 +457,8 @@ func classifyGitHub(pkg string, conf *installerconf.Conf, d *rawcache.Dir) ([]st
Filename: name,
Version: version,
Channel: channel,
OS: string(r.OS),
Arch: string(r.Arch),
OS: osStr,
Arch: archStr,
Libc: string(libc),
Format: string(r.Format),
Download: a.BrowserDownloadURL,
@@ -466,86 +474,6 @@ func classifyGitHub(pkg string, conf *installerconf.Conf, d *rawcache.Dir) ([]st
return assets, nil
}
var ffmpegOSMap = map[string]string{
"linux": "linux",
"darwin": "darwin",
"win32": "windows",
}
var ffmpegArchMap = map[string]string{
"x64": "x86_64",
"ia32": "x86",
"arm64": "aarch64",
"arm": "armv7",
}
// classifyFFmpegDist handles eugeneware/ffmpeg-static releases.
// Upstream uses non-standard names (x64, ia32, win32, arm) and ships both
// bare binaries and .gz-compressed copies. Only bare binaries are kept —
// the install template has no handler for single-file .gz extraction.
func classifyFFmpegDist(d *rawcache.Dir) ([]storage.Asset, error) {
releases, err := ReadAllRaw(d)
if err != nil {
return nil, err
}
var assets []storage.Asset
for _, data := range releases {
var rel ghRelease
if err := json.Unmarshal(data, &rel); err != nil {
continue
}
if rel.Draft {
continue
}
version := strings.TrimPrefix(rel.TagName, "b")
channel := "stable"
if rel.Prerelease {
channel = "beta"
}
date := ""
if len(rel.PublishedAt) >= 10 {
date = rel.PublishedAt[:10]
}
for _, a := range rel.Assets {
if strings.Contains(a.Name, ".") {
continue
}
if !strings.HasPrefix(a.Name, "ffmpeg-") {
continue
}
parts := strings.SplitN(a.Name, "-", 3)
if len(parts) != 3 {
continue
}
os, osOK := ffmpegOSMap[parts[1]]
arch, archOK := ffmpegArchMap[parts[2]]
if !osOK || !archOK {
continue
}
assets = append(assets, storage.Asset{
Filename: a.Name,
Version: version,
Channel: channel,
OS: os,
Arch: arch,
Format: "",
Download: a.BrowserDownloadURL,
Date: date,
})
}
}
return assets, nil
}
// classifyServiceman handles serviceman's dual-repo layout: binary releases
// from therootcompany/serviceman (≤v0.8.x) and source-only releases from
// bnnanet/serviceman (v0.9.x+). Emits binary assets where available, plus
+32
View File
@@ -96,6 +96,16 @@ type Conf struct {
// kubectx/kubens) to select only the relevant assets.
AssetFilter string
// ArchMap translates non-standard arch strings in asset filenames to
// canonical webi arch names. Format: "upstream:canonical" pairs,
// whitespace-delimited. Example: "x64:x86_64 ia32:x86 arm:armv7"
ArchMap map[string]string
// OSMap translates non-standard OS strings in asset filenames to
// canonical webi OS names. Format: "upstream:canonical" pairs,
// whitespace-delimited. Example: "win32:windows"
OSMap map[string]string
// Variants documents known build variant names for this package.
// Whitespace-delimited. This is a human-readable cue — actual
// variant detection logic lives in Go code per-package.
@@ -243,6 +253,14 @@ func Read(path string) (*Conf, error) {
}
c.AssetFilter = raw["asset_filter"]
if v := raw["arch_map"]; v != "" {
c.ArchMap = parseKVMap(v)
}
if v := raw["os_map"]; v != "" {
c.OSMap = parseKVMap(v)
}
c.OS = raw["os"]
c.AliasOf = raw["alias_of"]
@@ -269,6 +287,8 @@ func Read(path string) (*Conf, error) {
"exclude": true,
"asset_exclude": true,
"asset_filter": true,
"arch_map": true,
"os_map": true,
"os": true,
"variants": true,
"alias_of": true,
@@ -284,3 +304,15 @@ func Read(path string) (*Conf, error) {
return c, nil
}
// parseKVMap parses whitespace-delimited "key:value" pairs into a map.
func parseKVMap(s string) map[string]string {
m := make(map[string]string)
for _, pair := range strings.Fields(s) {
k, v, ok := strings.Cut(pair, ":")
if ok {
m[k] = v
}
}
return m
}