2021-12-07 12:29:37 -07:00
|
|
|
import * as core from '@actions/core'
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Collects information on what entries were saved and restored during the action.
|
|
|
|
* This information is used to generate a summary of the cache usage.
|
|
|
|
*/
|
|
|
|
export class CacheListener {
|
|
|
|
cacheEntries: CacheEntryListener[] = []
|
2022-06-02 22:44:08 -06:00
|
|
|
isCacheReadOnly = false
|
|
|
|
isCacheWriteOnly = false
|
2021-12-07 12:29:37 -07:00
|
|
|
|
|
|
|
get fullyRestored(): boolean {
|
|
|
|
return this.cacheEntries.every(x => !x.wasRequestedButNotRestored())
|
|
|
|
}
|
|
|
|
|
|
|
|
entry(name: string): CacheEntryListener {
|
|
|
|
for (const entry of this.cacheEntries) {
|
|
|
|
if (entry.entryName === name) {
|
|
|
|
return entry
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const newEntry = new CacheEntryListener(name)
|
|
|
|
this.cacheEntries.push(newEntry)
|
|
|
|
return newEntry
|
|
|
|
}
|
|
|
|
|
|
|
|
stringify(): string {
|
|
|
|
return JSON.stringify(this)
|
|
|
|
}
|
|
|
|
|
|
|
|
static rehydrate(stringRep: string): CacheListener {
|
2022-01-20 09:36:57 -07:00
|
|
|
if (stringRep === '') {
|
|
|
|
return new CacheListener()
|
|
|
|
}
|
2021-12-07 12:29:37 -07:00
|
|
|
const rehydrated: CacheListener = Object.assign(new CacheListener(), JSON.parse(stringRep))
|
|
|
|
const entries = rehydrated.cacheEntries
|
|
|
|
for (let index = 0; index < entries.length; index++) {
|
|
|
|
const rawEntry = entries[index]
|
|
|
|
entries[index] = Object.assign(new CacheEntryListener(rawEntry.entryName), rawEntry)
|
|
|
|
}
|
|
|
|
return rehydrated
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Collects information on the state of a single cache entry.
|
|
|
|
*/
|
|
|
|
export class CacheEntryListener {
|
|
|
|
entryName: string
|
|
|
|
requestedKey: string | undefined
|
|
|
|
requestedRestoreKeys: string[] | undefined
|
|
|
|
restoredKey: string | undefined
|
|
|
|
restoredSize: number | undefined
|
|
|
|
|
|
|
|
savedKey: string | undefined
|
|
|
|
savedSize: number | undefined
|
|
|
|
|
2022-06-02 22:39:55 -06:00
|
|
|
unchanged: string | undefined
|
|
|
|
|
2021-12-07 12:29:37 -07:00
|
|
|
constructor(entryName: string) {
|
|
|
|
this.entryName = entryName
|
|
|
|
}
|
|
|
|
|
|
|
|
wasRequestedButNotRestored(): boolean {
|
|
|
|
return this.requestedKey !== undefined && this.restoredKey === undefined
|
|
|
|
}
|
|
|
|
|
|
|
|
markRequested(key: string, restoreKeys: string[] = []): CacheEntryListener {
|
|
|
|
this.requestedKey = key
|
|
|
|
this.requestedRestoreKeys = restoreKeys
|
|
|
|
return this
|
|
|
|
}
|
|
|
|
|
|
|
|
markRestored(key: string, size: number | undefined): CacheEntryListener {
|
|
|
|
this.restoredKey = key
|
|
|
|
this.restoredSize = size
|
|
|
|
return this
|
|
|
|
}
|
|
|
|
|
|
|
|
markSaved(key: string, size: number | undefined): CacheEntryListener {
|
|
|
|
this.savedKey = key
|
|
|
|
this.savedSize = size
|
|
|
|
return this
|
|
|
|
}
|
2022-01-19 12:11:51 -07:00
|
|
|
|
|
|
|
markAlreadyExists(key: string): CacheEntryListener {
|
|
|
|
this.savedKey = key
|
|
|
|
this.savedSize = 0
|
|
|
|
return this
|
|
|
|
}
|
2022-06-02 22:39:55 -06:00
|
|
|
|
|
|
|
markUnchanged(message: string): CacheEntryListener {
|
|
|
|
this.unchanged = message
|
|
|
|
return this
|
|
|
|
}
|
2021-12-07 12:29:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
export function logCachingReport(listener: CacheListener): void {
|
|
|
|
if (listener.cacheEntries.length === 0) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-06-02 22:39:55 -06:00
|
|
|
core.summary.addHeading('Gradle Home Caching Summary', 3)
|
2022-06-02 14:21:10 -06:00
|
|
|
|
|
|
|
const entries = listener.cacheEntries
|
|
|
|
.map(
|
|
|
|
entry =>
|
|
|
|
`Entry: ${entry.entryName}
|
2021-12-07 12:29:37 -07:00
|
|
|
Requested Key : ${entry.requestedKey ?? ''}
|
|
|
|
Restored Key : ${entry.restoredKey ?? ''}
|
|
|
|
Size: ${formatSize(entry.restoredSize)}
|
2022-06-02 22:44:08 -06:00
|
|
|
${getRestoredMessage(entry, listener.isCacheWriteOnly)}
|
2021-12-07 12:29:37 -07:00
|
|
|
Saved Key : ${entry.savedKey ?? ''}
|
2022-06-02 22:39:55 -06:00
|
|
|
Size: ${formatSize(entry.savedSize)}
|
2022-06-02 22:44:08 -06:00
|
|
|
${getSavedMessage(entry, listener.isCacheReadOnly)}
|
2022-06-02 22:39:55 -06:00
|
|
|
---`
|
2022-06-02 14:21:10 -06:00
|
|
|
)
|
|
|
|
.join('\n')
|
|
|
|
|
|
|
|
core.summary.addRaw(
|
|
|
|
`
|
|
|
|
|
|
|
|
| | Count | Size (Mb) | Size (B) |
|
|
|
|
| - | -: | -: | -: |
|
|
|
|
| Restored | ${getCount(listener.cacheEntries, e => e.restoredSize)} | ${getMegaBytes(
|
|
|
|
listener.cacheEntries,
|
|
|
|
e => e.restoredSize
|
|
|
|
)} | ${getBytes(listener.cacheEntries, e => e.restoredSize)} |
|
|
|
|
| Saved | ${getCount(listener.cacheEntries, e => e.savedSize)} | ${getMegaBytes(
|
|
|
|
listener.cacheEntries,
|
|
|
|
e => e.savedSize
|
|
|
|
)} | ${getBytes(listener.cacheEntries, e => e.savedSize)} |
|
|
|
|
|
|
|
|
`
|
|
|
|
)
|
|
|
|
|
2022-06-02 22:44:08 -06:00
|
|
|
if (listener.isCacheReadOnly) {
|
|
|
|
core.summary.addRaw('- **Cache is read-only**\n')
|
|
|
|
}
|
|
|
|
if (listener.isCacheWriteOnly) {
|
|
|
|
core.summary.addRaw('- **Cache is write-only**\n')
|
|
|
|
}
|
|
|
|
|
2022-06-02 14:21:10 -06:00
|
|
|
core.summary.addDetails(
|
|
|
|
'Cache Entry Details',
|
|
|
|
`
|
|
|
|
<pre>
|
|
|
|
${entries}
|
|
|
|
</pre>
|
2022-06-02 22:39:09 -06:00
|
|
|
|
2022-06-02 14:21:10 -06:00
|
|
|
`
|
|
|
|
)
|
2021-12-07 12:29:37 -07:00
|
|
|
}
|
|
|
|
|
2022-06-02 22:44:08 -06:00
|
|
|
function getRestoredMessage(entry: CacheEntryListener, isCacheWriteOnly: boolean): string {
|
|
|
|
if (isCacheWriteOnly) {
|
|
|
|
return '(Entry not restored: cache is write-only)'
|
|
|
|
}
|
2022-06-02 22:39:55 -06:00
|
|
|
if (entry.restoredKey === undefined) {
|
2022-06-02 22:44:08 -06:00
|
|
|
return '(Entry not restored: no match found)'
|
2022-06-02 22:39:55 -06:00
|
|
|
}
|
|
|
|
if (entry.restoredKey === entry.requestedKey) {
|
2022-06-02 22:44:08 -06:00
|
|
|
return '(Entry restored: exact match found)'
|
2022-06-02 22:39:55 -06:00
|
|
|
}
|
2022-06-02 22:44:08 -06:00
|
|
|
return '(Entry restored: partial match found)'
|
2022-06-02 22:39:55 -06:00
|
|
|
}
|
|
|
|
|
2022-06-02 22:44:08 -06:00
|
|
|
function getSavedMessage(entry: CacheEntryListener, isCacheReadOnly: boolean): string {
|
2022-06-02 22:39:55 -06:00
|
|
|
if (entry.unchanged) {
|
|
|
|
return `(Entry not saved: ${entry.unchanged})`
|
|
|
|
}
|
|
|
|
if (entry.savedKey === undefined) {
|
2022-06-02 22:44:08 -06:00
|
|
|
if (isCacheReadOnly) {
|
|
|
|
return '(Entry not saved: cache is read-only)'
|
|
|
|
}
|
|
|
|
return '(Entry not saved: reason unknown)'
|
2022-06-02 22:39:55 -06:00
|
|
|
}
|
|
|
|
if (entry.savedSize === 0) {
|
2022-06-02 22:44:08 -06:00
|
|
|
return '(Entry not saved: entry with key already exists)'
|
2022-06-02 22:39:55 -06:00
|
|
|
}
|
|
|
|
return '(Entry saved)'
|
|
|
|
}
|
|
|
|
|
2021-12-07 12:29:37 -07:00
|
|
|
function getCount(
|
|
|
|
cacheEntries: CacheEntryListener[],
|
|
|
|
predicate: (value: CacheEntryListener) => number | undefined
|
|
|
|
): number {
|
|
|
|
return cacheEntries.filter(e => predicate(e) !== undefined).length
|
|
|
|
}
|
|
|
|
|
2022-06-02 14:21:10 -06:00
|
|
|
function getBytes(
|
2021-12-07 12:29:37 -07:00
|
|
|
cacheEntries: CacheEntryListener[],
|
|
|
|
predicate: (value: CacheEntryListener) => number | undefined
|
2022-06-02 14:21:10 -06:00
|
|
|
): number {
|
|
|
|
return cacheEntries.map(e => predicate(e) ?? 0).reduce((p, v) => p + v, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
function getMegaBytes(
|
|
|
|
cacheEntries: CacheEntryListener[],
|
|
|
|
predicate: (value: CacheEntryListener) => number | undefined
|
|
|
|
): number {
|
|
|
|
const bytes = getBytes(cacheEntries, predicate)
|
|
|
|
return Math.round(bytes / (1024 * 1024))
|
2021-12-07 12:29:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
function formatSize(bytes: number | undefined): string {
|
2022-01-19 12:11:51 -07:00
|
|
|
if (bytes === undefined) {
|
2021-12-07 12:29:37 -07:00
|
|
|
return ''
|
|
|
|
}
|
2022-01-19 12:11:51 -07:00
|
|
|
if (bytes === 0) {
|
|
|
|
return '0 (Entry already exists)'
|
|
|
|
}
|
2021-12-07 12:29:37 -07:00
|
|
|
return `${Math.round(bytes / (1024 * 1024))} MB (${bytes} B)`
|
|
|
|
}
|