From 5a12a0d2144663f367d915a089a704f3f595d651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arwid=20Thornstr=C3=B6m?= Date: Tue, 25 Mar 2025 08:55:14 +0100 Subject: [PATCH] added sync command (#25) --- bin/pwdb.md | 14 ++ .../aws/s3/sync_images/sync_images.ts | 137 ++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 src/commands/aws/s3/sync_images/sync_images.ts diff --git a/bin/pwdb.md b/bin/pwdb.md index 67eea2c..6467af3 100644 --- a/bin/pwdb.md +++ b/bin/pwdb.md @@ -6,3 +6,17 @@ You often have the address in your .pgpass Sync the downloaded file to your localhost with 4 cores `./pwdb sync [address] localhost -j 4 -p` To get a production db with grants + +If something is wrong with the db. Like you get errors from API2. +Then you open postgres console with `psql photowall` and run + +``` +REVOKE ALL ON SCHEMA public FROM public; +GRANT USAGE ON SCHEMA public TO photowall; +GRANT SELECT, UPDATE, INSERT, DELETE ON ALL TABLES IN SCHEMA public TO photowall; +GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO photowall; +ALTER DEFAULT PRIVILEGES IN SCHEMA public + GRANT SELECT, UPDATE, INSERT, DELETE ON TABLES TO photowall; +ALTER DEFAULT PRIVILEGES IN SCHEMA public + GRANT USAGE, SELECT ON SEQUENCES TO photowall; +``` diff --git a/src/commands/aws/s3/sync_images/sync_images.ts b/src/commands/aws/s3/sync_images/sync_images.ts new file mode 100644 index 0000000..8698e46 --- /dev/null +++ b/src/commands/aws/s3/sync_images/sync_images.ts @@ -0,0 +1,137 @@ +import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu'; +import chalk = require('chalk'); +import { defaultMenuSettings } from '../../../../globals'; +const { MultiSelect, Confirm } = require('enquirer'); + +module.exports = { + name: 'Sync Images on S3', + alias: ['si'], + description: 'Sync images between S3 buckets (a s3 si)', + hidden: false, + run: async (toolbox: GluegunMenuToolbox) => { + const { system, print } = toolbox; + + // Define the folder options + const folderOptions = [ + 'products', + 'interiors', + 'interior-images', + 'articles', + ]; + + // Ask the user to select one or many folders + const prompt = new MultiSelect({ + name: 'folders', + message: + 'Select folder(s) to sync (use space to select, enter to confirm)', + choices: folderOptions, + result(names) { + return this.map(names); + }, + }); + + let selectedFolders; + try { + selectedFolders = await prompt.run(); + } catch (error) { + print.error('Selection cancelled'); + if (toolbox.fromMenu()) { + await toolbox.menu.showMenu('aws s3', defaultMenuSettings); + } + return; + } + + if (Object.keys(selectedFolders).length === 0) { + print.info('No folders selected'); + if (toolbox.fromMenu()) { + await toolbox.menu.showMenu('aws s3', defaultMenuSettings); + } + return; + } + + // Display selected folders + print.info('\nSelected folders:'); + Object.keys(selectedFolders).forEach((folder) => { + print.info(`- ${chalk.yellow(folder)}`); + }); + + // Ask if the user wants to use --dryrun flag for all commands + const dryRunPrompt = new Confirm({ + name: 'dryrun', + message: `Do you want to use the ${chalk.cyan( + '--dryrun' + )} flag for all commands?`, + }); + + let useDryRun = false; + try { + useDryRun = await dryRunPrompt.run(); + } catch (error) { + print.error('Operation cancelled'); + if (toolbox.fromMenu()) { + await toolbox.menu.showMenu('aws s3', defaultMenuSettings); + } + return; + } + + // Process each folder with individual confirmation + let completedSyncs = 0; + for (const folder of Object.keys(selectedFolders)) { + // Create the command with or without dryrun flag + const dryRunFlag = useDryRun ? ' --dryrun' : ''; + const cmd = `aws s3 sync s3://photowall-images/${folder}/ s3://photowall-images-dev/${folder}/${dryRunFlag}`; + + // Show the command that will be executed + print.info(`\nCommand for ${chalk.yellow(folder)}:`); + print.info(chalk.cyan(cmd)); + + // Ask for confirmation to run this specific command + const confirmPrompt = new Confirm({ + name: 'confirm', + message: `Do you want to run this command for ${chalk.yellow(folder)}?`, + }); + + let runThisCommand; + try { + runThisCommand = await confirmPrompt.run(); + } catch (error) { + print.info(`Skipping ${chalk.yellow(folder)}`); + continue; // Skip to the next folder + } + + if (!runThisCommand) { + print.info(`Skipping ${chalk.yellow(folder)}`); + continue; // Skip to the next folder + } + + // Run the command since it was confirmed + print.info(`\nSyncing ${chalk.yellow(folder)}...`); + + // Run command and capture output + try { + const output = await system.run(cmd, { trim: true }); + + // Display command output + print.info(chalk.green('\nCommand output:')); + if (output && output.length > 0) { + print.info(output); + } else { + print.info('No output (command completed successfully)'); + } + completedSyncs++; + } catch (error) { + print.error(`Error executing command: ${error.message || error}`); + } + } + + if (completedSyncs > 0) { + print.success(`\nCompleted ${completedSyncs} sync command(s)`); + } else { + print.info('\nNo sync commands were executed'); + } + + if (toolbox.fromMenu()) { + await toolbox.menu.showMenu('aws s3', defaultMenuSettings); + } + }, +};