fileutils-cli
Version:
A collection of powerful command line file utilities
193 lines (181 loc) • 7.93 kB
JavaScript
const chalk = require('chalk');
const fs = require('fs-extra');
const nunjucks = require('../util/nunjucks');
const path = require('path');
const pathExists = require('path-exists');
const readlineSync = require('readline-sync');
const { FileData } = require('./FileData');
module.exports.Operation = class Operation {
constructor(input, options, sequelize) {
this.currentDir = process.cwd() + path.sep;
this.options = options;
this.sequelize = sequelize;
this.inputFileString = input;
this.inputFilePath = path.parse(input);
this.fileData = new FileData(input, options);
this.outputString = '';
this.outputFilePath = (path.parse(this.outputString));
this.outputFileString = '';
this.conflict = false;
this.alreadyExists = false;
this.directoryExists = true;
}
async replaceVariables() {
let data = await this.fileData.get();
this.outputString = nunjucks.renderString(this.options.outputPattern, data);
await this.parseOutputPath();
}
async printData() {
let data;
if (this.userData) {
data = await Object.assign(await this.fileData.get(), this.userData);
} else {
data = await this.fileData.get();
}
console.dir(data);
}
async parseOutputPath() {
let resolved = path.resolve(this.outputString);
// check if existing directory
const exists = await fs.pathExists(resolved);
if (exists) {
const stats = await fs.lstat(resolved);
if (stats.isDirectory()) { // output is an existing directory, copy file into this directory with original file name
this.outputString = path.join(this.outputString, this.inputFilePath.base);
await this.parseOutputPath();
return;
}
}
// parse output path
this.outputFilePath = path.parse(resolved);
if (!this.outputFilePath.ext && !this.options.noExt && this.inputFilePath.ext) {
this.outputFilePath.ext = this.inputFilePath.ext;
}
if (this.options.noMove) {
this.outputFilePath.dir = this.inputFilePath.dir;
}
let ext = this.outputFilePath.ext || '';
if (!ext && !this.options.noExt) ext = this.inputFilePath.ext; // no extension specified, use original extension
this.outputFileString = `${this.outputFilePath.dir}${path.sep}${this.outputFilePath.name}${ext}`;
if (this.inputFileString.toLowerCase() !== this.outputFileString.toLowerCase()) {
this.alreadyExists = await fs.pathExists(this.outputFileString);
this.directoryExists = await fs.pathExists(this.outputFilePath.dir);
} else { // prevent already exists warning if changing the case of a file name
this.alreadyExists = false;
this.directoryExists = true;
}
}
async setIndex(index) {
if (this.outputString.indexOf('--FILEINDEXHERE--') > -1) {
this.outputString = this.outputString.replaceAll('--FILEINDEXHERE--', index);
} else {
this.outputString = this.appendToFileName(this.outputString, index);
}
await this.parseOutputPath();
}
setConflict(conflict) {
this.conflict = conflict;
}
getOperationText() {
return `${this.inputFileString.replace(this.currentDir, '')} → ${this.outputFileString.replace(this.currentDir, '')}`;
}
appendToFileName(str, append) {
let pathObj = path.parse(str);
return `${pathObj.dir}${pathObj.dir !== '' ? path.sep : ''}${pathObj.name}${append}${pathObj.ext}`;
}
async run(batchId) {
if (this.inputFileString.toLowerCase() !== this.outputFileString.toLowerCase()) {
this.alreadyExists = await fs.pathExists(this.outputFileString);
}
if (this.alreadyExists && this.options.keep && !this.options.force) {
let newFileName;
let appender = 0;
do {
appender += 1;
newFileName = this.appendToFileName(this.outputString, `-${appender}`);
} while(pathExists.sync(newFileName));
this.outputString = newFileName;
await this.parseOutputPath();
}
const operationText = this.getOperationText();
if (this.options.ignoreDirectories && this.fileData.stats.isDirectory()) {
if (this.options.verbose) console.log(chalk`{yellow Skipping ${this.inputFileString.replace(this.currentDir, '')} because it is a directory}`);
return;
} else if (!this.options.simulate && !this.options.force && this.alreadyExists) {
console.log(chalk`{red
${operationText}
WARNING: ${this.outputFileString.replace(this.currentDir, '')} already exists!}`);
let response = readlineSync.keyInSelect(['Overwrite the file', 'Keep both files'], `What would you like to do?`, { cancel: 'Skip' });
if (response === 0 && this.options.verbose) {
console.log(chalk`{yellow Overwriting ${this.outputFileString.replace(this.currentDir, '')}}`);
} else if (response === 1) { // prompt for new file name
let ext = this.outputFilePath.ext || '';
if (!ext && !this.options.noExt) { ext = this.inputFilePath.ext; }
const defaultInput = `${this.outputFilePath.dir}${path.sep}${this.outputFilePath.name}1${ext}`;
this.outputString = readlineSync.question('Please input the desired file name (Default: $<defaultInput>): ', { defaultInput: defaultInput.replace(this.currentDir, '') });
await this.parseOutputPath();
await this.run();
return;
} else if (response === -1) {
if (this.options.verbose) console.log(`Skipping ${this.outputFileString.replace(this.currentDir, '')}`);
return;
}
} else if (!this.options.simulate && !this.options.force && !this.options.keep && this.conflict) {
console.log(chalk`{keyword('orange')
${operationText}
WARNING: This operation conflicts with other operations in this batch!
}`);
if (!readlineSync.keyInYN(chalk.keyword('orange')('Would you like to proceed with this operation? [y/n]: '), { guide: false })) {
if (this.options.verbose) console.log(`Skipping ${this.outputFileString.replace(this.currentDir, '')}`);
return;
}
} else if (!this.options.createDirs && !this.directoryExists && !this.options.simulate) {
console.log(chalk`{keyword('orange')
${operationText}
WARNING: The directory does not exist!
}`);
if (!readlineSync.keyInYN(chalk.keyword('orange')('Would you like to create the directory? [y/n]: '), { guide: false })) {
if (this.options.verbose) console.log(`Skipping ${this.outputFileString.replace(this.currentDir, '')}`);
return;
}
} else if (this.options.verbose || this.options.simulate) {
console.log(operationText);
}
if (this.options.simulate) return; // Don't perform operation
// If it has made it this far, it's now time to move/copy
if (!this.directoryExists) await fs.mkdirp(this.outputFilePath.dir);
if (await fs.pathExists(this.inputFileString)) {
const input = this.inputFileString.replace(/\\\[/g, '[').replace(/\\\]/g, ']');
const output = this.outputFileString.replace(/\\\[/g, '[').replace(/\\\]/g, ']');
switch (this.type) {
case 'move': {
await fs.rename(input, output);
break;
}
case 'copy': {
await fs.copy(input, output);
break;
}
case 'link': {
if (this.options.soft) await fs.symlink(input, output);
else await fs.link(input, output);
break;
}
default: {
console.log(chalk`{red ${this.type} not implemented yet!}`);
return;
}
}
if (!this.options.noUndo && this.sequelize) { // write operations to database
await this.sequelize.models.Op.create({
type: this.type,
input: input,
output: output,
BatchId: batchId
});
}
} else if (this.options.verbose) {
console.log(chalk`{yellow Skipping ${this.inputFileString.replace(this.currentDir, '')} because the file no longer exists}`);
}
}
};