From 2ca743aeedd4a0773d3a2889976f9042544a8783 Mon Sep 17 00:00:00 2001 From: dabreadman Date: Wed, 14 Apr 2021 00:21:04 +0100 Subject: [PATCH] Add Podman option support --- action.yml | 8 +- main.ts | 71 +++++--- post.ts | 80 +++++---- src/ImageDetector.ts | 46 +++-- src/LayerCache.ts | 392 +++++++++++++++++++++++++------------------ 5 files changed, 369 insertions(+), 228 deletions(-) diff --git a/action.yml b/action.yml index 1a822ea9..9d0bc857 100644 --- a/action.yml +++ b/action.yml @@ -10,6 +10,10 @@ inputs: description: An explicit key for restoring and saving the cache required: true default: docker-layer-caching-${{ github.workflow }}-{hash} + container: + description: Docker or Podman + required: false + default: "Docker" restore-keys: description: An ordered list of keys to use for restoring the cache if no cache hit occurred for key required: false @@ -17,11 +21,11 @@ inputs: concurrency: description: The number of concurrency when restoring and saving layers required: true - default: '4' + default: "4" skip-save: description: Skip saving layers in the post step required: false - default: 'false' + default: "false" runs: using: node12 diff --git a/main.ts b/main.ts index b271fca0..336c09cb 100644 --- a/main.ts +++ b/main.ts @@ -1,30 +1,57 @@ -import * as core from '@actions/core' -import * as exec from 'actions-exec-listener' -import { LayerCache } from './src/LayerCache' -import { ImageDetector } from './src/ImageDetector' +import * as core from "@actions/core"; +import { LayerCache } from "./src/LayerCache"; +import { ImageDetector } from "./src/ImageDetector"; const main = async () => { - const primaryKey = core.getInput(`key`, { required: true }) - const restoreKeys = core.getInput(`restore-keys`, { required: false }).split(`\n`).filter(key => key !== ``) + const primaryKey = core.getInput(`key`, { required: true }); + const restoreKeys = core + .getInput(`restore-keys`, { required: false }) + .split(`\n`) + .filter((key) => key !== ``); - const imageDetector = new ImageDetector() + const imageDetector = new ImageDetector(); - const alreadyExistingImages = await imageDetector.getExistingImages() - core.saveState(`already-existing-images`, JSON.stringify(alreadyExistingImages)) + const container = core.getInput(`container`).toLowerCase(); + if (container !== "docker" && container !== "podman") { + throw new Error("Wrong container name: " + container); + } - const layerCache = new LayerCache([]) - layerCache.concurrency = parseInt(core.getInput(`concurrency`, { required: true }), 10) - const restoredKey = await layerCache.restore(primaryKey, restoreKeys) - await layerCache.cleanUp() + const alreadyExistingImages = await imageDetector.getExistingImages( + container + ); + core.saveState( + `already-existing-images`, + JSON.stringify(alreadyExistingImages) + ); - core.saveState(`restored-key`, JSON.stringify(restoredKey !== undefined ? restoredKey : '')) - core.saveState(`restored-images`, JSON.stringify(await imageDetector.getImagesShouldSave(alreadyExistingImages))) -} + const layerCache = new LayerCache([]); + layerCache.concurrency = parseInt( + core.getInput(`concurrency`, { required: true }), + 10 + ); + const restoredKey = await layerCache.restore( + primaryKey, + container, + restoreKeys + ); + await layerCache.cleanUp(); -main().catch(e => { - console.error(e) - core.setFailed(e) + core.saveState( + `restored-key`, + JSON.stringify(restoredKey !== undefined ? restoredKey : "") + ); + core.saveState( + `restored-images`, + JSON.stringify( + await imageDetector.getImagesShouldSave(alreadyExistingImages, container) + ) + ); +}; - core.saveState(`restored-key`, JSON.stringify(``)) - core.saveState(`restored-images`, JSON.stringify([])) -}) +main().catch((e) => { + console.error(e); + core.setFailed(e); + + core.saveState(`restored-key`, JSON.stringify(``)); + core.saveState(`restored-images`, JSON.stringify([])); +}); diff --git a/post.ts b/post.ts index a3a977d2..17079bdb 100644 --- a/post.ts +++ b/post.ts @@ -1,43 +1,61 @@ -import * as core from '@actions/core' +import * as core from "@actions/core"; -import { LayerCache } from './src/LayerCache' -import { ImageDetector } from './src/ImageDetector' -import { assertType } from 'typescript-is' +import { LayerCache } from "./src/LayerCache"; +import { ImageDetector } from "./src/ImageDetector"; +import { assertType } from "typescript-is"; const main = async () => { - if (JSON.parse(core.getInput('skip-save', { required: true }))) { - core.info('Skipping save.') - return + if (JSON.parse(core.getInput("skip-save", { required: true }))) { + core.info("Skipping save."); + return; } - const primaryKey = core.getInput('key', { required: true }) + const primaryKey = core.getInput("key", { required: true }); - const restoredKey = JSON.parse(core.getState(`restored-key`)) - const alreadyExistingImages = JSON.parse(core.getState(`already-existing-images`)) - const restoredImages = JSON.parse(core.getState(`restored-images`)) + const restoredKey = JSON.parse(core.getState(`restored-key`)); + const alreadyExistingImages = JSON.parse( + core.getState(`already-existing-images`) + ); + const restoredImages = JSON.parse(core.getState(`restored-images`)); - assertType(restoredKey) - assertType(alreadyExistingImages) - assertType(restoredImages) + assertType(restoredKey); + assertType(alreadyExistingImages); + assertType(restoredImages); - const imageDetector = new ImageDetector() + const imageDetector = new ImageDetector(); - const existingAndRestoredImages = alreadyExistingImages.concat(restoredImages) - const newImages = await imageDetector.getImagesShouldSave(existingAndRestoredImages) - if (newImages.length < 1) { - core.info(`There is no image to save.`) - return + const container = core.getInput(`container`).toLowerCase(); + if (container !== "docker" && container !== "podman") { + throw new Error("Wrong container name: " + container); } - const imagesToSave = await imageDetector.getImagesShouldSave(alreadyExistingImages) - const layerCache = new LayerCache(imagesToSave) - layerCache.concurrency = parseInt(core.getInput(`concurrency`, { required: true }), 10) - - await layerCache.store(primaryKey) - await layerCache.cleanUp() -} + const existingAndRestoredImages = alreadyExistingImages.concat( + restoredImages + ); + const newImages = await imageDetector.getImagesShouldSave( + existingAndRestoredImages, + container + ); + if (newImages.length < 1) { + core.info(`There is no image to save.`); + return; + } -main().catch(e => { - console.error(e) - core.setFailed(e) -}) + const imagesToSave = await imageDetector.getImagesShouldSave( + alreadyExistingImages, + container + ); + const layerCache = new LayerCache(imagesToSave); + layerCache.concurrency = parseInt( + core.getInput(`concurrency`, { required: true }), + 10 + ); + + await layerCache.store(primaryKey, container); + await layerCache.cleanUp(); +}; + +main().catch((e) => { + console.error(e); + core.setFailed(e); +}); diff --git a/src/ImageDetector.ts b/src/ImageDetector.ts index 905881ac..e8c7a7cb 100644 --- a/src/ImageDetector.ts +++ b/src/ImageDetector.ts @@ -1,20 +1,40 @@ -import * as exec from 'actions-exec-listener' -import * as core from '@actions/core' +import * as exec from "actions-exec-listener"; +import * as core from "@actions/core"; export class ImageDetector { - async getExistingImages(): Promise { - const existingSet = new Set([]) - const ids = (await exec.exec(`docker image ls -q`, [], { silent: true, listeners: { stderr: console.warn }})).stdoutStr.split(`\n`).filter(id => id !== ``) - const repotags = (await exec.exec(`docker`, `image ls --format {{.Repository}}:{{.Tag}} --filter dangling=false`.split(' '), { silent: true, listeners: { stderr: console.warn }})).stdoutStr.split(`\n`).filter(id => id !== ``); + async getExistingImages(container: "docker" | "podman"): Promise { + const existingSet = new Set([]); + const ids = ( + await exec.exec(`${container} image ls -q`, [], { + silent: true, + listeners: { stderr: console.warn }, + }) + ).stdoutStr + .split(`\n`) + .filter((id) => id !== ``); + const repotags = ( + await exec.exec( + `${container}`, + `image ls --format {{.Repository}}:{{.Tag}} --filter dangling=false`.split( + " " + ), + { silent: true, listeners: { stderr: console.warn } } + ) + ).stdoutStr + .split(`\n`) + .filter((id) => id !== ``); core.debug(JSON.stringify({ log: "getExistingImages", ids, repotags })); - ([...ids, ...repotags]).forEach(image => existingSet.add(image)) - core.debug(JSON.stringify({ existingSet })) - return Array.from(existingSet) + [...ids, ...repotags].forEach((image) => existingSet.add(image)); + core.debug(JSON.stringify({ existingSet })); + return Array.from(existingSet); } - async getImagesShouldSave(alreadRegisteredImages: string[]): Promise { - const resultSet = new Set(await this.getExistingImages()) - alreadRegisteredImages.forEach(image => resultSet.delete(image)) - return Array.from(resultSet) + async getImagesShouldSave( + alreadRegisteredImages: string[], + container: "docker" | "podman" + ): Promise { + const resultSet = new Set(await this.getExistingImages(container)); + alreadRegisteredImages.forEach((image) => resultSet.delete(image)); + return Array.from(resultSet); } } diff --git a/src/LayerCache.ts b/src/LayerCache.ts index 5fdfe646..b9244258 100644 --- a/src/LayerCache.ts +++ b/src/LayerCache.ts @@ -1,301 +1,373 @@ -import * as path from 'path' -import * as exec from 'actions-exec-listener' -import crypto from 'crypto' -import * as core from '@actions/core' -import * as cache from '@actions/cache' -import { ExecOptions } from '@actions/exec/lib/interfaces' -import { promises as fs } from 'fs' -import recursiveReaddir from 'recursive-readdir' -import { Manifest, loadManifests, loadRawManifests } from './Tar' -import format from 'string-format' -import PromisePool from 'native-promise-pool' +import * as path from "path"; +import * as exec from "actions-exec-listener"; +import crypto from "crypto"; +import * as core from "@actions/core"; +import * as cache from "@actions/cache"; +import { ExecOptions } from "@actions/exec/lib/interfaces"; +import { promises as fs } from "fs"; +import recursiveReaddir from "recursive-readdir"; +import { Manifest, loadManifests, loadRawManifests } from "./Tar"; +import format from "string-format"; +import PromisePool from "native-promise-pool"; class LayerCache { - ids: string[] = [] - unformattedSaveKey: string = '' - restoredRootKey: string = '' - imagesDir: string = path.join(__dirname, '..', '.adlc') - enabledParallel = true - concurrency: number = 4 + ids: string[] = []; + unformattedSaveKey: string = ""; + restoredRootKey: string = ""; + imagesDir: string = path.join(__dirname, "..", ".adlc"); + enabledParallel = true; + concurrency: number = 4; - static ERROR_CACHE_ALREAD_EXISTS_STR = `Unable to reserve cache with key` - static ERROR_LAYER_CACHE_NOT_FOUND_STR = `Layer cache not found` + static ERROR_CACHE_ALREAD_EXISTS_STR = `Unable to reserve cache with key`; + static ERROR_LAYER_CACHE_NOT_FOUND_STR = `Layer cache not found`; constructor(ids: string[]) { - this.ids = ids + this.ids = ids; } async exec(command: string, args?: string[], options?: ExecOptions) { - const result = await exec.exec(command, args, options) + const result = await exec.exec(command, args, options); - return result + return result; } - async store(key: string) { - this.unformattedSaveKey = key + async store(key: string, container: "docker" | "podman") { + this.unformattedSaveKey = key; - await this.saveImageAsUnpacked() + await this.saveImageAsUnpacked(container); if (this.enabledParallel) { - await this.separateAllLayerCaches() + await this.separateAllLayerCaches(); } - if (await this.storeRoot() === undefined) { - core.info(`cache key already exists, aborting.`) - return false + if ((await this.storeRoot()) === undefined) { + core.info(`cache key already exists, aborting.`); + return false; } - await Promise.all(this.enabledParallel ? await this.storeLayers() : []) - return true + await Promise.all(this.enabledParallel ? await this.storeLayers() : []); + return true; } - private async saveImageAsUnpacked() { - await fs.mkdir(this.getUnpackedTarDir(), { recursive: true }) - await this.exec(`sh -c`, [`docker save '${(await this.makeRepotagsDockerSaveArgReady(this.ids)).join(`' '`)}' | tar xf - -C .`], { cwd: this.getUnpackedTarDir() }) + private async saveImageAsUnpacked(container: "docker" | "podman") { + await fs.mkdir(this.getUnpackedTarDir(), { recursive: true }); + await this.exec( + `sh -c`, + [ + `${container} save '${( + await this.makeRepotagsDockerSaveArgReady(this.ids, container) + ).join(`' '`)}' | tar xf - -C .`, + ], + { cwd: this.getUnpackedTarDir() } + ); } - private async makeRepotagsDockerSaveArgReady(repotags: string[]): Promise { + private async makeRepotagsDockerSaveArgReady( + repotags: string[], + container: "docker" | "podman" + ): Promise { const getMiddleIdsWithRepotag = async (id: string): Promise => { - return [id, ...(await this.getAllImageIdsFrom(id))] - } - return (await Promise.all(repotags.map(getMiddleIdsWithRepotag))).flat() - } - - private async getAllImageIdsFrom(repotag: string): Promise { - const { stdoutStr: rawHistoryIds } = await this.exec(`docker history -q`, [repotag], { silent: true, listeners: { stderr: console.warn }}) - const historyIds = rawHistoryIds.split(`\n`).filter(id => id !== `` && id !== ``) - return historyIds + return [id, ...(await this.getAllImageIdsFrom(id, container))]; + }; + return (await Promise.all(repotags.map(getMiddleIdsWithRepotag))).flat(); + } + + private async getAllImageIdsFrom( + repotag: string, + container: "docker" | "podman" + ): Promise { + const { stdoutStr: rawHistoryIds } = await this.exec( + `${container} history -q`, + [repotag], + { + silent: true, + listeners: { stderr: console.warn }, + } + ); + const historyIds = rawHistoryIds + .split(`\n`) + .filter((id) => id !== `` && id !== ``); + return historyIds; } private async getManifests() { - return loadManifests(this.getUnpackedTarDir()) + return loadManifests(this.getUnpackedTarDir()); } private async storeRoot() { - const rootKey = await this.generateRootSaveKey() - const paths = [ - this.getUnpackedTarDir(), - ] - core.info(`Start storing root cache, key: ${rootKey}, dir: ${paths}`) - const cacheId = await LayerCache.dismissError(cache.saveCache(paths, rootKey), LayerCache.ERROR_CACHE_ALREAD_EXISTS_STR, -1) - core.info(`Stored root cache, key: ${rootKey}, id: ${cacheId}`) - return cacheId !== -1 ? cacheId : undefined + const rootKey = await this.generateRootSaveKey(); + const paths = [this.getUnpackedTarDir()]; + core.info(`Start storing root cache, key: ${rootKey}, dir: ${paths}`); + const cacheId = await LayerCache.dismissError( + cache.saveCache(paths, rootKey), + LayerCache.ERROR_CACHE_ALREAD_EXISTS_STR, + -1 + ); + core.info(`Stored root cache, key: ${rootKey}, id: ${cacheId}`); + return cacheId !== -1 ? cacheId : undefined; } private async separateAllLayerCaches() { - await this.moveLayerTarsInDir(this.getUnpackedTarDir(), this.getLayerCachesDir()) + await this.moveLayerTarsInDir( + this.getUnpackedTarDir(), + this.getLayerCachesDir() + ); } private async joinAllLayerCaches() { - await this.moveLayerTarsInDir(this.getLayerCachesDir(), this.getUnpackedTarDir()) + await this.moveLayerTarsInDir( + this.getLayerCachesDir(), + this.getUnpackedTarDir() + ); } private async moveLayerTarsInDir(fromDir: string, toDir: string) { const layerTars = (await recursiveReaddir(fromDir)) - .filter(layerPath => path.basename(layerPath) === `layer.tar`) - .map(layerPath => path.relative(fromDir, layerPath)) + .filter((layerPath) => path.basename(layerPath) === `layer.tar`) + .map((layerPath) => path.relative(fromDir, layerPath)); const moveLayer = async (layer: string) => { - const from = path.join(fromDir, layer) - const to = path.join(toDir, layer) - core.debug(`Moving layer tar from ${from} to ${to}`) - await fs.mkdir(path.dirname(to), { recursive: true }) - await fs.rename(from, to) - } - await Promise.all(layerTars.map(moveLayer)) + const from = path.join(fromDir, layer); + const to = path.join(toDir, layer); + core.debug(`Moving layer tar from ${from} to ${to}`); + await fs.mkdir(path.dirname(to), { recursive: true }); + await fs.rename(from, to); + }; + await Promise.all(layerTars.map(moveLayer)); } private async storeLayers(): Promise { - const pool = new PromisePool(this.concurrency) + const pool = new PromisePool(this.concurrency); - const result = Promise.all( - (await this.getLayerIds()).map( - layerId => { - return pool.open(() => this.storeSingleLayerBy(layerId)) - } - ) - ) - return result + const result = Promise.all( + (await this.getLayerIds()).map((layerId) => { + return pool.open(() => this.storeSingleLayerBy(layerId)); + }) + ); + return result; } - static async dismissError(promise: Promise, dismissStr: string, defaultResult: T): Promise { + static async dismissError( + promise: Promise, + dismissStr: string, + defaultResult: T + ): Promise { try { - return await promise + return await promise; } catch (e) { - core.debug(`catch error: ${e.toString()}`) - if (typeof e.message !== 'string' || !e.message.includes(dismissStr)) { - core.error(`Unexpected error: ${e.toString()}`) - throw e + core.debug(`catch error: ${e.toString()}`); + if (typeof e.message !== "string" || !e.message.includes(dismissStr)) { + core.error(`Unexpected error: ${e.toString()}`); + throw e; } - core.info(`${dismissStr}: ${e.toString()}`) - core.debug(e) - return defaultResult + core.info(`${dismissStr}: ${e.toString()}`); + core.debug(e); + return defaultResult; } } private async storeSingleLayerBy(layerId: string): Promise { - const path = this.genSingleLayerStorePath(layerId) - const key = await this.generateSingleLayerSaveKey(layerId) + const path = this.genSingleLayerStorePath(layerId); + const key = await this.generateSingleLayerSaveKey(layerId); - core.info(`Start storing layer cache: ${JSON.stringify({ layerId, key })}`) - const cacheId = await LayerCache.dismissError(cache.saveCache([path], key), LayerCache.ERROR_CACHE_ALREAD_EXISTS_STR, -1) - core.info(`Stored layer cache: ${JSON.stringify({ key, cacheId })}`) + core.info(`Start storing layer cache: ${JSON.stringify({ layerId, key })}`); + const cacheId = await LayerCache.dismissError( + cache.saveCache([path], key), + LayerCache.ERROR_CACHE_ALREAD_EXISTS_STR, + -1 + ); + core.info(`Stored layer cache: ${JSON.stringify({ key, cacheId })}`); - core.debug(JSON.stringify({ log: `storeSingleLayerBy`, layerId, path, key, cacheId})) - return cacheId + core.debug( + JSON.stringify({ log: `storeSingleLayerBy`, layerId, path, key, cacheId }) + ); + return cacheId; } // --- - async restore(primaryKey: string, restoreKeys?: string[]) { - const restoredCacheKey = await this.restoreRoot(primaryKey, restoreKeys) + async restore( + primaryKey: string, + container: "docker" | "podman", + restoreKeys?: string[] + ) { + const restoredCacheKey = await this.restoreRoot(primaryKey, restoreKeys); if (restoredCacheKey === undefined) { - core.info(`Root cache could not be found. aborting.`) - return undefined + core.info(`Root cache could not be found. aborting.`); + return undefined; } if (this.enabledParallel) { - const hasRestoredAllLayers = await this.restoreLayers() + const hasRestoredAllLayers = await this.restoreLayers(); if (!hasRestoredAllLayers) { - core.info(`Some layer cache could not be found. aborting.`) - return undefined + core.info(`Some layer cache could not be found. aborting.`); + return undefined; } - await this.joinAllLayerCaches() + await this.joinAllLayerCaches(); } - await this.loadImageFromUnpacked() - return restoredCacheKey - } - - private async restoreRoot(primaryKey: string, restoreKeys?: string[]): Promise { - core.debug(`Trying to restore root cache: ${ JSON.stringify({ restoreKeys, dir: this.getUnpackedTarDir() }) }`) - const restoredRootKey = await cache.restoreCache([this.getUnpackedTarDir()], primaryKey, restoreKeys) - core.debug(`restoredRootKey: ${restoredRootKey}`) + await this.loadImageFromUnpacked(container); + return restoredCacheKey; + } + + private async restoreRoot( + primaryKey: string, + restoreKeys?: string[] + ): Promise { + core.debug( + `Trying to restore root cache: ${JSON.stringify({ + restoreKeys, + dir: this.getUnpackedTarDir(), + })}` + ); + const restoredRootKey = await cache.restoreCache( + [this.getUnpackedTarDir()], + primaryKey, + restoreKeys + ); + core.debug(`restoredRootKey: ${restoredRootKey}`); if (restoredRootKey === undefined) { - return undefined + return undefined; } - this.restoredRootKey = restoredRootKey + this.restoredRootKey = restoredRootKey; - return restoredRootKey + return restoredRootKey; } private async restoreLayers(): Promise { - const pool = new PromisePool(this.concurrency) - const tasks = (await this.getLayerIds()).map( - layerId => pool.open(() => this.restoreSingleLayerBy(layerId)) - ) + const pool = new PromisePool(this.concurrency); + const tasks = (await this.getLayerIds()).map((layerId) => + pool.open(() => this.restoreSingleLayerBy(layerId)) + ); try { - await Promise.all(tasks) + await Promise.all(tasks); } catch (e) { - if (typeof e.message === `string` && e.message.includes(LayerCache.ERROR_LAYER_CACHE_NOT_FOUND_STR)) { - core.info(e.message) + if ( + typeof e.message === `string` && + e.message.includes(LayerCache.ERROR_LAYER_CACHE_NOT_FOUND_STR) + ) { + core.info(e.message); // Avoid UnhandledPromiseRejectionWarning - tasks.map(task => task.catch(core.info)) + tasks.map((task) => task.catch(core.info)); - return false + return false; } - throw e + throw e; } - return true + return true; } private async restoreSingleLayerBy(id: string): Promise { - const layerPath = this.genSingleLayerStorePath(id) - const key = await this.recoverSingleLayerKey(id) - const dir = path.dirname(layerPath) + const layerPath = this.genSingleLayerStorePath(id); + const key = await this.recoverSingleLayerKey(id); + const dir = path.dirname(layerPath); - core.debug(JSON.stringify({ log: `restoreSingleLayerBy`, id, layerPath, dir, key })) + core.debug( + JSON.stringify({ log: `restoreSingleLayerBy`, id, layerPath, dir, key }) + ); - await fs.mkdir(dir, { recursive: true }) - const result = await cache.restoreCache([layerPath], key) + await fs.mkdir(dir, { recursive: true }); + const result = await cache.restoreCache([layerPath], key); if (result == null) { - throw new Error(`${LayerCache.ERROR_LAYER_CACHE_NOT_FOUND_STR}: ${JSON.stringify({ id })}`) + throw new Error( + `${LayerCache.ERROR_LAYER_CACHE_NOT_FOUND_STR}: ${JSON.stringify({ + id, + })}` + ); } - return result + return result; } - private async loadImageFromUnpacked() { - await exec.exec(`sh -c`, [`tar cf - . | docker load`], { cwd: this.getUnpackedTarDir() }) + private async loadImageFromUnpacked(container: "docker" | "podman") { + await exec.exec(`sh -c`, [`tar cf - . | ${container} load`], { + cwd: this.getUnpackedTarDir(), + }); } async cleanUp() { - await fs.rmdir(this.getImagesDir(), { recursive: true }) + await fs.rmdir(this.getImagesDir(), { recursive: true }); } // --- getImagesDir(): string { - return this.imagesDir + return this.imagesDir; } getUnpackedTarDir(): string { - return path.join(this.getImagesDir(), this.getCurrentTarStoreDir()) + return path.join(this.getImagesDir(), this.getCurrentTarStoreDir()); } getLayerCachesDir() { - return `${this.getUnpackedTarDir()}-layers` + return `${this.getUnpackedTarDir()}-layers`; } getCurrentTarStoreDir(): string { - return 'image' + return "image"; } genSingleLayerStorePath(id: string) { - return path.join(this.getLayerCachesDir(), id, `layer.tar`) + return path.join(this.getLayerCachesDir(), id, `layer.tar`); } async generateRootHashFromManifest(): Promise { - const manifest = await loadRawManifests(this.getUnpackedTarDir()) - return crypto.createHash(`sha256`).update(manifest, `utf8`).digest(`hex`) + const manifest = await loadRawManifests(this.getUnpackedTarDir()); + return crypto.createHash(`sha256`).update(manifest, `utf8`).digest(`hex`); } async generateRootSaveKey(): Promise { - const rootHash = await this.generateRootHashFromManifest() - const formatted = await this.getFormattedSaveKey(rootHash) - core.debug(JSON.stringify({ log: `generateRootSaveKey`, rootHash, formatted })) - return `${formatted}-root` + const rootHash = await this.generateRootHashFromManifest(); + const formatted = await this.getFormattedSaveKey(rootHash); + core.debug( + JSON.stringify({ log: `generateRootSaveKey`, rootHash, formatted }) + ); + return `${formatted}-root`; } async generateSingleLayerSaveKey(id: string) { - const formatted = await this.getFormattedSaveKey(id) - core.debug(JSON.stringify({ log: `generateSingleLayerSaveKey`, formatted, id })) - return `layer-${formatted}` + const formatted = await this.getFormattedSaveKey(id); + core.debug( + JSON.stringify({ log: `generateSingleLayerSaveKey`, formatted, id }) + ); + return `layer-${formatted}`; } - + async recoverSingleLayerKey(id: string) { - const unformatted = await this.recoverUnformattedSaveKey() - return format(`layer-${unformatted}`, { hash: id }) + const unformatted = await this.recoverUnformattedSaveKey(); + return format(`layer-${unformatted}`, { hash: id }); } async getFormattedSaveKey(hash: string) { - const result = format(this.unformattedSaveKey, { hash }) - core.debug(JSON.stringify({ log: `getFormattedSaveKey`, hash, result })) - return result + const result = format(this.unformattedSaveKey, { hash }); + core.debug(JSON.stringify({ log: `getFormattedSaveKey`, hash, result })); + return result; } async recoverUnformattedSaveKey() { - const hash = await this.generateRootHashFromManifest() - core.debug(JSON.stringify({ log: `recoverUnformattedSaveKey`, hash})) + const hash = await this.generateRootHashFromManifest(); + core.debug(JSON.stringify({ log: `recoverUnformattedSaveKey`, hash })); - return this.restoredRootKey.replace(hash, `{hash}`).replace(/-root$/, ``) + return this.restoredRootKey.replace(hash, `{hash}`).replace(/-root$/, ``); } async getLayerTarFiles(): Promise { - const getTarFilesFromManifest = (manifest: Manifest) => manifest.Layers + const getTarFilesFromManifest = (manifest: Manifest) => manifest.Layers; - const tarFilesThatMayDuplicate = (await this.getManifests()).flatMap(getTarFilesFromManifest) - const tarFiles = [...new Set(tarFilesThatMayDuplicate)] - return tarFiles + const tarFilesThatMayDuplicate = (await this.getManifests()).flatMap( + getTarFilesFromManifest + ); + const tarFiles = [...new Set(tarFilesThatMayDuplicate)]; + return tarFiles; } async getLayerIds(): Promise { const layerIds = (await this.getLayerTarFiles()).map(path.dirname); - core.debug(JSON.stringify({ log: `getLayerIds`, layerIds })) - return layerIds + core.debug(JSON.stringify({ log: `getLayerIds`, layerIds })); + return layerIds; } } -export { LayerCache } +export { LayerCache };