Skip to content

Commit

Permalink
Add support for offline compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
delasy committed Jan 26, 2025
1 parent a4a000b commit 329451e
Show file tree
Hide file tree
Showing 8 changed files with 1,549 additions and 1,655 deletions.
2,923 changes: 1,313 additions & 1,610 deletions dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions dist/licenses.txt
Original file line number Diff line number Diff line change
Expand Up @@ -638,11 +638,11 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


uuid
unicorn-magic
MIT
The MIT License (MIT)
MIT License

Copyright (c) 2010-2020 Robert Kieffer and other contributors
Copyright (c) Sindre Sorhus <[email protected]> (https://sindresorhus.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

Expand Down
2 changes: 1 addition & 1 deletion dist/sourcemap-register.js

Large diffs are not rendered by default.

89 changes: 89 additions & 0 deletions src/cmake.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { execa } from 'execa'

export interface CMakeVariable {
name: string
type?: string
value: string
}

export interface CMakeGenerateOptions {
buildPath?: string
generator?: string
variables?: CMakeVariable[]
}

export interface CMakeBuildOptions {
config?: string
preset?: string
target?: string
}

export interface CMakeInstallOptions {
config?: string
prefix?: string
}

// https://cmake.org/cmake/help/latest/manual/cmake.1.html
export class CMake {
public async generate (sourcePath: string, options: CMakeGenerateOptions = {}): Promise<void> {
const args = [sourcePath]

if (options.buildPath !== undefined) {
args.push('-B', options.buildPath)
}

if (options.generator !== undefined) {
args.push('-G', options.generator)
}

if (options.variables !== undefined) {
args.push(...this.variables(options.variables))
}

await execa('cmake', args)
}

public async build (dir: string, options: CMakeBuildOptions = {}): Promise<void> {
const args = ['--build', dir]

if (options.config !== undefined) {
args.push('--config', options.config)
}

if (options.preset !== undefined) {
args.push('--preset', options.preset)
}

if (options.target !== undefined) {
args.push('--target', options.target)
}

await execa('cmake', args)
}

public async install (dir: string, options: CMakeInstallOptions = {}): Promise<void> {
const args = ['--install', dir]

if (options.config !== undefined) {
args.push('--config', options.config)
}

if (options.prefix !== undefined) {
args.push('--prefix', options.prefix)
}

await execa('cmake', args)
}

private variables (variables: CMakeVariable[]): string[] {
return variables.map((variable) => {
if (variable.type !== undefined) {
return ['-D', `${variable.name}:${variable.type}=${variable.value}`]
}

return ['-D', `${variable.name}=${variable.value}`]
}).flat()
}
}

export const cmake = new CMake()
31 changes: 31 additions & 0 deletions src/git.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { execa } from 'execa'

export interface GitCloneOptions {
depth?: number
directory?: string
singleBranch?: boolean
}

export class Git {
public async clone (repository: string, options: GitCloneOptions = {}): Promise<void> {
const args = ['clone']

if (options.depth !== undefined) {
args.push('--depth', options.depth.toString())
}

if (options.singleBranch !== undefined) {
args.push('--single-branch')
}

args.push(repository)

if (options.directory !== undefined) {
args.push(options.directory)
}

await execa('git', args)
}
}

export const git = new Git()
101 changes: 70 additions & 31 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,78 @@ import * as core from '@actions/core'
import * as fs from 'fs'
import * as path from 'path'
import * as tc from '@actions/tool-cache'
import { downloadFilename, downloadUrl, getInstalledVersion, platformName } from './utils'
import * as utils from './utils'
import { cmake } from './cmake'
import { git } from './git'

async function installCompiler (version: string): Promise<void> {
core.debug('Installing The compiler dependencies ...')

const tempDirectory = utils.tempDirectory()
const installationDirectory = path.join(tempDirectory, `the-${version}-deps`)

const dependenciesTarballPath = await tc.downloadTool('https://cdn.thelang.io/deps.tar.gz')
const dependenciesPath = await tc.extractTar(dependenciesTarballPath, path.join(installationDirectory, path.join(installationDirectory, 'deps')))

core.exportVariable('DEPS_DIR', path.join(dependenciesPath, utils.dependenciesPath()))

core.debug('Installing The compiler ...')

const compilerDirectory = path.join(installationDirectory, 'the')
const compilerBuildDirectory = path.join(compilerDirectory, 'build')
const compilerTargetLocation = path.join(utils.homeDirectory(), '.the', 'bin', 'compiler')

await git.clone('https://github.com/thelang-io/the.git', {
depth: 1,
directory: compilerDirectory,
singleBranch: true
})

await cmake.generate(compilerDirectory, {
buildPath: compilerBuildDirectory,
variables: [
{ name: 'CMAKE_BUILD_TYPE', value: 'Release' }
]
})

await cmake.build(compilerBuildDirectory, { target: 'the' })
fs.copyFileSync(path.join(compilerBuildDirectory, 'the'), compilerTargetLocation)
}

async function install (version: string): Promise<string> {
core.debug(`Could not find The programming language version ${version} in cache, downloading it ...`)

const tempDirectory = utils.tempDirectory()
const installationDirectory = path.join(tempDirectory, `the-${version}`)
const installationPath = await tc.downloadTool(utils.cliUrl(version), path.join(installationDirectory, utils.cliFilename()))

if (utils.platformName() !== 'windows') {
fs.chmodSync(installationPath, 0o755)
}

const cachedPath = await tc.cacheDir(installationDirectory, 'the', version)
core.debug(`Cached The programming language version ${version} to ${cachedPath}.`)

return cachedPath
}

async function run (): Promise<void> {
try {
const tempDirectory = process.env.RUNNER_TEMP ?? ''

if (tempDirectory === '') {
throw new Error('GitHub runner temporary directory is not set')
}

const version = core.getInput('the-version', { required: true })
let cachedPath = tc.find('the', version)

if (cachedPath.length === 0) {
core.debug(`Could not find The programming language version ${version} in cache, downloading it ...`)
const installationDirectory = path.join(tempDirectory, `the-${version}`)
const installationPath = await tc.downloadTool(downloadUrl(version), path.join(installationDirectory, downloadFilename()))

if (platformName() !== 'windows') {
fs.chmodSync(installationPath, 0o755)
}

cachedPath = await tc.cacheDir(installationDirectory, 'the', version)
core.debug(`Cached The programming language version ${version} to ${cachedPath}.`)
}

core.addPath(cachedPath)
core.setOutput('the-version', getInstalledVersion())
} catch (err) {
if (err instanceof Error) {
core.setFailed(err.message)
}
const version = core.getInput('the-version', { required: true })
let cachedPath = tc.find('the', version)

if (cachedPath.length === 0) {
cachedPath = await install(version)
await installCompiler(version)
}

core.addPath(cachedPath)
core.setOutput('the-version', utils.installedVersion())
}

run().catch(console.error)
run().catch((err) => {
if (err instanceof Error) {
core.setFailed(err.message)
} else if (typeof err === 'string') {
core.setFailed(err)
}
})
50 changes: 41 additions & 9 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { execa } from 'execa'
import * as path from 'path'

export function downloadFilename (): string {
export function cliFilename (): string {
return 'the' + (platformName() === 'windows' ? '.exe' : '')
}

export function downloadUrl (version: string): string {
export function cliUrl (version: string): string {
const platform = platformName()
const arch = platformArch()
const [major = '', minor = ''] = version.split('.')
Expand All @@ -17,23 +18,33 @@ export function downloadUrl (version: string): string {
}
}

export function extractVersionFromOutput (output: string): string | null {
const [match] = output.match(/Version ([.\d]+) \([\w ]+\)/g) ?? [null]
export function dependenciesPath (): string {
const platform = platformName()
const arch = platformArch()

if (match === null) {
return null
if (platform === 'macos') {
return path.join('native', platform, arch)
}

return path.join('native', platform)
}

export function homeDirectory (): string {
const result = process.env.HOME ?? ''

if (result === '') {
throw new Error('HOME environment variable is not set')
}

const [result] = match.match(/[.\d]+/g) ?? [null]
return result
}

export async function getInstalledVersion (): Promise<string> {
export async function installedVersion (): Promise<string> {
const { stderr, stdout } = await execa('the', ['-v'])
let version = null

if (stderr.length === 0 && stdout.length !== 0) {
version = extractVersionFromOutput(stdout)
version = versionFromOutput(stdout)
}

if (version === null) {
Expand All @@ -60,3 +71,24 @@ export function platformName (): string {
return 'linux'
}
}

export function tempDirectory (): string {
const result = process.env.RUNNER_TEMP ?? ''

if (result === '') {
return path.join(__dirname, 'tmp')
}

return result
}

export function versionFromOutput (output: string): string | null {
const [match] = output.match(/Version ([.\d]+) \([\w ]+\)/g) ?? [null]

if (match === null) {
return null
}

const [result] = match.match(/[.\d]+/g) ?? [null]
return result
}

0 comments on commit 329451e

Please sign in to comment.