|
1 |
| -import { |
2 |
| - startGroup, |
3 |
| - endGroup, |
4 |
| - addPath, |
5 |
| - exportVariable, |
6 |
| - info, |
7 |
| -} from '@actions/core'; |
| 1 | +import { startGroup, endGroup, addPath, info } from '@actions/core'; |
8 | 2 | import { exec as _exec } from '@actions/exec';
|
9 | 3 | import { sep, join } from 'path';
|
10 |
| -import { appendFileSync } from 'fs'; |
| 4 | +import { existsSync, appendFileSync } from 'fs'; |
11 | 5 | import { EOL } from 'os';
|
| 6 | +import { env, platform } from 'process'; |
12 | 7 |
|
| 8 | +// Export a key=value pair to GITHUB_ENV and process.env |
| 9 | +function exportEnv(key, value) { |
| 10 | + const envFile = process.env.GITHUB_ENV; |
| 11 | + if (!envFile) throw new Error('GITHUB_ENV not defined'); |
| 12 | + appendFileSync(envFile, `${key}=${value}${EOL}`); |
| 13 | + env[key] = value; |
| 14 | +} |
| 15 | + |
| 16 | +// Resolve the absolute path of a named conda environment |
13 | 17 | async function getCondaPrefix(envName) {
|
14 | 18 | let raw = '';
|
15 | 19 | await _exec('conda', ['env', 'list', '--json'], {
|
16 | 20 | silent: true,
|
17 |
| - listeners: { stdout: d => (raw += d.toString()) }, |
| 21 | + listeners: { stdout: (d) => (raw += d.toString()) } |
18 | 22 | });
|
| 23 | + |
19 | 24 | const { envs } = JSON.parse(raw);
|
20 | 25 | for (const p of envs) {
|
21 | 26 | if (p.endsWith(sep + envName) || p.endsWith('/' + envName)) return p;
|
22 | 27 | }
|
| 28 | + |
23 | 29 | throw new Error(`Unable to locate Conda environment "${envName}".`);
|
24 | 30 | }
|
25 | 31 |
|
26 |
| -async function setUlimits() { |
27 |
| - if (process.platform !== 'linux') return; |
28 |
| - |
29 |
| - startGroup('Set unlimited ulimits (Linux, persistent)'); |
30 |
| - const ulimitCmd = 'ulimit -c unlimited -d unlimited -f unlimited -m unlimited -s unlimited -t unlimited -v unlimited -x unlimited'; |
31 |
| - |
32 |
| - // Inject into bash shell for all future steps |
33 |
| - appendFileSync(process.env.GITHUB_ENV, `BASH_ENV=${process.env.RUNNER_TEMP}/ulimit.sh${EOL}`); |
34 |
| - appendFileSync(`${process.env.RUNNER_TEMP}/ulimit.sh`, `${ulimitCmd}${EOL}`); |
35 |
| - |
| 32 | +// Optional: Set unlimited ulimits for Linux |
| 33 | +function setLinuxUlimits() { |
| 34 | + startGroup('Setting unlimited ulimits (Linux)'); |
| 35 | + const ulimitCmd = |
| 36 | + 'ulimit -c unlimited -d unlimited -f unlimited -m unlimited -s unlimited -t unlimited -v unlimited -x unlimited'; |
| 37 | + const script = `${process.env.RUNNER_TEMP}/ulimit.sh`; |
| 38 | + appendFileSync(script, `${ulimitCmd}${EOL}`); |
| 39 | + appendFileSync(process.env.GITHUB_ENV, `BASH_ENV=${script}${EOL}`); |
| 40 | + info('ulimit settings exported to BASH_ENV'); |
36 | 41 | endGroup();
|
37 | 42 | }
|
38 | 43 |
|
| 44 | +// Main setup function |
39 | 45 | export async function setup(version = '') {
|
40 |
| - const packageName = version ? `flang=${version}` : 'flang'; |
41 |
| - |
42 |
| - startGroup('Conda install'); |
43 |
| - await _exec('conda', [ |
44 |
| - 'install', |
45 |
| - '--yes', |
46 |
| - '--name', |
47 |
| - 'fortran', |
48 |
| - packageName, |
49 |
| - '-c', |
50 |
| - 'conda-forge', |
51 |
| - ]); |
| 46 | + if (platform !== 'linux') { |
| 47 | + throw new Error('This setup script is only supported on Linux.'); |
| 48 | + } |
| 49 | + |
| 50 | + // Define the set of Conda packages to install |
| 51 | + const Pkg = version ? `flang=${version}` : 'flang'; |
| 52 | + const packages = [Pkg, 'llvm', 'clang-tools', 'llvm-openmp', 'lld']; |
| 53 | + |
| 54 | + startGroup('Installing Conda packages'); |
| 55 | + try { |
| 56 | + await _exec('conda', [ |
| 57 | + 'install', |
| 58 | + '--yes', |
| 59 | + '--name', |
| 60 | + 'fortran', |
| 61 | + ...packages, |
| 62 | + '-c', |
| 63 | + 'conda-forge', |
| 64 | + '--update-all', |
| 65 | + '--all', |
| 66 | + '--force-reinstall' |
| 67 | + ]); |
| 68 | + info('Conda packages installed'); |
| 69 | + } catch (err) { |
| 70 | + throw new Error(`Conda install failed: ${err.message}`); |
| 71 | + } |
52 | 72 | endGroup();
|
53 | 73 |
|
| 74 | + // Add Conda bin paths to PATH so tools are usable |
54 | 75 | const prefix = await getCondaPrefix('fortran');
|
| 76 | + const binPath = join(prefix, 'bin'); |
| 77 | + const libPath = join(prefix, 'lib'); |
55 | 78 |
|
56 |
| - startGroup('Environment setup'); |
57 |
| - addPath(join(prefix, 'bin')); |
| 79 | + startGroup('Setting up environment paths'); |
| 80 | + const paths = [binPath]; |
| 81 | + for (const p of paths) { |
| 82 | + if (existsSync(p)) { |
| 83 | + addPath(p); |
| 84 | + info(`Added to PATH: ${p}`); |
| 85 | + } |
| 86 | + } |
| 87 | + endGroup(); |
| 88 | + |
| 89 | + // Set LD_LIBRARY_PATH |
| 90 | + const ldPath = [libPath, env.LD_LIBRARY_PATH || ''].filter(Boolean).join(':'); |
| 91 | + exportEnv('LD_LIBRARY_PATH', ldPath); |
| 92 | + info(`Set LD_LIBRARY_PATH → ${ldPath}`); |
| 93 | + |
| 94 | + // Verify that the compilers are installed and working |
| 95 | + startGroup('Verifying compiler versions'); |
| 96 | + await _exec('which', ['flang']); |
| 97 | + await _exec('flang', ['--version']); |
| 98 | + await _exec('which', ['clang']); |
| 99 | + await _exec('clang', ['--version']); |
| 100 | + await _exec('which', ['clang++']); |
| 101 | + await _exec('clang++', ['--version']); |
| 102 | + endGroup(); |
| 103 | + |
| 104 | + // Export compiler-related environment variables |
| 105 | + startGroup('Exporting compiler environment variables'); |
| 106 | + const envVars = { |
| 107 | + FC: 'flang', |
| 108 | + CC: 'clang', |
| 109 | + CXX: 'clang++', |
| 110 | + FPM_FC: 'flang', |
| 111 | + FPM_CC: 'clang', |
| 112 | + FPM_CXX: 'clang++', |
| 113 | + CMAKE_Fortran_COMPILER: 'flang', |
| 114 | + CMAKE_C_COMPILER: 'clang', |
| 115 | + CMAKE_CXX_COMPILER: 'clang++', |
| 116 | + LD_LIBRARY_PATH: ldPath |
| 117 | + }; |
58 | 118 |
|
59 |
| - const newLd = `${join(prefix, 'lib')}:${process.env.LD_LIBRARY_PATH || ''}`; |
60 |
| - exportVariable('LD_LIBRARY_PATH', newLd); |
61 |
| - info(`LD_LIBRARY_PATH → ${newLd}`); |
| 119 | + for (const [key, value] of Object.entries(envVars)) { |
| 120 | + exportEnv(key, value); |
| 121 | + info(`Exported: ${key}=${value}`); |
| 122 | + } |
| 123 | + endGroup(); |
| 124 | + |
| 125 | + setLinuxUlimits(); |
| 126 | + |
| 127 | + // Export all environment variables to process.env and GITHUB_ENV |
| 128 | + startGroup('Exporting all environment variables to process.env and GITHUB_ENV'); |
| 129 | + for (const [key, value] of Object.entries(env)) { |
| 130 | + if (typeof value === 'string') { |
| 131 | + try { |
| 132 | + process.env[key] = value; |
| 133 | + appendFileSync(process.env.GITHUB_ENV, `${key}=${value}${EOL}`); |
| 134 | + info(`Exported: ${key}`); |
| 135 | + } catch (err) { |
| 136 | + info(`⚠️ Failed to export: ${key} (${err.message})`); |
| 137 | + } |
| 138 | + } |
| 139 | + } |
62 | 140 | endGroup();
|
63 | 141 |
|
64 |
| - await setUlimits(); |
| 142 | + info('✅ compiler setup complete'); |
65 | 143 | }
|
0 commit comments