From e52562bcc606f5cb5d9232b5933b18ba322e2406 Mon Sep 17 00:00:00 2001 From: MSP-Greg Date: Fri, 18 Jun 2021 11:11:24 -0500 Subject: [PATCH 1/2] Add Windows MSYS2 ucrt support --- common.js | 12 +++++++++++- dist/index.js | 16 +++++++++++++--- windows.js | 4 ++-- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/common.js b/common.js index 9153130c1..c7385cf4e 100644 --- a/common.js +++ b/common.js @@ -149,6 +149,13 @@ export 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$/))) +} + export function setupPath(newPathEntries) { const envPath = windows ? 'Path' : 'PATH' const originalPath = process.env[envPath].split(path.delimiter) @@ -170,8 +177,11 @@ export function setupPath(newPathEntries) { // Then add new path entries using core.addPath() let newPath if (windows) { + // 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\\mingw64\\bin', 'C:\\msys64\\usr\\bin'] + const msys2 = [`C:\\msys64\\${build_sys}\\bin`, 'C:\\msys64\\usr\\bin'] newPath = [...newPathEntries, ...msys2] } else { newPath = newPathEntries diff --git a/dist/index.js b/dist/index.js index 9cc41f932..4f22874fc 100644 --- a/dist/index.js +++ b/dist/index.js @@ -390,6 +390,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) @@ -411,8 +418,11 @@ function setupPath(newPathEntries) { // Then add new path entries using core.addPath() let newPath if (windows) { + // 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\\mingw64\\bin', 'C:\\msys64\\usr\\bin'] + const msys2 = [`C:\\msys64\\${build_sys}\\bin`, 'C:\\msys64\\usr\\bin'] newPath = [...newPathEntries, ...msys2] } else { newPath = newPathEntries @@ -59003,12 +59013,12 @@ 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]) + return rubyPrefix } diff --git a/windows.js b/windows.js index e88411fd5..d9e978849 100644 --- a/windows.js +++ b/windows.js @@ -50,12 +50,12 @@ 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]) + return rubyPrefix } From ec363ecfebe24cb1abd6be0c599265e7c759a136 Mon Sep 17 00:00:00 2001 From: Lars Kanis Date: Fri, 2 Jul 2021 13:10:55 +0200 Subject: [PATCH 2/2] Windows: Use "ridk enable" equivalent setup and install Devkit version of ruby-head The Devkit version bundles all important MSYS2 tools for the UCRT environment. --- common.js | 30 +++++++++++++++------- dist/index.js | 48 +++++++++++++++++++++++++----------- generate-windows-versions.rb | 2 +- windows-versions.js | 2 +- windows.js | 18 +++++++++----- 5 files changed, 68 insertions(+), 32 deletions(-) diff --git a/common.js b/common.js index c7385cf4e..4e47b29eb 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') @@ -175,16 +176,27 @@ export function setupPath(newPathEntries) { } // Then add new path entries using core.addPath() - let newPath + let newPath = newPathEntries if (windows) { - // 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] - } 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 4f22874fc..9819cad33 100644 --- a/dist/index.js +++ b/dist/index.js @@ -245,6 +245,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) @@ -416,16 +417,27 @@ function setupPath(newPathEntries) { } // Then add new path entries using core.addPath() - let newPath + let newPath = newPathEntries if (windows) { - // main Ruby dll determines whether mingw or ucrt build - let build_sys = rubyIsUCRT(newPathEntries[0]) ? 'ucrt64' : 'mingw64' + 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] - } else { - newPath = newPathEntries + // 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) { @@ -58943,7 +58955,7 @@ const versions = { "2.7.3": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.7.3-1/rubyinstaller-2.7.3-1-x64.7z", "3.0.0": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.0.0-1/rubyinstaller-3.0.0-1-x64.7z", "3.0.1": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.0.1-1/rubyinstaller-3.0.1-1-x64.7z", - "head": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-x64.7z", + "head": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-devkit-head-x64.exe", "mingw": "https://github.com/MSP-Greg/ruby-loco/releases/download/ruby-master/ruby-mingw.7z", "mswin": "https://github.com/MSP-Greg/ruby-loco/releases/download/ruby-master/ruby-mswin.7z" } @@ -58994,10 +59006,10 @@ function getAvailableVersions(platform, engine) { async function install(platform, engine, version) { const url = rubyInstallerVersions[version] - if (!url.endsWith('.7z')) { - throw new Error(`URL should end in .7z: ${url}`) + if (!url.endsWith('.7z') && !url.endsWith('.exe')) { + throw new Error(`URL should end in .7z or .exe: ${url}`) } - const base = url.slice(url.lastIndexOf('/') + 1, url.length - '.7z'.length) + const base = url.slice(url.lastIndexOf('/') + 1, url.length).replace(/\.(exe|7z)$/, "") let rubyPrefix, inToolCache if (common.shouldUseToolCache(engine, version)) { @@ -59027,11 +59039,17 @@ async function downloadAndExtract(engine, version, url, base, rubyPrefix) { const downloadPath = await common.measure('Downloading Ruby', async () => { console.log(url) - return await tc.downloadTool(url) + const fname = url.slice(url.lastIndexOf('/') + 1, url.length) + return await tc.downloadTool(url, fname) }) - await common.measure('Extracting Ruby', async () => - exec.exec('7z', ['x', downloadPath, `-xr!${base}\\share\\doc`, `-o${parentDir}`], { silent: true })) + await common.measure('Extracting Ruby', async () => { + if (url.endsWith('.7z')) { + await exec.exec('7z', ['x', downloadPath, `-xr!${base}\\share\\doc`, `-o${parentDir}`], { silent: true }) + } else if (url.endsWith('.exe')) { + await exec.exec('cmd', ['/c', `${downloadPath} /verysilent /dir=${parentDir}\\${base} /tasks=noassocfiles,nomodpath,noridkinstall /components=ruby,msys2`]) + } + }) if (base !== path.basename(rubyPrefix)) { await io.mv(path.join(parentDir, base), rubyPrefix) diff --git a/generate-windows-versions.rb b/generate-windows-versions.rb index d0b9cd245..ec535f631 100644 --- a/generate-windows-versions.rb +++ b/generate-windows-versions.rb @@ -25,7 +25,7 @@ [version, entry[:href]] }.to_h -versions['head'] = 'https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-x64.7z' +versions['head'] = 'https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-devkit-head-x64.exe' versions['mingw'] = 'https://github.com/MSP-Greg/ruby-loco/releases/download/ruby-master/ruby-mingw.7z' versions['mswin'] = 'https://github.com/MSP-Greg/ruby-loco/releases/download/ruby-master/ruby-mswin.7z' diff --git a/windows-versions.js b/windows-versions.js index c7c8c893d..6911ae21f 100644 --- a/windows-versions.js +++ b/windows-versions.js @@ -36,7 +36,7 @@ export const versions = { "2.7.3": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.7.3-1/rubyinstaller-2.7.3-1-x64.7z", "3.0.0": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.0.0-1/rubyinstaller-3.0.0-1-x64.7z", "3.0.1": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.0.1-1/rubyinstaller-3.0.1-1-x64.7z", - "head": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-x64.7z", + "head": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-devkit-head-x64.exe", "mingw": "https://github.com/MSP-Greg/ruby-loco/releases/download/ruby-master/ruby-mingw.7z", "mswin": "https://github.com/MSP-Greg/ruby-loco/releases/download/ruby-master/ruby-mswin.7z" } diff --git a/windows.js b/windows.js index d9e978849..bca2af88f 100644 --- a/windows.js +++ b/windows.js @@ -31,10 +31,10 @@ export function getAvailableVersions(platform, engine) { export async function install(platform, engine, version) { const url = rubyInstallerVersions[version] - if (!url.endsWith('.7z')) { - throw new Error(`URL should end in .7z: ${url}`) + if (!url.endsWith('.7z') && !url.endsWith('.exe')) { + throw new Error(`URL should end in .7z or .exe: ${url}`) } - const base = url.slice(url.lastIndexOf('/') + 1, url.length - '.7z'.length) + const base = url.slice(url.lastIndexOf('/') + 1, url.length).replace(/\.(exe|7z)$/, "") let rubyPrefix, inToolCache if (common.shouldUseToolCache(engine, version)) { @@ -64,11 +64,17 @@ async function downloadAndExtract(engine, version, url, base, rubyPrefix) { const downloadPath = await common.measure('Downloading Ruby', async () => { console.log(url) - return await tc.downloadTool(url) + const fname = url.slice(url.lastIndexOf('/') + 1, url.length) + return await tc.downloadTool(url, fname) }) - await common.measure('Extracting Ruby', async () => - exec.exec('7z', ['x', downloadPath, `-xr!${base}\\share\\doc`, `-o${parentDir}`], { silent: true })) + await common.measure('Extracting Ruby', async () => { + if (url.endsWith('.7z')) { + await exec.exec('7z', ['x', downloadPath, `-xr!${base}\\share\\doc`, `-o${parentDir}`], { silent: true }) + } else if (url.endsWith('.exe')) { + await exec.exec('cmd', ['/c', `${downloadPath} /verysilent /dir=${parentDir}\\${base} /tasks=noassocfiles,nomodpath,noridkinstall /components=ruby,msys2`]) + } + }) if (base !== path.basename(rubyPrefix)) { await io.mv(path.join(parentDir, base), rubyPrefix)