Skip to content

Instantly share code, notes, and snippets.

@utensil
Last active August 29, 2015 13:59
Show Gist options
  • Select an option

  • Save utensil/10634908 to your computer and use it in GitHub Desktop.

Select an option

Save utensil/10634908 to your computer and use it in GitHub Desktop.
batch rename tool
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();
// });
{
"name": "batch-rename",
"version": "0.0.0",
"description": "",
"main": "index.js",
"scripts": {
},
"author": "",
"license": "MIT",
"dependencies": {
"shelljs": "~0.2.6"
}
}
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);
});
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