Skip to content

Instantly share code, notes, and snippets.

@leogdion
Last active December 16, 2015 01:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leogdion/5357452 to your computer and use it in GitHub Desktop.
Save leogdion/5357452 to your computer and use it in GitHub Desktop.
node_modules
config.json
examples
examples.zip
var os = require('os'),
async = require('async'),
wrench = require('wrench'),
path = require('path'),
detect = require('./Detect.js'),
zip = require('./Zip.js'),
fs = require('fs'),
cloud = require('./Cloud.js'),
randomizer = require('./Random.js'),
dateFormat = require('dateformat'),
rmdir = require('./RmDir.js'),
spawn = require('child_process').spawn;
var backup = function (configurationPath) {
};
backup.prototype = {
start : function (error) {
if (error) {
console.log('exec error: ' + error);
process.exit(1);
}
var configreader = require('./ConfigReader.js');
configreader.get( this.ongetconfiguration.bind(this));
},
ongetconfiguration : function (error, config) {
if (error) {
console.log(error);
process.exit(1);
}
console.log("reading configuration...");
this.config = config;
this.cloud = cloud.configure(this.config.cloud);
this.now = new Date();
async.concat(config.directories, detect.parse, this.parsedball.bind(this));
},
parsedball : function (error, results) {
async.map(results, this.createtemp.bind(this), this.upload.bind(this));
},
createtemp : function (configuration, cb) {
var tmpDir = path.resolve(os.tmpDir(), randomizer());
configuration.tmpDir = tmpDir;
fs.mkdir(tmpDir, this.tempcreated.bind(this, configuration, cb));
},
tempcreated : function (configuration, cb, error) {
fs.mkdir(path.resolve(configuration.tmpDir, 'web'), this.webcreated.bind(this, configuration, cb));
},
webcreated : function (configuration, cb, error) {
console.log(configuration.name + ": copying files...");
wrench.copyDirRecursive(configuration.directory, path.resolve(configuration.tmpDir, 'web'), this.parseDb.bind(this, configuration ,cb));
},
parseDb : function (configuration, cb, error, files) {
configuration.web.parse(configuration, this.backupdb.bind(this, configuration, cb));
},
backupdb : function (configuration, cb, error) {
var fd = fs.createWriteStream(path.resolve(configuration.tmpDir, 'database.sql'));
var dumpps = spawn('mysqldump', ['--add-drop-table', '-u' + this.config.database.user, '-p' + this.config.database.password, configuration.databaseName]);
console.log(configuration.name + ": beginning database backup...");
dumpps.stdout.pipe(fd);
dumpps.stderr.pipe(process.stderr);
dumpps.on('close', this.compress.bind(this, configuration, cb));
},
compress : function (configuration, cb, code) {
console.log(configuration.name + ": creating zip file...");
zip(configuration.tmpDir, function(error, zipfile) {
if (error) {
cb(error);
return;
}
configuration.tmpzip = zipfile;
cb(undefined, configuration);
});
},
upload : function (error, results) {
if (error) {
cb(error);
return;
}
async.eachSeries(results, this.uploadFile.bind(this), this.cleanup.bind(this, results));
},
uploadFile : function (configuration, cb) {
console.log(configuration.name + ": uploading backup...");
this.cloud.upload(configuration.tmpzip, this.filename(configuration), cb);
},
filename : function (configuration) {
return [dateFormat(this.now, "yy-mm-dd-HHMM"), path.basename(configuration.directory), path.extname(configuration.tmpzip).substring(1)].join('.');
},
cleanup : function (results, error) {
if (error) {
cb(error);
return;
}
console.log("cleaning up...");
async.each(results, this.deletefiles.bind(this), this.done.bind(this));
},
deletefiles : function (configuration, cb) {
fs.unlink(configuration.tmpzip, this.deletefolder.bind(this, configuration.tmpDir, cb));
},
deletefolder : function (directory, cb, error) {
if (error) {
cb(error);
return;
}
rmdir(directory, cb);
},
done : function (error) {
if (error) {
console.log(error);
return;
}
console.log('completed.');
}
};
backup.oninstall = function (configurationPath, error, stdout, stderr) {
var b = new backup(configurationPath);
b.start(error, stdout, stderr);
};
module.exports = backup;
var BaseWeb = (function () {
var fs = require('fs'),
path = require('path');
var my = function () {
};
my.prototype = {
evaluate : function (dirPath, cb) {
fs.exists(path.resolve(dirPath, this.configurationFile), cb);
},
parse : function (configuration ,cb) {
fs.readFile(path.resolve(configuration.directory, this.configurationFile), this.parseFile.bind(this, configuration, cb));
},
parseFile : function (configuration, cb, error, data) {
configuration.databaseName = data.toString().match(this.regex)[1];
cb();
},
build : function (configurationFile, regex) {
var that = function () {};
that.prototype = new my();
that.prototype.configurationFile = configurationFile;
that.prototype.regex = regex;
return that;
}
};
return my;
})();
module.exports = new BaseWeb();
var Cloud = (function () {
var fs = require('fs'),
path = require('path');
var my = function () {
};
my.prototype = {
configure : function (config) {
var type = Object.keys(config)[0];
return this.types[type].configure(config[type]);
},
types : {
"aws-s3" : require('./S3.js')
}
};
return my;
})();
module.exports = new Cloud();
{
"directories" : [
{ "parent" : "/usr/share/nginx" }
],
"database" : {
"user" : "root",
"password" : "*******"
},
"cloud" : {
"aws-s3" : {
"config" : {
"accessKeyId": "********",
"secretAccessKey": "**********************"
},
"Bucket" : "bucket-name",
"Folder" : "path"
}
}
}
var ConfigReader = (function () {
var my = function () {
};
my.prototype = {
get : function (filenameOrCallback, cb) {
var config;
var filename = typeof(filenameOrCallback) === 'string' ? filenameOrCallback : './config.json';
cb = typeof(filenameOrCallback) === 'string' ? cb : filenameOrCallback;
try {
config = require(filename);
cb(undefined, config);
} catch (ex) {
cb(ex, config);
}
}
};
return my;
})();
module.exports = new ConfigReader();
var Detect = (function () {
var my = function () {
};
my.types = {
'parent' : require('./ParentDetect.js')
};
my.prototype = {
parse : function (configuration, cb) {
if (configuration) {
for (var key in configuration) {
var detector = my.types[key];
if (detector) {
detector.begin(configuration, cb);
return;
}
}
}
cb('Invalid Configuration');
}
};
return my;
})();
module.exports = new Detect();
var DirectoryDetect = (function () {
var async = require('async'),
path = require('path'),
webs = require('./Webs.js');
var my = function () {
};
my.prototype = {
begin : function (configuration, cb) {
for (var key in configuration) {
var value = configuration[key];
async.detect(Object.keys(webs), this.test.bind(this, value), this.ondetect.bind(this, configuration, cb));
return;
}
cb();
},
test : function (value, type, cb) {
webs[type].evaluate(value, cb);
},
ondetect : function (configuration, cb, result) {
if (result) {
configuration.web = webs[result];
configuration.webname = result;
configuration.name = path.basename(configuration.directory);
console.log(configuration.name + " (" + configuration.webname + ")");
cb(undefined, [configuration]);
} else if (configuration.optional) {
cb(undefined, []);
} else {
cb("Could not detect directory type.");
}
}
};
return my;
})();
module.exports = new DirectoryDetect();
var npminstall = require('./npminstall.js');
process.chdir(__dirname);
npminstall.begin('./backup.js', './config.json');
var MediaWiki = (function () {
var my = require('./BaseWeb.js').build('LocalSettings.php', /\$wgDBname \= \"([^"]+)\"/);
return my;
})();
module.exports = new MediaWiki();
var exec = require('child_process').exec;
module.exports = {
begin : function (cb) {
console.log("installing modules...");
if (typeof(cb) === 'string') {
var modName = cb;
cb = function () {
var mod = require(modName);
mod.oninstall.apply(arguments);
};
}
exec('npm install', {env: process.env}, cb);
}
};
{
"name" : "web-backup",
"version" : "0.0.1",
"dependencies" : {
"aws-sdk" : "*",
"async" : "*",
"wrench" : "*",
"node-zip": "*",
"dateformat" : "*"
}
}
var fs = require('fs'),
path = require('path'),
async = require('async');
var ParentDetect = (function () {
var directorydetect = require('./DirectoryDetect.js');
var parser = function (parent) {
this.parent = parent;
};
parser.prototype = {
begin : function (file, cb) {
fs.stat(path.resolve(this.parent, file), this.onstat.bind(this, file, cb));
},
onstat : function (file, cb, error, stat) {
if (stat.isDirectory()) {
directorydetect.begin({
"directory" : path.resolve(this.parent, file),
"optional" : true
}, cb);
} else {
cb();
}
}
};
function onreaddir (cb, parent, error, files) {
if (error) {
console.log(error);
process.exit(1);
}
var p = new parser (parent);
async.concat(files, p.begin.bind(p), cb);
}
var my = function () {
};
my.prototype = {
begin : function (configuration, cb) {
for (var key in configuration) {
var value = configuration[key];
fs.readdir(value, onreaddir.bind(undefined, cb, value));
break;
}
}
};
return my;
})();
module.exports = new ParentDetect();
module.exports = function ()
{
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < 5; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
};
var RmDir = (function () {
var async = require('async'),
fs = require('fs'),
path = require('path');
var my = function (directory, cb) {
console.log(directory);
my.deletedir(directory, cb);
};
my.deletedir = function (directory, cb) {
fs.readdir(directory, my.deletefiles.bind(undefined, directory, cb));
};
my.deletefiles = function (directory, cb, error, files) {
async.each(files, my.deleteitem.bind(undefined, directory), my.rmdir.bind(undefined, directory, cb));
};
my.deleteitem = function (directory, file, cb) {
file = path.resolve(directory, file);
fs.stat(file, my.stat.bind(undefined, file, cb));
};
my.stat = function (file, cb, error, stats) {
if (stats.isDirectory()) {
my.deletedir(file, cb);
} else {
fs.unlink(file, cb);
}
};
my.rmdir = function (directory, cb, error) {
fs.rmdir(directory, cb);
};
return my;
})();
module.exports = RmDir;
var S3 = (function () {
var fs = require('fs');
var instance = function (config) {
this.config = config;
this.AWS = require('aws-sdk');
this.AWS.config.update(config.config);
this.s3 = new this.AWS.S3();
};
instance.prototype = {
upload : function (file, key, cb) {
fs.readFile(file, this.put.bind(this, file, key, cb));
},
put : function (file, key, cb, error, data) {
if (error) {
cb(error);
return;
}
console.log(key);
key = this.config.Folder ?
[this.config.Folder, key].join('/') :
key;
var obj = {
Bucket : this.config.Bucket,
Key : key,
Body: data
};
this.s3.client.putObject(obj, cb);
}
};
var my = function () {
};
my.prototype = {
configure : function (config) {
return new instance(config);
}
};
return my;
})();
module.exports = new S3();
module.exports = {
"wordpress" : require('./WordPress.js'),
"mediawiki" : require('./MediaWiki.js')
};
var WordPress = (function () {
var my = require('./BaseWeb.js').build('wp-config.php', /define\(\'DB_NAME\', \'([^\']+)\'\);/);
return my;
})();
module.exports = new WordPress();
var Zip = (function () {
var randomizer = require('./Random.js'),
spawn = require('child_process').spawn,
os = require('os'),
async = require('async'),
fs = require('fs'),
path = require('path');
};
var my = function (directory, cb) {
var zipfile = path.join(os.tmpDir(), randomizer() + ".zip");
console.log('zipping ' + directory + ' to ' + zipfile);
var zipps = spawn('zip', ['-R', zipfile, "*"], { cwd : directory });
zipps.stdout.on('data', function (data) {
// console.log(data.toString());
});
zipps.stderr.on('data', function (data) {
console.log(data.toString());
cb(data);
});
zipps.on('close', function (code) {
console.log('completed ' + zipfile);
cb(code || undefined, zipfile);
});
};
return my;
})();
module.exports = Zip;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment