2021-08-22 22:14:47 -04:00
|
|
|
import path from 'path'
|
|
|
|
import fs from 'fs'
|
|
|
|
import os from 'os'
|
2021-09-11 11:10:44 -04:00
|
|
|
import * as core from '@actions/core'
|
|
|
|
import * as glob from '@actions/glob'
|
2021-09-11 14:08:18 -04:00
|
|
|
import * as exec from '@actions/exec'
|
2021-08-22 22:14:47 -04:00
|
|
|
|
2021-10-04 17:59:08 -04:00
|
|
|
import {AbstractCache, hashFileNames, tryDelete} from './cache-utils'
|
2021-09-12 12:08:34 -04:00
|
|
|
|
|
|
|
// Which paths under Gradle User Home should be cached
|
2021-09-27 22:57:47 -04:00
|
|
|
const CACHE_PATH = ['caches', 'notifications']
|
2021-09-15 08:36:54 -04:00
|
|
|
|
2021-09-06 13:16:08 -04:00
|
|
|
export class GradleUserHomeCache extends AbstractCache {
|
2021-09-27 22:57:47 -04:00
|
|
|
private gradleUserHome: string
|
|
|
|
|
|
|
|
constructor(rootDir: string) {
|
2021-09-06 13:16:08 -04:00
|
|
|
super('gradle', 'Gradle User Home')
|
2021-09-27 22:57:47 -04:00
|
|
|
this.gradleUserHome = this.determineGradleUserHome(rootDir)
|
2021-08-22 22:14:47 -04:00
|
|
|
}
|
|
|
|
|
2021-09-15 13:20:33 -04:00
|
|
|
async afterRestore(): Promise<void> {
|
2021-10-15 13:11:05 -04:00
|
|
|
await this.reportGradleUserHomeSize('as restored from cache')
|
2021-10-15 14:34:38 -04:00
|
|
|
await this.restoreArtifactBundles()
|
2021-10-15 13:11:05 -04:00
|
|
|
await this.reportGradleUserHomeSize('after restoring common artifacts')
|
2021-09-11 14:08:18 -04:00
|
|
|
}
|
2021-09-11 11:10:44 -04:00
|
|
|
|
2021-10-15 14:34:38 -04:00
|
|
|
private async restoreArtifactBundles(): Promise<void> {
|
2021-09-11 22:56:40 -04:00
|
|
|
const processes: Promise<void>[] = []
|
2021-10-15 14:34:38 -04:00
|
|
|
for (const [bundle, pattern] of this.getArtifactBundles()) {
|
|
|
|
const p = this.restoreArtifactBundle(bundle, pattern)
|
2021-09-12 16:08:22 -04:00
|
|
|
// Run sequentially when debugging enabled
|
|
|
|
if (this.cacheDebuggingEnabled) {
|
|
|
|
await p
|
|
|
|
}
|
2021-09-11 22:56:40 -04:00
|
|
|
processes.push(p)
|
|
|
|
}
|
2021-09-12 16:08:22 -04:00
|
|
|
|
2021-09-11 22:56:40 -04:00
|
|
|
await Promise.all(processes)
|
|
|
|
}
|
|
|
|
|
2021-10-15 14:34:38 -04:00
|
|
|
private async restoreArtifactBundle(
|
2021-09-15 08:36:54 -04:00
|
|
|
bundle: string,
|
2021-09-27 22:57:47 -04:00
|
|
|
artifactPath: string
|
2021-09-15 08:36:54 -04:00
|
|
|
): Promise<void> {
|
2021-10-15 14:34:38 -04:00
|
|
|
const bundleMetaFile = this.getBundleMetaFile(bundle)
|
|
|
|
if (fs.existsSync(bundleMetaFile)) {
|
|
|
|
const cacheKey = fs.readFileSync(bundleMetaFile, 'utf-8').trim()
|
2021-09-27 22:57:47 -04:00
|
|
|
const restoreKey = await this.restoreCache([artifactPath], cacheKey)
|
2021-09-14 15:30:23 -04:00
|
|
|
if (restoreKey) {
|
2021-09-15 17:48:55 -04:00
|
|
|
core.info(
|
2021-09-27 22:57:47 -04:00
|
|
|
`Restored ${bundle} with key ${cacheKey} to ${artifactPath}`
|
2021-09-15 08:36:54 -04:00
|
|
|
)
|
2021-09-14 15:30:23 -04:00
|
|
|
} else {
|
|
|
|
this.debug(
|
2021-10-15 13:11:05 -04:00
|
|
|
`Did not restore ${bundle} with key ${cacheKey} to ${artifactPath}`
|
2021-09-12 12:08:34 -04:00
|
|
|
)
|
2021-09-11 14:08:18 -04:00
|
|
|
}
|
2021-09-11 22:56:40 -04:00
|
|
|
} else {
|
2021-09-12 16:08:22 -04:00
|
|
|
this.debug(
|
2021-10-15 14:34:38 -04:00
|
|
|
`No metafile found to restore ${bundle}: ${bundleMetaFile}`
|
2021-09-12 12:08:34 -04:00
|
|
|
)
|
2021-09-11 14:08:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-15 14:34:38 -04:00
|
|
|
private getBundleMetaFile(name: string): string {
|
2021-09-15 08:36:54 -04:00
|
|
|
return path.resolve(
|
2021-09-27 22:57:47 -04:00
|
|
|
this.gradleUserHome,
|
2021-09-15 08:36:54 -04:00
|
|
|
'caches',
|
|
|
|
`.gradle-build-action.${name}.cache`
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-09-15 13:20:33 -04:00
|
|
|
async beforeSave(): Promise<void> {
|
2021-10-15 13:11:05 -04:00
|
|
|
await this.reportGradleUserHomeSize('before saving common artifacts')
|
2021-10-15 14:34:38 -04:00
|
|
|
await this.saveArtifactBundles()
|
2021-10-15 13:11:05 -04:00
|
|
|
await this.reportGradleUserHomeSize('after saving common artifacts')
|
2021-09-11 14:08:18 -04:00
|
|
|
}
|
|
|
|
|
2021-10-15 14:34:38 -04:00
|
|
|
private async saveArtifactBundles(): Promise<void> {
|
2021-09-11 22:56:40 -04:00
|
|
|
const processes: Promise<void>[] = []
|
2021-10-15 14:34:38 -04:00
|
|
|
for (const [bundle, pattern] of this.getArtifactBundles()) {
|
|
|
|
const p = this.saveArtifactBundle(bundle, pattern)
|
2021-09-12 16:08:22 -04:00
|
|
|
// Run sequentially when debugging enabled
|
|
|
|
if (this.cacheDebuggingEnabled) {
|
|
|
|
await p
|
|
|
|
}
|
2021-09-11 22:56:40 -04:00
|
|
|
processes.push(p)
|
|
|
|
}
|
2021-09-12 16:08:22 -04:00
|
|
|
|
2021-09-11 22:56:40 -04:00
|
|
|
await Promise.all(processes)
|
|
|
|
}
|
2021-09-11 11:10:44 -04:00
|
|
|
|
2021-10-15 14:34:38 -04:00
|
|
|
private async saveArtifactBundle(
|
2021-09-15 08:36:54 -04:00
|
|
|
bundle: string,
|
2021-09-27 22:57:47 -04:00
|
|
|
artifactPath: string
|
2021-09-15 08:36:54 -04:00
|
|
|
): Promise<void> {
|
2021-10-15 14:34:38 -04:00
|
|
|
const bundleMetaFile = this.getBundleMetaFile(bundle)
|
2021-09-11 22:56:40 -04:00
|
|
|
|
2021-09-27 22:57:47 -04:00
|
|
|
const globber = await glob.create(artifactPath)
|
2021-10-15 14:34:38 -04:00
|
|
|
const bundleFiles = await globber.glob()
|
2021-09-12 16:08:22 -04:00
|
|
|
|
2021-09-15 08:36:54 -04:00
|
|
|
// Handle no matching files
|
2021-10-15 14:34:38 -04:00
|
|
|
if (bundleFiles.length === 0) {
|
2021-09-15 08:36:54 -04:00
|
|
|
this.debug(`No files found to cache for ${bundle}`)
|
2021-10-15 14:34:38 -04:00
|
|
|
if (fs.existsSync(bundleMetaFile)) {
|
|
|
|
tryDelete(bundleMetaFile)
|
2021-09-15 08:36:54 -04:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2021-09-11 14:08:18 -04:00
|
|
|
|
2021-10-15 14:34:38 -04:00
|
|
|
const previouslyRestoredKey = fs.existsSync(bundleMetaFile)
|
|
|
|
? fs.readFileSync(bundleMetaFile, 'utf-8').trim()
|
2021-09-15 08:36:54 -04:00
|
|
|
: ''
|
2021-10-15 14:34:38 -04:00
|
|
|
const cacheKey = this.createCacheKey(bundle, bundleFiles)
|
2021-09-15 08:36:54 -04:00
|
|
|
|
|
|
|
if (previouslyRestoredKey === cacheKey) {
|
2021-09-12 16:08:22 -04:00
|
|
|
this.debug(
|
2021-09-15 08:36:54 -04:00
|
|
|
`No change to previously restored ${bundle}. Not caching.`
|
2021-09-12 12:08:34 -04:00
|
|
|
)
|
2021-09-15 08:36:54 -04:00
|
|
|
} else {
|
2021-09-15 17:48:55 -04:00
|
|
|
core.info(`Caching ${bundle} with cache key: ${cacheKey}`)
|
2021-09-27 22:57:47 -04:00
|
|
|
await this.saveCache([artifactPath], cacheKey)
|
2021-09-15 08:36:54 -04:00
|
|
|
|
2021-10-15 14:34:38 -04:00
|
|
|
this.debug(`Writing cache metafile: ${bundleMetaFile}`)
|
|
|
|
fs.writeFileSync(bundleMetaFile, cacheKey)
|
2021-09-11 14:08:18 -04:00
|
|
|
}
|
2021-09-11 22:56:40 -04:00
|
|
|
|
2021-10-15 14:34:38 -04:00
|
|
|
for (const file of bundleFiles) {
|
2021-10-04 17:59:08 -04:00
|
|
|
tryDelete(file)
|
2021-09-15 08:36:54 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-27 23:05:17 -04:00
|
|
|
protected createCacheKey(bundle: string, files: string[]): string {
|
2021-09-15 08:36:54 -04:00
|
|
|
const cacheKeyPrefix = process.env['CACHE_KEY_PREFIX'] || ''
|
2021-09-27 23:05:17 -04:00
|
|
|
const relativeFiles = files.map(x =>
|
|
|
|
path.relative(this.gradleUserHome, x)
|
|
|
|
)
|
|
|
|
const key = hashFileNames(relativeFiles)
|
|
|
|
|
2021-10-15 13:11:05 -04:00
|
|
|
this.debug(
|
|
|
|
`Generating cache key for ${bundle} from files: ${relativeFiles}`
|
|
|
|
)
|
|
|
|
|
2021-09-15 17:48:55 -04:00
|
|
|
return `${cacheKeyPrefix}${bundle}-${key}`
|
2021-09-12 12:08:34 -04:00
|
|
|
}
|
|
|
|
|
2021-09-27 22:57:47 -04:00
|
|
|
protected determineGradleUserHome(rootDir: string): string {
|
|
|
|
const customGradleUserHome = process.env['GRADLE_USER_HOME']
|
|
|
|
if (customGradleUserHome) {
|
|
|
|
return path.resolve(rootDir, customGradleUserHome)
|
|
|
|
}
|
|
|
|
|
2021-09-12 12:08:34 -04:00
|
|
|
return path.resolve(os.homedir(), '.gradle')
|
2021-09-11 11:10:44 -04:00
|
|
|
}
|
|
|
|
|
2021-09-06 13:16:08 -04:00
|
|
|
protected cacheOutputExists(): boolean {
|
|
|
|
// Need to check for 'caches' directory to avoid incorrect detection on MacOS agents
|
2021-09-27 22:57:47 -04:00
|
|
|
const dir = path.resolve(this.gradleUserHome, 'caches')
|
2021-09-06 13:16:08 -04:00
|
|
|
return fs.existsSync(dir)
|
2021-08-22 22:14:47 -04:00
|
|
|
}
|
|
|
|
|
2021-09-06 13:16:08 -04:00
|
|
|
protected getCachePath(): string[] {
|
2021-09-27 22:57:47 -04:00
|
|
|
return CACHE_PATH.map(x => path.resolve(this.gradleUserHome, x))
|
|
|
|
}
|
|
|
|
|
2021-10-15 14:34:38 -04:00
|
|
|
private getArtifactBundles(): Map<string, string> {
|
2021-10-15 14:45:15 -04:00
|
|
|
const artifactBundleDefinition = core.getInput('cache-artifact-bundles')
|
|
|
|
this.debug(
|
|
|
|
`Using artifact bundle definition: ${artifactBundleDefinition}`
|
|
|
|
)
|
|
|
|
const artifactBundles = JSON.parse(artifactBundleDefinition)
|
2021-09-27 22:57:47 -04:00
|
|
|
return new Map(
|
2021-10-15 14:45:15 -04:00
|
|
|
Array.from(artifactBundles, ([key, value]) => [
|
2021-09-27 22:57:47 -04:00
|
|
|
key,
|
|
|
|
path.resolve(this.gradleUserHome, value)
|
|
|
|
])
|
|
|
|
)
|
2021-08-22 22:14:47 -04:00
|
|
|
}
|
2021-10-15 13:11:05 -04:00
|
|
|
|
|
|
|
private async reportGradleUserHomeSize(label: string): Promise<void> {
|
|
|
|
if (!this.cacheDebuggingEnabled) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if (!fs.existsSync(this.gradleUserHome)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
const result = await exec.getExecOutput(
|
|
|
|
'du',
|
|
|
|
['-h', '-c', '-t', '5M'],
|
|
|
|
{
|
|
|
|
cwd: this.gradleUserHome,
|
|
|
|
silent: true,
|
|
|
|
ignoreReturnCode: true
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
core.info(`Gradle User Home cache entry (directories >5M): ${label}`)
|
|
|
|
|
|
|
|
core.info(
|
|
|
|
result.stdout
|
|
|
|
.trimEnd()
|
|
|
|
.replace(/\t/g, ' ')
|
|
|
|
.split('\n')
|
|
|
|
.map(it => {
|
|
|
|
return ` ${it}`
|
|
|
|
})
|
|
|
|
.join('\n')
|
|
|
|
)
|
|
|
|
|
|
|
|
core.info('-----------------------')
|
|
|
|
}
|
2021-08-22 22:14:47 -04:00
|
|
|
}
|