UNPKG

@adpt/cli

Version:
174 lines 6.63 kB
"use strict"; /* * Copyright 2018-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 fs = tslib_1.__importStar(require("fs-extra")); const pacote = tslib_1.__importStar(require("pacote")); const path = tslib_1.__importStar(require("path")); const utils_1 = require("@adpt/utils"); const error_1 = require("../error"); const adapt_shared_1 = require("../types/adapt_shared"); const utils_2 = require("../utils"); const defaultOptions = { loglevel: "normal", progress: true, }; async function finalProjectOptions(userOpts) { let session = userOpts && userOpts.session; if (!session) session = await tempSession(); session.projectDir = path.resolve(session.projectDir); return Object.assign({}, defaultOptions, userOpts, { session }); } function yarnCommonOptions(projOpts, tmpModules) { const yOpts = { cwd: projOpts.session.projectDir, loglevel: projOpts.loglevel, noProgress: !projOpts.progress, }; if (projOpts.registry) yOpts.registry = projOpts.registry; if (tmpModules) yOpts.modulesFolder = tmpModules; return yOpts; } function yarnInstallOptions(projOpts, tmpModules) { const yOpts = yarnCommonOptions(projOpts, tmpModules); return Object.assign({}, yOpts, { production: true }); } async function load(projectSpec, projectOpts) { const finalOpts = await finalProjectOptions(projectOpts); const session = finalOpts.session; const pacoteOpts = { cache: session.cacheDir, }; if (finalOpts.registry) pacoteOpts.registry = finalOpts.registry; const manifest = await pacote.manifest(projectSpec, pacoteOpts); let inPlace = false; if (utils_2.isLocal(projectSpec)) { projectSpec = path.resolve(projectSpec); if (projectSpec === session.projectDir) inPlace = true; } if (!inPlace) await pacote.extract(projectSpec, session.projectDir, pacoteOpts); return new Project(manifest, session.projectDir, finalOpts); } exports.load = load; async function projectAdaptModule(projectRoot) { const entryFile = require.resolve("@adpt/core", { paths: [projectRoot] }); // Load Adapt at runtime. We've already done some version // verification before getting here, but we don't // have types. // TODO(mark): What's the right way to type this? We actually // don't want to have a dependency on @adpt/core. // tslint:disable-next-line:no-implicit-dependencies return adapt_shared_1.verifyAdaptModule(await require(entryFile)); } exports.projectAdaptModule = projectAdaptModule; class Project { constructor(manifest, projectDir, options) { this.manifest = manifest; this.projectDir = projectDir; this.options = options; this.installed = false; this.name = manifest.name; } getLockedVersion(pkgName) { if (!this.installed) { throw new Error(`Internal error: must call installModules before checking package versions`); } try { const pkgJsonPath = path.join(this.projectDir, "node_modules", pkgName, "package.json"); const pkgJson = fs.readJsonSync(pkgJsonPath); const version = pkgJson.version; if (!version || typeof version !== "string") { throw new Error(`Version information for package ${pkgName} is invalid (${version})`); } return version; } catch (err) { return null; } } async create(options) { return this.deploy(options, (adapt) => adapt.createDeployment(options)); } async update(options) { return this.deploy(options, (adapt) => adapt.updateDeployment(options)); } async status(options) { return this.deploy(options, (adapt) => adapt.fetchStatus(options)); } /** * NOTE: This function is purposely NOT async and returns the promise-like * execa ChildProcess object, NOT a promise to that object. That gives * the caller access to the output streams without having to wait for * completion of the yarn process. */ installModules() { if (this.installed) return; const ret = utils_1.yarn.install(yarnInstallOptions(this.options)); ret.then(() => this.installed = true).catch(); return ret; } async deploy(options, action) { if (!this.installed) { throw new Error(`Internal error: must call installModules before any deploy operation`); } const projectRoot = this.options.session.projectDir; options.fileName = path.resolve(projectRoot, options.fileName); options.projectRoot = projectRoot; const adapt = await projectAdaptModule(projectRoot); try { return adapt_shared_1.verifyDeployState(await action(adapt)); } catch (err) { if (err instanceof adapt.ProjectCompileError) { if (err.message) throw new error_1.UserError(err.message); } else if (err instanceof adapt.ProjectRunError) { if (err.message && err.projectStack) { throw new error_1.UserError(`${err.message}\n${err.projectStack}`); } } else if (err instanceof utils_1.ValidationError) { throw new Error(`Internal error: unrecognized response ` + `from Adapt build: ${err.message}`); } throw err; } } } exports.Project = Project; async function tempSession() { const dir = await utils_1.mkdtmp("adapt-cli"); const cacheDir = path.join(dir, "cache"); const projectDir = path.join(dir, "project"); await fs.ensureDir(cacheDir); await fs.ensureDir(projectDir); return { cacheDir, projectDir, remove: () => fs.removeSync(dir), }; } exports.tempSession = tempSession; //# sourceMappingURL=project.js.map