diff options
7 files changed, 1158 insertions, 0 deletions
diff --git a/util/docker/coreboot.org-status/board-status.html/boards.go b/util/docker/coreboot.org-status/board-status.html/boards.go new file mode 100644 index 0000000000..dc68cb6d46 --- /dev/null +++ b/util/docker/coreboot.org-status/board-status.html/boards.go @@ -0,0 +1,601 @@ +package main + +import ( + "fmt" + "io/fs" + "os" + "path/filepath" + "regexp" + "sort" + "strings" +) + +func readBoardInfo(dir NamedFS) map[string]string { + result := make(map[string]string) + c, err := fs.ReadFile(dir.FS, filepath.Join(dir.Name, "board_info.txt")) + if err != nil { + return result + } + ls := strings.Split(string(c), "\n") + for _, l := range ls { + spl := strings.SplitN(l, ":", 2) + if len(spl) != 2 { + // This shouldn't ever happen, but let's try to + // extract as much information from erroneous + // board_info files (if they exist) as possible. + continue + } + result[strings.TrimSpace(spl[0])] = strings.TrimSpace(spl[1]) + } + return result +} + +func fetchBoards(dirs chan<- NamedFS) { + defer close(dirs) + ds, err := fs.Glob(cbdirFS, filepath.Join("src", "mainboard", "*", "*")) + if err != nil { + fmt.Fprintf(os.Stderr, "Could not find mainboard directories: %v\n", err) + return + } + for _, d := range ds { + if _, err := fs.ReadDir(cbdirFS, d); err != nil { + continue + } + dirs <- NamedFS{ + FS: cbdirFS, + Name: d, + } + } +} + +var niceVendors = make(map[string]string) + +func getNiceVendor(dir string, vendor string) (string, error) { + if _, exists := niceVendors[vendor]; !exists { + c, err := fs.ReadFile(cbdirFS, filepath.Join(dir, "..", "Kconfig.name")) + if err != nil { + return "", err + } + re, err := regexp.Compile("(?i)config VENDOR_" + vendor) + if err != nil { + return "", err + } + ls := strings.Split(string(c), "\n") + next := false + for _, l := range ls { + if next { + niceVendors[vendor] = strings.Split(l, "\"")[1] + break + } + if re.Match([]byte(l)) { + next = true + } + } + } + return niceVendors[vendor], nil +} + +func readKconfig(dir NamedFS) (string, string, string, string, string, error) { + var north, south, superio, cpu, partnum string + c, err := fs.ReadFile(dir.FS, filepath.Join(dir.Name, "Kconfig")) + if err != nil { + return north, south, superio, cpu, partnum, err + } + ls := strings.Split(string(c), "\n") + partoffset := 0 + for _, l := range ls { + l = strings.TrimSpace(l) + if len(l) < 7 { + continue + } + // TODO: handling of MAINBOARD_PART_NUMBER is rather broken + // and fragile. Doesn't help that many boards use different + // part numbers for different models and this code can't + // figure it out. + if strings.Contains(strings.ToLower(l), "config mainboard_part_number") { + partoffset = 2 + continue + } + if partoffset > 0 { + partoffset-- + if strings.Contains(l, "default") { + partnum = strings.Split(l, "\"")[1] + continue + } + } + if l[0:7] != "select " { + continue + } + l = l[7:] + if len(l) > 12 && l[0:12] == "NORTHBRIDGE_" { + north = l[12:] + continue + } + if len(l) > 12 && l[0:12] == "SOUTHBRIDGE_" { + if strings.Contains(l, "SKIP_") || + strings.Contains(l, "DISABLE_") { + continue + } + south = l[12:] + continue + } + if len(l) > 8 && l[0:8] == "SUPERIO_" { + superio = l[8:] + continue + } + if len(l) > 4 && (l[0:4] == "CPU_" || l[0:4] == "SOC_") { + if strings.Contains(l, "AMD_AGESA_FAMILY") || + strings.Contains(l, "AMD_COMMON_") || + strings.Contains(l, "INTEL_COMMON_") || + strings.Contains(l, "INTEL_DISABLE_") || + strings.Contains(l, "INTEL_CSE_") || + strings.Contains(l, "CPU_MICROCODE_CBFS_NONE") { + continue + } + cpu = l[4:] + } + } + return north, south, superio, cpu, partnum, nil +} + +type reReplace struct { + pattern *regexp.Regexp + replace string +} + +func prettify(input string, rules *[]reReplace) string { + for _, rule := range *rules { + input = rule.pattern.ReplaceAllString(input, rule.replace) + } + return input +} + +var northbridgeRules = []reReplace{ + { + pattern: regexp.MustCompile("AMD_AGESA_FAMILY([0-9a-fA-F]*)(.*)"), + replace: "AMD Family ${1}h${2} (AGESA)", + }, + { + pattern: regexp.MustCompile("AMD_PI_(.*)"), + replace: "AMD ${1} (PI)", + }, + { + pattern: regexp.MustCompile("INTEL_FSP_(.*)"), + replace: "Intel® ${1} (FSP)", + }, + { + pattern: regexp.MustCompile("AMD_FAMILY([0-9a-fA-F]*)"), + replace: "AMD Family ${1}h,", + }, + { + pattern: regexp.MustCompile("AMD_AMDFAM([0-9a-fA-F]*)"), + replace: "AMD Family ${1}h", + }, + { + pattern: regexp.MustCompile("_"), + replace: " ", + }, + { + pattern: regexp.MustCompile("INTEL"), + replace: "Intel®", + }, +} + +func prettifyNorthbridge(northbridge string) string { + return prettify(northbridge, &northbridgeRules) +} + +var southbridgeRules = []reReplace{ + { + pattern: regexp.MustCompile("_"), + replace: " ", + }, + { + pattern: regexp.MustCompile("INTEL"), + replace: "Intel®", + }, +} + +func prettifySouthbridge(southbridge string) string { + return prettify(southbridge, &southbridgeRules) +} + +var superIORules = []reReplace{ + { + pattern: regexp.MustCompile("_"), + replace: " ", + }, + { + pattern: regexp.MustCompile("WINBOND"), + replace: "Winbond™,", + }, + { + pattern: regexp.MustCompile("ITE"), + replace: "ITE™", + }, + { + pattern: regexp.MustCompile("SMSC"), + replace: "SMSC®", + }, + { + pattern: regexp.MustCompile("NUVOTON"), + replace: "Nuvoton ", + }, +} + +func prettifySuperIO(superio string) string { + return prettify(superio, &superIORules) +} + +type cpuMapping struct { + cpu string + socket string +} + +var cpuMappings = map[string]cpuMapping{ + "ALLWINNER_A10": { + cpu: "Allwinner A10", + socket: "?", + }, + "AMD_GEODE_LX": { + cpu: "AMD Geode™ LX", + socket: "—", + }, + "AMD_SOCKET_754": { + cpu: "AMD Sempron™ / Athlon™ 64 / Turion™ 64", + socket: "Socket 754", + }, + "AMD_SOCKET_ASB2": { + cpu: "AMD Turion™ II Neo/Athlon™ II Neo", + socket: "ASB2 (BGA812)", + }, + "AMD_SOCKET_S1G1": { + cpu: "AMD Turion™ / X2 Sempron™", + socket: "Socket S1G1", + }, + "AMD_SOCKET_G34": { + cpu: "AMD Opteron™ Magny-Cours/Interlagos", + socket: "Socket G34", + }, + "AMD_SOCKET_G34_NON_AGESA": { + cpu: "AMD Opteron™ Magny-Cours/Interlagos", + socket: "Socket G34", + }, + "AMD_SOCKET_C32": { + cpu: "AMD Opteron™ Magny-Cours/Interlagos", + socket: "Socket C32", + }, + "AMD_SOCKET_C32_NON_AGESA": { + cpu: "AMD Opteron™ Magny-Cours/Interlagos", + socket: "Socket C32", + }, + "AMD_SOCKET_AM2": { + cpu: "?", + socket: "Socket AM2", + }, + "AMD_SOCKET_AM3": { + cpu: "AMD Athlon™ 64 / FX / X2", + socket: "Socket AM3", + }, + "AMD_SOCKET_AM2R2": { + cpu: "AMD Athlon™ 64 / X2 / FX, Sempron™", + socket: "Socket AM2+", + }, + "AMD_SOCKET_F": { + cpu: "AMD Opteron™", + socket: "Socket F", + }, + "AMD_SOCKET_F_1207": { + cpu: "AMD Opteron™", + socket: "Socket F 1207", + }, + "AMD_SOCKET_940": { + cpu: "AMD Opteron™", + socket: "Socket 940", + }, + "AMD_SOCKET_939": { + cpu: "AMD Athlon™ 64 / FX / X2", + socket: "Socket 939", + }, + "AMD_SC520": { + cpu: "AMD Élan™SC520", + socket: "—", + }, + "AMD_STONEYRIDGE_FP4": { + cpu: "AMD Stoney Ridge", + socket: "FP4 BGA", + }, + "ARMLTD_CORTEX_A9": { + cpu: "ARM Cortex A9", + socket: "?", + }, + "DMP_VORTEX86EX": { + cpu: "DMP VORTEX86EX", + socket: "?", + }, + "MEDIATEK_MT8173": { + cpu: "MediaTek MT8173", + socket: "—", + }, + "NVIDIA_TEGRA124": { + cpu: "NVIDIA Tegra 124", + socket: "—", + }, + "NVIDIA_TEGRA210": { + cpu: "NVIDIA Tegra 210", + socket: "—", + }, + "SAMSUNG_EXYNOS5420": { + cpu: "Samsung Exynos 5420", + socket: "?", + }, + "SAMSUNG_EXYNOS5250": { + cpu: "Samsung Exynos 5250", + socket: "?", + }, + "TI_AM335X": { + cpu: "TI AM335X", + socket: "?", + }, + "INTEL_APOLLOLAKE": { + cpu: "Intel® Apollo Lake", + socket: "—", + }, + "INTEL_BAYTRAIL": { + cpu: "Intel® Bay Trail", + socket: "—", + }, + "INTEL_BRASWELL": { + cpu: "Intel® Braswell", + socket: "—", + }, + "INTEL_BROADWELL": { + cpu: "Intel® Broadwell", + socket: "—", + }, + "INTEL_DENVERTON_NS": { + cpu: "Intel® Denverton-NS", + socket: "—", + }, + "INTEL_FSP_BROADWELL_DE": { + cpu: "Intel® Broadwell-DE", + socket: "—", + }, + "INTEL_GLK": { + cpu: "Intel® Gemini Lake", + socket: "—", + }, + "INTEL_GEMINILAKE": { + cpu: "Intel® Gemini Lake", + socket: "—", + }, + "INTEL_ICELAKE": { + cpu: "Intel® Ice Lake", + socket: "—", + }, + "INTEL_KABYLAKE": { + cpu: "Intel® Kaby Lake", + socket: "—", + }, + "INTEL_SANDYBRIDGE": { + cpu: "Intel® Sandy Bridge", + socket: "—", + }, + "INTEL_SKYLAKE": { + cpu: "Intel® Skylake", + socket: "—", + }, + "INTEL_SLOT_1": { + cpu: "Intel® Pentium® II/III, Celeron®", + socket: "Slot 1", + }, + "INTEL_SOCKET_MPGA604": { + cpu: "Intel® Xeon®", + socket: "Socket 604", + }, + "INTEL_SOCKET_M": { + cpu: "Intel® Core™ 2 Duo Mobile, Core™ Duo/Solo, Celeron® M", + socket: "Socket M (mPGA478MT)", + }, + "INTEL_SOCKET_LGA771": { + cpu: "Intel Xeon™ 5000 series", + socket: "Socket LGA771", + }, + "INTEL_SOCKET_LGA775": { + cpu: "Intel® Core 2, Pentium 4/D", + socket: "Socket LGA775", + }, + "INTEL_SOCKET_PGA370": { + cpu: "Intel® Pentium® III-800, Celeron®", + socket: "Socket PGA370", + }, + "INTEL_SOCKET_MPGA479M": { + cpu: "Intel® Mobile Celeron", + socket: "Socket 479", + }, + "INTEL_HASWELL": { + cpu: "Intel® 4th Gen (Haswell) Core i3/i5/i7", + socket: "?", + }, + "INTEL_FSP_RANGELEY": { + cpu: "Intel® Atom Rangeley (FSP)", + socket: "?", + }, + "INTEL_SOCKET_441": { + cpu: "Intel® Atom™ 230", + socket: "Socket 441", + }, + "INTEL_SOCKET_FC_PGA370": { + cpu: "Intel® Pentium® III, Celeron®", + socket: "Socket PGA370", + }, + "INTEL_EP80579": { + cpu: "Intel® EP80579", + socket: "Intel® EP80579", + }, + "INTEL_SOCKET_MFCBGA479": { + cpu: "Intel® Mobile Celeron", + socket: "Socket 479", + }, + "INTEL_WHISKEYLAKE": { + cpu: "Intel® Whiskey Lake", + socket: "—", + }, + "QC_IPQ806X": { + cpu: "Qualcomm IPQ806x", + socket: "—", + }, + "QUALCOMM_QCS405": { + cpu: "Qualcomm QCS405", + socket: "—", + }, + "ROCKCHIP_RK3288": { + cpu: "Rockchip RK3288", + socket: "—", + }, + "ROCKCHIP_RK3399": { + cpu: "Rockchip RK3399", + socket: "—", + }, + "VIA_C3": { + cpu: "VIA C3™", + socket: "?", + }, + "VIA_C7": { + cpu: "VIA C7™", + socket: "?", + }, + "VIA_NANO": { + cpu: "VIA NANO™", + socket: "?", + }, + "QEMU_X86": { + cpu: "QEMU x86", + socket: "—", + }, +} + +func prettifyCPU(cpu, north string, northNice string) (string, string) { + if match, ok := cpuMappings[cpu]; ok { + return match.cpu, match.socket + } + if cpu == "" { + if match, ok := cpuMappings[north]; ok { + return match.cpu, match.socket + } + if north == "INTEL_IRONLAKE" { + return "Intel® 1st Gen (Westmere) Core i3/i5/i7", "?" + } + if north == "RDC_R8610" { + return "RDC R8610", "—" + } + if (len(north) > 10 && north[0:10] == "AMD_AGESA_") || (len(north) > 7 && north[0:7] == "AMD_PI_") { + return northNice, "?" + } + return north, north + } + if cpu == "INTEL_SOCKET_BGA956" { + if north == "INTEL_GM45" { + return "Intel® Core 2 Duo (Penryn)", "Socket P" + } + return "Intel® Pentium® M", "BGA956" + } + if cpu == "INTEL_SOCKET_RPGA989" || cpu == "INTEL_SOCKET_LGA1155" || cpu == "INTEL_SOCKET_RPGA988B" { + socket := "Socket " + cpu[13:] + if north == "INTEL_HASWELL" { + return "Intel® 4th Gen (Haswell) Core i3/i5/i7", socket + } + if north == "INTEL_IVYBRIDGE" || north == "INTEL_FSP_IVYBRIDGE" { + return "Intel® 3rd Gen (Ivybridge) Core i3/i5/i7", socket + } + if north == "INTEL_SANDYBRIDGE" { + return "Intel® 2nd Gen (Sandybridge) Core i3/i5/i7", socket + } + return north, socket + } + return cpu, cpu +} + +func collectBoards(dirs <-chan NamedFS) { + for dir := range dirs { + path := strings.Split(dir.Name, string(filepath.Separator)) + vendor, board := path[2], path[3] + vendorNice, err := getNiceVendor(dir.Name, vendor) + + if err != nil { + fmt.Fprintf(os.Stderr, "Could not find nice vendor name for %s: %v\n", dir.Name, err) + continue + } + + bi := readBoardInfo(dir) + cat := Category(bi["Category"]) + if _, ok := data.CategoryNiceNames[cat]; !ok { + cat = "unclass" + } + if bi["Vendor cooperation score"] == "" { + bi["Vendor cooperation score"] = "—" + } + + north, south, superio, cpu, partnum, err := readKconfig(dir) + if err != nil { + fmt.Fprintf(os.Stderr, "'%s' is not a mainboard directory: %v\n", dir.Name, err) + // Continue with the path because that's what the + // shell script did. We might want to change semantics + // later. + } + northbridgeNice := prettifyNorthbridge(north) + southbridgeNice := prettifySouthbridge(south) + superIONice := prettifySuperIO(superio) + cpuNice, socketNice := prettifyCPU(cpu, north, northbridgeNice) + + boardNice := bi["Board name"] + if boardNice == "" { + boardNice = partnum + } + if boardNice == "" { + boardNice = strings.ReplaceAll(boardNice, "_", " ") + boardNice = strings.ToUpper(boardNice) + } + + b := Board{ + Vendor: vendor, + Vendor2nd: bi["Vendor name"], + VendorNice: vendorNice, + VendorBoard: vendor + "/" + board, + Board: board, + BoardNice: boardNice, + BoardURL: bi["Board URL"], + NorthbridgeNice: northbridgeNice, + SouthbridgeNice: southbridgeNice, + SuperIONice: superIONice, + CPUNice: cpuNice, + SocketNice: socketNice, + ROMPackage: bi["ROM package"], + ROMProtocol: bi["ROM protocol"], + ROMSocketed: bi["ROM socketed"], + FlashromSupport: bi["Flashrom support"], + VendorCooperationScore: bi["Vendor cooperation score"], + VendorCooperationPage: bi["Vendor cooperation page"], + } + if b.ROMPackage == "" { + b.ROMPackage = "?" + } + if b.ROMProtocol == "" { + b.ROMProtocol = "?" + } + + if data.BoardsByCategory[cat] == nil { + data.BoardsByCategory[cat] = []Board{} + } + data.BoardsByCategory[cat] = append(data.BoardsByCategory[cat], b) + } + for ci := range data.BoardsByCategory { + cat := data.BoardsByCategory[ci] + sort.Slice(data.BoardsByCategory[ci], func(i, j int) bool { + if cat[i].Vendor == cat[j].Vendor { + return cat[i].Board < cat[j].Board + } + return cat[i].Vendor < cat[j].Vendor + }) + } +} diff --git a/util/docker/coreboot.org-status/board-status.html/go.mod b/util/docker/coreboot.org-status/board-status.html/go.mod new file mode 100644 index 0000000000..7fcf434cd6 --- /dev/null +++ b/util/docker/coreboot.org-status/board-status.html/go.mod @@ -0,0 +1,23 @@ +module review.coreboot.org/coreboot.git/util/docker/coreboot.org-status/board-status.html + +go 1.17 + +require ( + github.com/Microsoft/go-winio v0.4.16 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect + github.com/acomagu/bufpipe v1.0.3 // indirect + github.com/emirpasic/gods v1.12.0 // indirect + github.com/go-git/gcfg v1.5.0 // indirect + github.com/go-git/go-billy/v5 v5.3.1 // indirect + github.com/go-git/go-git/v5 v5.4.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/sergi/go-diff v1.1.0 // indirect + github.com/xanzy/ssh-agent v0.3.0 // indirect + golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect + golang.org/x/net v0.0.0-20210326060303-6b1517762897 // indirect + golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect +) diff --git a/util/docker/coreboot.org-status/board-status.html/go.sum b/util/docker/coreboot.org-status/board-status.html/go.sum new file mode 100644 index 0000000000..2ea7b18d45 --- /dev/null +++ b/util/docker/coreboot.org-status/board-status.html/go.sum @@ -0,0 +1,84 @@ +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= +github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= +github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= +github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= +github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= +github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210326060303-6b1517762897 h1:KrsHThm5nFk34YtATK1LsThyGhGbGe1olrte/HInHvs= +golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79 h1:RX8C8PRZc2hTIod4ds8ij+/4RQX3AqhYj3uOHmyaz4E= +golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/util/docker/coreboot.org-status/board-status.html/logs.go b/util/docker/coreboot.org-status/board-status.html/logs.go new file mode 100644 index 0000000000..21e91f2d9a --- /dev/null +++ b/util/docker/coreboot.org-status/board-status.html/logs.go @@ -0,0 +1,165 @@ +package main + +import ( + "fmt" + "io/fs" + "os" + "os/exec" + "path/filepath" + "sort" + "strings" + "time" +) + +// Color returns a HTML color code between green and yellow based on the +// number of days that passed since ds. +func (ds DateString) Color() string { + date, _ := time.Parse("2006-01-02T15:04:05Z", string(ds)) + days := int(time.Since(date).Hours() / 24) + if days > 255 { + days = 255 + } + return fmt.Sprintf("#%02xff00", days) +} + +func fetchLogs(dirs chan<- NamedFS) { + err := fs.WalkDir(bsdirFS, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if path[0] == '.' { + return nil + } + if d.IsDir() && len(strings.Split(path, string(filepath.Separator))) == 4 { + dirs <- NamedFS{ + FS: bsdirFS, + Name: path, + } + } + return nil + }) + if err != nil { + fmt.Fprintf(os.Stderr, "Reading logs failed: %v\n", err) + } + close(dirs) +} + +func collectLogs(dirs <-chan NamedFS) { + data.Logs = make(map[Timeframe][]Log) + data.VendorBoardDate = make(map[string]DateString) + data.VendorBoardReferenced = make(map[string]bool) + timeframes := make(map[Timeframe]bool) + gitcache := make(map[string]string) + for dir := range dirs { + upstream := "" + revB, err := fs.ReadFile(dir.FS, filepath.Join(dir.Name, "revision.txt")) + if err != nil { + continue + } + rev := string(revB) + skipDir := false + for _, line := range strings.Split(rev, "\n") { + item := strings.SplitN(line, ":", 2) + if len(item) != 2 { + // This is an error, but let's try to extract + // as much value out of revision.txt files as + // possible, even if some lines are erroneous. + continue + } + if item[0] == "Upstream revision" { + upstream = strings.TrimSpace(item[1]) + // tried using go-git, but its resolver + // couldn't expand short hashes despite the + // docs claiming that it can. + if val, ok := gitcache[upstream]; ok { + upstream = val + } else { + res, err := exec.Command("/usr/bin/git", "-C", cbdir, "log", "-n1", "--format=%H", upstream).Output() + if err != nil { + fmt.Fprintf(os.Stderr, "revision %s not found \n", upstream) + skipDir = true + break + } + gitcache[upstream] = strings.TrimSpace(string(res)) + upstream = gitcache[upstream] + } + } + } + if skipDir { + continue + } + + rawFiles, err := fs.Glob(dir.FS, filepath.Join(dir.Name, "*")) + if err != nil { + fmt.Fprintf(os.Stderr, "Could not fetch log data, skipping: %v\n", err) + continue + } + + pieces := strings.Split(dir.Name, string(filepath.Separator)) + if len(pieces) < 4 { + fmt.Fprintf(os.Stderr, "log directory %s is malformed, skipping\n", dir.Name) + continue + } + vendorBoard := strings.Join(pieces[:2], "/") + // TODO: these need to become "second to last" and "last" item + // but only after compatibility to the current system has been ensured. + dateTimePath := pieces[3] + dateTime, err := time.Parse(time.RFC3339, strings.ReplaceAll(dateTimePath, "_", ":")) + if err != nil { + fmt.Fprintf(os.Stderr, "Could not parse timestamp from %s: %v\n", dir.Name, err) + continue + } + dateTimeNormal := dateTime.UTC().Format("2006-01-02T15:04:05Z") + dateTimeHuman := dateTime.UTC().Format(time.UnixDate) + tfYear, tfWeek := dateTime.ISOWeek() + timeframe := Timeframe(fmt.Sprintf("%dW%02d", tfYear, tfWeek)) + + if !timeframes[timeframe] { + timeframes[timeframe] = true + data.Timeframes = append(data.Timeframes, timeframe) + data.Logs[timeframe] = []Log{} + } + + files := []Path{} + l := len(dir.Name) + 1 + for _, file := range rawFiles { + if file[l:] == "revision.txt" { + continue + } + files = append(files, Path{ + Path: dir.Name + "/", + Basename: file[l:], + }) + } + + data.Logs[timeframe] = append(data.Logs[timeframe], Log{ + VendorBoard: vendorBoard, + Time: dateTimeNormal, + TimeReadable: dateTimeHuman, + Upstream: upstream, + Files: files, + }) + } + sort.Slice(data.Timeframes, func(i, j int) bool { + // reverse sort + return data.Timeframes[i] > data.Timeframes[j] + }) + for bi := range data.Logs { + bucket := data.Logs[bi] + sort.Slice(data.Logs[bi], func(i, j int) bool { + if bucket[i].Time == bucket[j].Time { + return (bucket[i].VendorBoard > bucket[j].VendorBoard) + } + return (bucket[i].Time > bucket[j].Time) + }) + } + for _, ts := range data.Timeframes { + for li, l := range data.Logs[ts] { + if _, match := data.VendorBoardDate[l.VendorBoard]; match { + continue + } + data.VendorBoardDate[l.VendorBoard] = DateString(l.Time) + data.Logs[ts][li].Reference = true + } + } +} diff --git a/util/docker/coreboot.org-status/board-status.html/status-to-html.go b/util/docker/coreboot.org-status/board-status.html/status-to-html.go new file mode 100644 index 0000000000..ae341faac8 --- /dev/null +++ b/util/docker/coreboot.org-status/board-status.html/status-to-html.go @@ -0,0 +1,92 @@ +package main + +import ( + "embed" + "errors" + "flag" + "fmt" + "html/template" + "io/fs" + "os" + "path/filepath" +) + +//go:embed templates +var templates embed.FS + +var data = TemplateData{ + Categories: []Category{ + "laptop", + "server", + "desktop", + "half", + "mini", + "settop", + "eval", + "sbc", + "emulation", + "misc", + "unclass", + }, + CategoryNiceNames: map[Category]string{ + "desktop": "Desktops / Workstations", + "server": "Servers", + "laptop": "Laptops", + "half": "Embedded / PC/104 / Half-size boards", + "mini": "Mini-ITX / Micro-ITX / Nano-ITX", + "settop": "Set-top-boxes / Thin clients", + "eval": "Devel/Eval Boards", + "sbc": "Single-Board computer", + "emulation": "Emulation", + "misc": "Miscellaneous", + "unclass": "Unclassified", + }, + BoardsByCategory: map[Category][]Board{}, +} + +var ( + cbdirFS fs.FS + cbdir string + bsdirFS fs.FS +) + +func main() { + var cbDir, bsDir string + flag.StringVar(&cbDir, "coreboot-dir", filepath.Join("..", "coreboot.git"), "coreboot.git checkout") + flag.StringVar(&bsDir, "board-status-dir", filepath.Join("..", "board-status.git"), "board-status.git checkout") + flag.Parse() + + tpls, err := template.ParseFS(templates, filepath.Join("templates", "*")) + if err != nil { + fmt.Fprintf(os.Stderr, "Parsing templates failed: %v\n", err) + os.Exit(1) + } + + if _, err := os.Stat(cbDir); errors.Is(err, os.ErrNotExist) { + fmt.Fprintf(os.Stderr, "coreboot root %s does not exist\n", cbDir) + os.Exit(1) + } + + if _, err := os.Stat(bsDir); errors.Is(err, os.ErrNotExist) { + fmt.Fprintf(os.Stderr, "board-status dir %s does not exist\n", bsDir) + os.Exit(1) + } + + cbdirFS = os.DirFS(cbDir) + cbdir = cbDir + bsdirFS = os.DirFS(bsDir) + + dirs := make(chan NamedFS) + go fetchLogs(dirs) + collectLogs(dirs) + + dirs = make(chan NamedFS) + go fetchBoards(dirs) + collectBoards(dirs) + + err = tpls.ExecuteTemplate(os.Stdout, "board-status.html", data) + if err != nil { + fmt.Fprintf(os.Stderr, "Executing template failed: %v\n", err) + os.Exit(1) + } +} diff --git a/util/docker/coreboot.org-status/board-status.html/templates/board-status.html b/util/docker/coreboot.org-status/board-status.html/templates/board-status.html new file mode 100644 index 0000000000..93fcc45101 --- /dev/null +++ b/util/docker/coreboot.org-status/board-status.html/templates/board-status.html @@ -0,0 +1,133 @@ +{{$data := . -}} +{{- define "colorcode" -}} +{{- if eq . "n" }}<td style="background:red">N</td>{{else + if eq . "y" }}<td style="background:lime">Y</td>{{else + if eq . "" }}<td>?</td>{{else + }}<td>{{.}}</td>{{end -}} +{{end -}} +<html> +<head> + <meta charset="utf-8"> + <title>status report for coreboot boards</title> +</head> +<body> +<h1>Mainboards supported by coreboot</h1> + +<p>This page shows two representations of the same data:</p> + +<p>First a list of all mainboards supported by coreboot (current within +one hour) ordered by category. For each mainboard the table shows the +latest user-contributed report of a successful boot on the device.</p> + +<p>After that, the page provides a time-ordered list of these contributed +reports, with the newest report first.</p> + +<p>Boards without such reports may boot or there may be some maintenance +required. The reports contain the coreboot configuration and precise commit +id, so it is possible to reproduce the build.</p> + +<p>We encourage developers and users to contribute reports so we know which +devices are well-tested. We have +<a href='https://review.coreboot.org/plugins/gitiles/coreboot/+/refs/heads/master/util/board_status/'>a tool in the coreboot repository</a> +to make contributing easy. The data resides in the +<a href='https://review.coreboot.org/plugins/gitiles/board-status/'>board status repository</a>. +Contributing requires an account on review.coreboot.org. After +logging into the site with your preferred OpenID or GitHub/Google +credentials, you can get a user name and password for git pushes on <a +href="https://review.coreboot.org/settings/#HTTPCredentials">gerrit's +settings screen</a>.</p> + +<p>Sometimes the same board is sold under different names, we've tried to +list all known names but some names might be missing.</p> + +<p>If the board is not found in the coreboot's source code, there might +be some form of support that is not ready yet for inclusion in coreboot, +usually people willing to send their patches to coreboot goes through +<a href='https://review.coreboot.org'>gerrit</a>, so looking there could find some +code for boards that are not yet merged.</p> + +<h1>Vendor trees</h1> +<p>Some vendors have their own coreboot trees/fork, for instance: +<ul> + <li><a href='https://chromium.googlesource.com/chromiumos/third_party/coreboot/'>chrome/chromium's tree</a> +</ul> +</p> +<h1>Motherboards supported in coreboot</h1> + +<table border="0" style="font-size: smaller"> +<tr bgcolor="#6699ff"> +<td>Vendor</td> +<td>Mainboard</td> +<td>Latest known good</td> +<td>Northbridge</td> +<td>Southbridge</td> +<td>Super I/O</td> +<td>CPU</td> +<td>Socket</td> +<td><span title="ROM chip package">ROM <sup>1</sup></span></td> +<td><span title="ROM chip protocol">P <sup>2</sup></span></td> +<td><span title="ROM chip socketed?">S <sup>3</sup></span></td> +<td><span title="Board supported by flashrom?">F <sup>4</sup></span></td> +<td><span title="Vendor Cooperation Score">VCS<sup>5</sup></span></td> +</tr> +{{range $category := .Categories -}} +<tr bgcolor="#6699ff"> +<td colspan="13"><h4>{{index $data.CategoryNiceNames $category}}</h4></td> +</tr> + +{{$color := "#eeeeee" -}} +{{$oldVendor := "" -}} +{{range $b := index $data.BoardsByCategory $category -}} +{{if ne $oldVendor $b.VendorNice}}{{$oldVendor = $b.VendorNice -}} +{{if eq $color "#dddddd"}}{{$color = "#eeeeee"}}{{else}}{{$color = "#dddddd"}}{{end -}} +{{end -}} +<tr bgcolor="{{$color}}"> +<td>{{if $b.BoardURL}}<a href='{{$b.BoardURL}}'>{{$b.VendorNice}}</a>{{else}}{{$b.VendorNice}}{{end}} +{{if $b.Vendor2nd}} ({{$b.Vendor2nd}}) +{{end -}} +</td><td><a href='https://www.coreboot.org/Board:{{$b.Vendor}}/{{$b.Board}}'>{{$b.BoardNice}}</a></td> +{{if eq "" (index $data.VendorBoardDate $b.VendorBoard) -}} +<td style="background:red">Unknown</td> +{{- else -}} +{{- $date := index $data.VendorBoardDate $b.VendorBoard -}} +<td style="background:{{ $date.Color }}"><a href='#{{ $b.VendorBoard }}'>{{ $date }}</a></td> +{{- end}} +<td>{{$b.NorthbridgeNice}}</td> +<td>{{$b.SouthbridgeNice}}</td> +<td>{{$b.SuperIONice}}</td> +<td>{{$b.CPUNice}}</td> +<td>{{$b.SocketNice}}</td> +<td>{{$b.ROMPackage}}</td> +<td>{{$b.ROMProtocol}}</td> +{{template "colorcode" $b.ROMSocketed}} +{{template "colorcode" $b.FlashromSupport}} +<td>{{$b.VendorCooperationScore}} +</td></tr> +{{end -}} +{{end -}} +</table> +<small> +<sup>1</sup> ROM chip package (PLCC, DIP32, DIP8, SOIC8).<br /> +<sup>2</sup> ROM chip protocol/type (parallel flash, LPC, FWH, SPI).<br /> +<sup>3</sup> ROM chip socketed (Y/N)?<br /> +<sup>4</sup> Board supported by [http://www.flashrom.org flashrom] (Y/N)?<br /> +<sup>5</sup> Vendor Cooperation Score.<br /> +<sup>6</sup> [http://www.flashrom.org flashrom] does not work when the vendor BIOS is booted, but it does work when the machine is booted with coreboot.<br /> +<sup>7</sup> Some boards have ROM sockets, others are soldered.<br /> +</small> +{{range $t := .Timeframes -}} +<h1>{{$t}}</h1> +{{range $l := index $data.Logs $t -}} +{{if $l.Reference}}<span id="{{$l.VendorBoard}}"></span> +{{end -}} +<a href='https://www.coreboot.org/Board:{{$l.VendorBoard}}'>{{$l.VendorBoard}}</a> at {{$l.TimeReadable}} +<a href='https://review.coreboot.org/plugins/gitiles/coreboot/+/{{$l.Upstream}}'>upstream tree</a> ( +{{range $f := $l.Files -}} +<a href='https://review.coreboot.org/plugins/gitiles/board-status/+/refs/heads/master/{{$f.Path}}{{$f.Basename}}'>{{$f.Basename}}</a> {{/* */}} +{{end -}} +)<br /> +{{- end -}} +{{end -}} +{{/* */}} +</body> +</html> diff --git a/util/docker/coreboot.org-status/board-status.html/types.go b/util/docker/coreboot.org-status/board-status.html/types.go new file mode 100644 index 0000000000..93094d3857 --- /dev/null +++ b/util/docker/coreboot.org-status/board-status.html/types.go @@ -0,0 +1,60 @@ +package main + +import ( + "io/fs" +) + +type Board struct { + Vendor string + VendorNice string + Vendor2nd string + VendorBoard string + Board string + BoardNice string + BoardURL string + NorthbridgeNice string + SouthbridgeNice string + SuperIONice string + CPUNice string + SocketNice string + ROMPackage string + ROMProtocol string + ROMSocketed string + FlashromSupport string + VendorCooperationScore string + VendorCooperationPage string +} + +type Path struct { + Path string + Basename string +} + +type Log struct { + Reference bool + VendorBoard string + Time string + TimeReadable string + Upstream string + Files []Path +} + +type Category string +type Timeframe string + +type DateString string + +type TemplateData struct { + Categories []Category + CategoryNiceNames map[Category]string + BoardsByCategory map[Category][]Board + Timeframes []Timeframe + Logs map[Timeframe][]Log + VendorBoardDate map[string]DateString + VendorBoardReferenced map[string]bool +} + +type NamedFS struct { + FS fs.FS + Name string +} |