New option to work with one or more hex.pm mirrors (#197)

* New option to work with one or more hex.pm mirrors

Add a new option called `hexpm-mirrors` for one or more hex.pm mirrors.
Default list is `builds.hex.pm`, so behavior is unaffected unless option is
used.

Signed-off-by: Paul Guyot <pguyot@kallisys.net>

* Implement suggested rewording changes from @paulo-ferraz-oliveira

Co-authored-by: Paulo F. Oliveira <paulo.ferraz.oliveira@gmail.com>
Signed-off-by: Paul Guyot <pguyot@kallisys.net>

---------

Signed-off-by: Paul Guyot <pguyot@kallisys.net>
Co-authored-by: Paulo F. Oliveira <paulo.ferraz.oliveira@gmail.com>
This commit is contained in:
Paul Guyot
2023-05-04 08:27:05 +02:00
committed by GitHub
parent 9641cb96c1
commit cf692c3264
13 changed files with 362 additions and 99 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
param([Parameter(Mandatory=$true)][string]${VSN})
param([Parameter(Mandatory=$true)][string]${VSN}, [Parameter(Mandatory=$true)][string]${HEX_MIRROR})
$ErrorActionPreference="Stop"
@@ -9,7 +9,7 @@ $FILE_OUTPUT="elixir.zip"
$DIR_FOR_BIN=".setup-beam/elixir"
$ProgressPreference="SilentlyContinue"
Invoke-WebRequest "https://builds.hex.pm/builds/elixir/${FILE_INPUT}" -OutFile "${FILE_OUTPUT}"
Invoke-WebRequest "${HEX_MIRROR}/builds/elixir/${FILE_INPUT}" -OutFile "${FILE_OUTPUT}"
$ProgressPreference="Continue"
New-Item "${DIR_FOR_BIN}" -ItemType Directory | Out-Null
$ProgressPreference="SilentlyContinue"
+2 -1
View File
@@ -5,11 +5,12 @@ set -eo pipefail
cd "${RUNNER_TEMP}"
VSN=${1}
HEX_MIRROR=${2}
FILE_INPUT="${VSN}.zip"
FILE_OUTPUT=elixir.zip
DIR_FOR_BIN=.setup-beam/elixir
wget -q -O "${FILE_OUTPUT}" "https://builds.hex.pm/builds/elixir/${FILE_INPUT}"
wget -q -O "${FILE_OUTPUT}" "${HEX_MIRROR}/builds/elixir/${FILE_INPUT}"
mkdir -p "${DIR_FOR_BIN}"
unzip -q -o -d "${DIR_FOR_BIN}" "${FILE_OUTPUT}"
echo "Installed Elixir version follows"
+2 -1
View File
@@ -6,11 +6,12 @@ cd "${RUNNER_TEMP}"
OS=${1}
VSN=${2}
HEX_MIRROR=${3}
FILE_INPUT="${VSN}.tar.gz"
FILE_OUTPUT=otp.tar.gz
DIR_FOR_BIN=.setup-beam/otp
wget -q -O "${FILE_OUTPUT}" "https://builds.hex.pm/builds/otp/${OS}/${FILE_INPUT}"
wget -q -O "${FILE_OUTPUT}" "${HEX_MIRROR}/builds/otp/${OS}/${FILE_INPUT}"
mkdir -p "${DIR_FOR_BIN}"
tar zxf "${FILE_OUTPUT}" -C "${DIR_FOR_BIN}" --strip-components=1
"${DIR_FOR_BIN}/Install" -minimal "$(pwd)/${DIR_FOR_BIN}"
+46 -9
View File
@@ -1,3 +1,4 @@
const core = require('@actions/core')
const { exec } = require('@actions/exec')
const path = require('path')
@@ -6,11 +7,28 @@ const path = require('path')
*
* @param {string} osVersion
* @param {string} otpVersion
* @param {string[]} hexMirrors
*/
async function installOTP(osVersion, otpVersion) {
async function installOTP(osVersion, otpVersion, hexMirrors) {
const OS = process.platform
if (OS === 'linux') {
await exec(path.join(__dirname, 'install-otp.sh'), [osVersion, otpVersion])
if (hexMirrors.length === 0) {
throw new Error(
`Could not install Erlang/OTP ${otpVersion} from any hex.pm mirror`,
)
}
const [hexMirror, ...hexMirrorsT] = hexMirrors
try {
await exec(path.join(__dirname, 'install-otp.sh'), [
osVersion,
otpVersion,
hexMirror,
])
return
} catch (err) {
core.info(`install-otp.sh failed for mirror ${hexMirror}`)
}
await installOTP(osVersion, otpVersion, hexMirrorsT)
} else if (OS === 'win32') {
const script = path.join(__dirname, 'install-otp.ps1')
await exec(`pwsh.exe ${script} -VSN:${otpVersion}`)
@@ -21,15 +39,34 @@ async function installOTP(osVersion, otpVersion) {
* Install Elixir.
*
* @param {string} elixirVersion
* @param {string[]} hexMirrors
*/
async function installElixir(elixirVersion) {
const OS = process.platform
if (OS === 'linux') {
await exec(path.join(__dirname, 'install-elixir.sh'), [elixirVersion])
} else if (OS === 'win32') {
const script = path.join(__dirname, 'install-elixir.ps1')
await exec(`pwsh.exe ${script} -VSN:${elixirVersion}`)
async function installElixir(elixirVersion, hexMirrors) {
if (hexMirrors.length === 0) {
throw new Error(
`Could not install Elixir ${elixirVersion} from any hex.pm mirror`,
)
}
const [hexMirror, ...hexMirrorsT] = hexMirrors
const OS = process.platform
let script
try {
if (OS === 'linux') {
script = path.join(__dirname, 'install-elixir.sh')
await exec(script, [elixirVersion, hexMirror])
return
}
if (OS === 'win32') {
script = path.join(__dirname, 'install-elixir.ps1')
await exec(
`pwsh.exe ${script} -VSN:${elixirVersion} -HEX_MIRROR:${hexMirror}`,
)
return
}
} catch (err) {
core.info(`${script} failed for mirror ${hexMirror}`)
}
await installElixir(elixirVersion, hexMirrorsT)
}
/**
+68 -28
View File
@@ -30,16 +30,23 @@ async function main() {
const elixirSpec = getInput('elixir-version', false, 'elixir', versions)
const gleamSpec = getInput('gleam-version', false, 'gleam', versions)
const rebar3Spec = getInput('rebar3-version', false, 'rebar', versions)
const hexMirrors = core.getMultilineInput('hexpm-mirrors', {
required: false,
})
if (otpSpec !== 'false') {
await installOTP(otpSpec, osVersion)
const elixirInstalled = await maybeInstallElixir(elixirSpec, otpSpec)
await installOTP(otpSpec, osVersion, hexMirrors)
const elixirInstalled = await maybeInstallElixir(
elixirSpec,
otpSpec,
hexMirrors,
)
if (elixirInstalled === true) {
const shouldMixRebar = getInput('install-rebar', false)
await mix(shouldMixRebar, 'rebar')
await mix(shouldMixRebar, 'rebar', hexMirrors)
const shouldMixHex = getInput('install-hex', false)
await mix(shouldMixHex, 'hex')
await mix(shouldMixHex, 'hex', hexMirrors)
}
} else if (!gleamSpec) {
throw new Error('otp-version=false is only available when installing Gleam')
@@ -49,12 +56,12 @@ async function main() {
await maybeInstallRebar3(rebar3Spec)
}
async function installOTP(otpSpec, osVersion) {
const otpVersion = await getOTPVersion(otpSpec, osVersion)
async function installOTP(otpSpec, osVersion, hexMirrors) {
const otpVersion = await getOTPVersion(otpSpec, osVersion, hexMirrors)
console.log(
`##[group]Installing Erlang/OTP ${otpVersion} - built on ${osVersion}`,
)
await installer.installOTP(osVersion, otpVersion)
await installer.installOTP(osVersion, otpVersion, hexMirrors)
core.setOutput('otp-version', otpVersion)
core.addPath(`${process.env.RUNNER_TEMP}/.setup-beam/otp/bin`)
console.log('##[endgroup]')
@@ -62,13 +69,17 @@ async function installOTP(otpSpec, osVersion) {
return otpVersion
}
async function maybeInstallElixir(elixirSpec, otpVersion) {
async function maybeInstallElixir(elixirSpec, otpSpec, hexMirrors) {
let installed = false
if (elixirSpec) {
const elixirVersion = await getElixirVersion(elixirSpec, otpVersion)
const elixirVersion = await getElixirVersion(
elixirSpec,
otpSpec,
hexMirrors,
)
console.log(`##[group]Installing Elixir ${elixirVersion}`)
await installer.installElixir(elixirVersion)
await installer.installElixir(elixirVersion, hexMirrors)
core.setOutput('elixir-version', elixirVersion)
const disableProblemMatchers = getInput('disable_problem_matchers', false)
if (disableProblemMatchers === 'false') {
@@ -87,12 +98,28 @@ async function maybeInstallElixir(elixirSpec, otpVersion) {
return installed
}
async function mix(shouldMix, what) {
async function mixWithMirrors(cmd, args, hexMirrors) {
if (hexMirrors.length === 0) {
throw new Error('mix failed with every mirror')
}
const [hexMirror, ...hexMirrorsT] = hexMirrors
process.env.HEX_MIRROR = hexMirror
try {
return await exec(cmd, args)
} catch (err) {
core.info(
`mix failed with mirror ${process.env.HEX_MIRROR} with message ${err.message})`,
)
}
return mixWithMirrors(cmd, args, hexMirrorsT)
}
async function mix(shouldMix, what, hexMirrors) {
if (shouldMix === 'true') {
const cmd = 'mix'
const args = [`local.${what}`, '--force']
console.log(`##[group]Running ${cmd} ${args}`)
await exec(cmd, args)
await mixWithMirrors(cmd, args, hexMirrors)
console.log('##[endgroup]')
}
}
@@ -136,8 +163,8 @@ async function maybeInstallRebar3(rebar3Spec) {
return installed
}
async function getOTPVersion(otpSpec0, osVersion) {
const otpVersions = await getOTPVersions(osVersion)
async function getOTPVersion(otpSpec0, osVersion, hexMirrors) {
const otpVersions = await getOTPVersions(osVersion, hexMirrors)
let otpSpec = otpSpec0 // might be a branch (?)
const otpVersion = getVersionFromSpec(
otpSpec,
@@ -156,10 +183,10 @@ async function getOTPVersion(otpSpec0, osVersion) {
return otpVersions.get(otpVersion) // from the reference, for download
}
async function getElixirVersion(exSpec0, otpVersion0) {
async function getElixirVersion(exSpec0, otpVersion0, hexMirrors) {
const otpVersion = otpVersion0.match(/^([^-]+-)?(.+)$/)[2]
const otpVersionMajor = otpVersion.match(/^([^.]+).*$/)[1]
const elixirVersions = await getElixirVersions()
const elixirVersions = await getElixirVersions(hexMirrors)
const semverVersions = Array.from(elixirVersions.keys()).sort()
const exSpec = exSpec0.replace(/-otp-.*$/, '')
const elixirVersionFromSpec = getVersionFromSpec(exSpec, semverVersions, true)
@@ -219,19 +246,19 @@ async function getRebar3Version(r3Spec) {
return rebar3Version
}
async function getOTPVersions(osVersion) {
let originListing
let pageIdxs
async function getOTPVersions(osVersion, hexMirrors) {
let otpVersionsListings
if (process.platform === 'linux') {
originListing = `https://builds.hex.pm/builds/otp/${osVersion}/builds.txt`
pageIdxs = [null]
otpVersionsListings = await getWithMirrors(
`/builds/otp/${osVersion}/builds.txt`,
hexMirrors,
)
} else if (process.platform === 'win32') {
originListing =
const originListing =
'https://api.github.com/repos/erlang/otp/releases?per_page=100'
pageIdxs = [1, 2, 3]
otpVersionsListings = await get(originListing, [1, 2, 3])
}
const otpVersionsListings = await get(originListing, pageIdxs)
const otpVersions = new Map()
if (process.platform === 'linux') {
@@ -261,10 +288,10 @@ async function getOTPVersions(osVersion) {
return otpVersions
}
async function getElixirVersions() {
const elixirVersionsListings = await get(
'https://builds.hex.pm/builds/elixir/builds.txt',
[null],
async function getElixirVersions(hexMirrors) {
const elixirVersionsListings = await getWithMirrors(
'/builds/elixir/builds.txt',
hexMirrors,
)
const otpVersionsForElixirMap = new Map()
@@ -448,6 +475,19 @@ async function get(url0, pageIdxs) {
return Promise.all(pageIdxs.map(getPage))
}
async function getWithMirrors(resourcePath, hexMirrors) {
if (hexMirrors.length === 0) {
throw new Error(`Could not fetch ${resourcePath} from any hex.pm mirror`)
}
const [hexMirror, ...hexMirrorsT] = hexMirrors
try {
return await get(`${hexMirror}${resourcePath}`, [null])
} catch (err) {
core.info(`get failed for URL ${hexMirror}${resourcePath}`)
}
return getWithMirrors(resourcePath, hexMirrorsT)
}
function maybePrependWithV(v) {
if (isVersion(v)) {
return `v${v.replace('v', '')}`