From 9d0693d90975503f0038f36f19b7f0e1d4189d1f Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Sun, 15 Dec 2024 06:48:52 +0000 Subject: [PATCH] ref(webi): complete transition from 'request' for 'fetch' --- _common/gitea.js | 8 +- _webi/builds-cacher.js | 4 +- _webi/classify-one.js | 4 +- _webi/transform-releases.js | 3 +- flutter/releases.js | 39 ++++++--- go/releases.js | 113 ++++++++++++++---------- gpg/releases.js | 107 +++++++++++++---------- iterm2/releases.js | 109 +++++++++++------------ macos/releases.js | 105 ++++++++++++++--------- node/releases.js | 108 +++++++++++++---------- terraform/releases.js | 84 +++++++++--------- zig/releases.js | 166 ++++++++++++++++++------------------ 12 files changed, 465 insertions(+), 385 deletions(-) diff --git a/_common/gitea.js b/_common/gitea.js index 51b0e811e..3789d933d 100644 --- a/_common/gitea.js +++ b/_common/gitea.js @@ -41,9 +41,7 @@ if (module === require.main) { 'https://git.rootprojects.org', '', '', - ).then( - function (all) { - console.info(JSON.stringify(all, null, 2)); - }, - ); + ).then(function (all) { + console.info(JSON.stringify(all, null, 2)); + }); } diff --git a/_webi/builds-cacher.js b/_webi/builds-cacher.js index a644ef215..b2780e6d5 100644 --- a/_webi/builds-cacher.js +++ b/_webi/builds-cacher.js @@ -9,8 +9,6 @@ let HostTargets = require('./build-classifier/host-targets.js'); let Lexver = require('./build-classifier/lexver.js'); let Triplet = require('./build-classifier/triplet.js'); -let request = require('@root/request'); - var ALIAS_RE = /^alias: (\w+)$/m; var LEGACY_ARCH_MAP = { @@ -153,7 +151,7 @@ async function getLatestBuilds(Releases, installersDir, cacheDir, name, date) { } async function getLatestBuildsInner(Releases, cacheDir, name, date) { - let data = await Releases.latest(request); + let data = await Releases.latest(); if (!date) { date = new Date(); diff --git a/_webi/classify-one.js b/_webi/classify-one.js index 561274aca..7a1d376de 100644 --- a/_webi/classify-one.js +++ b/_webi/classify-one.js @@ -6,8 +6,6 @@ let Path = require('node:path'); let BuildsCacher = require('./builds-cacher.js'); let Triplet = require('./build-classifier/triplet.js'); -let request = require('@root/request'); - async function main() { let projName = process.argv[2]; if (!projName) { @@ -47,7 +45,7 @@ async function main() { Releases.latest = Releases; } - let projInfo = await Releases.latest(request); + let projInfo = await Releases.latest(); // let packages = await Builds.getPackage({ name: projName }); // console.log(packages); diff --git a/_webi/transform-releases.js b/_webi/transform-releases.js index 050c9ebe8..d6e33d447 100644 --- a/_webi/transform-releases.js +++ b/_webi/transform-releases.js @@ -3,7 +3,6 @@ var Releases = module.exports; var path = require('path'); -var request = require('@root/request'); var _normalize = require('./normalize.js'); var cache = {}; @@ -28,7 +27,7 @@ Releases.get = async function (pkgdir) { throw err; } - let all = await get.latest(request); + let all = await get.latest(); return _normalize(all); }; diff --git a/flutter/releases.js b/flutter/releases.js index 472d446a3..f985b444b 100644 --- a/flutter/releases.js +++ b/flutter/releases.js @@ -2,7 +2,10 @@ var FLUTTER_OSES = ['macos', 'linux', 'windows']; -// stable, beta, dev +/** + * stable, beta, dev + * @type {Object.} + */ var channelMap = {}; // This can be spot-checked against @@ -53,25 +56,39 @@ var channelMap = {}; // ] // } +/** + * @typedef BuildInfo + * @prop {String} version + * @prop {String} [_version] + * @prop {Boolean} lts + * @prop {String} channel + * @prop {String} date + * @prop {String} download + * @prop {String} [_filename] + */ + module.exports = async function () { let all = { download: '', + /** @type {Array} */ releases: [], + /** @type {Array} */ channels: [], }; for (let osname of FLUTTER_OSES) { - const response = await fetch(`https://storage.googleapis.com/flutter_infra_release/releases/releases_${osname}.json`, { - method: 'GET', - headers: { Accept: 'application/json' }, - }); + let response = await fetch( + `https://storage.googleapis.com/flutter_infra_release/releases/releases_${osname}.json`, + { headers: { Accept: 'application/json' } }, + ); if (!response.ok) { - throw new Error(`Failed to fetch data for ${osname}: ${response.statusText}`); + throw new Error( + `Failed to fetch data for ${osname}: ${response.statusText}`, + ); } - const respBody = await response.json(); - - let osBaseUrl = respBody.base_url; - let osReleases = respBody.releases; + let data = await response.json(); + let osBaseUrl = data.base_url; + let osReleases = data.releases; for (let asset of osReleases) { if (!channelMap[asset.channel]) { @@ -100,7 +117,7 @@ module.exports = async function () { }; if (module === require.main) { - module.exports(require('@root/request')).then(function (all) { + module.exports().then(function (all) { all.releases = all.releases.slice(25); console.info(JSON.stringify(all, null, 2)); }); diff --git a/go/releases.js b/go/releases.js index 715bdbc72..2bf61a10a 100644 --- a/go/releases.js +++ b/go/releases.js @@ -1,14 +1,19 @@ 'use strict'; +/** @type {Object.} */ var osMap = { darwin: 'macos', }; +/** @type {Object.} */ var archMap = { 386: 'x86', }; let ODDITIES = ['bootstrap', '-arm6.']; +/** + * @param {String} filename + */ function isOdd(filename) { for (let oddity of ODDITIES) { let isOddity = filename.includes(oddity); @@ -18,6 +23,21 @@ function isOdd(filename) { } } +/** + * @typedef BuildInfo + * @prop {String} version + * @prop {String} [_version] + * @prop {String} arch + * @prop {String} channel + * @prop {String} date + * @prop {String} download + * @prop {String} ext + * @prop {String} [_filename] + * @prop {String} hash + * @prop {Boolean} lts + * @prop {String} os + */ + async function getDistributables() { /* { @@ -37,60 +57,63 @@ async function getDistributables() { ] }; */ - const response = await fetch('https://golang.org/dl/?mode=json&include=all', { - method: 'GET', - headers: { Accept: 'application/json' }, - }); - if (!response.ok) { - throw new Error(`Failed to fetch Go releases: ${response.statusText}`); + let response = await fetch('https://golang.org/dl/?mode=json&include=all', { + method: 'GET', + headers: { Accept: 'application/json' }, + }); + if (!response.ok) { + throw new Error(`Failed to fetch Go releases: ${response.statusText}`); + } + + let goReleases = await response.json(); + let all = { + /** @type {Array} */ + releases: [], + download: '', + }; + + for (let release of goReleases) { + // Strip 'go' prefix, standardize version + let parts = release.version.slice(2).split('.'); + while (parts.length < 3) { + parts.push('0'); } - - const goReleases = await response.json(); - const all = { - releases: [], - download: '', - }; + let version = parts.join('.'); + let fileversion = release.version.slice(2); - goReleases.forEach((release) => { - // Strip 'go' prefix and standardize version - const parts = release.version.slice(2).split('.'); - while (parts.length < 3) { - parts.push('0'); + for (let asset of release.files) { + if (isOdd(asset.filename)) { + return; } - const version = parts.join('.'); - const fileversion = release.version.slice(2); - - release.files.forEach((asset) => { - if (isOdd(asset.filename)) { - return; - } - - const filename = asset.filename; - const os = osMap[asset.os] || asset.os || '-'; - const arch = archMap[asset.arch] || asset.arch || '-'; - all.releases.push({ - version: version, - _version: fileversion, - lts: (parts[0] > 0 && release.stable) || false, - channel: (release.stable && 'stable') || 'beta', - date: '1970-01-01', // Placeholder - os: os, - arch: arch, - ext: '', // Let normalize run the split/test/join - hash: '-', // Placeholder for hash - download: `https://dl.google.com/go/${filename}`, - }); - }); - }); - - return all; + + let filename = asset.filename; + let os = osMap[asset.os] || asset.os || '-'; + let arch = archMap[asset.arch] || asset.arch || '-'; + let build = { + version: version, + _version: fileversion, + lts: (parts[0] > 0 && release.stable) || false, + channel: (release.stable && 'stable') || 'beta', + date: '1970-01-01', // the world may never know + os: os, + arch: arch, + ext: '', // let normalize run the split/test/join + hash: '-', // not ready to standardize this yet + download: `https://dl.google.com/go/${filename}`, + }; + all.releases.push(build); + } } + return all; +} + module.exports = getDistributables; if (module === require.main) { - getDistributables(require('@root/request')).then(function (all) { + getDistributables().then(function (all) { all = require('../_webi/normalize.js')(all); + //@ts-expect-error all.releases = all.releases.slice(0, 10); console.info(JSON.stringify(all, null, 2)); }); diff --git a/gpg/releases.js b/gpg/releases.js index ef8e844a8..3794773c2 100644 --- a/gpg/releases.js +++ b/gpg/releases.js @@ -16,84 +16,97 @@ function createUrlMatcher() { ); } +/** + * @typedef BuildInfo + * @prop {String} version + * @prop {String} [_version] + * @prop {String} arch + * @prop {String} channel + * @prop {String} date + * @prop {String} download + * @prop {String} ext + * @prop {String} [_filename] + * @prop {String} hash + * @prop {Boolean} lts + * @prop {String} os + */ + async function getRawReleases() { let matcher = createRssMatcher(); - const response = await fetch('https://sourceforge.net/projects/gpgosx/rss?path=/', { - method: 'GET', - headers: { - 'Accept': 'application/rss+xml', // Ensure the correct content type is requested - }, + let resp = await fetch('https://sourceforge.net/projects/gpgosx/rss?path=/', { + headers: { Accept: 'application/rss+xml' }, }); - - // Validate the response status - if (!response.ok) { - throw new Error(`Failed to fetch RSS feed: HTTP ${response.status} - ${response.statusText}`); + let text = await resp.text(); // Fetch RSS feed as plain text + if (!resp.ok) { + throw new Error(`Failed to fetch RSS feed: HTTP ${resp.status}: ${text}`); } - const contentType = response.headers.get('Content-Type'); + let contentType = resp.headers.get('Content-Type'); if (!contentType || !contentType.includes('xml')) { throw new Error(`Unexpected content type: ${contentType}`); } - const body = await response.text(); // Fetch RSS feed as plain text - let links = []; for (;;) { - let m = matcher.exec(body); + let m = matcher.exec(text); if (!m) { break; } links.push(m[1]); } + return links; } +/** + * @param {Array} links + */ function transformReleases(links) { //console.log(JSON.stringify(links, null, 2)); //console.log(links.length); let matcher = createUrlMatcher(); - let releases = links - .map(function (link) { - let isLts = ltsRe.test(link); - let parts = link.match(matcher); - if (!parts || !parts[2]) { - return null; - } - let segs = parts[2].split('.'); - let version = segs.slice(0, 3).join('.'); - if (segs.length > 3) { - version += '+' + segs.slice(3); - } - let fileversion = segs.join('.'); - - return { - name: parts[1], - version: version, - _version: fileversion, - // all go versions >= 1.0.0 are effectively LTS - lts: isLts, - channel: 'stable', - // TODO Sat, 19 Nov 2016 16:17:33 UT - date: '1970-01-01', // the world may never know - os: 'macos', - arch: 'amd64', - ext: 'dmg', - download: link, - }; - }) - .filter(Boolean); + let builds = []; + for (let link of links) { + let isLts = ltsRe.test(link); + let parts = link.match(matcher); + if (!parts || !parts[2]) { + continue; + } + + let segs = parts[2].split('.'); + let version = segs.slice(0, 3).join('.'); + if (segs.length > 3) { + version += '+' + segs.slice(3); + } + let fileversion = segs.join('.'); + + let build = { + name: parts[1], + version: version, + _version: fileversion, + lts: isLts, + channel: 'stable', + // TODO Sat, 19 Nov 2016 16:17:33 UT + date: '1970-01-01', // the world may never know + os: 'macos', + arch: 'amd64', + ext: 'dmg', + download: link, + }; + builds.push(build); + } return { _names: ['GnuPG', 'gpgosx'], - releases: releases, + releases: builds, }; } -async function getDistributables(request) { - let releases = await getRawReleases(request); +async function getDistributables() { + let releases = await getRawReleases(); let all = transformReleases(releases); return all; } @@ -101,7 +114,7 @@ async function getDistributables(request) { module.exports = getDistributables; if (module === require.main) { - getDistributables(require('@root/request')).then(function (all) { + getDistributables().then(function (all) { all = require('../_webi/normalize.js')(all); all.releases = all.releases.slice(0, 10000); console.info(JSON.stringify(all, null, 2)); diff --git a/iterm2/releases.js b/iterm2/releases.js index 6d5503541..2c24d8f85 100644 --- a/iterm2/releases.js +++ b/iterm2/releases.js @@ -1,89 +1,82 @@ 'use strict'; async function getRawReleases() { - const response = await fetch('https://iterm2.com/downloads.html', { - method: 'GET', - headers: { - 'Accept': 'text/html', // Explicitly request HTML content - }, + let resp = await fetch('https://iterm2.com/downloads.html', { + headers: { Accept: 'text/html' }, }); - - // Validate HTTP response - if (!response.ok) { - throw new Error(`Failed to fetch releases: HTTP ${response.status} - ${response.statusText}`); + let text = await resp.text(); + if (!resp.ok) { + throw new Error(`Failed to fetch releases: HTTP ${resp.status}: ${text}`); } - // Validate Content-Type header - const contentType = response.headers.get('Content-Type'); + let contentType = resp.headers.get('Content-Type'); if (!contentType || !contentType.includes('text/html')) { throw new Error(`Unexpected Content-Type: ${contentType}`); } - // Parse HTML content - const body = await response.text(); - var links = body - .split(/[<>]+/g) - .map(function (str) { - var m = str.match( - /href="(https:\/\/iterm2\.com\/downloads\/.*\.zip)"/, - ); + let lines = text.split(/[<>]+/g); + + /** @type {Array} */ + let links = []; + for (let str of lines) { + var m = str.match(/href="(https:\/\/iterm2\.com\/downloads\/.*\.zip)"/); if (m && /iTerm2-[34]/.test(m[1])) { - return m[1]; + if (m[1]) { + links.push(m[1]); + } } - }) - .filter(Boolean); + } + return links; } +/** + * @param {Array} links + */ function transformReleases(links) { - //console.log(JSON.stringify(links, null, 2)); - //console.log(links.length); + let builds = []; + for (let link of links) { + var channel = /\/stable\//.test(link) ? 'stable' : 'beta'; - return { - _names: ['iTerm2', 'iterm2'], - releases: links - .map(function (link) { - var channel = /\/stable\//.test(link) ? 'stable' : 'beta'; + var parts = link.replace(/.*\/iTerm2[-_]v?(\d_.*)\.zip/, '$1').split('_'); + var version = parts.join('.').replace(/([_-])?beta/, '-beta'); - var parts = link - .replace(/.*\/iTerm2[-_]v?(\d_.*)\.zip/, '$1') - .split('_'); - var version = parts.join('.').replace(/([_-])?beta/, '-beta'); + // ex: 3.5.0-beta17 => 3_5_0beta17 + // ex: 3.0.2-preview => 3_0_2-preview + let fileversion = version.replace(/\./g, '_'); + fileversion = fileversion.replace(/-beta/g, 'beta'); - // ex: 3.5.0-beta17 => 3_5_0beta17 - // ex: 3.0.2-preview => 3_0_2-preview - let fileversion = version.replace(/\./g, '_'); - fileversion = fileversion.replace(/-beta/g, 'beta'); + let build = { + version: version, + _version: fileversion, + lts: 'stable' === channel, + channel: channel, + date: '1970-01-01', // the world may never know + os: 'macos', + arch: 'amd64', + ext: '', // let normalize run the split/test/join + download: link, + }; + builds.push(build); + } - return { - version: version, - _version: fileversion, - // all go versions >= 1.0.0 are effectively LTS - lts: 'stable' === channel, - channel: channel, - date: '1970-01-01', // the world may never know - os: 'macos', - arch: 'amd64', - ext: '', // let normalize run the split/test/join - download: link, - }; - }) - .filter(Boolean), + return { + _names: ['iTerm2', 'iterm2'], + releases: builds, }; } -function getDistributables(request) { - return getRawReleases(request) - .then(transformReleases) - .then(function (all) { - return all; - }); +async function getDistributables() { + let rawReleases = await getRawReleases(); + let all = transformReleases(rawReleases); + + return all; } module.exports = getDistributables; if (module === require.main) { - getDistributables(require('@root/request')).then(function (all) { + getDistributables().then(function (all) { all = require('../_webi/normalize.js')(all); all.releases = all.releases.slice(0, 10000); console.info(JSON.stringify(all, null, 2)); diff --git a/macos/releases.js b/macos/releases.js index 10d0ad231..3bc9294ad 100644 --- a/macos/releases.js +++ b/macos/releases.js @@ -40,65 +40,90 @@ var headers = { 'Accept-Language': 'en-US,en;q=0.9,sq;q=0.8', }; +/** + * @param {typeof oses[0]} os + */ async function fetchReleasesForOS(os) { - // Fetch the webpage for the given OS - const response = await fetch(os.url, { - method: 'GET', + let resp = await fetch(os.url, { headers: headers, }); - - // Validate HTTP response - if (!response.ok) { - throw new Error(`Failed to fetch URL: ${os.url}. HTTP ${response.status} - ${response.statusText}`); + let text = await resp.text(); + if (!resp.ok) { + throw new Error( + `Failed to fetch URL: ${os.url}. HTTP ${resp.status}: ${text}`, + ); } - // Parse the response body - const body = await response.text(); - // Extract the download link - const match = body.match(/(http[^>]+Install[^>]+\.dmg)/); - return match ? match[1] : null; + let match = text.match(/(http[^>]+Install[^>]+\.dmg)/); + if (match) { + return match[1]; + } } +/** + * @typedef BuildInfo + * @prop {String} version + * @prop {String} [_version] + * @prop {String} arch + * @prop {String} channel + * @prop {String} date + * @prop {String} download + * @prop {String} ext + * @prop {String} [_filename] + * @prop {String} hash + * @prop {Boolean} lts + * @prop {String} os + */ + +let osnames = ['macos', 'linux']; + async function getDistributables() { - const all = { + let all = { _names: ['InstallOS'], download: '', + /** @type {Array} */ releases: [], }; // Fetch data for each OS and populate the releases array - await Promise.all( - oses.map(async (os) => { - try { - const download = await fetchReleasesForOS(os); - - // Add releases for macOS and Linux - ['macos', 'linux'].forEach((osname) => { - all.releases.push({ - version: os.version, - lts: os.lts || false, - channel: os.channel || 'beta', - date: os.date, - os: osname, - arch: 'amd64', - ext: 'dmg', - hash: '-', // Placeholder for hash - download: download, - }); - }); - } catch (err) { - console.error(`Error fetching for ${os.name}: ${err.message}`); - } - }), - ); + for (let os of oses) { + let download = await fetchReleasesForOS(os); + if (!download) { + continue; + } + + // Add releases for macOS and Linux + for (let osname of osnames) { + let build = { + version: os.version, + lts: os.lts || false, + channel: os.channel || 'beta', + date: os.date, + os: osname, + arch: 'amd64', + ext: 'dmg', + hash: '-', + download: download, + }; + + all.releases.push(build); + } + } // Sort releases - all.releases.sort((a, b) => { + all.releases.sort(function (a, b) { if (a.version === '10.11.6') { return -1; } - return a.date > b.date ? 1 : -1; + + if (a.date > b.date) { + return 1; + } else if (a.date < b.date) { + return -1; + } + + return 0; }); return all; @@ -107,7 +132,7 @@ async function getDistributables() { module.exports = getDistributables; if (module === require.main) { - module.exports(require('@root/request')).then(function (all) { + module.exports().then(function (all) { console.info(JSON.stringify(all, null, 2)); }); } diff --git a/node/releases.js b/node/releases.js index 00a57c85f..3e4fdcc6d 100644 --- a/node/releases.js +++ b/node/releases.js @@ -7,6 +7,7 @@ const END_OF_LIFE = 366 * 24 * 60 * 60 * 1000; // OSes +/** @type {Object.} */ let osMap = { osx: 'macos', // NOTE: filename is 'darwin' linux: 'linux', @@ -16,6 +17,7 @@ let osMap = { }; // CPU architectures +/** @type {Object.} */ let archMap = { x64: 'amd64', x86: 'x86', @@ -28,6 +30,7 @@ let archMap = { }; // file extensions +/** @type {Object.>} */ let pkgMap = { pkg: ['pkg'], //exe: ['exe'], // disable @@ -40,8 +43,25 @@ let pkgMap = { musl: ['tar.gz', 'tar.xz'], }; +/** + * @typedef BuildInfo + * @prop {String} version + * @prop {String} [_version] + * @prop {String} arch + * @prop {String} channel + * @prop {String} date + * @prop {String} download + * @prop {String} ext + * @prop {String} [_filename] + * @prop {String} [hash] + * @prop {String} libc + * @prop {Boolean} lts + * @prop {String} os + */ + async function getDistributables() { let all = { + /** @type {Array} */ releases: [], download: '', }; @@ -64,51 +84,52 @@ async function getDistributables() { ] */ - // Alternate: 'https://nodejs.org/dist/index.json', - let baseUrl = `https://nodejs.org/download/release`; + { + // Alternate: 'https://nodejs.org/dist/index.json', + let baseUrl = `https://nodejs.org/download/release`; - // Fetch official builds - let officialP = fetch(`${baseUrl}/index.json`, { - method: 'GET', - headers: { Accept: 'application/json' }, - }).then((response) => { - if (!response.ok) { - throw new Error(`Failed to fetch official builds: HTTP ${response.status} - ${response.statusText}`); + // Fetch official builds + let resp = await fetch(`${baseUrl}/index.json`, { + headers: { Accept: 'application/json' }, + }); + let text = await resp.text(); + if (!resp.ok) { + throw new Error( + `Failed to fetch official builds: HTTP ${resp.status}: ${text}`, + ); } - return response.json(); - }) - .then((data) => { - transform(baseUrl, data); - }); + let data = JSON.parse(text); + void transform(baseUrl, data); + } - // Fetch unofficial builds - let unofficialBaseUrl = `https://unofficial-builds.nodejs.org/download/release`; - let unofficialP = fetch(`${unofficialBaseUrl}/index.json`, { - method: 'GET', - headers: { Accept: 'application/json' }, - }) - .then((response) => { - if (!response.ok) { - throw new Error(`Failed to fetch unofficial builds: HTTP ${response.status} - ${response.statusText}`); - } - return response.json(); - }) - .then((data) => { - transform(unofficialBaseUrl, data); - }) - .catch((err) => { - console.error('failed to fetch unofficial-builds'); - console.error(err); + { + // Fetch unofficial builds + let unofficialBaseUrl = `https://unofficial-builds.nodejs.org/download/release`; + let resp = await fetch(`${unofficialBaseUrl}/index.json`, { + headers: { Accept: 'application/json' }, }); + let text = await resp.text(); + if (!resp.ok) { + throw new Error( + `Failed to fetch official builds: HTTP ${resp.status}: ${text}`, + ); + } + let data = JSON.parse(text); + transform(unofficialBaseUrl, data); + } + /** + * @param {String} baseUrl + * @param {Array} builds + */ function transform(baseUrl, builds) { - builds.forEach(function (build) { + for (let build of builds) { let buildDate = new Date(build.date).valueOf(); let age = Date.now() - buildDate; let maintained = age < END_OF_LIFE; if (!maintained) { - return; + continue; } let lts = false !== build.lts; @@ -122,9 +143,9 @@ async function getDistributables() { channel = 'beta'; } - build.files.forEach(function (file) { + for (let file of build.files) { if ('src' === file || 'headers' === file) { - return; + continue; } let fileParts = file.split('-'); @@ -140,7 +161,7 @@ async function getDistributables() { pkgs = pkgMap.tar; } if (!pkgs?.length) { - return; + continue; } let extra = ''; @@ -157,7 +178,7 @@ async function getDistributables() { osPart = 'darwin'; } - pkgs.forEach(function (pkg) { + for (let pkg of pkgs) { let filename = `node-${build.version}-${osPart}-${archPart}${extra}.${pkg}`; if ('msi' === pkg) { filename = `node-${build.version}-${archPart}${extra}.${pkg}`; @@ -178,20 +199,17 @@ async function getDistributables() { }; all.releases.push(release); - }); - }); - }); + } + } + } } - await officialP; - await unofficialP; - return all; } module.exports = getDistributables; if (module === require.main) { - getDistributables(require('@root/request')).then(function (all) { + getDistributables().then(function (all) { all = require('../_webi/normalize.js')(all); console.info(JSON.stringify(all)); //console.info(JSON.stringify(all, null, 2)); diff --git a/terraform/releases.js b/terraform/releases.js index 1928d9e18..19c3c1fd7 100644 --- a/terraform/releases.js +++ b/terraform/releases.js @@ -1,59 +1,53 @@ 'use strict'; +/** + * @typedef BuildInfo + * @prop {String} version + * @prop {String} download + */ + async function getDistributables() { - try { - // Fetch the Terraform releases JSON - const response = await fetch('https://releases.hashicorp.com/terraform/index.json', { - method: 'GET', - headers: { Accept: 'application/json' }, - }); - - // Validate the HTTP response - if (!response.ok) { - throw new Error(`Failed to fetch releases: HTTP ${response.status} - ${response.statusText}`); - } + let resp = await fetch( + 'https://releases.hashicorp.com/terraform/index.json', + { headers: { Accept: 'application/json' } }, + ); + let text = await resp.text(); + if (!resp.ok) { + throw new Error(`Failed to fetch releases: HTTP ${resp.status}: ${text}`); + } - // Parse the JSON response - const releases = await response.json(); - - let all = { - releases: [], - download: '', // Full URI provided in response body - }; - - function getBuildsForVersion(version) { - releases.versions[version].builds.forEach(function (build) { - let r = { - version: build.version, - download: build.url, - // These are generic enough for the autodetect, - // and the per-file logic has proven to get outdated sooner - //os: convert[build.os], - //arch: convert[build.arch], - //channel: 'stable|-rc|-beta|-alpha', - }; - all.releases.push(r); - }); + let releases = JSON.parse(text); + let all = { + /** @type {Array} */ + releases: [], + download: '', + }; + + let allVersions = Object.keys(releases.versions); + allVersions.reverse(); // Releases are listed chronologically, we want the latest first. + + for (let version of allVersions) { + for (let build of releases.versions[version].builds) { + let r = { + version: build.version, + download: build.url, + // These are generic enough for the autodetect, + // and the per-file logic has proven to get outdated sooner + //os: convert[build.os], + //arch: convert[build.arch], + //channel: 'stable|-rc|-beta|-alpha', + }; + all.releases.push(r); } - - // Releases are listed chronologically, we want the latest first. - const allVersions = Object.keys(releases.versions).reverse(); - - allVersions.forEach(function (version) { - getBuildsForVersion(version); - }); - - return all; - } catch (err) { - console.error('Error fetching Terraform releases:', err.message); - return { releases: [], download: '' }; } + + return all; } module.exports = getDistributables; if (module === require.main) { - getDistributables(require('@root/request')).then(function (all) { + getDistributables().then(function (all) { all = require('../_webi/normalize.js')(all); console.info(JSON.stringify(all)); }); diff --git a/zig/releases.js b/zig/releases.js index 4c447eb9d..b6fc27c65 100644 --- a/zig/releases.js +++ b/zig/releases.js @@ -3,100 +3,104 @@ var NON_BUILDS = ['bootstrap', 'src']; var ODDITIES = NON_BUILDS.concat(['armv6kz-linux']); -module.exports = async function () { - try { - // Fetch the Zig language download index JSON - const response = await fetch('https://ziglang.org/download/index.json', { - method: 'GET', - headers: { Accept: 'application/json' }, - }); - - // Validate HTTP response - if (!response.ok) { - throw new Error(`Failed to fetch releases: HTTP ${response.status} - ${response.statusText}`); - } - - // Parse the JSON response - const versions = await response.json(); +/** + * @typedef BuildInfo + * @prop {String} version + * @prop {String} [_version] + * @prop {String} [arch] + * @prop {String} channel + * @prop {String} date + * @prop {String} download + * @prop {String} [ext] + * @prop {String} [_filename] + * @prop {String} [hash] + * @prop {String} [libc] + * @prop {Boolean} [lts] + * @prop {String} [size] + * @prop {String} os + */ - let releases = []; +module.exports = async function () { + let resp = await fetch('https://ziglang.org/download/index.json', { + method: 'GET', + headers: { Accept: 'application/json' }, + }); + let text = await resp.text(); + if (!resp.ok) { + throw new Error(`Failed to fetch releases: HTTP ${resp.status}: ${text}`); + } + let versions = JSON.parse(text); - let refs = Object.keys(versions); - refs.forEach(function (ref) { - let pkgs = versions[ref]; - let version = pkgs.version || ref; + /** @type {Array} */ + let releases = []; + let refs = Object.keys(versions); + for (let ref of refs) { + let pkgs = versions[ref]; + let version = pkgs.version || ref; - // "platform" = arch + os combo - let platforms = Object.keys(pkgs); - platforms.forEach(function (platform) { - let pkg = pkgs[platform]; + // "platform" = arch + os combo + let platforms = Object.keys(pkgs); + for (let platform of platforms) { + let pkg = pkgs[platform]; - // don't grab 'date' or 'notes', which are (confusingly) - // at the same level as platform releases - let isNotPackage = !pkg || 'object' !== typeof pkg || !pkg.tarball; - if (isNotPackage) { - return; - } + // don't grab 'date' or 'notes', which are (confusingly) + // at the same level as platform releases + let isNotPackage = !pkg || 'object' !== typeof pkg || !pkg.tarball; + if (isNotPackage) { + continue; + } - let isOdd = ODDITIES.includes(platform); - if (isOdd) { - return; - } + let isOdd = ODDITIES.includes(platform); + if (isOdd) { + continue; + } - // Ex: aarch64-macos => ['aarch64', 'macos'] - let parts = platform.split('-'); - //let arch = parts[0]; - let os = parts[1]; - if (parts.length > 2) { - console.warn( - `unexpected platform name with multiple '-': ${platform}`, - ); - return; - } + // Ex: aarch64-macos => ['aarch64', 'macos'] + let parts = platform.split('-'); + //let arch = parts[0]; + let os = parts[1]; + if (parts.length > 2) { + console.warn(`unexpected platform name with multiple '-': ${platform}`); + continue; + } - let p = { - version: version, - date: pkgs.date, - channel: 'stable', - // linux, macos, windows - os: os, - // TODO map explicitly (rather than normalization auto-detect) - //arch: arch, - download: pkg.tarball, - hash: pkg.shasum, - size: pkg.size, - // TODO docs + release notes? - //docs: 'https://ziglang.org/documentation/0.9.1/', - //stdDocs: 'https://ziglang.org/documentation/0.9.1/std/', - //notes: 'https://ziglang.org/download/0.9.1/release-notes.html' - }; + let p = { + version: version, + date: pkgs.date, + channel: 'stable', + // linux, macos, windows + os: os, + // TODO map explicitly (rather than normalization auto-detect) + //arch: arch, + download: pkg.tarball, + hash: pkg.shasum, + size: pkg.size, + // TODO docs + release notes? + //docs: 'https://ziglang.org/documentation/0.9.1/', + //stdDocs: 'https://ziglang.org/documentation/0.9.1/std/', + //notes: 'https://ziglang.org/download/0.9.1/release-notes.html' + }; - // Mark branches or tags as beta (for now) - // Ex: 'master' - // Also mark prereleases (with build tags) as beta - // Ex: 0.10.0-dev.1606+97a53bb8a - let isNotStable = !/\./.test(ref) || /\+|-/.test(p.version); - if (isNotStable) { - p.channel = 'beta'; - } + // Mark branches or tags as beta (for now) + // Ex: 'master' + // Also mark prereleases (with build tags) as beta + // Ex: 0.10.0-dev.1606+97a53bb8a + let isNotStable = !/\./.test(ref) || /\+|-/.test(p.version); + if (isNotStable) { + p.channel = 'beta'; + } - releases.push(p); - }); - }); + releases.push(p); + } + } - return { - releases: releases, - }; - }catch (err) { - console.error('Error fetching Zig releases:', err.message); - return { - releases: [], - }; + return { + releases: releases, }; -} +}; if (module === require.main) { - module.exports(require('@root/request')).then(function (all) { + module.exports().then(function (all) { all = require('../_webi/normalize.js')(all); // just select the first 5 for demonstration all.releases = all.releases.slice(0, 5);