UNPKG

@docker/actions-toolkit

Version:
199 lines 6.81 kB
/** * Copyright 2023 actions-toolkit authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import fs from 'fs'; import os from 'os'; import path from 'path'; import * as core from '@actions/core'; import * as io from '@actions/io'; import { Context } from '../context.js'; import { Cache } from '../cache.js'; import { Exec } from '../exec.js'; import { Util } from '../util.js'; export class Docker { static get configDir() { return process.env.DOCKER_CONFIG || path.join(os.homedir(), '.docker'); } static configFile() { const f = path.join(Docker.configDir, 'config.json'); if (!fs.existsSync(f)) { return undefined; } return JSON.parse(fs.readFileSync(f, { encoding: 'utf-8' })); } static async isAvailable() { return await io .which('docker', true) .then(res => { core.debug(`Docker.isAvailable ok: ${res}`); return true; }) .catch(error => { core.debug(`Docker.isAvailable error: ${error}`); return false; }); } static async isDaemonRunning() { try { await Docker.getExecOutput([`version`], { silent: true }); return true; } catch { return false; } } static async exec(args, options) { return Exec.exec('docker', args, Docker.execOptions(options)); } static async getExecOutput(args, options) { return Exec.getExecOutput('docker', args, Docker.execOptions(options)); } static execOptions(options) { if (!options) { options = {}; } if (!options.env) { options.env = Object.assign({}, process.env, { DOCKER_CONTENT_TRUST: 'false' }); } else { options.env.DOCKER_CONTENT_TRUST = 'false'; } return options; } static async context(name) { const args = ['context', 'inspect', '--format', '{{.Name}}']; if (name) { args.push(name); } return await Docker.getExecOutput(args, { ignoreReturnCode: true, silent: true }).then(res => { if (res.stderr.length > 0 && res.exitCode != 0) { throw new Error(res.stderr); } return res.stdout.trim(); }); } static async contextInspect(name) { const args = ['context', 'inspect', '--format=json']; if (name) { args.push(name); } return await Docker.getExecOutput(args, { ignoreReturnCode: true, silent: true }).then(res => { if (res.stderr.length > 0 && res.exitCode != 0) { throw new Error(res.stderr.trim()); } return JSON.parse(res.stdout.trim())[0]; }); } static async printVersion() { await Docker.exec(['version']); } static async printInfo() { await Docker.exec(['info']); } static parseRepoTag(image) { let sepPos; const digestPos = image.indexOf('@'); const colonPos = image.lastIndexOf(':'); if (digestPos >= 0) { // priority on digest sepPos = digestPos; } else if (colonPos >= 0) { sepPos = colonPos; } else { return { repository: image, tag: 'latest' }; } const tag = image.slice(sepPos + 1); if (tag.indexOf('/') === -1) { return { repository: image.slice(0, sepPos), tag: tag }; } return { repository: image, tag: 'latest' }; } static async pull(image, cache) { const parsedImage = Docker.parseRepoTag(image); const repoSanitized = parsedImage.repository.replace(/[^a-zA-Z0-9.]+/g, '--'); const tagSanitized = parsedImage.tag.replace(/[^a-zA-Z0-9.]+/g, '--'); const imageCache = new Cache({ htcName: repoSanitized, htcVersion: tagSanitized, baseCacheDir: path.join(Docker.configDir, '.cache', 'images', repoSanitized), cacheFile: 'image.tar' }); let cacheFoundPath; if (cache) { cacheFoundPath = await imageCache.find(); if (cacheFoundPath) { core.info(`Image found from cache in ${cacheFoundPath}`); await Docker.getExecOutput(['load', '-i', cacheFoundPath], { ignoreReturnCode: true }).then(res => { if (res.stderr.length > 0 && res.exitCode != 0) { core.warning(`Failed to load image from cache: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`); } }); } } let pulled = true; await Docker.getExecOutput(['pull', image], { ignoreReturnCode: true }).then(res => { if (res.stderr.length > 0 && res.exitCode != 0) { pulled = false; const err = res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'; if (cacheFoundPath) { core.warning(`Failed to pull image, using one from cache: ${err}`); } else { throw new Error(err); } } }); if (cache && pulled) { const imageTarPath = path.join(Context.tmpDir(), `${Util.hash(image)}.tar`); await Docker.getExecOutput(['save', '-o', imageTarPath, image], { ignoreReturnCode: true }).then(async (res) => { if (res.stderr.length > 0 && res.exitCode != 0) { core.warning(`Failed to save image: ${res.stderr.match(/(.*)\s*$/)?.[0]?.trim() ?? 'unknown error'}`); } else { const cachePath = await imageCache.save(imageTarPath); core.info(`Image cached to ${cachePath}`); } }); } } } //# sourceMappingURL=docker.js.map