UNPKG

@ipp/cli

Version:

An image build orchestrator for the modern web

113 lines (112 loc) 4.66 kB
"use strict"; /** * Image Processing Pipeline - Copyright (c) Marcus Cemes * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.startCli = void 0; const constants_1 = require("constants"); const fs_1 = require("fs"); const path_1 = require("path"); const constants_2 = require("./constants"); const context_1 = require("./lib/context"); const exception_1 = require("./lib/exception"); const state_1 = require("./lib/state"); const buffer_1 = require("./lib/stream/operators/buffer"); const passthrough_1 = require("./lib/stream/operators/passthrough"); const to_promise_1 = require("./lib/stream/operators/to_promise"); const counters_1 = require("./operators/counters"); const exceptions_1 = require("./operators/exceptions"); const manifest_1 = require("./operators/manifest"); const process_1 = require("./operators/process"); const save_1 = require("./operators/save"); const search_1 = require("./operators/search"); const ui_1 = require("./ui"); const MANIFEST_FILE = "manifest.json"; const BUFFER_SIZE = 8; async function startCli(config, ui = ui_1.DynamicUI) { return withCliContext(config.concurrency, !!config.manifest, !!config.clean, constants_2.VERSION, ui, async (ctx) => { try { // Unregister handler to allow force quitting ctx.interrupt.rejecter.catch(() => { ctx.interrupt.destroy(); setStatus(ctx, state_1.Status.INTERRUPT); }); if (config.clean) await deleteDirectory(config.output); await ensureOutputPath(config.output); setStatus(ctx, state_1.Status.PROCESSING); await createPipeline(ctx, config, MANIFEST_FILE).pipe((0, to_promise_1.toPromise)()); setStatus(ctx, state_1.Status.COMPLETE); } catch (err) { setStatus(ctx, state_1.Status.ERROR); throw err; } }); } exports.startCli = startCli; async function withCliContext(concurrency, manifest, clean, version, ui, fn) { const ctx = (0, context_1.createContext)(concurrency, manifest, clean, version, ui); try { await fn(ctx); } finally { await ctx.ui.stop(ctx.state.complete()); ctx.interrupt.destroy(); } } function createPipeline(ctx, config, manifestFile) { const paths = typeof config.input === "string" ? [config.input] : config.input; return (0, search_1.searchForImages)(paths) .pipe((0, counters_1.sourceCounter)(ctx)) .pipe((0, buffer_1.buffer)(BUFFER_SIZE)) .pipe((0, process_1.processImages)(config.pipeline, config.concurrency)) .pipe((0, counters_1.completedCounter)(ctx)) .pipe((0, buffer_1.buffer)(BUFFER_SIZE)) .pipe((0, save_1.saveImages)(config.output, !!config.flat)) .pipe(config.manifest ? (0, manifest_1.saveManifest)((0, path_1.resolve)(config.output, manifestFile), config.manifest) : (0, passthrough_1.passthrough)()) .pipe((0, counters_1.exceptionCounter)(ctx)) .pipe(config.suppressErrors ? (0, passthrough_1.passthrough)() : (0, exceptions_1.exceptionHandler)(config.output, config.errorOutput)); } function setStatus(ctx, status) { ctx.state.update((state) => (state.status = status)); } async function ensureOutputPath(path) { try { await fs_1.promises.access(path, constants_1.W_OK); } catch (err) { await fs_1.promises.mkdir(path); } } async function deleteDirectory(path) { try { const stat = await fs_1.promises.stat(path); if (!stat.isDirectory()) { throw new exception_1.CliException("Output clean error", exception_1.CliExceptionCode.CLEAN, "Output clean error", "The output path already exists but is not a directory.\n" + "Please remove the file and try again.\n"); } } catch (error) { if (hasErrorCode(error, "ENOENT")) return; throw error; } try { await fs_1.promises.rm(path, { recursive: true }); } catch (err) { throw new exception_1.CliException("Output clean error:\n" + err.message, exception_1.CliExceptionCode.CLEAN, "Output clean error", "An error occurred while trying to clean the out directory.\n" + "You may not have sufficient permissions to do so.\n" + "You can disable output cleaning in the config file.\n\n" + String(err)); } } function hasErrorCode(error, code) { return error instanceof Error && error.code === code; }