diff --git a/common.js b/common.js index 9153130c1..42b8b479d 100644 --- a/common.js +++ b/common.js @@ -4,6 +4,7 @@ const fs = require('fs') const util = require('util') const stream = require('stream') const crypto = require('crypto') +const child_process = require('child_process') const core = require('@actions/core') const { performance } = require('perf_hooks') @@ -149,6 +150,13 @@ export function win2nix(path) { return path.replace(/\\/g, '/').replace(/ /g, '\\ ') } +// JRuby is installed after setupPath is called, so folder doesn't exist +export function rubyIsUCRT(path) { + return !!(fs.existsSync(path) && + fs.readdirSync(path, { withFileTypes: true }).find(dirent => + dirent.isFile() && dirent.name.match(/^x64-ucrt-ruby\d{3}\.dll$/))) +} + export function setupPath(newPathEntries) { const envPath = windows ? 'Path' : 'PATH' const originalPath = process.env[envPath].split(path.delimiter) @@ -168,13 +176,27 @@ export function setupPath(newPathEntries) { } // Then add new path entries using core.addPath() - let newPath + let newPath = newPathEntries if (windows) { - // add MSYS2 in path for all Rubies on Windows, as it provides a better bash shell and a native toolchain - const msys2 = ['C:\\msys64\\mingw64\\bin', 'C:\\msys64\\usr\\bin'] - newPath = [...newPathEntries, ...msys2] - } else { - newPath = newPathEntries + try { + // Use RubyInstaller mechanisms to set various evenironment variables including the PATH to MSYS2 tools + // Same as "ridk enable" on the command line + const envbuf = child_process.execFileSync(`${newPathEntries[0]}\\ruby`, ['-rruby_installer/runtime', '-e', 'puts RubyInstaller::Runtime.msys2_installation.enable_msys_apps_per_cmd']) + const envvars = envbuf.toString().trim().split(/\r?\n/) + + envvars.forEach( (envvar) => { + console.log(`SET ${envvar}`) + const parts = envvar.split("=", 2) + core.exportVariable(parts[0], parts[1]) + }) + } catch (ex) { + // main Ruby dll determines whether mingw or ucrt build + let build_sys = rubyIsUCRT(newPathEntries[0]) ? 'ucrt64' : 'mingw64' + + // add MSYS2 in path for all Rubies on Windows, as it provides a better bash shell and a native toolchain + const msys2 = [`C:\\msys64\\${build_sys}\\bin`, 'C:\\msys64\\usr\\bin'] + newPath = [...newPathEntries, ...msys2] + } } console.log(`Entries added to ${envPath} to use selected Ruby:`) for (const entry of newPath) { diff --git a/dist/index.js b/dist/index.js index 9cc41f932..c40206c18 100644 --- a/dist/index.js +++ b/dist/index.js @@ -237,6 +237,7 @@ __nccwpck_require__.r(__webpack_exports__); /* harmony export */ "getToolCacheRubyPrefix": () => (/* binding */ getToolCacheRubyPrefix), /* harmony export */ "createToolCacheCompleteFile": () => (/* binding */ createToolCacheCompleteFile), /* harmony export */ "win2nix": () => (/* binding */ win2nix), +/* harmony export */ "rubyIsUCRT": () => (/* binding */ rubyIsUCRT), /* harmony export */ "setupPath": () => (/* binding */ setupPath) /* harmony export */ }); const os = __nccwpck_require__(2087) @@ -245,6 +246,7 @@ const fs = __nccwpck_require__(5747) const util = __nccwpck_require__(1669) const stream = __nccwpck_require__(2413) const crypto = __nccwpck_require__(6417) +const child_process = __nccwpck_require__(3129) const core = __nccwpck_require__(2186) const { performance } = __nccwpck_require__(630) @@ -390,6 +392,13 @@ function win2nix(path) { return path.replace(/\\/g, '/').replace(/ /g, '\\ ') } +// JRuby is installed after setupPath is called, so folder doesn't exist +function rubyIsUCRT(path) { + return !!(fs.existsSync(path) && + fs.readdirSync(path, { withFileTypes: true }).find(dirent => + dirent.isFile() && dirent.name.match(/^x64-ucrt-ruby\d{3}\.dll$/))) +} + function setupPath(newPathEntries) { const envPath = windows ? 'Path' : 'PATH' const originalPath = process.env[envPath].split(path.delimiter) @@ -409,13 +418,27 @@ function setupPath(newPathEntries) { } // Then add new path entries using core.addPath() - let newPath + let newPath = newPathEntries if (windows) { - // add MSYS2 in path for all Rubies on Windows, as it provides a better bash shell and a native toolchain - const msys2 = ['C:\\msys64\\mingw64\\bin', 'C:\\msys64\\usr\\bin'] - newPath = [...newPathEntries, ...msys2] - } else { - newPath = newPathEntries + try { + // Use RubyInstaller mechanisms to set various evenironment variables including the PATH to MSYS2 tools + // Same as "ridk enable" on the command line + const envbuf = child_process.execFileSync(`${newPathEntries[0]}\\ruby`, ['-rruby_installer/runtime', '-e', 'puts RubyInstaller::Runtime.msys2_installation.enable_msys_apps_per_cmd']) + const envvars = envbuf.toString().trim().split(/\r?\n/) + + envvars.forEach( (envvar) => { + console.log(`SET ${envvar}`) + const parts = envvar.split("=", 2) + core.exportVariable(parts[0], parts[1]) + }) + } catch (ex) { + // main Ruby dll determines whether mingw or ucrt build + let build_sys = rubyIsUCRT(newPathEntries[0]) ? 'ucrt64' : 'mingw64' + + // add MSYS2 in path for all Rubies on Windows, as it provides a better bash shell and a native toolchain + const msys2 = [`C:\\msys64\\${build_sys}\\bin`, 'C:\\msys64\\usr\\bin'] + newPath = [...newPathEntries, ...msys2] + } } console.log(`Entries added to ${envPath} to use selected Ruby:`) for (const entry of newPath) { @@ -59003,12 +59026,16 @@ async function install(platform, engine, version) { let toolchainPaths = (version === 'mswin') ? await setupMSWin() : await setupMingw(version) - common.setupPath([`${rubyPrefix}\\bin`, ...toolchainPaths]) - if (!inToolCache) { await downloadAndExtract(engine, version, url, base, rubyPrefix); } + common.setupPath([`${rubyPrefix}\\bin`, ...toolchainPaths]) + + if (common.rubyIsUCRT(`${rubyPrefix}\\bin`)) { + await installUCRT() + } + return rubyPrefix } @@ -59032,6 +59059,12 @@ async function downloadAndExtract(engine, version, url, base, rubyPrefix) { } } +async function installUCRT() { + await common.measure('Installing MSYS2 UCRT build tools', async () => { + cp.execSync(`pacman -S --noconfirm --noprogressbar --needed %MINGW_PACKAGE_PREFIX%-gcc`) + }) +} + async function setupMingw(version) { core.exportVariable('MAKE', 'make.exe') diff --git a/windows.js b/windows.js index e88411fd5..76ba760f0 100644 --- a/windows.js +++ b/windows.js @@ -50,12 +50,16 @@ export async function install(platform, engine, version) { let toolchainPaths = (version === 'mswin') ? await setupMSWin() : await setupMingw(version) - common.setupPath([`${rubyPrefix}\\bin`, ...toolchainPaths]) - if (!inToolCache) { await downloadAndExtract(engine, version, url, base, rubyPrefix); } + common.setupPath([`${rubyPrefix}\\bin`, ...toolchainPaths]) + + if (common.rubyIsUCRT(`${rubyPrefix}\\bin`)) { + await installUCRT() + } + return rubyPrefix } @@ -79,6 +83,12 @@ async function downloadAndExtract(engine, version, url, base, rubyPrefix) { } } +async function installUCRT() { + await common.measure('Installing MSYS2 UCRT build tools', async () => { + cp.execSync(`pacman -S --noconfirm --noprogressbar --needed %MINGW_PACKAGE_PREFIX%-gcc`) + }) +} + async function setupMingw(version) { core.exportVariable('MAKE', 'make.exe')