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'
|
|
|
|
import * as cache from '@actions/cache'
|
2021-09-11 14:08:18 -04:00
|
|
|
import * as exec from '@actions/exec'
|
2021-08-22 22:14:47 -04:00
|
|
|
|
2021-09-06 13:16:08 -04:00
|
|
|
import {AbstractCache} from './cache-utils'
|
2021-08-22 22:14:47 -04:00
|
|
|
|
2021-09-12 12:08:34 -04:00
|
|
|
// Paths to artifacts that are common to all/many Gradle User Home caches
|
|
|
|
// These artifacts are cached separately to avoid blowing out the size of each GUH cache
|
|
|
|
const COMMON_ARTIFACT_PATHS = [
|
2021-09-11 16:50:34 -04:00
|
|
|
'~/.gradle/wrapper/dists/*/*/*.zip',
|
2021-09-11 17:40:26 -04:00
|
|
|
'~/.gradle/caches/*/generated-gradle-jars/*.jar',
|
|
|
|
'~/.gradle/caches/modules-*/files-*/**/*.jar'
|
2021-09-11 16:50:34 -04:00
|
|
|
]
|
2021-09-12 12:08:34 -04:00
|
|
|
|
|
|
|
// When a common artifact is cached separately, it is replaced by a marker file to allow for restore.
|
|
|
|
const MARKER_FILE_EXTENSION = '.cached'
|
|
|
|
|
|
|
|
// Which paths under Gradle User Home should be cached
|
|
|
|
// TODO: This should adapt for the `GRADLE_USER_HOME` environment variable
|
|
|
|
const CACHE_PATH = [
|
|
|
|
'~/.gradle/caches', // All directories in 'caches'
|
|
|
|
'~/.gradle/notifications', // Prevent the re-rendering of first-use message for version
|
|
|
|
`~/.gradle/wrapper/dists/*/*/*.zip${MARKER_FILE_EXTENSION}` // Only wrapper zips are required : We do not want to cache the exploded distributions
|
|
|
|
]
|
2021-09-11 16:50:34 -04:00
|
|
|
|
2021-09-06 13:16:08 -04:00
|
|
|
export class GradleUserHomeCache extends AbstractCache {
|
|
|
|
constructor() {
|
|
|
|
super('gradle', 'Gradle User Home')
|
2021-08-22 22:14:47 -04:00
|
|
|
}
|
|
|
|
|
2021-09-11 11:10:44 -04:00
|
|
|
async restore(): Promise<void> {
|
|
|
|
await super.restore()
|
2021-09-12 12:08:34 -04:00
|
|
|
await this.reportCacheEntrySize('excluding common artifacts')
|
|
|
|
await this.restoreCommonArtifacts()
|
|
|
|
await this.reportCacheEntrySize('including common artifacts')
|
2021-09-11 14:08:18 -04:00
|
|
|
}
|
2021-09-11 11:10:44 -04:00
|
|
|
|
2021-09-12 12:08:34 -04:00
|
|
|
private async restoreCommonArtifacts(): Promise<void> {
|
|
|
|
const markerFilePatterns = COMMON_ARTIFACT_PATHS.map(targetPath => {
|
2021-09-11 16:50:34 -04:00
|
|
|
return targetPath + MARKER_FILE_EXTENSION
|
|
|
|
}).join('\n')
|
2021-09-11 11:10:44 -04:00
|
|
|
|
2021-09-11 16:50:34 -04:00
|
|
|
const globber = await glob.create(markerFilePatterns)
|
|
|
|
const markerFiles = await globber.glob()
|
2021-09-11 14:08:18 -04:00
|
|
|
|
2021-09-11 22:56:40 -04:00
|
|
|
const processes: Promise<void>[] = []
|
2021-09-11 16:50:34 -04:00
|
|
|
for (const markerFile of markerFiles) {
|
2021-09-12 12:08:34 -04:00
|
|
|
const p = this.restoreCommonArtifact(markerFile)
|
2021-09-11 22:56:40 -04:00
|
|
|
processes.push(p)
|
|
|
|
}
|
|
|
|
await Promise.all(processes)
|
|
|
|
}
|
|
|
|
|
2021-09-12 12:08:34 -04:00
|
|
|
private async restoreCommonArtifact(markerFile: string): Promise<void> {
|
|
|
|
const artifactFile = markerFile.substring(
|
2021-09-11 22:56:40 -04:00
|
|
|
0,
|
|
|
|
markerFile.length - MARKER_FILE_EXTENSION.length
|
|
|
|
)
|
2021-09-12 12:08:34 -04:00
|
|
|
core.debug(
|
|
|
|
`Found marker file: ${markerFile}. Will attempt to restore ${artifactFile}`
|
|
|
|
)
|
2021-09-11 22:56:40 -04:00
|
|
|
|
2021-09-12 12:08:34 -04:00
|
|
|
if (!fs.existsSync(artifactFile)) {
|
|
|
|
const key = path.relative(this.getGradleUserHome(), artifactFile)
|
|
|
|
const cacheKey = `gradle-artifact-${key}`
|
2021-09-11 22:56:40 -04:00
|
|
|
|
2021-09-12 12:08:34 -04:00
|
|
|
const restoreKey = await cache.restoreCache(
|
|
|
|
[artifactFile],
|
|
|
|
cacheKey
|
|
|
|
)
|
2021-09-11 22:56:40 -04:00
|
|
|
if (restoreKey) {
|
2021-09-12 12:08:34 -04:00
|
|
|
core.info(`Restored ${cacheKey} from cache to ${artifactFile}`)
|
2021-09-11 14:08:18 -04:00
|
|
|
} else {
|
2021-09-12 12:08:34 -04:00
|
|
|
core.warning(
|
|
|
|
`Failed to restore from ${cacheKey} to ${artifactFile}`
|
|
|
|
)
|
2021-09-11 14:08:18 -04:00
|
|
|
}
|
2021-09-11 22:56:40 -04:00
|
|
|
} else {
|
2021-09-12 12:08:34 -04:00
|
|
|
core.debug(
|
|
|
|
`Artifact file already exists, not restoring: ${artifactFile}`
|
|
|
|
)
|
2021-09-11 14:08:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-12 12:08:34 -04:00
|
|
|
private async reportCacheEntrySize(label: string): Promise<void> {
|
2021-09-11 14:08:18 -04:00
|
|
|
const gradleUserHome = path.resolve(os.homedir(), '.gradle')
|
|
|
|
if (!fs.existsSync(gradleUserHome)) {
|
|
|
|
return
|
|
|
|
}
|
2021-09-12 12:08:34 -04:00
|
|
|
core.info(`Gradle User Home cache entry: ${label}`)
|
2021-09-11 14:08:18 -04:00
|
|
|
await exec.exec('du', ['-h', '-c', '-t', '5M'], {
|
|
|
|
cwd: gradleUserHome,
|
|
|
|
ignoreReturnCode: true
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-09-11 11:10:44 -04:00
|
|
|
async save(): Promise<void> {
|
2021-09-12 12:08:34 -04:00
|
|
|
await this.saveCommonArtifacts()
|
2021-09-11 14:08:18 -04:00
|
|
|
await super.save()
|
|
|
|
}
|
|
|
|
|
2021-09-12 12:08:34 -04:00
|
|
|
private async saveCommonArtifacts(): Promise<void> {
|
|
|
|
const artifactFilePatterns = COMMON_ARTIFACT_PATHS.join('\n')
|
|
|
|
const globber = await glob.create(artifactFilePatterns)
|
|
|
|
const commonArtifactFiles = await globber.glob()
|
2021-09-11 11:10:44 -04:00
|
|
|
|
2021-09-11 22:56:40 -04:00
|
|
|
const processes: Promise<void>[] = []
|
2021-09-12 12:08:34 -04:00
|
|
|
for (const artifactFile of commonArtifactFiles) {
|
|
|
|
const p = this.saveCommonArtifact(artifactFile)
|
2021-09-11 22:56:40 -04:00
|
|
|
processes.push(p)
|
|
|
|
}
|
|
|
|
await Promise.all(processes)
|
|
|
|
}
|
2021-09-11 11:10:44 -04:00
|
|
|
|
2021-09-12 12:08:34 -04:00
|
|
|
private async saveCommonArtifact(artifactFile: string): Promise<void> {
|
|
|
|
const markerFile = `${artifactFile}${MARKER_FILE_EXTENSION}`
|
2021-09-11 22:56:40 -04:00
|
|
|
|
|
|
|
if (!fs.existsSync(markerFile)) {
|
2021-09-12 12:08:34 -04:00
|
|
|
const filePath = path.relative(
|
|
|
|
this.getGradleUserHome(),
|
|
|
|
artifactFile
|
|
|
|
)
|
|
|
|
const cacheKey = `gradle-artifact-${filePath}`
|
|
|
|
core.info(`Caching ${artifactFile} with cache key: ${cacheKey}`)
|
2021-09-11 22:56:40 -04:00
|
|
|
try {
|
2021-09-12 12:08:34 -04:00
|
|
|
await cache.saveCache([artifactFile], cacheKey)
|
2021-09-11 22:56:40 -04:00
|
|
|
} catch (error) {
|
|
|
|
// Fail on validation errors or non-errors (the latter to keep Typescript happy)
|
|
|
|
if (
|
|
|
|
error instanceof cache.ValidationError ||
|
|
|
|
!(error instanceof Error)
|
|
|
|
) {
|
|
|
|
throw error
|
2021-09-12 14:28:04 -04:00
|
|
|
} else if (error instanceof cache.ReserveCacheError) {
|
|
|
|
// These are expected if the artifact is already cached
|
|
|
|
this.debug(error.message)
|
|
|
|
} else {
|
|
|
|
core.warning(error.message)
|
2021-09-11 22:56:40 -04:00
|
|
|
}
|
2021-09-11 11:10:44 -04:00
|
|
|
}
|
2021-09-11 14:08:18 -04:00
|
|
|
|
2021-09-12 12:08:34 -04:00
|
|
|
// Write the marker file that will stand in place of the original
|
|
|
|
fs.writeFileSync(markerFile, 'cached')
|
2021-09-11 22:56:40 -04:00
|
|
|
} else {
|
2021-09-12 12:08:34 -04:00
|
|
|
core.debug(
|
|
|
|
`Marker file already exists: ${markerFile}. Not caching ${artifactFile}`
|
|
|
|
)
|
2021-09-11 14:08:18 -04:00
|
|
|
}
|
2021-09-11 22:56:40 -04:00
|
|
|
|
|
|
|
// TODO : Should not need to delete. Just exclude from cache path.
|
2021-09-12 12:08:34 -04:00
|
|
|
// Delete the original artifact file
|
|
|
|
fs.unlinkSync(artifactFile)
|
|
|
|
}
|
|
|
|
|
|
|
|
protected getGradleUserHome(): string {
|
|
|
|
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-11 16:50:34 -04:00
|
|
|
const dir = path.resolve(this.getGradleUserHome(), '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[] {
|
|
|
|
return CACHE_PATH
|
2021-08-22 22:14:47 -04:00
|
|
|
}
|
|
|
|
}
|