diff --git a/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts b/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts index e684e53304..756663fd0e 100644 --- a/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts +++ b/packages/core/data-transfer/lib/providers/local-file-destination-provider.ts @@ -56,7 +56,7 @@ class LocalFileDestinationProvider implements IDestinationProvider { results: ILocalFileDestinationProviderTransferResults = {}; #providersMetadata: { source?: IMetadata; destination?: IMetadata } = {}; - #archive: { stream?: tar.Pack } = {}; + #archive: { stream?: tar.Pack; pipeline?: Stream } = {}; constructor(options: ILocalFileDestinationProviderOptions) { this.options = options; @@ -117,25 +117,24 @@ class LocalFileDestinationProvider implements IDestinationProvider { archiveTransforms.push(createEncryptionCipher(encryption.key)); } - chain([this.#archive.stream, ...archiveTransforms, outStream]); + this.#archive.pipeline = chain([this.#archive.stream, ...archiveTransforms, outStream]); this.results.file = { path: this.#archivePath }; } async close() { - const { stream } = this.#archive; + const { stream, pipeline } = this.#archive; if (!stream) { return; } await this.#writeMetadata(); - stream.finalize(); - if (!stream.closed) { + if (pipeline && !pipeline.closed) { await new Promise((resolve, reject) => { - stream.on('close', resolve).on('error', reject); + pipeline.on('close', resolve).on('error', reject); }); } } diff --git a/packages/core/strapi/bin/strapi.js b/packages/core/strapi/bin/strapi.js index 55aebc7e99..a9e09af01f 100755 --- a/packages/core/strapi/bin/strapi.js +++ b/packages/core/strapi/bin/strapi.js @@ -8,6 +8,7 @@ const _ = require('lodash'); const resolveCwd = require('resolve-cwd'); const { yellow } = require('chalk'); const { Command, Option } = require('commander'); +const inquirer = require('inquirer'); const program = new Command(); @@ -285,7 +286,9 @@ program .default(true) .argParser(parseInputBool) ) - .addOption(new Option('--key', 'Provide encryption key in command instead of using a prompt')) + .addOption( + new Option('--key ', 'Provide encryption key in command instead of using a prompt') + ) .addOption( new Option('--max-size ', 'split final file when exceeding size in MB') ) @@ -295,8 +298,8 @@ program 'split internal jsonl files when exceeding max size in MB' ) ) + .addOption(new Option('-f, --file ', 'name to use for exported file (without extensions)')) .addOption(excludeOption) - .arguments('[filename]') .allowExcessArguments(false) .hook('preAction', promptEncryptionKey) .action(getLocalScript('transfer/export')); @@ -320,11 +323,35 @@ program .choices(['exact', 'strict', 'subset', 'bypass']) .default('exact') ) - .addOption( - new Option('--key [encryptionKey]', 'prompt for [or provide directly] the decryption key') + .requiredOption( + '-f, --file ', + 'path and filename to the Strapi export file you want to import' + ) + .addOption( + new Option('--key ', 'Provide encryption key in command instead of using a prompt') ) - .arguments('') .allowExcessArguments(false) + .hook('preAction', async (thisCommand) => { + const opts = thisCommand.opts(); + + // check extension to guess if we should prompt for key + if (String(opts.file).endsWith('.enc')) { + if (!opts.key) { + const answers = await inquirer.prompt([ + { + type: 'password', + message: 'Please enter your decryption key', + name: 'key', + }, + ]); + if (!answers.key?.length) { + console.log('No key entered, aborting import.'); + process.exit(0); + } + opts.key = answers.key; + } + } + }) .hook( 'preAction', confirmKeyValue( diff --git a/packages/core/strapi/lib/commands/transfer/export.js b/packages/core/strapi/lib/commands/transfer/export.js index 4dc86db866..1b9c7b20cf 100644 --- a/packages/core/strapi/lib/commands/transfer/export.js +++ b/packages/core/strapi/lib/commands/transfer/export.js @@ -40,12 +40,14 @@ const logger = console; const BYTES_IN_MB = 1024 * 1024; -module.exports = async (filename, opts) => { +module.exports = async (opts) => { // validate inputs from Commander if (!_.isObject(opts)) { logger.error('Could not parse arguments'); process.exit(1); } + const filename = opts.file; + /** * From local Strapi instance */ diff --git a/packages/core/strapi/lib/commands/transfer/import.js b/packages/core/strapi/lib/commands/transfer/import.js index e9d48e75d2..746b065eec 100644 --- a/packages/core/strapi/lib/commands/transfer/import.js +++ b/packages/core/strapi/lib/commands/transfer/import.js @@ -7,18 +7,18 @@ const { // TODO: we need to solve this issue with typescript modules // eslint-disable-next-line import/no-unresolved, node/no-missing-require } = require('@strapi/data-transfer'); -const _ = require('lodash/fp'); - +const { isObject } = require('lodash/fp'); const strapi = require('../../index'); const logger = console; -module.exports = async (filename, opts) => { +module.exports = async (opts) => { // validate inputs from Commander - if (!_.isString(filename) || !_.isObject(opts)) { + if (!isObject(opts)) { logger.error('Could not parse arguments'); process.exit(1); } + const filename = opts.file; /** * From strapi backup file @@ -59,7 +59,7 @@ module.exports = async (filename, opts) => { logger.log('Results:', result); process.exit(0); } catch (e) { - logger.log('Import process failed unexpectedly'); + logger.log(`Import process failed unexpectedly: ${e.message}`); process.exit(1); } };