setup-hugo/src/hugo.ts

170 lines
4.7 KiB
TypeScript

import * as core from '@actions/core'
import { Hugo } from './constants'
import { IGithubRelease, IReleaseLookup } from './asset-lookup'
import { Platform } from './os'
import { components } from '@octokit/openapi-types'
import * as tc from '@actions/tool-cache'
import path from 'path'
import * as os from 'node:os'
import { mv, rmRF } from '@actions/io'
import { randomUUID } from 'crypto'
import { errorMsg } from './utils/error'
export interface IHugoInstallCommand {
version?: string
extended?: boolean
withDeploy?: boolean
}
export class HugoInstaller {
private readonly releaseLookup: IReleaseLookup
private readonly platform: Platform
constructor(releaseLookup: IReleaseLookup, platform?: Platform) {
this.platform = platform ?? new Platform()
this.releaseLookup = releaseLookup
}
async install(cmd: IHugoInstallCommand): Promise<void> {
const release = await this.releaseLookup.getRelease(
Hugo.Org,
Hugo.Repo,
cmd.version,
HugoReleaseTransformer
)
core.debug(`Hugo extended: ${cmd.extended ?? false}`)
core.debug(`Hugo with deploy: ${cmd.withDeploy ?? false}`)
core.debug(`Operating System: ${this.platform.os}`)
core.debug(`Processor Architecture: ${this.platform.arch}`)
const hugoBinName = this.platform.binaryName(Hugo.CmdName)
const tmpDir = os.tmpdir()
let versionSpec = release.tag_name
if (cmd.extended) {
versionSpec = `${release.tag_name}+extended`
} else if (cmd.withDeploy) {
versionSpec = `${release.tag_name}+extended+withdeploy`
}
try {
const cachedTool = tc.find(Hugo.Name, versionSpec, this.platform.arch)
if (cachedTool) {
core.addPath(cachedTool)
return
}
} catch (e) {
core.warning(`Failed to lookup tool in cache: ${errorMsg(e)}`)
}
const toolUrl = release.assetUrl(
this.platform,
cmd.extended,
cmd.withDeploy
)
if (!toolUrl) {
throw new Error('No matching URL detected for given platform')
}
const destPath = path.join(
tmpDir,
`hugo_${randomUUID()}${this.platform.archiveExtension()}`
)
await tc.downloadTool(toolUrl, destPath)
core.debug(`Extract archive: ${destPath}`)
if (this.platform.isWindows()) {
await tc.extractZip(destPath, tmpDir)
} else {
await tc.extractTar(destPath, tmpDir)
}
await rmRF(destPath)
try {
const cachedHugoPath = await tc.cacheFile(
path.join(tmpDir, hugoBinName),
hugoBinName,
Hugo.Name,
versionSpec,
this.platform.arch
)
core.addPath(cachedHugoPath)
} catch (e) {
core.warning(`Failed to cache Hugo install: ${errorMsg(e)}`)
const binDir = await this.platform.ensureBinDir()
core.debug(`move binaries to binDir: ${binDir}`)
await mv(path.join(tmpDir, hugoBinName), binDir)
core.addPath(binDir)
}
}
}
export const HugoReleaseTransformer = {
map(release: components['schemas']['release']): HugoRelease {
return new HugoRelease(release.tag_name.replace('v', ''), release.assets)
}
}
export class HugoRelease implements IGithubRelease {
private static readonly keyReplacementRegex = new RegExp(
'hugo_(extended_)*(withdeploy_)*(\\d+.\\d+.\\d+)_'
)
readonly tag_name: string
private readonly defaultAssets: Map<string, string>
private readonly extendedAssets: Map<string, string>
private readonly withDeployAssets: Map<string, string>
constructor(
tag_name: string,
assets: components['schemas']['release']['assets']
) {
this.tag_name = tag_name
this.defaultAssets = new Map<string, string>()
this.extendedAssets = new Map<string, string>()
this.withDeployAssets = new Map<string, string>()
for (const asset of assets) {
if (asset.name.includes('extended_withdeploy')) {
this.withDeployAssets.set(
asset.name.replace(HugoRelease.keyReplacementRegex, ''),
asset.browser_download_url
)
} else if (asset.name.includes('extended')) {
this.extendedAssets.set(
asset.name.replace(HugoRelease.keyReplacementRegex, ''),
asset.browser_download_url
)
} else {
this.defaultAssets.set(
asset.name.replace(HugoRelease.keyReplacementRegex, ''),
asset.browser_download_url
)
}
}
}
assetUrl(
platform: Platform,
extended?: boolean,
withDeploy?: boolean
): string | undefined {
let assets = this.defaultAssets
if (extended) {
assets = this.extendedAssets
} else if (withDeploy) {
assets = this.withDeployAssets
}
const arch = platform.os === 'darwin' ? 'universal' : platform.arch
const key = `${platform.os}-${arch}${platform.archiveExtension()}`
return assets.get(key)
}
}