mirror of
https://github.com/julia-actions/setup-julia.git
synced 2026-02-14 12:06:54 +08:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3ce119a16 | ||
|
|
405bfcbfbd | ||
|
|
b8741b9a13 | ||
|
|
9956ebe960 | ||
|
|
71b841c6f2 | ||
|
|
45f46ba622 | ||
|
|
c5d801f77b | ||
|
|
82b1b42f54 | ||
|
|
3503abc570 | ||
|
|
def57cde21 | ||
|
|
c639390e13 |
1
.github/workflows/example-builds-nightly.yml
vendored
1
.github/workflows/example-builds-nightly.yml
vendored
@@ -33,4 +33,5 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
version: nightly
|
version: nightly
|
||||||
arch: ${{ matrix.julia-arch }}
|
arch: ${{ matrix.julia-arch }}
|
||||||
|
show-versioninfo: 'true'
|
||||||
- run: julia --version
|
- run: julia --version
|
||||||
|
|||||||
2
.github/workflows/example-builds.yml
vendored
2
.github/workflows/example-builds.yml
vendored
@@ -26,8 +26,10 @@ jobs:
|
|||||||
npm run pack
|
npm run pack
|
||||||
|
|
||||||
- name: "Set up Julia"
|
- name: "Set up Julia"
|
||||||
|
id: setup-julia
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
version: ${{ matrix.julia-version }}
|
version: ${{ matrix.julia-version }}
|
||||||
arch: ${{ matrix.julia-arch }}
|
arch: ${{ matrix.julia-arch }}
|
||||||
|
show-versioninfo: 'true'
|
||||||
- run: julia --version
|
- run: julia --version
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -49,9 +49,7 @@ You can either specify specific Julia versions or version ranges. If you specify
|
|||||||
|
|
||||||
Internally the action uses node's semver package to resolve version ranges. Its [documentation](https://github.com/npm/node-semver#advanced-range-syntax) contains more details on the version range syntax. You can test what version will be selected for a given input in this JavaScript [REPL](https://repl.it/@SaschaMann/setup-julia-version-logic).
|
Internally the action uses node's semver package to resolve version ranges. Its [documentation](https://github.com/npm/node-semver#advanced-range-syntax) contains more details on the version range syntax. You can test what version will be selected for a given input in this JavaScript [REPL](https://repl.it/@SaschaMann/setup-julia-version-logic).
|
||||||
|
|
||||||
#### WARNING: Version ranges are experimental and potentially out of date
|
The available Julia versions are pulled from [`versions.json`](https://julialang-s3.julialang.org/bin/versions.json). This file is automatically updated once a day. Therefore it may take up to 24 hours until a newly released Julia version is available in the action.
|
||||||
|
|
||||||
Currently the list of available versions is hardcoded. You have to use the latest version of the action to be able to install the latest Julia versions. Once available we will use a list of versions provided on julialang.org.
|
|
||||||
|
|
||||||
### Matrix Testing
|
### Matrix Testing
|
||||||
|
|
||||||
@@ -143,13 +141,17 @@ You can specify commits, branches or tags in your workflows as follows:
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: julia-actions/setup-julia@6ae948d # commit SHA
|
- uses: julia-actions/setup-julia@d26d1111976eae5f00db04f0515ab744ec9cd79e # commit SHA of the tagged 1.3.1 commit
|
||||||
- uses: julia-actions/setup-julia@master # branch
|
- uses: julia-actions/setup-julia@master # branch
|
||||||
- uses: julia-actions/setup-julia@latest # latest version tag (may break existing workflows)
|
- uses: julia-actions/setup-julia@latest # latest version tag (may break existing workflows)
|
||||||
- uses: julia-actions/setup-julia@v1 # major version tag
|
- uses: julia-actions/setup-julia@v1 # major version tag
|
||||||
- uses: julia-actions/setup-julia@v0.1.0 # specific version tag
|
- uses: julia-actions/setup-julia@v0.1.0 # specific version tag
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If your workflow requires access to secrets, you should always pin it to a commit SHA instead of a tag.
|
||||||
|
This will protect you in case a bad actor gains access to the setup-julia repo.
|
||||||
|
You can find more information in [GitHub's security hardening guide](https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions).
|
||||||
|
|
||||||
## Debug logs
|
## Debug logs
|
||||||
|
|
||||||
You can enable [Step Debug Logs](https://github.com/actions/toolkit/blob/main/docs/action-debugging.md#step-debug-logs) for more detailed logs.
|
You can enable [Step Debug Logs](https://github.com/actions/toolkit/blob/main/docs/action-debugging.md#step-debug-logs) for more detailed logs.
|
||||||
|
|||||||
4827
__tests__/fixtures/versions.json
Normal file
4827
__tests__/fixtures/versions.json
Normal file
File diff suppressed because it is too large
Load Diff
113
__tests__/installer.test.ts
Normal file
113
__tests__/installer.test.ts
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
// The testing setup has been derived from the actions/setup-go@bc6edb5 action.
|
||||||
|
// Check README.md for licence information.
|
||||||
|
|
||||||
|
import * as path from 'path'
|
||||||
|
|
||||||
|
import * as io from '@actions/io'
|
||||||
|
|
||||||
|
import nock = require('nock')
|
||||||
|
import * as semver from 'semver'
|
||||||
|
|
||||||
|
const testVersions = [
|
||||||
|
'0.1.2', '0.2.0', '0.2.1', '0.3.0',
|
||||||
|
'0.3.1', '0.3.10', '0.3.11', '0.3.12',
|
||||||
|
'0.3.2', '0.3.3', '0.3.4', '0.3.5',
|
||||||
|
'0.3.6', '0.3.7', '0.3.8', '0.3.9',
|
||||||
|
'0.4.0', '0.4.0-rc1', '0.4.0-rc2', '0.4.0-rc3',
|
||||||
|
'0.4.0-rc4', '0.4.1', '0.4.2', '0.4.3',
|
||||||
|
'0.4.4', '0.4.5', '0.4.6', '0.4.7',
|
||||||
|
'0.5.0', '0.5.0-rc0', '0.5.0-rc1', '0.5.0-rc2',
|
||||||
|
'0.5.0-rc3', '0.5.0-rc4', '0.5.1', '0.5.2',
|
||||||
|
'0.6.0', '0.6.0-pre.alpha', '0.6.0-pre.beta', '0.6.0-rc1',
|
||||||
|
'0.6.0-rc2', '0.6.0-rc3', '0.6.1', '0.6.2',
|
||||||
|
'0.6.3', '0.6.4', '0.7.0', '0.7.0-alpha',
|
||||||
|
'0.7.0-beta', '0.7.0-beta2', '0.7.0-rc1', '0.7.0-rc2',
|
||||||
|
'0.7.0-rc3', '1.0.0', '1.0.0-rc1', '1.0.1',
|
||||||
|
'1.0.2', '1.0.3', '1.0.4', '1.0.5',
|
||||||
|
'1.1.0', '1.1.0-rc1', '1.1.0-rc2', '1.1.1',
|
||||||
|
'1.2.0', '1.2.0-rc1', '1.2.0-rc2', '1.2.0-rc3',
|
||||||
|
'1.3.0-alpha', '1.3.0-rc1', '1.3.0-rc2', '1.3.0-rc3',
|
||||||
|
'1.3.0-rc4'
|
||||||
|
]
|
||||||
|
|
||||||
|
const toolDir = path.join(__dirname, 'runner', 'tools')
|
||||||
|
const tempDir = path.join(__dirname, 'runner', 'temp')
|
||||||
|
const fixtureDir = path.join(__dirname, 'fixtures')
|
||||||
|
|
||||||
|
process.env['RUNNER_TOOL_CACHE'] = toolDir
|
||||||
|
process.env['RUNNER_TEMP'] = tempDir
|
||||||
|
|
||||||
|
import * as installer from '../src/installer'
|
||||||
|
|
||||||
|
describe('version matching tests', () => {
|
||||||
|
describe('specific versions', () => {
|
||||||
|
it('Doesn\'t change the version when given a valid semver version', () => {
|
||||||
|
expect(installer.getJuliaVersion([], '1.0.5')).toEqual('1.0.5')
|
||||||
|
expect(installer.getJuliaVersion(['v1.0.5', 'v1.0.6'], '1.0.5')).toEqual('1.0.5')
|
||||||
|
expect(installer.getJuliaVersion(['v1.0.4', 'v1.0.5'], '1.0.5')).toEqual('1.0.5')
|
||||||
|
expect(installer.getJuliaVersion(['v1.0.4'], '1.0.5')).toEqual('1.0.5')
|
||||||
|
expect(installer.getJuliaVersion([], '1.3.0-alpha')).toEqual('1.3.0-alpha')
|
||||||
|
expect(installer.getJuliaVersion(['v1.2.0', 'v1.3.0-alpha', 'v1.3.0-rc1', 'v1.3.0'], '1.3.0-alpha')).toEqual('1.3.0-alpha')
|
||||||
|
expect(installer.getJuliaVersion([], '1.3.0-rc2')).toEqual('1.3.0-rc2')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Doesn\'t change the version when given `nightly`', () => {
|
||||||
|
expect(installer.getJuliaVersion([], 'nightly')).toEqual('nightly')
|
||||||
|
expect(installer.getJuliaVersion(testVersions, 'nightly')).toEqual('nightly')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('version ranges', () => {
|
||||||
|
it('Chooses the highest available version that matches the input', () => {
|
||||||
|
expect(installer.getJuliaVersion(testVersions, '1')).toEqual('1.2.0')
|
||||||
|
expect(installer.getJuliaVersion(testVersions, '1.0')).toEqual('1.0.5')
|
||||||
|
expect(installer.getJuliaVersion(testVersions, '^1.3.0-rc1')).toEqual('1.3.0-rc4')
|
||||||
|
expect(installer.getJuliaVersion(testVersions, '^1.2.0-rc1')).toEqual('1.2.0')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('node-semver behaviour', () => {
|
||||||
|
describe('Windows installer change', () => {
|
||||||
|
it('Correctly understands >1.4.0', () => {
|
||||||
|
expect(semver.gtr('1.4.0-rc1', '1.3', {includePrerelease: true})).toBeTruthy()
|
||||||
|
expect(semver.gtr('1.4.0-DEV', '1.3', {includePrerelease: true})).toBeTruthy()
|
||||||
|
expect(semver.gtr('1.3.1', '1.3', {includePrerelease: true})).toBeFalsy()
|
||||||
|
expect(semver.gtr('1.3.2-rc1', '1.3', {includePrerelease: true})).toBeFalsy()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('installer tests', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await io.rmRF(toolDir)
|
||||||
|
await io.rmRF(tempDir)
|
||||||
|
}, 100000)
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
try {
|
||||||
|
await io.rmRF(toolDir)
|
||||||
|
await io.rmRF(tempDir)
|
||||||
|
} catch {
|
||||||
|
console.log('Failed to remove test directories')
|
||||||
|
}
|
||||||
|
}, 100000)
|
||||||
|
|
||||||
|
describe('versions.json parsing', () => {
|
||||||
|
// Instead of downloading versions.json, use fixtures/versions.json
|
||||||
|
beforeEach(() => {
|
||||||
|
nock('https://julialang-s3.julialang.org').persist()
|
||||||
|
.get('/bin/versions.json')
|
||||||
|
.replyWithFile(200, path.join(fixtureDir, 'versions.json'))
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
nock.cleanAll()
|
||||||
|
nock.enableNetConnect()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Extracts the list of available versions', async () => {
|
||||||
|
expect(await (await installer.getJuliaVersions(await installer.getJuliaVersionInfo())).sort()).toEqual(testVersions.sort())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
import * as installer from '../src/installer'
|
|
||||||
|
|
||||||
import * as semver from 'semver'
|
|
||||||
|
|
||||||
const testVersions = ['v1.3.0-rc4', 'v1.3.0-rc3', 'v1.3.0-rc2', 'v1.0.5', 'v1.2.0', 'v1.3.0-rc1', 'v1.2.0-rc3', 'v1.3.0-alpha', 'v1.2.0-rc2', 'v1.2.0-rc1', 'v1.1.1', 'v1.0.4', 'v1.1.0', 'v1.1.0-rc2', 'v1.1.0-rc1', 'v1.0.3', 'v1.0.2', 'v1.0.1', 'v1.0.0']
|
|
||||||
|
|
||||||
describe('installer tests', () => {
|
|
||||||
describe('version matching', () => {
|
|
||||||
describe('specific versions', () => {
|
|
||||||
it('Doesn\'t change the version when given a valid semver version', async () => {
|
|
||||||
expect(await installer.getJuliaVersion([], '1.0.5')).toEqual('1.0.5')
|
|
||||||
expect(await installer.getJuliaVersion(['v1.0.5', 'v1.0.6'], '1.0.5')).toEqual('1.0.5')
|
|
||||||
expect(await installer.getJuliaVersion(['v1.0.4', 'v1.0.5'], '1.0.5')).toEqual('1.0.5')
|
|
||||||
expect(await installer.getJuliaVersion(['v1.0.4'], '1.0.5')).toEqual('1.0.5')
|
|
||||||
expect(await installer.getJuliaVersion([], '1.3.0-alpha')).toEqual('1.3.0-alpha')
|
|
||||||
expect(await installer.getJuliaVersion(['v1.2.0', 'v1.3.0-alpha', 'v1.3.0-rc1', 'v1.3.0'], '1.3.0-alpha')).toEqual('1.3.0-alpha')
|
|
||||||
expect(await installer.getJuliaVersion([], '1.3.0-rc2')).toEqual('1.3.0-rc2')
|
|
||||||
})
|
|
||||||
it('Doesn\'t change the version when given `nightly`', async () => {
|
|
||||||
expect(await installer.getJuliaVersion([], 'nightly')).toEqual('nightly')
|
|
||||||
expect(await installer.getJuliaVersion(testVersions, 'nightly')).toEqual('nightly')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
describe('version ranges', () => {
|
|
||||||
it('Chooses the highest available version that matches the input', async () => {
|
|
||||||
expect(await installer.getJuliaVersion(testVersions, '1')).toEqual('1.2.0')
|
|
||||||
expect(await installer.getJuliaVersion(testVersions, '1.0')).toEqual('1.0.5')
|
|
||||||
expect(await installer.getJuliaVersion(testVersions, '^1.3.0-rc1')).toEqual('1.3.0-rc4')
|
|
||||||
expect(await installer.getJuliaVersion(testVersions, '^1.2.0-rc1')).toEqual('1.2.0')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
describe('invalid version range (#38)', () => {
|
|
||||||
it('Throws an error if a version range does not match any available version', () => {
|
|
||||||
expect(() => {
|
|
||||||
installer.getJuliaVersion(['v1.5.0-rc1', 'v1.5.0-beta1', 'v1.4.2', 'v1.4.1', 'v1.4.0', 'v1.4.0-rc2', 'v1.4.0-rc1'], '1.6')
|
|
||||||
}).toThrowError()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
describe('node-semver behaviour', () => {
|
|
||||||
describe('Windows installer change', () => {
|
|
||||||
it('Correctly understands >1.4.0', () => {
|
|
||||||
expect(semver.gtr('1.4.0-rc1', '1.3', {includePrerelease: true})).toBeTruthy()
|
|
||||||
expect(semver.gtr('1.4.0-DEV', '1.3', {includePrerelease: true})).toBeTruthy()
|
|
||||||
expect(semver.gtr('1.3.1', '1.3', {includePrerelease: true})).toBeFalsy()
|
|
||||||
expect(semver.gtr('1.3.2-rc1', '1.3', {includePrerelease: true})).toBeFalsy()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -13,6 +13,9 @@ inputs:
|
|||||||
description: 'Display InteractiveUtils.versioninfo() after installing'
|
description: 'Display InteractiveUtils.versioninfo() after installing'
|
||||||
required: false
|
required: false
|
||||||
default: 'false'
|
default: 'false'
|
||||||
|
outputs:
|
||||||
|
julia-bindir:
|
||||||
|
description: 'Path to the directory containing the Julia executable. Equivalent to JULIA_BINDIR: https://docs.julialang.org/en/v1/manual/environment-variables/#JULIA_BINDIR'
|
||||||
runs:
|
runs:
|
||||||
using: 'node12'
|
using: 'node12'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
|
|||||||
272
dist/index.js
vendored
272
dist/index.js
vendored
@@ -926,6 +926,32 @@ module.exports = require("tls");
|
|||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ 82:
|
||||||
|
/***/ (function(__unusedmodule, exports) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// We use any as a valid input type
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
/**
|
||||||
|
* Sanitizes an input into a string so it can be passed into issueCommand safely
|
||||||
|
* @param input input to sanitize into a string
|
||||||
|
*/
|
||||||
|
function toCommandValue(input) {
|
||||||
|
if (input === null || input === undefined) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
else if (typeof input === 'string' || input instanceof String) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
return JSON.stringify(input);
|
||||||
|
}
|
||||||
|
exports.toCommandValue = toCommandValue;
|
||||||
|
//# sourceMappingURL=utils.js.map
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
/***/ 87:
|
/***/ 87:
|
||||||
/***/ (function(module) {
|
/***/ (function(module) {
|
||||||
|
|
||||||
@@ -933,6 +959,42 @@ module.exports = require("os");
|
|||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ 102:
|
||||||
|
/***/ (function(__unusedmodule, exports, __webpack_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// For internal use, subject to change.
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||||
|
result["default"] = mod;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
// We use any as a valid input type
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
const fs = __importStar(__webpack_require__(747));
|
||||||
|
const os = __importStar(__webpack_require__(87));
|
||||||
|
const utils_1 = __webpack_require__(82);
|
||||||
|
function issueCommand(command, message) {
|
||||||
|
const filePath = process.env[`GITHUB_${command}`];
|
||||||
|
if (!filePath) {
|
||||||
|
throw new Error(`Unable to find environment variable for file command ${command}`);
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(filePath)) {
|
||||||
|
throw new Error(`Missing file at path: ${filePath}`);
|
||||||
|
}
|
||||||
|
fs.appendFileSync(filePath, `${utils_1.toCommandValue(message)}${os.EOL}`, {
|
||||||
|
encoding: 'utf8'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.issueCommand = issueCommand;
|
||||||
|
//# sourceMappingURL=file-command.js.map
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
/***/ 129:
|
/***/ 129:
|
||||||
/***/ (function(module) {
|
/***/ (function(module) {
|
||||||
|
|
||||||
@@ -2856,6 +2918,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const os = __importStar(__webpack_require__(87));
|
const os = __importStar(__webpack_require__(87));
|
||||||
|
const utils_1 = __webpack_require__(82);
|
||||||
/**
|
/**
|
||||||
* Commands
|
* Commands
|
||||||
*
|
*
|
||||||
@@ -2909,28 +2972,14 @@ class Command {
|
|||||||
return cmdStr;
|
return cmdStr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Sanitizes an input into a string so it can be passed into issueCommand safely
|
|
||||||
* @param input input to sanitize into a string
|
|
||||||
*/
|
|
||||||
function toCommandValue(input) {
|
|
||||||
if (input === null || input === undefined) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
else if (typeof input === 'string' || input instanceof String) {
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
return JSON.stringify(input);
|
|
||||||
}
|
|
||||||
exports.toCommandValue = toCommandValue;
|
|
||||||
function escapeData(s) {
|
function escapeData(s) {
|
||||||
return toCommandValue(s)
|
return utils_1.toCommandValue(s)
|
||||||
.replace(/%/g, '%25')
|
.replace(/%/g, '%25')
|
||||||
.replace(/\r/g, '%0D')
|
.replace(/\r/g, '%0D')
|
||||||
.replace(/\n/g, '%0A');
|
.replace(/\n/g, '%0A');
|
||||||
}
|
}
|
||||||
function escapeProperty(s) {
|
function escapeProperty(s) {
|
||||||
return toCommandValue(s)
|
return utils_1.toCommandValue(s)
|
||||||
.replace(/%/g, '%25')
|
.replace(/%/g, '%25')
|
||||||
.replace(/\r/g, '%0D')
|
.replace(/\r/g, '%0D')
|
||||||
.replace(/\n/g, '%0A')
|
.replace(/\n/g, '%0A')
|
||||||
@@ -2964,6 +3013,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const command_1 = __webpack_require__(431);
|
const command_1 = __webpack_require__(431);
|
||||||
|
const file_command_1 = __webpack_require__(102);
|
||||||
|
const utils_1 = __webpack_require__(82);
|
||||||
const os = __importStar(__webpack_require__(87));
|
const os = __importStar(__webpack_require__(87));
|
||||||
const path = __importStar(__webpack_require__(622));
|
const path = __importStar(__webpack_require__(622));
|
||||||
/**
|
/**
|
||||||
@@ -2990,9 +3041,17 @@ var ExitCode;
|
|||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
function exportVariable(name, val) {
|
function exportVariable(name, val) {
|
||||||
const convertedVal = command_1.toCommandValue(val);
|
const convertedVal = utils_1.toCommandValue(val);
|
||||||
process.env[name] = convertedVal;
|
process.env[name] = convertedVal;
|
||||||
command_1.issueCommand('set-env', { name }, convertedVal);
|
const filePath = process.env['GITHUB_ENV'] || '';
|
||||||
|
if (filePath) {
|
||||||
|
const delimiter = '_GitHubActionsFileCommandDelimeter_';
|
||||||
|
const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}`;
|
||||||
|
file_command_1.issueCommand('ENV', commandValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
command_1.issueCommand('set-env', { name }, convertedVal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exports.exportVariable = exportVariable;
|
exports.exportVariable = exportVariable;
|
||||||
/**
|
/**
|
||||||
@@ -3008,7 +3067,13 @@ exports.setSecret = setSecret;
|
|||||||
* @param inputPath
|
* @param inputPath
|
||||||
*/
|
*/
|
||||||
function addPath(inputPath) {
|
function addPath(inputPath) {
|
||||||
command_1.issueCommand('add-path', {}, inputPath);
|
const filePath = process.env['GITHUB_PATH'] || '';
|
||||||
|
if (filePath) {
|
||||||
|
file_command_1.issueCommand('PATH', inputPath);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
command_1.issueCommand('add-path', {}, inputPath);
|
||||||
|
}
|
||||||
process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`;
|
process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`;
|
||||||
}
|
}
|
||||||
exports.addPath = addPath;
|
exports.addPath = addPath;
|
||||||
@@ -3904,6 +3969,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||||||
const core = __importStar(__webpack_require__(470));
|
const core = __importStar(__webpack_require__(470));
|
||||||
const exec = __importStar(__webpack_require__(986));
|
const exec = __importStar(__webpack_require__(986));
|
||||||
const tc = __importStar(__webpack_require__(533));
|
const tc = __importStar(__webpack_require__(533));
|
||||||
|
const fs = __importStar(__webpack_require__(747));
|
||||||
const https = __importStar(__webpack_require__(211));
|
const https = __importStar(__webpack_require__(211));
|
||||||
const path = __importStar(__webpack_require__(622));
|
const path = __importStar(__webpack_require__(622));
|
||||||
const installer = __importStar(__webpack_require__(749));
|
const installer = __importStar(__webpack_require__(749));
|
||||||
@@ -3939,24 +4005,29 @@ function run() {
|
|||||||
if (!arch) {
|
if (!arch) {
|
||||||
throw new Error(`Arch input must not be null`);
|
throw new Error(`Arch input must not be null`);
|
||||||
}
|
}
|
||||||
const availableReleases = installer.juliaVersions;
|
const versionInfo = yield installer.getJuliaVersionInfo();
|
||||||
|
const availableReleases = yield installer.getJuliaVersions(versionInfo);
|
||||||
const version = installer.getJuliaVersion(availableReleases, versionInput);
|
const version = installer.getJuliaVersion(availableReleases, versionInput);
|
||||||
core.debug(`selected Julia version: ${arch}/${version}`);
|
core.debug(`selected Julia version: ${arch}/${version}`);
|
||||||
// Search in cache
|
// Search in cache
|
||||||
let juliaPath;
|
let juliaPath;
|
||||||
juliaPath = tc.find('julia', version, arch);
|
juliaPath = tc.find('julia', version, arch);
|
||||||
if (!juliaPath) {
|
if (!juliaPath) {
|
||||||
core.debug(`could not find Julia ${version} in cache`);
|
core.debug(`could not find Julia ${arch}/${version} in cache`);
|
||||||
const juliaInstallationPath = yield installer.installJulia(version, arch);
|
const juliaInstallationPath = yield installer.installJulia(versionInfo, version, arch);
|
||||||
// Add it to cache
|
// Add it to cache
|
||||||
juliaPath = yield tc.cacheDir(juliaInstallationPath, 'julia', version, arch);
|
juliaPath = yield tc.cacheDir(juliaInstallationPath, 'julia', version, arch);
|
||||||
core.debug(`added Julia to cache: ${juliaPath}`);
|
core.debug(`added Julia to cache: ${juliaPath}`);
|
||||||
|
// Remove temporary dir
|
||||||
|
fs.rmdirSync(juliaInstallationPath, { recursive: true });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
core.debug(`using cached version of Julia: ${juliaPath}`);
|
core.debug(`using cached version of Julia: ${juliaPath}`);
|
||||||
}
|
}
|
||||||
// Add it to PATH
|
// Add it to PATH
|
||||||
core.addPath(path.join(juliaPath, 'bin'));
|
core.addPath(path.join(juliaPath, 'bin'));
|
||||||
|
// Set output
|
||||||
|
core.setOutput('julia-bindir', path.join(juliaPath, 'bin'));
|
||||||
// Test if Julia has been installed
|
// Test if Julia has been installed
|
||||||
exec.exec('julia', ['--version']);
|
exec.exec('julia', ['--version']);
|
||||||
// If enabled, also show the full version info
|
// If enabled, also show the full version info
|
||||||
@@ -4005,14 +4076,65 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||||||
const core = __importStar(__webpack_require__(470));
|
const core = __importStar(__webpack_require__(470));
|
||||||
const exec = __importStar(__webpack_require__(986));
|
const exec = __importStar(__webpack_require__(986));
|
||||||
const tc = __importStar(__webpack_require__(533));
|
const tc = __importStar(__webpack_require__(533));
|
||||||
|
const crypto = __importStar(__webpack_require__(417));
|
||||||
|
const fs = __importStar(__webpack_require__(747));
|
||||||
const os = __importStar(__webpack_require__(87));
|
const os = __importStar(__webpack_require__(87));
|
||||||
const path = __importStar(__webpack_require__(622));
|
const path = __importStar(__webpack_require__(622));
|
||||||
const semver = __importStar(__webpack_require__(280));
|
const semver = __importStar(__webpack_require__(280));
|
||||||
|
// Translations between actions input and Julia arch names
|
||||||
|
const osMap = {
|
||||||
|
'win32': 'winnt',
|
||||||
|
'darwin': 'mac',
|
||||||
|
'linux': 'linux'
|
||||||
|
};
|
||||||
|
const archMap = {
|
||||||
|
'x86': 'i686',
|
||||||
|
'x64': 'x86_64'
|
||||||
|
};
|
||||||
// Store information about the environment
|
// Store information about the environment
|
||||||
const osPlat = os.platform(); // possible values: win32 (Windows), linux (Linux), darwin (macOS)
|
const osPlat = os.platform(); // possible values: win32 (Windows), linux (Linux), darwin (macOS)
|
||||||
core.debug(`platform: ${osPlat}`);
|
core.debug(`platform: ${osPlat}`);
|
||||||
// This is temporary until we have a better way of fetching releases (see #1, #4 for details)
|
/**
|
||||||
exports.juliaVersions = ['v1.5.2', 'v1.5.1', 'v1.5.0', 'v1.5.0-rc2', 'v1.5.0-rc1', 'v1.5.0-beta1', 'v1.4.2', 'v1.4.1', 'v1.4.0', 'v1.4.0-rc2', 'v1.4.0-rc1', 'v1.3.1', 'v1.3.0', 'v1.3.0-rc5', 'v1.3.0-rc4', 'v1.3.0-rc3', 'v1.3.0-rc2', 'v1.0.5', 'v1.2.0', 'v1.3.0-rc1', 'v1.2.0-rc3', 'v1.3.0-alpha', 'v1.2.0-rc2', 'v1.2.0-rc1', 'v1.1.1', 'v1.0.4', 'v1.1.0', 'v1.1.0-rc2', 'v1.1.0-rc1', 'v1.0.3', 'v1.0.2', 'v1.0.1', 'v1.0.0', 'v0.7.0', 'v1.0.0-rc1', 'v0.7.0-rc3', 'v0.7.0-rc2', 'v0.7.0-rc1', 'v0.7.0-beta2', 'v0.6.4', 'v0.7.0-beta', 'v0.7.0-alpha', 'v0.6.3', 'v0.6.2', 'v0.6.1', 'v0.6.0', 'v0.6.0-rc3', 'v0.6.0-rc2', 'v0.5.2', 'v0.6.0-rc1', 'v0.6.0-pre.beta', 'v0.5.1', 'v0.6.0-pre.alpha', 'v0.5.0', 'v0.4.7', 'v0.5.0-rc4', 'v0.5.0-rc3', 'v0.5.0-rc2', 'v0.5.0-rc1', 'v0.5.0-rc0', 'v0.4.6', 'v0.4.5', 'v0.4.4', 'v0.4.3', 'v0.4.2', 'v0.4.1', 'v0.3.12', 'v0.4.0', 'v0.4.0-rc4', 'v0.4.0-rc3', 'v0.4.0-rc2', 'v0.4.0-rc1', 'v0.3.11', 'v0.3.10', 'v0.3.9', 'v0.3.8', 'v0.3.7', 'v0.3.6', 'v0.3.5', 'v0.3.4', 'v0.3.3', 'v0.3.2', 'v0.3.1', 'v0.3.0', 'v0.3.0-rc4', 'v0.3.0-rc3', 'v0.3.0-rc2', 'v0.3.0-rc1', 'v0.2.0-rc1', 'v0.2.0-rc3', 'v0.2.0-rc4', 'v0.2.0', 'v0.2.0-rc2'];
|
* @returns The SHA256 checksum of a given file.
|
||||||
|
*/
|
||||||
|
function calculateChecksum(file) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const hash = crypto.createHash('sha256');
|
||||||
|
const input = fs.createReadStream(file);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
input.on('data', (chunk) => {
|
||||||
|
hash.update(chunk);
|
||||||
|
});
|
||||||
|
input.on('end', () => {
|
||||||
|
const digest = hash.digest('hex');
|
||||||
|
digest ? resolve(digest) : reject(new Error(`Could not calculate checksum of file ${file}: digest was empty.`));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @returns The content of the downloaded versions.json file as object.
|
||||||
|
*/
|
||||||
|
function getJuliaVersionInfo() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const versionsFile = yield tc.downloadTool('https://julialang-s3.julialang.org/bin/versions.json');
|
||||||
|
return JSON.parse(fs.readFileSync(versionsFile).toString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.getJuliaVersionInfo = getJuliaVersionInfo;
|
||||||
|
/**
|
||||||
|
* @returns An array of all Julia versions available for download
|
||||||
|
*/
|
||||||
|
function getJuliaVersions(versionInfo) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
let versions = [];
|
||||||
|
for (let version in versionInfo) {
|
||||||
|
versions.push(version);
|
||||||
|
}
|
||||||
|
return versions;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.getJuliaVersions = getJuliaVersions;
|
||||||
function getJuliaVersion(availableReleases, versionInput) {
|
function getJuliaVersion(availableReleases, versionInput) {
|
||||||
if (semver.valid(versionInput) == versionInput) {
|
if (semver.valid(versionInput) == versionInput) {
|
||||||
// versionInput is a valid version, use it directly
|
// versionInput is a valid version, use it directly
|
||||||
@@ -4032,91 +4154,87 @@ function getJuliaVersion(availableReleases, versionInput) {
|
|||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
exports.getJuliaVersion = getJuliaVersion;
|
exports.getJuliaVersion = getJuliaVersion;
|
||||||
function getMajorMinorVersion(version) {
|
function getNightlyFileName(arch) {
|
||||||
return version.split('.').slice(0, 2).join('.');
|
|
||||||
}
|
|
||||||
function getDownloadURL(version, arch) {
|
|
||||||
let platform;
|
|
||||||
if (osPlat === 'win32') { // Windows
|
|
||||||
platform = 'winnt';
|
|
||||||
}
|
|
||||||
else if (osPlat === 'darwin') { // macOS
|
|
||||||
if (arch == 'x86') {
|
|
||||||
throw new Error('32-bit Julia is not available on macOS');
|
|
||||||
}
|
|
||||||
platform = 'mac';
|
|
||||||
}
|
|
||||||
else if (osPlat === 'linux') { // Linux
|
|
||||||
platform = 'linux';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error(`Platform ${osPlat} is not supported`);
|
|
||||||
}
|
|
||||||
// nightlies
|
|
||||||
if (version == 'nightly') {
|
|
||||||
const baseURL = 'https://julialangnightlies-s3.julialang.org/bin';
|
|
||||||
return `${baseURL}/${platform}/${arch}/${getFileName('latest', arch)}`;
|
|
||||||
}
|
|
||||||
// normal versions
|
|
||||||
const baseURL = 'https://julialang-s3.julialang.org/bin';
|
|
||||||
const versionDir = getMajorMinorVersion(version);
|
|
||||||
return `${baseURL}/${platform}/${arch}/${versionDir}/${getFileName(version, arch)}`;
|
|
||||||
}
|
|
||||||
function getFileName(version, arch) {
|
|
||||||
let versionExt, ext;
|
let versionExt, ext;
|
||||||
if (osPlat === 'win32') { // Windows
|
if (osPlat == 'win32') {
|
||||||
versionExt = arch == 'x64' ? '-win64' : '-win32';
|
versionExt = arch == 'x64' ? '-win64' : '-win32';
|
||||||
ext = 'exe';
|
ext = 'exe';
|
||||||
}
|
}
|
||||||
else if (osPlat === 'darwin') { // macOS
|
else if (osPlat == 'darwin') {
|
||||||
if (arch == 'x86') {
|
if (arch == 'x86') {
|
||||||
throw new Error('32-bit Julia is not available on macOS');
|
throw new Error('32-bit Julia is not available on macOS');
|
||||||
}
|
}
|
||||||
versionExt = '-mac64';
|
versionExt = '-mac64';
|
||||||
ext = 'dmg';
|
ext = 'dmg';
|
||||||
}
|
}
|
||||||
else if (osPlat === 'linux') { // Linux
|
else if (osPlat === 'linux') {
|
||||||
if (version == 'latest') { // nightly version
|
versionExt = arch == 'x64' ? '-linux64' : '-linux32';
|
||||||
versionExt = arch == 'x64' ? '-linux64' : '-linux32';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
versionExt = arch == 'x64' ? '-linux-x86_64' : '-linux-i686';
|
|
||||||
}
|
|
||||||
ext = 'tar.gz';
|
ext = 'tar.gz';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new Error(`Platform ${osPlat} is not supported`);
|
throw new Error(`Platform ${osPlat} is not supported`);
|
||||||
}
|
}
|
||||||
return `julia-${version}${versionExt}.${ext}`;
|
return `julia-latest${versionExt}.${ext}`;
|
||||||
}
|
}
|
||||||
function installJulia(version, arch) {
|
function getFileInfo(versionInfo, version, arch) {
|
||||||
|
if (version == 'nightly') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (let file of versionInfo[version].files) {
|
||||||
|
if (file.os == osMap[osPlat] && file.arch == archMap[arch]) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw `Could not find ${archMap[arch]}/${version} binaries`;
|
||||||
|
}
|
||||||
|
exports.getFileInfo = getFileInfo;
|
||||||
|
function getDownloadURL(fileInfo, version, arch) {
|
||||||
|
// nightlies
|
||||||
|
if (version == 'nightly') {
|
||||||
|
const baseURL = 'https://julialangnightlies-s3.julialang.org/bin';
|
||||||
|
return `${baseURL}/${osMap[osPlat]}/${arch}/${getNightlyFileName(arch)}`;
|
||||||
|
}
|
||||||
|
return fileInfo.url;
|
||||||
|
}
|
||||||
|
exports.getDownloadURL = getDownloadURL;
|
||||||
|
function installJulia(versionInfo, version, arch) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
// Download Julia
|
// Download Julia
|
||||||
const downloadURL = getDownloadURL(version, arch);
|
const fileInfo = getFileInfo(versionInfo, version, arch);
|
||||||
|
const downloadURL = getDownloadURL(fileInfo, version, arch);
|
||||||
core.debug(`downloading Julia from ${downloadURL}`);
|
core.debug(`downloading Julia from ${downloadURL}`);
|
||||||
const juliaDownloadPath = yield tc.downloadTool(downloadURL);
|
const juliaDownloadPath = yield tc.downloadTool(downloadURL);
|
||||||
|
// Verify checksum
|
||||||
|
if (version != 'nightly') {
|
||||||
|
const checkSum = yield calculateChecksum(juliaDownloadPath);
|
||||||
|
if (fileInfo.sha256 != checkSum) {
|
||||||
|
throw new Error(`Checksum of downloaded file does not match the expected checksum from versions.json.\nExpected: ${fileInfo.sha256}\nGot: ${checkSum}`);
|
||||||
|
}
|
||||||
|
core.debug(`Checksum of downloaded file matches expected checksum: ${checkSum}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.debug('Skipping checksum check for nightly binaries.');
|
||||||
|
}
|
||||||
|
const tempInstallDir = fs.mkdtempSync(`julia-${arch}-${version}-`);
|
||||||
// Install it
|
// Install it
|
||||||
switch (osPlat) {
|
switch (osPlat) {
|
||||||
case 'linux':
|
case 'linux':
|
||||||
// tc.extractTar doesn't support stripping components, so we have to call tar manually
|
// tc.extractTar doesn't support stripping components, so we have to call tar manually
|
||||||
yield exec.exec('mkdir', [`${process.env.HOME}/julia`]);
|
yield exec.exec('tar', ['xf', juliaDownloadPath, '--strip-components=1', '-C', tempInstallDir]);
|
||||||
yield exec.exec('tar', ['xf', juliaDownloadPath, '--strip-components=1', '-C', `${process.env.HOME}/julia`]);
|
return tempInstallDir;
|
||||||
return `${process.env.HOME}/julia`;
|
|
||||||
case 'win32':
|
case 'win32':
|
||||||
const juliaInstallationPath = path.join('C:', 'Julia');
|
|
||||||
if (version == 'nightly' || semver.gtr(version, '1.3', { includePrerelease: true })) {
|
if (version == 'nightly' || semver.gtr(version, '1.3', { includePrerelease: true })) {
|
||||||
// The installer changed in 1.4: https://github.com/JuliaLang/julia/blob/ef0c9108b12f3ae177c51037934351ffa703b0b5/NEWS.md#build-system-changes
|
// The installer changed in 1.4: https://github.com/JuliaLang/julia/blob/ef0c9108b12f3ae177c51037934351ffa703b0b5/NEWS.md#build-system-changes
|
||||||
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/SILENT /dir=${juliaInstallationPath}" -NoNewWindow -Wait`]);
|
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/SILENT /dir=${path.join(process.cwd(), tempInstallDir)}" -NoNewWindow -Wait`]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/S /D=${juliaInstallationPath}" -NoNewWindow -Wait`]);
|
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/S /D=${path.join(process.cwd(), tempInstallDir)}" -NoNewWindow -Wait`]);
|
||||||
}
|
}
|
||||||
return juliaInstallationPath;
|
return tempInstallDir;
|
||||||
case 'darwin':
|
case 'darwin':
|
||||||
yield exec.exec('hdiutil', ['attach', juliaDownloadPath]);
|
yield exec.exec('hdiutil', ['attach', juliaDownloadPath]);
|
||||||
yield exec.exec('mkdir', [`${process.env.HOME}/julia`]);
|
yield exec.exec('/bin/bash', ['-c', `cp -a /Volumes/Julia-*/Julia-*.app/Contents/Resources/julia ${tempInstallDir}`]);
|
||||||
yield exec.exec('/bin/bash', ['-c', `cp -a /Volumes/Julia-*/Julia-*.app/Contents/Resources/julia ${process.env.HOME}`]);
|
return path.join(tempInstallDir, 'julia');
|
||||||
return `${process.env.HOME}/julia`;
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Platform ${osPlat} is not supported`);
|
throw new Error(`Platform ${osPlat} is not supported`);
|
||||||
}
|
}
|
||||||
|
|||||||
157
lib/installer.js
generated
157
lib/installer.js
generated
@@ -18,14 +18,65 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||||||
const core = __importStar(require("@actions/core"));
|
const core = __importStar(require("@actions/core"));
|
||||||
const exec = __importStar(require("@actions/exec"));
|
const exec = __importStar(require("@actions/exec"));
|
||||||
const tc = __importStar(require("@actions/tool-cache"));
|
const tc = __importStar(require("@actions/tool-cache"));
|
||||||
|
const crypto = __importStar(require("crypto"));
|
||||||
|
const fs = __importStar(require("fs"));
|
||||||
const os = __importStar(require("os"));
|
const os = __importStar(require("os"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
const semver = __importStar(require("semver"));
|
const semver = __importStar(require("semver"));
|
||||||
|
// Translations between actions input and Julia arch names
|
||||||
|
const osMap = {
|
||||||
|
'win32': 'winnt',
|
||||||
|
'darwin': 'mac',
|
||||||
|
'linux': 'linux'
|
||||||
|
};
|
||||||
|
const archMap = {
|
||||||
|
'x86': 'i686',
|
||||||
|
'x64': 'x86_64'
|
||||||
|
};
|
||||||
// Store information about the environment
|
// Store information about the environment
|
||||||
const osPlat = os.platform(); // possible values: win32 (Windows), linux (Linux), darwin (macOS)
|
const osPlat = os.platform(); // possible values: win32 (Windows), linux (Linux), darwin (macOS)
|
||||||
core.debug(`platform: ${osPlat}`);
|
core.debug(`platform: ${osPlat}`);
|
||||||
// This is temporary until we have a better way of fetching releases (see #1, #4 for details)
|
/**
|
||||||
exports.juliaVersions = ['v1.5.2', 'v1.5.1', 'v1.5.0', 'v1.5.0-rc2', 'v1.5.0-rc1', 'v1.5.0-beta1', 'v1.4.2', 'v1.4.1', 'v1.4.0', 'v1.4.0-rc2', 'v1.4.0-rc1', 'v1.3.1', 'v1.3.0', 'v1.3.0-rc5', 'v1.3.0-rc4', 'v1.3.0-rc3', 'v1.3.0-rc2', 'v1.0.5', 'v1.2.0', 'v1.3.0-rc1', 'v1.2.0-rc3', 'v1.3.0-alpha', 'v1.2.0-rc2', 'v1.2.0-rc1', 'v1.1.1', 'v1.0.4', 'v1.1.0', 'v1.1.0-rc2', 'v1.1.0-rc1', 'v1.0.3', 'v1.0.2', 'v1.0.1', 'v1.0.0', 'v0.7.0', 'v1.0.0-rc1', 'v0.7.0-rc3', 'v0.7.0-rc2', 'v0.7.0-rc1', 'v0.7.0-beta2', 'v0.6.4', 'v0.7.0-beta', 'v0.7.0-alpha', 'v0.6.3', 'v0.6.2', 'v0.6.1', 'v0.6.0', 'v0.6.0-rc3', 'v0.6.0-rc2', 'v0.5.2', 'v0.6.0-rc1', 'v0.6.0-pre.beta', 'v0.5.1', 'v0.6.0-pre.alpha', 'v0.5.0', 'v0.4.7', 'v0.5.0-rc4', 'v0.5.0-rc3', 'v0.5.0-rc2', 'v0.5.0-rc1', 'v0.5.0-rc0', 'v0.4.6', 'v0.4.5', 'v0.4.4', 'v0.4.3', 'v0.4.2', 'v0.4.1', 'v0.3.12', 'v0.4.0', 'v0.4.0-rc4', 'v0.4.0-rc3', 'v0.4.0-rc2', 'v0.4.0-rc1', 'v0.3.11', 'v0.3.10', 'v0.3.9', 'v0.3.8', 'v0.3.7', 'v0.3.6', 'v0.3.5', 'v0.3.4', 'v0.3.3', 'v0.3.2', 'v0.3.1', 'v0.3.0', 'v0.3.0-rc4', 'v0.3.0-rc3', 'v0.3.0-rc2', 'v0.3.0-rc1', 'v0.2.0-rc1', 'v0.2.0-rc3', 'v0.2.0-rc4', 'v0.2.0', 'v0.2.0-rc2'];
|
* @returns The SHA256 checksum of a given file.
|
||||||
|
*/
|
||||||
|
function calculateChecksum(file) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const hash = crypto.createHash('sha256');
|
||||||
|
const input = fs.createReadStream(file);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
input.on('data', (chunk) => {
|
||||||
|
hash.update(chunk);
|
||||||
|
});
|
||||||
|
input.on('end', () => {
|
||||||
|
const digest = hash.digest('hex');
|
||||||
|
digest ? resolve(digest) : reject(new Error(`Could not calculate checksum of file ${file}: digest was empty.`));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @returns The content of the downloaded versions.json file as object.
|
||||||
|
*/
|
||||||
|
function getJuliaVersionInfo() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const versionsFile = yield tc.downloadTool('https://julialang-s3.julialang.org/bin/versions.json');
|
||||||
|
return JSON.parse(fs.readFileSync(versionsFile).toString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.getJuliaVersionInfo = getJuliaVersionInfo;
|
||||||
|
/**
|
||||||
|
* @returns An array of all Julia versions available for download
|
||||||
|
*/
|
||||||
|
function getJuliaVersions(versionInfo) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
let versions = [];
|
||||||
|
for (let version in versionInfo) {
|
||||||
|
versions.push(version);
|
||||||
|
}
|
||||||
|
return versions;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.getJuliaVersions = getJuliaVersions;
|
||||||
function getJuliaVersion(availableReleases, versionInput) {
|
function getJuliaVersion(availableReleases, versionInput) {
|
||||||
if (semver.valid(versionInput) == versionInput) {
|
if (semver.valid(versionInput) == versionInput) {
|
||||||
// versionInput is a valid version, use it directly
|
// versionInput is a valid version, use it directly
|
||||||
@@ -45,91 +96,87 @@ function getJuliaVersion(availableReleases, versionInput) {
|
|||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
exports.getJuliaVersion = getJuliaVersion;
|
exports.getJuliaVersion = getJuliaVersion;
|
||||||
function getMajorMinorVersion(version) {
|
function getNightlyFileName(arch) {
|
||||||
return version.split('.').slice(0, 2).join('.');
|
|
||||||
}
|
|
||||||
function getDownloadURL(version, arch) {
|
|
||||||
let platform;
|
|
||||||
if (osPlat === 'win32') { // Windows
|
|
||||||
platform = 'winnt';
|
|
||||||
}
|
|
||||||
else if (osPlat === 'darwin') { // macOS
|
|
||||||
if (arch == 'x86') {
|
|
||||||
throw new Error('32-bit Julia is not available on macOS');
|
|
||||||
}
|
|
||||||
platform = 'mac';
|
|
||||||
}
|
|
||||||
else if (osPlat === 'linux') { // Linux
|
|
||||||
platform = 'linux';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error(`Platform ${osPlat} is not supported`);
|
|
||||||
}
|
|
||||||
// nightlies
|
|
||||||
if (version == 'nightly') {
|
|
||||||
const baseURL = 'https://julialangnightlies-s3.julialang.org/bin';
|
|
||||||
return `${baseURL}/${platform}/${arch}/${getFileName('latest', arch)}`;
|
|
||||||
}
|
|
||||||
// normal versions
|
|
||||||
const baseURL = 'https://julialang-s3.julialang.org/bin';
|
|
||||||
const versionDir = getMajorMinorVersion(version);
|
|
||||||
return `${baseURL}/${platform}/${arch}/${versionDir}/${getFileName(version, arch)}`;
|
|
||||||
}
|
|
||||||
function getFileName(version, arch) {
|
|
||||||
let versionExt, ext;
|
let versionExt, ext;
|
||||||
if (osPlat === 'win32') { // Windows
|
if (osPlat == 'win32') {
|
||||||
versionExt = arch == 'x64' ? '-win64' : '-win32';
|
versionExt = arch == 'x64' ? '-win64' : '-win32';
|
||||||
ext = 'exe';
|
ext = 'exe';
|
||||||
}
|
}
|
||||||
else if (osPlat === 'darwin') { // macOS
|
else if (osPlat == 'darwin') {
|
||||||
if (arch == 'x86') {
|
if (arch == 'x86') {
|
||||||
throw new Error('32-bit Julia is not available on macOS');
|
throw new Error('32-bit Julia is not available on macOS');
|
||||||
}
|
}
|
||||||
versionExt = '-mac64';
|
versionExt = '-mac64';
|
||||||
ext = 'dmg';
|
ext = 'dmg';
|
||||||
}
|
}
|
||||||
else if (osPlat === 'linux') { // Linux
|
else if (osPlat === 'linux') {
|
||||||
if (version == 'latest') { // nightly version
|
versionExt = arch == 'x64' ? '-linux64' : '-linux32';
|
||||||
versionExt = arch == 'x64' ? '-linux64' : '-linux32';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
versionExt = arch == 'x64' ? '-linux-x86_64' : '-linux-i686';
|
|
||||||
}
|
|
||||||
ext = 'tar.gz';
|
ext = 'tar.gz';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new Error(`Platform ${osPlat} is not supported`);
|
throw new Error(`Platform ${osPlat} is not supported`);
|
||||||
}
|
}
|
||||||
return `julia-${version}${versionExt}.${ext}`;
|
return `julia-latest${versionExt}.${ext}`;
|
||||||
}
|
}
|
||||||
function installJulia(version, arch) {
|
function getFileInfo(versionInfo, version, arch) {
|
||||||
|
if (version == 'nightly') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (let file of versionInfo[version].files) {
|
||||||
|
if (file.os == osMap[osPlat] && file.arch == archMap[arch]) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw `Could not find ${archMap[arch]}/${version} binaries`;
|
||||||
|
}
|
||||||
|
exports.getFileInfo = getFileInfo;
|
||||||
|
function getDownloadURL(fileInfo, version, arch) {
|
||||||
|
// nightlies
|
||||||
|
if (version == 'nightly') {
|
||||||
|
const baseURL = 'https://julialangnightlies-s3.julialang.org/bin';
|
||||||
|
return `${baseURL}/${osMap[osPlat]}/${arch}/${getNightlyFileName(arch)}`;
|
||||||
|
}
|
||||||
|
return fileInfo.url;
|
||||||
|
}
|
||||||
|
exports.getDownloadURL = getDownloadURL;
|
||||||
|
function installJulia(versionInfo, version, arch) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
// Download Julia
|
// Download Julia
|
||||||
const downloadURL = getDownloadURL(version, arch);
|
const fileInfo = getFileInfo(versionInfo, version, arch);
|
||||||
|
const downloadURL = getDownloadURL(fileInfo, version, arch);
|
||||||
core.debug(`downloading Julia from ${downloadURL}`);
|
core.debug(`downloading Julia from ${downloadURL}`);
|
||||||
const juliaDownloadPath = yield tc.downloadTool(downloadURL);
|
const juliaDownloadPath = yield tc.downloadTool(downloadURL);
|
||||||
|
// Verify checksum
|
||||||
|
if (version != 'nightly') {
|
||||||
|
const checkSum = yield calculateChecksum(juliaDownloadPath);
|
||||||
|
if (fileInfo.sha256 != checkSum) {
|
||||||
|
throw new Error(`Checksum of downloaded file does not match the expected checksum from versions.json.\nExpected: ${fileInfo.sha256}\nGot: ${checkSum}`);
|
||||||
|
}
|
||||||
|
core.debug(`Checksum of downloaded file matches expected checksum: ${checkSum}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.debug('Skipping checksum check for nightly binaries.');
|
||||||
|
}
|
||||||
|
const tempInstallDir = fs.mkdtempSync(`julia-${arch}-${version}-`);
|
||||||
// Install it
|
// Install it
|
||||||
switch (osPlat) {
|
switch (osPlat) {
|
||||||
case 'linux':
|
case 'linux':
|
||||||
// tc.extractTar doesn't support stripping components, so we have to call tar manually
|
// tc.extractTar doesn't support stripping components, so we have to call tar manually
|
||||||
yield exec.exec('mkdir', [`${process.env.HOME}/julia`]);
|
yield exec.exec('tar', ['xf', juliaDownloadPath, '--strip-components=1', '-C', tempInstallDir]);
|
||||||
yield exec.exec('tar', ['xf', juliaDownloadPath, '--strip-components=1', '-C', `${process.env.HOME}/julia`]);
|
return tempInstallDir;
|
||||||
return `${process.env.HOME}/julia`;
|
|
||||||
case 'win32':
|
case 'win32':
|
||||||
const juliaInstallationPath = path.join('C:', 'Julia');
|
|
||||||
if (version == 'nightly' || semver.gtr(version, '1.3', { includePrerelease: true })) {
|
if (version == 'nightly' || semver.gtr(version, '1.3', { includePrerelease: true })) {
|
||||||
// The installer changed in 1.4: https://github.com/JuliaLang/julia/blob/ef0c9108b12f3ae177c51037934351ffa703b0b5/NEWS.md#build-system-changes
|
// The installer changed in 1.4: https://github.com/JuliaLang/julia/blob/ef0c9108b12f3ae177c51037934351ffa703b0b5/NEWS.md#build-system-changes
|
||||||
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/SILENT /dir=${juliaInstallationPath}" -NoNewWindow -Wait`]);
|
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/SILENT /dir=${path.join(process.cwd(), tempInstallDir)}" -NoNewWindow -Wait`]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/S /D=${juliaInstallationPath}" -NoNewWindow -Wait`]);
|
yield exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/S /D=${path.join(process.cwd(), tempInstallDir)}" -NoNewWindow -Wait`]);
|
||||||
}
|
}
|
||||||
return juliaInstallationPath;
|
return tempInstallDir;
|
||||||
case 'darwin':
|
case 'darwin':
|
||||||
yield exec.exec('hdiutil', ['attach', juliaDownloadPath]);
|
yield exec.exec('hdiutil', ['attach', juliaDownloadPath]);
|
||||||
yield exec.exec('mkdir', [`${process.env.HOME}/julia`]);
|
yield exec.exec('/bin/bash', ['-c', `cp -a /Volumes/Julia-*/Julia-*.app/Contents/Resources/julia ${tempInstallDir}`]);
|
||||||
yield exec.exec('/bin/bash', ['-c', `cp -a /Volumes/Julia-*/Julia-*.app/Contents/Resources/julia ${process.env.HOME}`]);
|
return path.join(tempInstallDir, 'julia');
|
||||||
return `${process.env.HOME}/julia`;
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Platform ${osPlat} is not supported`);
|
throw new Error(`Platform ${osPlat} is not supported`);
|
||||||
}
|
}
|
||||||
|
|||||||
12
lib/setup-julia.js
generated
12
lib/setup-julia.js
generated
@@ -18,6 +18,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||||||
const core = __importStar(require("@actions/core"));
|
const core = __importStar(require("@actions/core"));
|
||||||
const exec = __importStar(require("@actions/exec"));
|
const exec = __importStar(require("@actions/exec"));
|
||||||
const tc = __importStar(require("@actions/tool-cache"));
|
const tc = __importStar(require("@actions/tool-cache"));
|
||||||
|
const fs = __importStar(require("fs"));
|
||||||
const https = __importStar(require("https"));
|
const https = __importStar(require("https"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
const installer = __importStar(require("./installer"));
|
const installer = __importStar(require("./installer"));
|
||||||
@@ -53,24 +54,29 @@ function run() {
|
|||||||
if (!arch) {
|
if (!arch) {
|
||||||
throw new Error(`Arch input must not be null`);
|
throw new Error(`Arch input must not be null`);
|
||||||
}
|
}
|
||||||
const availableReleases = installer.juliaVersions;
|
const versionInfo = yield installer.getJuliaVersionInfo();
|
||||||
|
const availableReleases = yield installer.getJuliaVersions(versionInfo);
|
||||||
const version = installer.getJuliaVersion(availableReleases, versionInput);
|
const version = installer.getJuliaVersion(availableReleases, versionInput);
|
||||||
core.debug(`selected Julia version: ${arch}/${version}`);
|
core.debug(`selected Julia version: ${arch}/${version}`);
|
||||||
// Search in cache
|
// Search in cache
|
||||||
let juliaPath;
|
let juliaPath;
|
||||||
juliaPath = tc.find('julia', version, arch);
|
juliaPath = tc.find('julia', version, arch);
|
||||||
if (!juliaPath) {
|
if (!juliaPath) {
|
||||||
core.debug(`could not find Julia ${version} in cache`);
|
core.debug(`could not find Julia ${arch}/${version} in cache`);
|
||||||
const juliaInstallationPath = yield installer.installJulia(version, arch);
|
const juliaInstallationPath = yield installer.installJulia(versionInfo, version, arch);
|
||||||
// Add it to cache
|
// Add it to cache
|
||||||
juliaPath = yield tc.cacheDir(juliaInstallationPath, 'julia', version, arch);
|
juliaPath = yield tc.cacheDir(juliaInstallationPath, 'julia', version, arch);
|
||||||
core.debug(`added Julia to cache: ${juliaPath}`);
|
core.debug(`added Julia to cache: ${juliaPath}`);
|
||||||
|
// Remove temporary dir
|
||||||
|
fs.rmdirSync(juliaInstallationPath, { recursive: true });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
core.debug(`using cached version of Julia: ${juliaPath}`);
|
core.debug(`using cached version of Julia: ${juliaPath}`);
|
||||||
}
|
}
|
||||||
// Add it to PATH
|
// Add it to PATH
|
||||||
core.addPath(path.join(juliaPath, 'bin'));
|
core.addPath(path.join(juliaPath, 'bin'));
|
||||||
|
// Set output
|
||||||
|
core.setOutput('julia-bindir', path.join(juliaPath, 'bin'));
|
||||||
// Test if Julia has been installed
|
// Test if Julia has been installed
|
||||||
exec.exec('julia', ['--version']);
|
exec.exec('julia', ['--version']);
|
||||||
// If enabled, also show the full version info
|
// If enabled, also show the full version info
|
||||||
|
|||||||
44
package-lock.json
generated
44
package-lock.json
generated
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "setup-julia",
|
"name": "setup-julia",
|
||||||
"version": "1.2.2",
|
"version": "1.4.1",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": {
|
"@actions/core": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz",
|
||||||
"integrity": "sha512-YJCEq8BE3CdN8+7HPZ/4DxJjk/OkZV2FFIf+DlZTC/4iBlzYCD5yjRR6eiOS5llO11zbRltIRuKAjMKaWTE6cg=="
|
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
|
||||||
},
|
},
|
||||||
"@actions/exec": {
|
"@actions/exec": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -5461,6 +5461,36 @@
|
|||||||
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
|
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"nock": {
|
||||||
|
"version": "11.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/nock/-/nock-11.7.2.tgz",
|
||||||
|
"integrity": "sha512-7swr5bL1xBZ5FctyubjxEVySXOSebyqcL7Vy1bx1nS9IUqQWj81cmKjVKJLr8fHhtzI1MV8nyCdENA/cGcY1+Q==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"debug": "^4.1.0",
|
||||||
|
"json-stringify-safe": "^5.0.1",
|
||||||
|
"lodash": "^4.17.13",
|
||||||
|
"mkdirp": "^0.5.0",
|
||||||
|
"propagate": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ms": "^2.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node-int64": {
|
"node-int64": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||||
@@ -5821,6 +5851,12 @@
|
|||||||
"sisteransi": "^1.0.4"
|
"sisteransi": "^1.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"propagate": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"psl": {
|
"psl": {
|
||||||
"version": "1.7.0",
|
"version": "1.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "setup-julia",
|
"name": "setup-julia",
|
||||||
"version": "1.2.2",
|
"version": "1.4.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "setup Julia action",
|
"description": "setup Julia action",
|
||||||
"main": "lib/setup-julia.js",
|
"main": "lib/setup-julia.js",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
"author": "Sascha Mann <git@mail.saschamann.eu>",
|
"author": "Sascha Mann <git@mail.saschamann.eu>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.2.4",
|
"@actions/core": "^1.2.6",
|
||||||
"@actions/exec": "^1.0.0",
|
"@actions/exec": "^1.0.0",
|
||||||
"@actions/io": "^1.0.0",
|
"@actions/io": "^1.0.0",
|
||||||
"@actions/tool-cache": "^1.0.0",
|
"@actions/tool-cache": "^1.0.0",
|
||||||
@@ -34,6 +34,7 @@
|
|||||||
"@zeit/ncc": "^0.22.0",
|
"@zeit/ncc": "^0.22.0",
|
||||||
"jest": "^24.8.0",
|
"jest": "^24.8.0",
|
||||||
"jest-circus": "^24.7.1",
|
"jest-circus": "^24.7.1",
|
||||||
|
"nock": "^11.7.2",
|
||||||
"prettier": "^1.17.1",
|
"prettier": "^1.17.1",
|
||||||
"ts-jest": "^26.0.0",
|
"ts-jest": "^26.0.0",
|
||||||
"typescript": "^3.5.1"
|
"typescript": "^3.5.1"
|
||||||
|
|||||||
163
src/installer.ts
163
src/installer.ts
@@ -2,17 +2,68 @@ import * as core from '@actions/core'
|
|||||||
import * as exec from '@actions/exec'
|
import * as exec from '@actions/exec'
|
||||||
import * as tc from '@actions/tool-cache'
|
import * as tc from '@actions/tool-cache'
|
||||||
|
|
||||||
|
import * as crypto from 'crypto'
|
||||||
|
import * as fs from 'fs'
|
||||||
import * as os from 'os'
|
import * as os from 'os'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
|
|
||||||
import * as semver from 'semver'
|
import * as semver from 'semver'
|
||||||
|
|
||||||
|
// Translations between actions input and Julia arch names
|
||||||
|
const osMap = {
|
||||||
|
'win32': 'winnt',
|
||||||
|
'darwin': 'mac',
|
||||||
|
'linux': 'linux'
|
||||||
|
}
|
||||||
|
const archMap = {
|
||||||
|
'x86': 'i686',
|
||||||
|
'x64': 'x86_64'
|
||||||
|
}
|
||||||
|
|
||||||
// Store information about the environment
|
// Store information about the environment
|
||||||
const osPlat = os.platform() // possible values: win32 (Windows), linux (Linux), darwin (macOS)
|
const osPlat = os.platform() // possible values: win32 (Windows), linux (Linux), darwin (macOS)
|
||||||
core.debug(`platform: ${osPlat}`)
|
core.debug(`platform: ${osPlat}`)
|
||||||
|
|
||||||
// This is temporary until we have a better way of fetching releases (see #1, #4 for details)
|
/**
|
||||||
export const juliaVersions = ['v1.5.2', 'v1.5.1', 'v1.5.0', 'v1.5.0-rc2', 'v1.5.0-rc1', 'v1.5.0-beta1', 'v1.4.2', 'v1.4.1', 'v1.4.0', 'v1.4.0-rc2', 'v1.4.0-rc1', 'v1.3.1', 'v1.3.0', 'v1.3.0-rc5', 'v1.3.0-rc4', 'v1.3.0-rc3', 'v1.3.0-rc2', 'v1.0.5', 'v1.2.0', 'v1.3.0-rc1', 'v1.2.0-rc3', 'v1.3.0-alpha', 'v1.2.0-rc2', 'v1.2.0-rc1', 'v1.1.1', 'v1.0.4', 'v1.1.0', 'v1.1.0-rc2', 'v1.1.0-rc1', 'v1.0.3', 'v1.0.2', 'v1.0.1', 'v1.0.0', 'v0.7.0', 'v1.0.0-rc1', 'v0.7.0-rc3', 'v0.7.0-rc2', 'v0.7.0-rc1', 'v0.7.0-beta2', 'v0.6.4', 'v0.7.0-beta', 'v0.7.0-alpha', 'v0.6.3', 'v0.6.2', 'v0.6.1', 'v0.6.0', 'v0.6.0-rc3', 'v0.6.0-rc2', 'v0.5.2', 'v0.6.0-rc1', 'v0.6.0-pre.beta', 'v0.5.1', 'v0.6.0-pre.alpha', 'v0.5.0', 'v0.4.7', 'v0.5.0-rc4', 'v0.5.0-rc3', 'v0.5.0-rc2', 'v0.5.0-rc1', 'v0.5.0-rc0', 'v0.4.6', 'v0.4.5', 'v0.4.4', 'v0.4.3', 'v0.4.2', 'v0.4.1', 'v0.3.12', 'v0.4.0', 'v0.4.0-rc4', 'v0.4.0-rc3', 'v0.4.0-rc2', 'v0.4.0-rc1', 'v0.3.11', 'v0.3.10', 'v0.3.9', 'v0.3.8', 'v0.3.7', 'v0.3.6', 'v0.3.5', 'v0.3.4', 'v0.3.3', 'v0.3.2', 'v0.3.1', 'v0.3.0', 'v0.3.0-rc4', 'v0.3.0-rc3', 'v0.3.0-rc2', 'v0.3.0-rc1', 'v0.2.0-rc1', 'v0.2.0-rc3', 'v0.2.0-rc4', 'v0.2.0', 'v0.2.0-rc2']
|
* @returns The SHA256 checksum of a given file.
|
||||||
|
*/
|
||||||
|
async function calculateChecksum(file: string): Promise<string> {
|
||||||
|
const hash = crypto.createHash('sha256')
|
||||||
|
const input = fs.createReadStream(file)
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
input.on('data', (chunk) => {
|
||||||
|
hash.update(chunk)
|
||||||
|
})
|
||||||
|
|
||||||
|
input.on('end', () => {
|
||||||
|
const digest = hash.digest('hex')
|
||||||
|
digest ? resolve(digest) : reject(new Error(`Could not calculate checksum of file ${file}: digest was empty.`))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns The content of the downloaded versions.json file as object.
|
||||||
|
*/
|
||||||
|
export async function getJuliaVersionInfo(): Promise<object> {
|
||||||
|
const versionsFile = await tc.downloadTool('https://julialang-s3.julialang.org/bin/versions.json')
|
||||||
|
|
||||||
|
return JSON.parse(fs.readFileSync(versionsFile).toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns An array of all Julia versions available for download
|
||||||
|
*/
|
||||||
|
export async function getJuliaVersions(versionInfo): Promise<string[]> {
|
||||||
|
let versions: string[] = []
|
||||||
|
|
||||||
|
for (let version in versionInfo) {
|
||||||
|
versions.push(version)
|
||||||
|
}
|
||||||
|
|
||||||
|
return versions
|
||||||
|
}
|
||||||
|
|
||||||
export function getJuliaVersion(availableReleases: string[], versionInput: string): string {
|
export function getJuliaVersion(availableReleases: string[], versionInput: string): string {
|
||||||
if (semver.valid(versionInput) == versionInput) {
|
if (semver.valid(versionInput) == versionInput) {
|
||||||
@@ -37,92 +88,90 @@ export function getJuliaVersion(availableReleases: string[], versionInput: strin
|
|||||||
return version
|
return version
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMajorMinorVersion(version: string): string {
|
function getNightlyFileName(arch: string): string {
|
||||||
return version.split('.').slice(0, 2).join('.')
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDownloadURL(version: string, arch: string): string {
|
|
||||||
let platform: string
|
|
||||||
|
|
||||||
if (osPlat === 'win32') { // Windows
|
|
||||||
platform = 'winnt'
|
|
||||||
} else if (osPlat === 'darwin') { // macOS
|
|
||||||
if (arch == 'x86') {
|
|
||||||
throw new Error('32-bit Julia is not available on macOS')
|
|
||||||
}
|
|
||||||
platform = 'mac'
|
|
||||||
} else if (osPlat === 'linux') { // Linux
|
|
||||||
platform = 'linux'
|
|
||||||
} else {
|
|
||||||
throw new Error(`Platform ${osPlat} is not supported`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// nightlies
|
|
||||||
if (version == 'nightly') {
|
|
||||||
const baseURL = 'https://julialangnightlies-s3.julialang.org/bin'
|
|
||||||
return `${baseURL}/${platform}/${arch}/${getFileName('latest', arch)}`
|
|
||||||
}
|
|
||||||
|
|
||||||
// normal versions
|
|
||||||
const baseURL = 'https://julialang-s3.julialang.org/bin'
|
|
||||||
const versionDir = getMajorMinorVersion(version)
|
|
||||||
|
|
||||||
return `${baseURL}/${platform}/${arch}/${versionDir}/${getFileName(version, arch)}`
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFileName(version: string, arch: string): string {
|
|
||||||
let versionExt: string, ext: string
|
let versionExt: string, ext: string
|
||||||
|
|
||||||
if (osPlat === 'win32') { // Windows
|
if (osPlat == 'win32') {
|
||||||
versionExt = arch == 'x64' ? '-win64' : '-win32'
|
versionExt = arch == 'x64' ? '-win64' : '-win32'
|
||||||
ext = 'exe'
|
ext = 'exe'
|
||||||
} else if (osPlat === 'darwin') { // macOS
|
} else if (osPlat == 'darwin') {
|
||||||
if (arch == 'x86') {
|
if (arch == 'x86') {
|
||||||
throw new Error('32-bit Julia is not available on macOS')
|
throw new Error('32-bit Julia is not available on macOS')
|
||||||
}
|
}
|
||||||
versionExt = '-mac64'
|
versionExt = '-mac64'
|
||||||
ext = 'dmg'
|
ext = 'dmg'
|
||||||
} else if (osPlat === 'linux') { // Linux
|
} else if (osPlat === 'linux') {
|
||||||
if (version == 'latest') { // nightly version
|
versionExt = arch == 'x64' ? '-linux64' : '-linux32'
|
||||||
versionExt = arch == 'x64' ? '-linux64' : '-linux32'
|
|
||||||
} else {
|
|
||||||
versionExt = arch == 'x64' ? '-linux-x86_64' : '-linux-i686'
|
|
||||||
}
|
|
||||||
ext = 'tar.gz'
|
ext = 'tar.gz'
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Platform ${osPlat} is not supported`)
|
throw new Error(`Platform ${osPlat} is not supported`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return `julia-${version}${versionExt}.${ext}`
|
return `julia-latest${versionExt}.${ext}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function installJulia(version: string, arch: string): Promise<string> {
|
export function getFileInfo(versionInfo, version: string, arch: string) {
|
||||||
|
if (version == 'nightly') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let file of versionInfo[version].files) {
|
||||||
|
if (file.os == osMap[osPlat] && file.arch == archMap[arch]) {
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw `Could not find ${archMap[arch]}/${version} binaries`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDownloadURL(fileInfo, version: string, arch: string): string {
|
||||||
|
// nightlies
|
||||||
|
if (version == 'nightly') {
|
||||||
|
const baseURL = 'https://julialangnightlies-s3.julialang.org/bin'
|
||||||
|
return `${baseURL}/${osMap[osPlat]}/${arch}/${getNightlyFileName(arch)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileInfo.url
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function installJulia(versionInfo, version: string, arch: string): Promise<string> {
|
||||||
// Download Julia
|
// Download Julia
|
||||||
const downloadURL = getDownloadURL(version, arch)
|
const fileInfo = getFileInfo(versionInfo, version, arch)
|
||||||
|
const downloadURL = getDownloadURL(fileInfo, version, arch)
|
||||||
core.debug(`downloading Julia from ${downloadURL}`)
|
core.debug(`downloading Julia from ${downloadURL}`)
|
||||||
const juliaDownloadPath = await tc.downloadTool(downloadURL)
|
const juliaDownloadPath = await tc.downloadTool(downloadURL)
|
||||||
|
|
||||||
|
// Verify checksum
|
||||||
|
if (version != 'nightly') {
|
||||||
|
const checkSum = await calculateChecksum(juliaDownloadPath)
|
||||||
|
if (fileInfo.sha256 != checkSum) {
|
||||||
|
throw new Error(`Checksum of downloaded file does not match the expected checksum from versions.json.\nExpected: ${fileInfo.sha256}\nGot: ${checkSum}`)
|
||||||
|
}
|
||||||
|
core.debug(`Checksum of downloaded file matches expected checksum: ${checkSum}`)
|
||||||
|
} else {
|
||||||
|
core.debug('Skipping checksum check for nightly binaries.')
|
||||||
|
}
|
||||||
|
|
||||||
|
const tempInstallDir = fs.mkdtempSync(`julia-${arch}-${version}-`)
|
||||||
|
|
||||||
// Install it
|
// Install it
|
||||||
switch (osPlat) {
|
switch (osPlat) {
|
||||||
case 'linux':
|
case 'linux':
|
||||||
// tc.extractTar doesn't support stripping components, so we have to call tar manually
|
// tc.extractTar doesn't support stripping components, so we have to call tar manually
|
||||||
await exec.exec('mkdir', [`${process.env.HOME}/julia`])
|
await exec.exec('tar', ['xf', juliaDownloadPath, '--strip-components=1', '-C', tempInstallDir])
|
||||||
await exec.exec('tar', ['xf', juliaDownloadPath, '--strip-components=1', '-C', `${process.env.HOME}/julia`])
|
return tempInstallDir
|
||||||
return `${process.env.HOME}/julia`
|
|
||||||
case 'win32':
|
case 'win32':
|
||||||
const juliaInstallationPath = path.join('C:', 'Julia')
|
|
||||||
if (version == 'nightly' || semver.gtr(version, '1.3', {includePrerelease: true})) {
|
if (version == 'nightly' || semver.gtr(version, '1.3', {includePrerelease: true})) {
|
||||||
// The installer changed in 1.4: https://github.com/JuliaLang/julia/blob/ef0c9108b12f3ae177c51037934351ffa703b0b5/NEWS.md#build-system-changes
|
// The installer changed in 1.4: https://github.com/JuliaLang/julia/blob/ef0c9108b12f3ae177c51037934351ffa703b0b5/NEWS.md#build-system-changes
|
||||||
await exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/SILENT /dir=${juliaInstallationPath}" -NoNewWindow -Wait`])
|
await exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/SILENT /dir=${path.join(process.cwd(), tempInstallDir)}" -NoNewWindow -Wait`])
|
||||||
} else {
|
} else {
|
||||||
await exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/S /D=${juliaInstallationPath}" -NoNewWindow -Wait`])
|
await exec.exec('powershell', ['-Command', `Start-Process -FilePath ${juliaDownloadPath} -ArgumentList "/S /D=${path.join(process.cwd(), tempInstallDir)}" -NoNewWindow -Wait`])
|
||||||
}
|
}
|
||||||
return juliaInstallationPath
|
return tempInstallDir
|
||||||
case 'darwin':
|
case 'darwin':
|
||||||
await exec.exec('hdiutil', ['attach', juliaDownloadPath])
|
await exec.exec('hdiutil', ['attach', juliaDownloadPath])
|
||||||
await exec.exec('mkdir', [`${process.env.HOME}/julia`])
|
await exec.exec('/bin/bash', ['-c', `cp -a /Volumes/Julia-*/Julia-*.app/Contents/Resources/julia ${tempInstallDir}`])
|
||||||
await exec.exec('/bin/bash', ['-c', `cp -a /Volumes/Julia-*/Julia-*.app/Contents/Resources/julia ${process.env.HOME}`])
|
return path.join(tempInstallDir, 'julia')
|
||||||
return `${process.env.HOME}/julia`
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Platform ${osPlat} is not supported`)
|
throw new Error(`Platform ${osPlat} is not supported`)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import * as core from '@actions/core'
|
|||||||
import * as exec from '@actions/exec'
|
import * as exec from '@actions/exec'
|
||||||
import * as tc from '@actions/tool-cache'
|
import * as tc from '@actions/tool-cache'
|
||||||
|
|
||||||
|
import * as fs from 'fs'
|
||||||
import * as https from 'https'
|
import * as https from 'https'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
|
|
||||||
@@ -43,7 +44,8 @@ async function run() {
|
|||||||
throw new Error(`Arch input must not be null`)
|
throw new Error(`Arch input must not be null`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const availableReleases = installer.juliaVersions
|
const versionInfo = await installer.getJuliaVersionInfo()
|
||||||
|
const availableReleases = await installer.getJuliaVersions(versionInfo)
|
||||||
const version = installer.getJuliaVersion(availableReleases, versionInput)
|
const version = installer.getJuliaVersion(availableReleases, versionInput)
|
||||||
core.debug(`selected Julia version: ${arch}/${version}`)
|
core.debug(`selected Julia version: ${arch}/${version}`)
|
||||||
|
|
||||||
@@ -52,18 +54,24 @@ async function run() {
|
|||||||
juliaPath = tc.find('julia', version, arch)
|
juliaPath = tc.find('julia', version, arch)
|
||||||
|
|
||||||
if (!juliaPath) {
|
if (!juliaPath) {
|
||||||
core.debug(`could not find Julia ${version} in cache`)
|
core.debug(`could not find Julia ${arch}/${version} in cache`)
|
||||||
const juliaInstallationPath = await installer.installJulia(version, arch);
|
const juliaInstallationPath = await installer.installJulia(versionInfo, version, arch)
|
||||||
|
|
||||||
// Add it to cache
|
// Add it to cache
|
||||||
juliaPath = await tc.cacheDir(juliaInstallationPath, 'julia', version, arch)
|
juliaPath = await tc.cacheDir(juliaInstallationPath, 'julia', version, arch)
|
||||||
core.debug(`added Julia to cache: ${juliaPath}`)
|
core.debug(`added Julia to cache: ${juliaPath}`)
|
||||||
|
|
||||||
|
// Remove temporary dir
|
||||||
|
fs.rmdirSync(juliaInstallationPath, {recursive: true})
|
||||||
} else {
|
} else {
|
||||||
core.debug(`using cached version of Julia: ${juliaPath}`)
|
core.debug(`using cached version of Julia: ${juliaPath}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add it to PATH
|
// Add it to PATH
|
||||||
core.addPath(path.join(juliaPath, 'bin'))
|
core.addPath(path.join(juliaPath, 'bin'))
|
||||||
|
|
||||||
|
// Set output
|
||||||
|
core.setOutput('julia-bindir', path.join(juliaPath, 'bin'))
|
||||||
|
|
||||||
// Test if Julia has been installed
|
// Test if Julia has been installed
|
||||||
exec.exec('julia', ['--version'])
|
exec.exec('julia', ['--version'])
|
||||||
|
|||||||
Reference in New Issue
Block a user