From 189059dba8e62308b41500f1daef3818ece4f952 Mon Sep 17 00:00:00 2001 From: Nafis Hossain Date: Thu, 20 Jun 2024 18:31:15 +1000 Subject: [PATCH] feat: dry run check state --- package.json | 3 +-- src/check.ts | 24 ++++++++++++++++++++++++ src/cli.ts | 29 ++++++++++++++++++++++++++--- src/config.ts | 45 ++++++++++++++++++++++++--------------------- src/run.ts | 2 -- src/state.ts | 21 ++++++++++++++++----- 6 files changed, 91 insertions(+), 33 deletions(-) create mode 100644 src/check.ts diff --git a/package.json b/package.json index 70acf01..ddbabae 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,7 @@ "main": "index.js", "scripts": { "test": "jest src/test", - "cli": "tsx src/cli.ts", - "check": "tsx src/check.ts" + "cli": "tsx src/cli.ts" }, "author": "nafis hossain ", "license": "BSD-3-Clause", diff --git a/src/check.ts b/src/check.ts new file mode 100644 index 0000000..806c0a4 --- /dev/null +++ b/src/check.ts @@ -0,0 +1,24 @@ +import { S3Client } from "@aws-sdk/client-s3"; + +import { getClient } from "./s3"; +import { buildState } from "./state"; +import { getConfig } from "./config"; +import { logger } from "./logger"; + +export const checkState = async (): Promise => { + try { + const config = getConfig(); + const { bucketName, inputConfig } = config; + + const s3Client: S3Client = await getClient(); + + await buildState(bucketName, inputConfig, s3Client); + } catch (err) { + if (err instanceof Error) { + logger.error(err.message); + } else { + logger.error("An unknown error occurred."); + } + process.exit(1); + } +}; diff --git a/src/cli.ts b/src/cli.ts index 4352bef..22316d2 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,5 +1,28 @@ +import { Command } from "commander"; + import { run } from "./run"; +import { checkState } from "./check"; + +const program = new Command(); + +program + .command("run") + .description("process all images") + .action(async () => { + await run(); + }); + +program + .command("check") + .description( + "check how many images have been processed and need to be processed" + ) + .action(async () => { + await checkState(); + }); + +program.parse(process.argv); -(async () => { - await run(); -})(); +if (!process.argv.slice(2).length) { + program.outputHelp(); +} diff --git a/src/config.ts b/src/config.ts index d4eaf39..f136a9c 100644 --- a/src/config.ts +++ b/src/config.ts @@ -28,6 +28,29 @@ const ConfigSchema = z.object({ export type Config = z.infer; +const validateConfig = (config: unknown): Config => { + const configObj = ConfigSchema.parse(config); + const { inputConfig } = configObj; + + const outputImages = inputConfig.outputImages; + const dimensionSet = new Set(); + + outputImages.forEach((image, index) => { + const dimensionKey = image.width + ? `width:${image.width}` + : `height:${image.height}`; + if (dimensionSet.has(dimensionKey)) { + throw new Error( + `Duplicate dimension found in OutputImageConfig at index ${index}: ${dimensionKey}` + ); + } + + dimensionSet.add(dimensionKey); + }); + + return configObj; +}; + export const getConfig = (): Config => { try { const explorerSync = cosmiconfigSync("lilsync"); @@ -37,27 +60,7 @@ export const getConfig = (): Config => { throw new Error("configuration file not found or is empty"); } - const configObj = ConfigSchema.parse(result.config); - const { inputConfig } = configObj; - - const outputImages = inputConfig.outputImages; - - const dimensionSet = new Set(); - - outputImages.forEach((image, index) => { - const dimensionKey = image.width - ? `width:${image.width}` - : `height:${image.height}`; - if (dimensionSet.has(dimensionKey)) { - throw new Error( - `Duplicate dimension found in OutputImageConfig at index ${index}: ${dimensionKey}` - ); - } - - dimensionSet.add(dimensionKey); - }); - - return configObj; + return validateConfig(result.config); } catch (err) { if (err instanceof z.ZodError) { const formattedErrors = err.errors diff --git a/src/run.ts b/src/run.ts index 2972673..060c1bc 100644 --- a/src/run.ts +++ b/src/run.ts @@ -11,8 +11,6 @@ export const run = async (): Promise => { const s3Client = await getClient(); - logger.info("building state"); - const state = await buildState(bucketName, inputConfig, s3Client); logger.info("processing images"); diff --git a/src/state.ts b/src/state.ts index 249172d..90d02b5 100644 --- a/src/state.ts +++ b/src/state.ts @@ -1,3 +1,4 @@ +import ansis from "ansis"; import { S3Client } from "@aws-sdk/client-s3"; import type { @@ -201,6 +202,8 @@ export const buildState = async ( config: InputConfig, s3Client: S3Client ): Promise => { + logger.info(ansis.gray("building state")); + const inputFileKeys = await listBucketObjects( bucketName, s3Client, @@ -214,11 +217,13 @@ export const buildState = async ( const allFileKeys = [...inputFileKeys, ...outputFileKeys]; - logger.info(`number of files: ${allFileKeys.length}`); + logger.info(`number of files: ${ansis.green(String(allFileKeys.length))}`); const inputBaseNames = collectInputImages(allFileKeys, config); - logger.info(`input images ${Object.keys(inputBaseNames).length}`); + logger.info( + `input images: ${ansis.green(String(Object.keys(inputBaseNames).length))}` + ); const publishedBaseNames = collectProcessedImages( allFileKeys, @@ -232,11 +237,17 @@ export const buildState = async ( }, 0 ); - logger.info(`output images already created: ${numOutputImages}`); + logger.info( + `output images already created: ${ansis.green(String(numOutputImages))}` + ); const unmatchedOutputImages = findUnmatchedImages(publishedBaseNames); - logger.info(`unmatched output images: ${unmatchedOutputImages.length}`); + logger.info( + `unmatched output images: ${ansis.green( + String(unmatchedOutputImages.length) + )}` + ); const missedImagesToCreate = getPartialProcessedImages( config, @@ -257,7 +268,7 @@ export const buildState = async ( 0 ); - logger.info(`images to create: ${numImagesToCreate}`); + logger.info(`images to create: ${ansis.green(String(numImagesToCreate))}`); return { config,