@@ -4,6 +4,7 @@ const io = require('@actions/io');
44const exec = require ( '@actions/exec' ) ;
55const path = require ( 'path' ) ;
66const github = require ( '@actions/github' ) ;
7+ const os = require ( 'os' ) ;
78
89// Main entry function
910//
@@ -39,32 +40,36 @@ async function main(){
3940
4041 }
4142
43+ // Detect architecture
44+ const arch = os . arch ( ) ;
45+ console . log ( `System architecture: ${ arch } ` ) ;
46+ console . log ( `This platform is ${ process . platform } ` ) ;
47+
4248 // Build download path
4349 const fetchPath = fpmRepo + '/releases/download/' + fpmVersion + '/' ;
44- const filename = getFPMFilename ( fpmVersion , process . platform ) ;
50+ const filename = getFPMFilename ( fpmVersion , process . platform , arch ) ;
4551
46- console . log ( `This platform is ${ process . platform } ` ) ;
4752 console . log ( `Fetching fpm from ${ fetchPath } ${ filename } ` ) ;
4853
4954 // Download release
5055 var fpmPath ;
5156 try {
52-
53- // Try downloading the file without the compiler suffix
54- const filename = getFPMFilename ( fpmVersion , process . platform ) ;
57+
58+ // Try downloading the file without the compiler suffix
59+ const filename = getFPMFilename ( fpmVersion , process . platform , arch ) ;
5560 fpmPath = await tc . downloadTool ( fetchPath + filename ) ;
5661
5762 } catch ( error ) {
58-
63+
5964 // If download fails, try adding compiler suffixes
6065 const compilers = [ 'gcc-10' , 'gcc-11' , 'gcc-12' , 'gcc-13' , 'gcc-14' ] ;
61-
66+
6267 let success = false ;
63-
68+
6469 for ( const compiler of compilers ) {
65-
70+
6671 // Generate the filename with the compiler suffix
67- const filenameWithSuffix = getFPMFilename ( fpmVersion , process . platform , compiler ) ;
72+ const filenameWithSuffix = getFPMFilename ( fpmVersion , process . platform , arch , compiler ) ;
6873 console . log ( `Trying to fetch compiler-built fpm: ${ filenameWithSuffix } ` ) ;
6974
7075 try {
@@ -74,10 +79,32 @@ async function main(){
7479 } catch ( error ) {
7580 console . log ( ` -> Failed to download ${ filenameWithSuffix } ` ) ;
7681 }
77-
82+
7883 }
7984
8085 if ( ! success ) {
86+ // On macOS ARM64, fall back to building from source
87+ if ( process . platform === 'darwin' && arch === 'arm64' ) {
88+ console . log ( 'No pre-built ARM64 binary found, falling back to building from source' ) ;
89+
90+ // For older versions without working install.sh, we can't build from source
91+ const versionNum = fpmVersion . replace ( 'v' , '' ) ;
92+ const versionParts = versionNum . split ( '.' ) . map ( Number ) ;
93+ const isOldVersion = versionParts [ 0 ] === 0 && versionParts [ 1 ] < 9 ;
94+
95+ if ( isOldVersion ) {
96+ core . setFailed (
97+ `Building fpm ${ fpmVersion } from source is not supported on macOS ARM64.\n` +
98+ 'Please use fpm v0.9.0 or later, which has a working install.sh script.\n' +
99+ 'For example, set fpm-version to "v0.9.0", "v0.10.1" or "latest".'
100+ ) ;
101+ return ;
102+ }
103+
104+ await installFromSource ( fpmVersion , fpmRepo ) ;
105+ return ;
106+ }
107+
81108 core . setFailed ( `Error while trying to fetch fpm - please check that a version exists at the above release url.` ) ;
82109 }
83110 }
@@ -120,31 +147,39 @@ async function main(){
120147//
121148// <version> is a string of form X.Y.Z corresponding to a release of fpm
122149// <os> is either 'linux', 'macos', or 'windows'
123- // <arch> here is always 'x86_64'
150+ // <arch> is 'x86_64' or 'arm64 '
124151// <compiler> is an optional string like '-gcc-12'
125152//
126- function getFPMFilename ( fpmVersion , platform , compiler = '' ) {
153+ function getFPMFilename ( fpmVersion , platform , arch , compiler = '' ) {
127154 var filename = 'fpm-' ;
128-
155+
129156 // Remove the leading 'v' if it exists
130157 filename += fpmVersion . replace ( 'v' , '' ) + '-' ;
131158
159+ // Map Node.js arch to FPM arch naming
160+ let fpmArch = 'x86_64' ;
161+ if ( arch === 'arm64' ) {
162+ fpmArch = 'arm64' ;
163+ } else if ( arch === 'x64' ) {
164+ fpmArch = 'x86_64' ;
165+ }
166+
132167 // Add the platform and architecture
133168 if ( platform === 'linux' ) {
134- filename += ' linux-x86_64' ;
169+ filename += ` linux-${ fpmArch } ` ;
135170 } else if ( platform === 'darwin' ) {
136- filename += ' macos-x86_64' ;
171+ filename += ` macos-${ fpmArch } ` ;
137172 } else if ( platform === 'win32' ) {
138- filename += ' windows-x86_64' ;
173+ filename += ` windows-${ fpmArch } ` ;
139174 } else {
140175 core . setFailed ( 'Unknown platform' ) ;
141176 }
142177
143- // If a compiler is provided, append it as a suffix
144- if ( compiler ) filename += `-${ compiler } ` ;
145-
146- // Add the '.exe' suffix for Windows
147- if ( platform === 'win32' ) filename += '.exe' ;
178+ // If a compiler is provided, append it as a suffix
179+ if ( compiler ) filename += `-${ compiler } ` ;
180+
181+ // Add the '.exe' suffix for Windows
182+ if ( platform === 'win32' ) filename += '.exe' ;
148183
149184 return filename ;
150185}
@@ -165,5 +200,102 @@ async function getLatestReleaseVersion(token){
165200}
166201
167202
203+ // Install fpm from source using the install.sh script
204+ // This is used on macOS ARM64 where pre-built binaries are not available
205+ //
206+ async function installFromSource ( fpmVersion , fpmRepo ) {
207+
208+ try {
209+
210+ // Find gfortran - it may be versioned (e.g., gfortran-13)
211+ // Use gcc <= 13 for compatibility with older fpm versions
212+ let gfortranCmd = 'gfortran' ;
213+ let foundGfortran = false ;
214+
215+ try {
216+ await exec . exec ( 'which' , [ 'gfortran' ] , { silent : true } ) ;
217+ foundGfortran = true ;
218+ } catch ( error ) {
219+ // gfortran not found, try versioned
220+ }
221+
222+ // If we found unversioned gfortran, check if it's gcc >= 14
223+ // If so, or if we didn't find unversioned gfortran, look for a versioned one <= 13
224+ // Always prefer versioned <= 13 for compatibility
225+ let foundVersioned = false ;
226+ for ( const ver of [ 13 , 12 , 11 , 10 ] ) {
227+ try {
228+ await exec . exec ( 'which' , [ `gfortran-${ ver } ` ] , { silent : true } ) ;
229+ gfortranCmd = `gfortran-${ ver } ` ;
230+ foundVersioned = true ;
231+ console . log ( `Found ${ gfortranCmd } ` ) ;
232+ break ;
233+ } catch ( e ) {
234+ // Continue searching
235+ }
236+ }
237+
238+ if ( ! foundVersioned && ! foundGfortran ) {
239+ core . setFailed (
240+ 'gfortran is required to build fpm from source on macOS ARM64.\n' +
241+ 'Please install gcc version 10-13 before running this action, for example:\n' +
242+ ' - name: Install gfortran\n' +
243+ ' run: brew install gcc@13\n' +
244+ 'Or use fortran-lang/setup-fortran to install a Fortran compiler.'
245+ ) ;
246+ return ;
247+ }
248+
249+ const versionNumber = fpmVersion . replace ( 'v' , '' ) ;
250+
251+ // Download the full source tarball for the requested version
252+ const tarballUrl = `${ fpmRepo } /archive/refs/tags/${ fpmVersion } .tar.gz` ;
253+ console . log ( `Downloading fpm source from: ${ tarballUrl } ` ) ;
254+ const tarballPath = await tc . downloadTool ( tarballUrl ) ;
255+
256+ // Create a temporary directory for building
257+ const buildDir = path . join ( process . env . RUNNER_TEMP || '/tmp' , 'fpm-build' ) ;
258+ await io . mkdirP ( buildDir ) ;
259+
260+ // Extract the tarball
261+ const extractDir = await tc . extractTar ( tarballPath , buildDir ) ;
262+ console . log ( `Extracted to: ${ extractDir } ` ) ;
263+
264+ // The extracted directory will be named fpm-<version> (without the 'v')
265+ const fpmSourceDir = path . join ( buildDir , `fpm-${ versionNumber } ` ) ;
266+
267+ console . log ( 'Installing fpm from source using install.sh...' ) ;
268+
269+ // Create installation directory
270+ const installPrefix = path . join ( process . env . HOME || process . env . USERPROFILE || '/tmp' , '.local' ) ;
271+ const installDir = path . join ( installPrefix , 'bin' ) ;
272+ await io . mkdirP ( installDir ) ;
273+
274+ // Run the install.sh script with FC environment variable
275+ const installScript = path . join ( fpmSourceDir , 'install.sh' ) ;
276+ await exec . exec ( 'bash' , [ installScript , `--prefix=${ installPrefix } ` ] , {
277+ cwd : fpmSourceDir ,
278+ env : {
279+ ...process . env ,
280+ FC : gfortranCmd
281+ }
282+ } ) ;
283+
284+ // Add to path
285+ core . addPath ( installDir ) ;
286+ console . log ( `fpm installed and added to path at ${ installDir } ` ) ;
287+
288+ // Clean up build directory
289+ await io . rmRF ( buildDir ) ;
290+
291+ } catch ( error ) {
292+
293+ core . setFailed ( `Failed to install fpm from source: ${ error . message } ` ) ;
294+
295+ }
296+
297+ }
298+
299+
168300// Call entry function
169301main ( ) ;
0 commit comments