From 8f3b5abb8da057f8d5b69df0e2e49b9b7316a03b Mon Sep 17 00:00:00 2001 From: Jordan Hotmann Date: Fri, 3 Mar 2017 10:51:36 -0700 Subject: [PATCH] Initial commit --- .eslintrc.json | 19 +++++++++++ .gitignore | 30 ++++++++++++++++++ README.md | 51 ++++++++++++++++++++++++++++++ bin.js | 44 ++++++++++++++++++++++++++ index.js | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ jsconfig.json | 16 ++++++++++ package.json | 25 +++++++++++++++ replacements.js | 59 +++++++++++++++++++++++++++++++++++ 8 files changed, 327 insertions(+) create mode 100644 .eslintrc.json create mode 100644 .gitignore create mode 100644 README.md create mode 100644 bin.js create mode 100644 index.js create mode 100644 jsconfig.json create mode 100644 package.json create mode 100644 replacements.js diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..4a84cd5 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,19 @@ +{ + "parserOptions": { + "ecmaVersion": 5, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true + } + }, + "extends": "eslint:recommended", + "rules": { + "semi": 2, + "eqeqeq": ["warn", "smart"], + "no-unused-vars": 1, + "no-console": 0 + }, + "env": { + "node": true + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fa76cfa --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- +node_modules + +# Debug log from npm +npm-debug.log diff --git a/README.md b/README.md new file mode 100644 index 0000000..e9b5b31 --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +# Rename-CLI [Beta] +A tool for renaming files quickly, especially multiple files at once. + +Currently in beta as it has only been tested on MacOS and should function great on Linux as well but Windows is currently an known. I will be adding more variable replacements over time or you can submit some via pull request. See replacements.js for example. + +``` +Usage: rename [options] files new-file-name + If you rename multiple files at once, an index will be appended + to the end of the file unless otherwise specified with {{i}}, or + the original file name is used via {{f}}. + If you do not specify a file extension in the new file name, the + original file extension will be used. + +Options: + + -h, --help Display this usage info + --f Force overwrite when output file name already exists + --s Simulate rename and just print new file names + +Available Variables: + + {{i}} Index: The index of the file when renaming multiple files + {{f}} File name: The original name of the file + {{p}} Parent directory: The name of the parent directory + {{y}} Year: The current year + {{m}} Month: The current month + {{d}} Day: The current day + +Examples: + + rename *.log {{y}}{{m}}{{d}}{{f}} + node.log → 20170303node.log + system.log → 20170303system.log + + rename *.log test + node.log → test1.log + system.log → test2.log + + note: index will prepend with zeros to keep file order the same + when there are more than 9 files renamed. +``` + +## Installation +1. Install NodeJS if you haven't already https://nodejs.org +1. Type `npm install -g rename-cli` into your terminal or command window + +## Libraries Used +- Minimist https://github.com/substack/minimist +- file-exists https://github.com/scottcorgan/file-exists +- prompt-sync https://github.com/0x00A/prompt-sync +- lodash https://lodash.com/ diff --git a/bin.js b/bin.js new file mode 100644 index 0000000..ceac706 --- /dev/null +++ b/bin.js @@ -0,0 +1,44 @@ +#!/usr/bin/env node +const packagejson = require('./package.json'); +const argv = require('minimist')(process.argv.slice(2), {boolean: true}); +const index = require('./index'); +const commandName = Object.keys(packagejson.bin)[0]; + +if (argv.help || argv.h) { + console.log(''); + console.log('Rename a file or multiple files with optional variable replacement.'); + console.log(''); + console.log('Usage: %s [options] files new-file-name', commandName); + console.log(' If you rename multiple files at once, an index will be appended'); + console.log(' to the end of the file unless otherwise specified with {{i}}, or'); + console.log(' the original file name is used via {{f}}.'); + console.log(' If you do not specify a file extension in the new file name, the'); + console.log(' original file extension will be used.'); + console.log(''); + console.log('Options:'); + console.log(''); + console.log(' -h, --help Display this usage info'); + console.log(' --f Force overwrite when output file name already exists'); + console.log(' --s Simulate rename and just print new file names'); + console.log(''); + console.log('Available Variables:'); + console.log(''); + index.getReplacements(); + console.log(''); + console.log('Examples:'); + console.log(''); + console.log(' rename *.log {{y}}{{m}}{{d}}{{f}}'); + console.log(' node.log → 20170303node.log'); + console.log(' system.log → 20170303system.log'); + console.log(''); + console.log(' rename *.log test'); + console.log(' node.log → test1.log'); + console.log(' system.log → test2.log'); + console.log(''); + console.log(' note: index will prepend with zeros to keep file order the same'); + console.log(' when there are more than 9 files renamed.'); + console.log(''); + process.exit(0); +} else { + index.thecommand(argv); +} \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..3a4e2c2 --- /dev/null +++ b/index.js @@ -0,0 +1,83 @@ +const _ = require('lodash'); +const fileExists = require('file-exists'); +const fs = require('fs'); +const path = require('path'); +const prompt = require('prompt-sync')(); +const replacements = require('./replacements'); + +module.exports = { + thecommand: function(args) { + if (args.s) { + console.log(''); + } + let newFileName = path.parse(_.last(args._)); + let files = _.dropRight(args._); + if (files.length === 0) { + console.log('ERROR: Not enough arguments specified. Type rename -h for help'); + process.exit(1); + } + let fileIndex = 1; + _.forEach(files, function(value) { + let uniqueName = (files.length > 1 ? false: true); + let fullPath = path.resolve(value); + let fileObj = path.parse(fullPath); + fileObj.newName = newFileName.name; + fileObj.newNameExt = (newFileName.ext ? newFileName.ext : fileObj.ext); + fileObj.index = fileIndexString(files.length, fileIndex); + + // replace the replacement strings with their value + _.forEach(replacements, function(value, key) { + if (fileObj.newName.indexOf(key) > -1 && value.unique) { + uniqueName = true; + } + fileObj.newName = fileObj.newName.replace(key, value.function(fileObj)); + }); + + // if output file names are not unique append file index + if (!uniqueName) { + fileObj.newName = fileObj.newName + fileObj.index; + } + + // if argument --s specified just print what the output would be + if (args.s) { + console.log(fileObj.base + ' → ' + fileObj.newName + fileObj.newNameExt); + } else { // rename the file(s) + let originalFileName = path.format({dir: fileObj.dir, base: fileObj.base}); + let outputFileName = path.format({dir: fileObj.dir, base: fileObj.newName + fileObj.newNameExt}); + + // if output file name already exists prompt for overwrite unless --f specified. + if (!args.f && fileExists.sync(outputFileName)) { + var response = prompt(fileObj.newName + fileObj.newNameExt + ' already exists. Would you like to replace it? (y/n) '); + if (response === 'y') { + renameFile(originalFileName, outputFileName); + } + } else { + renameFile(originalFileName, outputFileName); + } + } + fileIndex += 1; + }); + }, + getReplacements: function() { + _.forEach(replacements, function(value, key) { + console.log(' ' + key + ' ' + value.name + ': ' + value.description); + }); + } +}; + +function renameFile(oldName, newName) { + fs.rename(oldName, newName, function(err) { + if (err) { + console.log('ERROR: ' + err); + } + }); +} + +function fileIndexString(total, index) { + let totString = '' + total; + let returnString = '' + index; + while (returnString.length < totString.length) { + returnString = '0' + returnString; + } + return returnString; +} diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..6ad93ef --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,16 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=759670 + // for the documentation about the jsconfig.json format + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "allowSyntheticDefaultImports": true + }, + "exclude": [ + "node_modules", + "bower_components", + "jspm_packages", + "tmp", + "temp" + ] +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..e8caf3d --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "rename-cli", + "version": "0.0.1", + "description": "A command line utility for renaming files", + "main": "index.js", + "preferGlobal": true, + "bin": { + "rename": "./bin.js" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Jordan Hotmann", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/jhotmann/node-rename-cli.git" + }, + "dependencies": { + "file-exists": "^3.0.1", + "lodash": "^4.17.4", + "minimist": "^1.2.0", + "prompt-sync": "^4.1.4" + } +} diff --git a/replacements.js b/replacements.js new file mode 100644 index 0000000..a5db23a --- /dev/null +++ b/replacements.js @@ -0,0 +1,59 @@ +const path = require('path'); + +const replacements = { + '{{i}}': { + name: 'Index', + description: 'The index of the file when renaming multiple files', + unique: true, + function: function(fileObj) { + return fileObj.index; + } + }, + '{{f}}': { + name: 'File name', + description: "The original name of the file", + unique: true, + function: function(fileObj) { + return fileObj.name; + } + }, + '{{p}}': { + name: 'Parent directory', + description: "The name of the parent directory", + unique: false, + function: function(fileObj) { + return path.basename(fileObj.dir); + } + }, + '{{y}}': { + name: 'Year', + description: "The current year", + unique: false, + function: function() { + let d = new Date(); + return d.getFullYear(); + } + }, + '{{m}}': { + name: 'Month', + description: "The current month", + unique: false, + function: function() { + let d = new Date(); + let month = d.getMonth() + 1; + return (month < 10 ? '0' + month : month); + } + }, + '{{d}}': { + name: 'Day', + description: "The current day", + unique: false, + function: function() { + let d = new Date(); + let day = d.getDate(); + return (day < 10 ? '0' + day : day); + } + } +}; + +module.exports = replacements; \ No newline at end of file