@digicms/cms
Version:
An open source headless CMS solution to create and manage your own API. It provides a powerful dashboard and features to make your life easier. Databases supported: MySQL, MariaDB, PostgreSQL, SQLite
226 lines (191 loc) • 6.04 kB
JavaScript
;
const chalk = require('chalk');
const Table = require('cli-table3');
const { Option } = require('commander');
const {
engine: { TransferGroupPresets },
} = require('@strapi/data-transfer');
const {
configs: { createOutputFileConfiguration },
createLogger,
} = require('@strapi/logger');
const ora = require('ora');
const { readableBytes, exitWith } = require('../utils/helpers');
const strapi = require('../../index');
const { getParseListWithChoices } = require('../utils/commander');
const pad = (n) => {
return (n < 10 ? '0' : '') + String(n);
};
const yyyymmddHHMMSS = () => {
const date = new Date();
return (
date.getFullYear() +
pad(date.getMonth() + 1) +
pad(date.getDate()) +
pad(date.getHours()) +
pad(date.getMinutes()) +
pad(date.getSeconds())
);
};
const getDefaultExportName = () => {
return `export_${yyyymmddHHMMSS()}`;
};
const buildTransferTable = (resultData) => {
// Build pretty table
const table = new Table({
head: ['Type', 'Count', 'Size'].map((text) => chalk.bold.blue(text)),
});
let totalBytes = 0;
let totalItems = 0;
Object.keys(resultData).forEach((key) => {
const item = resultData[key];
table.push([
{ hAlign: 'left', content: chalk.bold(key) },
{ hAlign: 'right', content: item.count },
{ hAlign: 'right', content: `${readableBytes(item.bytes, 1, 11)} ` },
]);
totalBytes += item.bytes;
totalItems += item.count;
if (item.aggregates) {
Object.keys(item.aggregates)
.sort()
.forEach((subkey) => {
const subitem = item.aggregates[subkey];
table.push([
{ hAlign: 'left', content: `-- ${chalk.bold.grey(subkey)}` },
{ hAlign: 'right', content: chalk.grey(subitem.count) },
{ hAlign: 'right', content: chalk.grey(`(${readableBytes(subitem.bytes, 1, 11)})`) },
]);
});
}
});
table.push([
{ hAlign: 'left', content: chalk.bold.green('Total') },
{ hAlign: 'right', content: chalk.bold.green(totalItems) },
{ hAlign: 'right', content: `${chalk.bold.green(readableBytes(totalBytes, 1, 11))} ` },
]);
return table;
};
const DEFAULT_IGNORED_CONTENT_TYPES = [
'admin::permission',
'admin::user',
'admin::role',
'admin::api-token',
'admin::api-token-permission',
'admin::transfer-token',
'admin::transfer-token-permission',
'admin::audit-log',
];
const createStrapiInstance = async (logLevel = 'error') => {
try {
const appContext = await strapi.compile();
const app = strapi(appContext);
app.log.level = logLevel;
return await app.load();
} catch (err) {
if (err.code === 'ECONNREFUSED') {
throw new Error('Process failed. Check the database connection with your Strapi project.');
}
throw err;
}
};
const transferDataTypes = Object.keys(TransferGroupPresets);
const excludeOption = new Option(
'--exclude <comma-separated data types>',
`Exclude data using comma-separated types. Available types: ${transferDataTypes.join(',')}`
).argParser(getParseListWithChoices(transferDataTypes, 'Invalid options for "exclude"'));
const onlyOption = new Option(
'--only <command-separated data types>',
`Include only these types of data (plus schemas). Available types: ${transferDataTypes.join(',')}`
).argParser(getParseListWithChoices(transferDataTypes, 'Invalid options for "only"'));
const validateExcludeOnly = (command) => {
const { exclude, only } = command.opts();
if (!only || !exclude) {
return;
}
const choicesInBoth = only.filter((n) => {
return exclude.indexOf(n) !== -1;
});
if (choicesInBoth.length > 0) {
exitWith(
1,
`Data types may not be used in both "exclude" and "only" in the same command. Found in both: ${choicesInBoth.join(
','
)}`
);
}
};
const errorColors = {
fatal: chalk.red,
error: chalk.red,
silly: chalk.yellow,
};
const formatDiagnostic =
(operation) =>
({ details, kind }) => {
const logger = createLogger(
createOutputFileConfiguration(`${operation}_error_log_${Date.now()}.log`)
);
try {
if (kind === 'error') {
const { message, severity = 'fatal' } = details;
const colorizeError = errorColors[severity];
const errorMessage = colorizeError(`[${severity.toUpperCase()}] ${message}`);
logger.error(errorMessage);
}
if (kind === 'info') {
const { message, params } = details;
const msg = `${message}\n${params ? JSON.stringify(params, null, 2) : ''}`;
logger.info(msg);
}
if (kind === 'warning') {
const { origin, message } = details;
logger.warn(`(${origin ?? 'transfer'}) ${message}`);
}
} catch (err) {
logger.error(err);
}
};
const loadersFactory = (defaultLoaders = {}) => {
const loaders = defaultLoaders;
const updateLoader = (stage, data) => {
if (!(stage in loaders)) {
createLoader(stage);
}
const stageData = data[stage];
const elapsedTime = stageData?.startTime
? (stageData?.endTime || Date.now()) - stageData.startTime
: 0;
const size = `size: ${readableBytes(stageData?.bytes ?? 0)}`;
const elapsed = `elapsed: ${elapsedTime} ms`;
const speed =
elapsedTime > 0 ? `(${readableBytes(((stageData?.bytes ?? 0) * 1000) / elapsedTime)}/s)` : '';
loaders[stage].text = `${stage}: ${stageData?.count ?? 0} transfered (${size}) (${elapsed}) ${
!stageData?.endTime ? speed : ''
}`;
return loaders[stage];
};
const createLoader = (stage) => {
Object.assign(loaders, { [stage]: ora() });
return loaders[stage];
};
const getLoader = (stage) => {
return loaders[stage];
};
return {
updateLoader,
createLoader,
getLoader,
};
};
module.exports = {
loadersFactory,
buildTransferTable,
getDefaultExportName,
DEFAULT_IGNORED_CONTENT_TYPES,
createStrapiInstance,
excludeOption,
onlyOption,
validateExcludeOnly,
formatDiagnostic,
};