mirror of
https://github.com/docker/setup-qemu-action.git
synced 2025-05-12 05:02:49 +08:00
feat: binfmt image local cached
This commit is contained in:
parent
f30d974279
commit
ee123d82a5
3
.gitignore
vendored
3
.gitignore
vendored
@ -51,3 +51,6 @@ jspm_packages/
|
|||||||
.yarn/build-state.yml
|
.yarn/build-state.yml
|
||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
@ -23,6 +23,7 @@ describe('getInputs', () => {
|
|||||||
image: 'docker.io/tonistiigi/binfmt:latest',
|
image: 'docker.io/tonistiigi/binfmt:latest',
|
||||||
platforms: 'all',
|
platforms: 'all',
|
||||||
cacheImage: true,
|
cacheImage: true,
|
||||||
|
localCachePath: ''
|
||||||
} as context.Inputs
|
} as context.Inputs
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@ -36,6 +37,7 @@ describe('getInputs', () => {
|
|||||||
image: 'docker/binfmt:latest',
|
image: 'docker/binfmt:latest',
|
||||||
platforms: 'arm64,riscv64,arm',
|
platforms: 'arm64,riscv64,arm',
|
||||||
cacheImage: false,
|
cacheImage: false,
|
||||||
|
localCachePath: ''
|
||||||
} as context.Inputs
|
} as context.Inputs
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@ -48,6 +50,21 @@ describe('getInputs', () => {
|
|||||||
image: 'docker.io/tonistiigi/binfmt:latest',
|
image: 'docker.io/tonistiigi/binfmt:latest',
|
||||||
platforms: 'arm64,riscv64,arm',
|
platforms: 'arm64,riscv64,arm',
|
||||||
cacheImage: true,
|
cacheImage: true,
|
||||||
|
localCachePath: ''
|
||||||
|
} as context.Inputs
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3,
|
||||||
|
new Map<string, string>([
|
||||||
|
['platforms', 'arm64'],
|
||||||
|
['cache-image', 'false'],
|
||||||
|
['local-cache-path', '/tmp/cache'],
|
||||||
|
]),
|
||||||
|
{
|
||||||
|
image: 'docker.io/tonistiigi/binfmt:latest',
|
||||||
|
platforms: 'arm64',
|
||||||
|
cacheImage: false,
|
||||||
|
localCachePath: '/tmp/cache'
|
||||||
} as context.Inputs
|
} as context.Inputs
|
||||||
]
|
]
|
||||||
])(
|
])(
|
||||||
|
@ -19,6 +19,12 @@ inputs:
|
|||||||
description: 'Cache binfmt image to GitHub Actions cache backend'
|
description: 'Cache binfmt image to GitHub Actions cache backend'
|
||||||
default: 'true'
|
default: 'true'
|
||||||
required: false
|
required: false
|
||||||
|
local-cache-path:
|
||||||
|
description: >
|
||||||
|
Local path to store the binfmt image. Using this enables local caching instead of GitHub Actions cache.
|
||||||
|
Note: The "latest" tag won't auto-update - delete the cached file to fetch updates.
|
||||||
|
default: ''
|
||||||
|
required: false
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
platforms:
|
platforms:
|
||||||
|
@ -5,12 +5,14 @@ export interface Inputs {
|
|||||||
image: string;
|
image: string;
|
||||||
platforms: string;
|
platforms: string;
|
||||||
cacheImage: boolean;
|
cacheImage: boolean;
|
||||||
|
localCachePath: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getInputs(): Inputs {
|
export function getInputs(): Inputs {
|
||||||
return {
|
return {
|
||||||
image: core.getInput('image') || 'docker.io/tonistiigi/binfmt:latest',
|
image: core.getInput('image') || 'docker.io/tonistiigi/binfmt:latest',
|
||||||
platforms: Util.getInputList('platforms').join(',') || 'all',
|
platforms: Util.getInputList('platforms').join(',') || 'all',
|
||||||
cacheImage: core.getBooleanInput('cache-image')
|
cacheImage: core.getBooleanInput('cache-image'),
|
||||||
|
localCachePath: core.getInput('local-cache-path') || ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
57
src/local-cache.ts
Normal file
57
src/local-cache.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import {Docker} from '@docker/actions-toolkit/lib/docker/docker';
|
||||||
|
|
||||||
|
function getImageCacheFileName(imageName: string): string {
|
||||||
|
return `${imageName.replace(/[\/\:]/g, '-')}.tar`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadDockerImageFromCache(localCachePath: string, imageName: string): Promise<void> {
|
||||||
|
const cacheFilePath = path.join(localCachePath, getImageCacheFileName(imageName));
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(cacheFilePath)) {
|
||||||
|
await Docker.getExecOutput(['load', '-i', cacheFilePath], {
|
||||||
|
ignoreReturnCode: true
|
||||||
|
}).then(res => {
|
||||||
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
||||||
|
}
|
||||||
|
core.info(`Loaded image from ${cacheFilePath}`);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
core.info(`Cache file not found at ${cacheFilePath}, pulling image instead`);
|
||||||
|
await Docker.pull(imageName);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(`Failed to check/load cache file: ${error}`);
|
||||||
|
await Docker.pull(imageName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveDockerImageToCache(localCachePath: string, imageName: string): Promise<void> {
|
||||||
|
const cacheFilePath = path.join(localCachePath, getImageCacheFileName(imageName));
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!fs.existsSync(localCachePath)) {
|
||||||
|
fs.mkdirSync(localCachePath, {recursive: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs.existsSync(cacheFilePath)) {
|
||||||
|
core.info(`Cache file already exists at ${cacheFilePath}, skipping save`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await Docker.getExecOutput(['save', '-o', cacheFilePath, imageName], {
|
||||||
|
ignoreReturnCode: true
|
||||||
|
}).then(res => {
|
||||||
|
if (res.stderr.length > 0 && res.exitCode != 0) {
|
||||||
|
throw new Error(res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error');
|
||||||
|
}
|
||||||
|
core.info(`Saved image to ${cacheFilePath}`);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(`Failed to save image to cache file: ${error}`);
|
||||||
|
}
|
||||||
|
}
|
23
src/main.ts
23
src/main.ts
@ -3,6 +3,7 @@ import * as core from '@actions/core';
|
|||||||
import * as actionsToolkit from '@docker/actions-toolkit';
|
import * as actionsToolkit from '@docker/actions-toolkit';
|
||||||
|
|
||||||
import {Docker} from '@docker/actions-toolkit/lib/docker/docker';
|
import {Docker} from '@docker/actions-toolkit/lib/docker/docker';
|
||||||
|
import {loadDockerImageFromCache, saveDockerImageToCache} from './local-cache';
|
||||||
|
|
||||||
interface Platforms {
|
interface Platforms {
|
||||||
supported: string[];
|
supported: string[];
|
||||||
@ -19,9 +20,15 @@ actionsToolkit.run(
|
|||||||
await Docker.printInfo();
|
await Docker.printInfo();
|
||||||
});
|
});
|
||||||
|
|
||||||
await core.group(`Pulling binfmt Docker image`, async () => {
|
if (input.localCachePath !== '') {
|
||||||
await Docker.pull(input.image, input.cacheImage);
|
await core.group(`Pulling binfmt Docker image`, async () => {
|
||||||
});
|
await loadDockerImageFromCache(input.localCachePath, input.image);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await core.group(`Pulling binfmt Docker image`, async () => {
|
||||||
|
await Docker.pull(input.image, input.cacheImage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await core.group(`Image info`, async () => {
|
await core.group(`Image info`, async () => {
|
||||||
await Docker.getExecOutput(['image', 'inspect', input.image], {
|
await Docker.getExecOutput(['image', 'inspect', input.image], {
|
||||||
@ -56,5 +63,15 @@ actionsToolkit.run(
|
|||||||
core.setOutput('platforms', platforms.supported.join(','));
|
core.setOutput('platforms', platforms.supported.join(','));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// post
|
||||||
|
async () => {
|
||||||
|
const input: context.Inputs = context.getInputs();
|
||||||
|
if (input.localCachePath !== '') {
|
||||||
|
await core.group(`Saving binfmt Docker image`, async () => {
|
||||||
|
await saveDockerImageToCache(input.localCachePath, input.image);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user