Last active
August 29, 2015 13:59
-
-
Save utensil/10634908 to your computer and use it in GitHub Desktop.
batch rename tool
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| var shelljs = require('shelljs'); | |
| var fs = require("fs"); | |
| var path = require("path"); | |
| var root = process.argv[2]; | |
| if(!root) | |
| { | |
| console.log("root is not specified"); | |
| process.exit(); | |
| } | |
| var dryRun = process.argv[3] != "run"; | |
| if(dryRun) | |
| { | |
| console.log("dry run, no actual rename is performed"); | |
| } | |
| else | |
| { | |
| console.log("DANGER: performing actual rename"); | |
| } | |
| var allfiles = shelljs.ls('-R', root); | |
| var renameRule = function (base, ext) { | |
| var ext_pattern = /^\.(c|cpp|h|hpp|i)$/; | |
| if(ext_pattern.test(ext)) | |
| { | |
| base = base.replace(/^([a-z])/, function (m, $1) { | |
| return $1.toUpperCase(); | |
| }); | |
| base = base.replace(/_([a-z])/g, function (m, $1) { | |
| return $1.toUpperCase(); | |
| }); | |
| } | |
| return base + ext; | |
| }; | |
| var buildRenameCommand = function (renameObj) { | |
| if(!renameObj || !renameObj.dir || !renameObj.from || !renameObj.to) | |
| { | |
| return ""; | |
| } | |
| var from = path.join(renameObj.dir, renameObj.from); | |
| var to = path.join(renameObj.dir, renameObj.to); | |
| return [ | |
| "mv", | |
| from, | |
| to | |
| ].join(" "); | |
| }; | |
| var buildRenameSed = function (renameObj) { | |
| if(!renameObj || !renameObj.dir || !renameObj.from || !renameObj.to) | |
| { | |
| return ""; | |
| } | |
| var from = path.join(renameObj.dir, renameObj.from); | |
| var to = path.join(renameObj.dir, renameObj.to); | |
| from = from.replace(/\//, "\\/"); | |
| to = to.replace(/\//, "\\/"); | |
| return [ | |
| "s", | |
| from, | |
| to, | |
| "" | |
| ].join("/"); | |
| }; | |
| var renamefiles = []; | |
| var renameCommands = []; | |
| var renameSed = []; | |
| allfiles.forEach(function (file, i) { | |
| var dir = path.dirname(file); | |
| var filename = path.basename(file); | |
| var ext = path.extname(file); | |
| var base = path.basename(filename, ext); | |
| var filenameRenamed = renameRule(base, ext); | |
| if(filenameRenamed != filename) | |
| { | |
| //console.log(dir, base, ext, filename, '=>', filenameRenamed); | |
| var renameObj = { | |
| dir: dir, | |
| from: filename, | |
| to: filenameRenamed | |
| }; | |
| renamefiles.push(renameObj); | |
| renameCommands.push(buildRenameCommand(renameObj)); | |
| renameSed.push(buildRenameSed(renameObj)); | |
| } | |
| }); | |
| var Util = { | |
| mv: function (renameObj, isDryRun) { | |
| //console.log("mv", renameObj); | |
| var from = path.join(renameObj.dir, renameObj.from); | |
| var to = path.join(renameObj.dir, renameObj.to); | |
| console.log("mv", path.join(root, from), path.join(root, to)); | |
| if(!isDryRun) | |
| { | |
| var absFrom = path.join(root, from); | |
| var absTo = path.join(root, to); | |
| if(absFrom.toUpperCase() == absTo.toUpperCase()) | |
| { | |
| //by pass case insensitive issue | |
| shelljs.mv(absFrom, absTo + '.tmp'); | |
| shelljs.mv(absTo + '.tmp', absTo); | |
| } | |
| else | |
| { | |
| shelljs.mv(absFrom, absTo); | |
| } | |
| } | |
| }, | |
| sed: function (renameObj, isDryRun) { | |
| //console.log("sed", renameObj); | |
| //TODO there can be more directories to scan affection | |
| var all = shelljs.ls('-R', root); | |
| var from = path.join(renameObj.dir, renameObj.from); | |
| var to = path.join(renameObj.dir, renameObj.to); | |
| all.forEach(function (file) { | |
| if (shelljs.test('-d', path.join(root, file))) | |
| { | |
| return; | |
| } | |
| //only replace one level up | |
| var fromFilePath = [path.basename(path.dirname(from)), path.basename(from)].join('/'); | |
| var toFilePath = [path.basename(path.dirname(to)), path.basename(to)].join('/'); | |
| //console.log('grep', fromFilePath, path.join(root, file)); | |
| var toBeReplaced = shelljs.grep(fromFilePath, path.join(root, file)); | |
| if(toBeReplaced) | |
| { | |
| console.log("`" + file + "` has the following lines to be replaced: "); | |
| console.log(toBeReplaced); | |
| console.log("will be replaced to: "); | |
| console.log(toBeReplaced.replace(fromFilePath, toFilePath)); | |
| if(!isDryRun) | |
| { | |
| shelljs.sed('-i', fromFilePath, toFilePath, path.join(root, file)); | |
| } | |
| } | |
| //console.log(path.dirname(file).replace(/[\\\/]/, '/') , path.dirname(from).replace(/[\\\/]/, '/')); | |
| //in the same direcotry, they would do #include "header.hpp" without path | |
| if(path.dirname(file).replace(/[\\\/]/, '/') == path.dirname(from).replace(/[\\\/]/, '/')) | |
| { | |
| var fromFilePath = path.basename(from); | |
| var toFilePath = path.basename(to); | |
| var fromRegex = new RegExp('(#include[ ]+["<])' + fromFilePath + '([">])', 'g'); | |
| var toFun = function (match, $1, $2) { | |
| return $1 + toFilePath + $2; | |
| }; | |
| //console.log('grep', fromRegex, path.join(root, file)); | |
| var toBeReplaced = shelljs.grep(fromRegex, path.join(root, file)); | |
| if(toBeReplaced) | |
| { | |
| console.log("`" + file + "` has the following lines to be replaced(same direcotry!!!): "); | |
| console.log(toBeReplaced); | |
| console.log("will be replaced to: "); | |
| console.log(toBeReplaced.replace(fromRegex, toFun)); | |
| if(!isDryRun) | |
| { | |
| var f = path.join(root, file); | |
| var result = fs.readFileSync(f, 'utf8').replace(fromRegex, toFun); | |
| fs.writeFileSync(f, result, 'utf8'); | |
| } | |
| } | |
| } | |
| }); | |
| } | |
| }; | |
| fs.writeFileSync('mv.json', JSON.stringify(renamefiles, null, 4), 'utf8'); | |
| renamefiles.forEach(function (renameObj) { | |
| Util.mv(renameObj, dryRun); | |
| }); | |
| console.log('commit should happen between `mv` and updating reference so git can recognize renaming, run `node update_reference.js` after the commit of rename'); | |
| // process.stdin.on('data', function (chunk) { | |
| // if(!/y/.test(chunk)) | |
| // { | |
| // return; | |
| // } | |
| // //console.log('sed'); | |
| // renamefiles.forEach(function (renameObj) { | |
| // Util.sed(renameObj, dryRun); | |
| // }); | |
| // process.stdin.pause(); | |
| // }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "name": "batch-rename", | |
| "version": "0.0.0", | |
| "description": "", | |
| "main": "index.js", | |
| "scripts": { | |
| }, | |
| "author": "", | |
| "license": "MIT", | |
| "dependencies": { | |
| "shelljs": "~0.2.6" | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| var shelljs = require('shelljs'); | |
| var fs = require("fs"); | |
| var path = require("path"); | |
| var root = process.argv[2]; | |
| if(!root) | |
| { | |
| console.log("root is not specified"); | |
| process.exit(); | |
| } | |
| var dryRun = process.argv[3] != "run"; | |
| if(dryRun) | |
| { | |
| console.log("dry run, no actual rename is performed"); | |
| } | |
| else | |
| { | |
| console.log("DANGER: performing actual rename"); | |
| } | |
| var replacer = function (file, fromRegex, toFun, isDryRun) { | |
| //console.log('grep', fromRegex, path.join(root, file)); | |
| var toBeReplaced = shelljs.grep(fromRegex, path.join(root, file)); | |
| if(toBeReplaced) | |
| { | |
| var afterRepalce = toBeReplaced.replace(fromRegex, toFun); | |
| if(afterRepalce != toBeReplaced) | |
| { | |
| console.log("`" + file + "` has the following lines to be replaced(class declaration): "); | |
| console.log(toBeReplaced); | |
| console.log("will be replaced to: "); | |
| console.log(afterRepalce); | |
| if(!isDryRun) | |
| { | |
| var f = path.join(root, file); | |
| var result = fs.readFileSync(f, 'utf8').replace(fromRegex, toFun); | |
| fs.writeFileSync(f, result, 'utf8'); | |
| } | |
| } | |
| } | |
| } | |
| var allfiles = shelljs.ls('-R', root); | |
| allfiles.forEach(function (file) { | |
| var dir = path.dirname(file); | |
| var filename = path.basename(file); | |
| var ext = path.extname(file); | |
| var base = path.basename(filename, ext); | |
| if(!ext.match(/^\.(c|cpp|h|hpp)$/)) | |
| { | |
| return; | |
| } | |
| var fromRegex, toFun; | |
| /* | |
| class declaration | |
| */ | |
| fromRegex = new RegExp('((struct|class)[ ]+)' + base + '', 'i'); | |
| toFun = function (match, $1) { | |
| return $1 + base; | |
| }; | |
| replacer(file, fromRegex, toFun, dryRun); | |
| /* | |
| constructor and destructor | |
| */ | |
| fromRegex = new RegExp('(~?)' + base + '(\\()', 'i'); | |
| toFun = function (match, $1, $2) { | |
| return $1 + base + $2; | |
| }; | |
| replacer(file, fromRegex, toFun, dryRun); | |
| /* | |
| method | |
| */ | |
| fromRegex = new RegExp('' + base + '(::)', 'i'); | |
| toFun = function (match, $1) { | |
| return base + $1; | |
| }; | |
| replacer(file, fromRegex, toFun, dryRun); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| var shelljs = require('shelljs'); | |
| var fs = require("fs"); | |
| var path = require("path"); | |
| var root = process.argv[2]; | |
| if(!root) | |
| { | |
| console.log("root is not specified"); | |
| process.exit(); | |
| } | |
| var dryRun = process.argv[3] != "run"; | |
| if(dryRun) | |
| { | |
| console.log("dry run, no actual rename is performed"); | |
| } | |
| else | |
| { | |
| console.log("DANGER: performing actual rename"); | |
| } | |
| var mvJson = JSON.parse(fs.readFileSync('mv.json', 'utf8')); | |
| var replacer = function (file, fromRegex, toFun, isDryRun, purpose) { | |
| //console.log('grep', fromRegex, path.join(root, file)); | |
| var toBeReplaced = shelljs.grep(fromRegex, path.join(root, file)); | |
| if(toBeReplaced) | |
| { | |
| var afterRepalce = toBeReplaced.replace(fromRegex, toFun); | |
| if(afterRepalce != toBeReplaced) | |
| { | |
| console.log("`" + file + "` has the following lines to be replaced for [" + purpose + "]:"); | |
| console.log(toBeReplaced); | |
| console.log("will be replaced to: "); | |
| console.log(afterRepalce); | |
| if(!isDryRun) | |
| { | |
| var f = path.join(root, file); | |
| var result = fs.readFileSync(f, 'utf8').replace(fromRegex, toFun); | |
| fs.writeFileSync(f, result, 'utf8'); | |
| } | |
| } | |
| } | |
| } | |
| var allfiles = shelljs.ls('-R', root); | |
| mvJson.forEach(function (renameObj){ | |
| var from = path.join(renameObj.dir, renameObj.from); | |
| var to = path.join(renameObj.dir, renameObj.to); | |
| //only replace one level up | |
| var fromFilePath = [path.basename(path.dirname(from)), path.basename(from)].join('/'); | |
| var toFilePath = [path.basename(path.dirname(to)), path.basename(to)].join('/'); | |
| var fromRegex = new RegExp('([#%]include[ ]+["<].*)' + fromFilePath + '([">])', 'g'); | |
| var toFun = function (match, $1, $2) { | |
| return $1 + toFilePath + $2; | |
| }; | |
| allfiles.forEach(function (file) { | |
| var dir = path.dirname(file); | |
| var filename = path.basename(file); | |
| var ext = path.extname(file); | |
| var base = path.basename(filename, ext); | |
| if(!ext.match(/^\.(c|cpp|h|hpp|i)$/)) | |
| { | |
| return; | |
| } | |
| replacer(file, fromRegex, toFun, dryRun, '#include'); | |
| //in the same direcotry, they would do #include "header.hpp" without path | |
| if(path.dirname(file).replace(/[\\\/]/, '/') == path.dirname(from).replace(/[\\\/]/, '/')) | |
| { | |
| var fromFilePathBase = path.basename(from); | |
| var toFilePathBase = path.basename(to); | |
| var fromRegexBase = new RegExp('([#%]include[ ]+["<])' + fromFilePathBase + '([">])', 'g'); | |
| var toFunBase = function (match, $1, $2) { | |
| return $1 + toFilePathBase + $2; | |
| }; | |
| replacer(file, fromRegexBase, toFunBase, dryRun, '#include in the same directory'); | |
| } | |
| }); | |
| }); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment