UNPKG

@adpt/cloud

Version:
177 lines 6.66 kB
"use strict"; /* * Copyright 2019 Unbounded Systems, LLC * * 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. */ Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const core_1 = require("@adpt/core"); const utils_1 = require("@adpt/utils"); const fs_extra_1 = tslib_1.__importDefault(require("fs-extra")); const json_stable_stringify_1 = tslib_1.__importDefault(require("json-stable-stringify")); const path = tslib_1.__importStar(require("path")); const action_1 = require("../action"); const cli_1 = require("./cli"); /** * Locally builds a docker image * * @remarks * See {@link docker.LocalDockerImageProps}. * * @public */ class LocalDockerImage extends action_1.Action { constructor(props) { super(props); // Even though we have a custom deployedWhen, don't normally show // status from this component, unless there's an active action. this.deployedWhenIsTrivial = true; /** @internal */ this.deployedWhen = (goalStatus) => { if (goalStatus === core_1.DeployStatus.Destroyed) return true; if (this.buildComplete()) return true; if (this.state.imagePropsJson && this.state.imagePropsJson !== this.imagePropsJson) { return core_1.waiting("Waiting for Docker image to be re-built"); } return core_1.waiting("Waiting for Docker image to be built"); }; this.options_ = Object.assign({}, LocalDockerImage.defaultProps.options, (props.options || {})); if (!props.dockerfile && !props.dockerfileName) { throw new Error(`LocalDockerImage: one of dockerfile or ` + `dockerfileName must be given`); } } /* * Public instance properties/methods */ buildComplete() { return this.image() != null; } ready() { return this.buildComplete(); } image() { if (this.image_ == null) { if (this.state.image != null && // Ensure we've rebuilt at least once this OpID this.state.deployOpID === this.deployInfo.deployOpID && // And ensure the current build matches current props this.state.imagePropsJson === this.imagePropsJson) { this.image_ = this.state.image; } } return this.image_; } async pushTo(registryUrl, newTag) { const im = this.latestImage(); if (!im) return undefined; newTag = newTag || im.nameTag; if (!newTag) { throw new Error(`Unable to push image to registry: no nameTag ` + `set for this image and new tag not provided`); } const fullTag = `${registryUrl}/${newTag}`; const globals = cli_1.pickGlobals(this.options_); await cli_1.dockerTag(Object.assign({ existing: im.id, newTag: fullTag }, globals)); await cli_1.dockerPush(Object.assign({ nameTag: fullTag }, globals)); return { id: im.id, nameTag: fullTag, }; } latestImage() { return this.image_ || this.state.image; } /** * User-facing name to display in status messages. */ displayName() { return this.options_.imageName; } /** * Implementations for Action base class * @internal */ async shouldAct(op) { let imgName = this.options_.imageName || ""; if (imgName) imgName = ` '${imgName}'`; if (op === core_1.ChangeType.delete) return false; if (this.buildComplete()) return false; return { act: true, detail: `Building Docker image${imgName}`, }; } /** * Implementations for Action base class * @internal */ async action(op, ctx) { const options = Object.assign({}, this.options_, { deployID: ctx.buildData.deployID }); const prevUniqueTag = this.state.prevUniqueTag; if (op === core_1.ChangeType.delete) { throw new utils_1.InternalError(`Delete action should not happen due to check in shouldAct`); } let dockerfile = this.props.dockerfile; if (!dockerfile) { if (!this.props.dockerfileName) { throw new utils_1.InternalError(`dockerfileName should not be null`); } dockerfile = (await fs_extra_1.default.readFile(this.props.dockerfileName)).toString(); } const stages = this.props.stages || []; const image = await cli_1.withFilesImage(this.props.files, options, async (img) => { if (img) stages.push({ image: img.id, name: "files" }); const stageConfig = stages .map((s) => `FROM ${s.image} as ${s.name}`) .join("\n"); if (stageConfig) { dockerfile = `${stageConfig}\n\n${dockerfile}`; } let contextDir = this.props.contextDir || "."; contextDir = path.resolve(contextDir); return cli_1.dockerBuild("-", contextDir, Object.assign({}, options, { prevUniqueTag, stdin: dockerfile })); }); this.image_ = image; this.setState({ deployOpID: this.deployInfo.deployOpID, image, imagePropsJson: this.imagePropsJson, prevUniqueTag: options.uniqueTag ? image.nameTag : undefined, }); } /* * Component methods */ /** @internal */ initialState() { return {}; } /** @internal */ get imagePropsJson() { if (!this.imagePropsJson_) { const _a = this.props, { handle: _h, key } = _a, imageProps = tslib_1.__rest(_a, ["handle", "key"]); this.imagePropsJson_ = json_stable_stringify_1.default(imageProps); } return this.imagePropsJson_; } } LocalDockerImage.defaultProps = { options: { dockerHost: process.env.DOCKER_HOST, forceRm: true, }, }; exports.LocalDockerImage = LocalDockerImage; //# sourceMappingURL=LocalDockerImage.js.map