summaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorJohn McLear <john@mclear.co.uk>2014-12-04 02:34:21 +0000
committerJohn McLear <john@mclear.co.uk>2014-12-04 02:34:21 +0000
commit89adbb9f12276b509d77d82e47b245180e8e32da (patch)
tree844355538ef0f3f4fafae9213d760e47df7d2658 /bin
parent08097975edcc254fcb4903b3a7c5f9d5359c1534 (diff)
parentc7b1aebfe82d4c9eda968f2a0b5a1337d12590be (diff)
downloadetherpad-lite-89adbb9f12276b509d77d82e47b245180e8e32da.zip
Merge pull request #2329 from timrchavez/rebuild-pad-script
Restore pad to new location at a given revision
Diffstat (limited to 'bin')
-rw-r--r--bin/rebuildPad.js120
1 files changed, 120 insertions, 0 deletions
diff --git a/bin/rebuildPad.js b/bin/rebuildPad.js
new file mode 100644
index 00000000..c8383342
--- /dev/null
+++ b/bin/rebuildPad.js
@@ -0,0 +1,120 @@
+/*
+ This is a repair tool. It rebuilds an old pad at a new pad location up to a
+ known "good" revision.
+*/
+
+if(process.argv.length != 4 && process.argv.length != 5) {
+ console.error("Use: node bin/repairPad.js $PADID $REV [$NEWPADID]");
+ process.exit(1);
+}
+
+var npm = require("../src/node_modules/npm");
+var async = require("../src/node_modules/async");
+var ueberDB = require("../src/node_modules/ueberDB");
+
+var padId = process.argv[2];
+var newRevHead = process.argv[3];
+var newPadId = process.argv[4] || padId + "-rebuilt";
+
+var db, oldPad, newPad, settings;
+var AuthorManager, ChangeSet, Pad, PadManager;
+
+async.series([
+ function(callback) {
+ npm.load({}, function(err) {
+ if(err) {
+ console.error("Could not load NPM: " + err)
+ process.exit(1);
+ } else {
+ callback();
+ }
+ })
+ },
+ function(callback) {
+ // Get a handle into the database
+ db = require('../src/node/db/DB');
+ db.init(callback);
+ }, function(callback) {
+ PadManager = require('../src/node/db/PadManager');
+ Pad = require('../src/node/db/Pad').Pad;
+ // Get references to the original pad and to a newly created pad
+ // HACK: This is a standalone script, so we want to write everything
+ // out to the database immediately. The only problem with this is
+ // that a driver (like the mysql driver) can hardcode these values.
+ db.db.db.settings = {cache: 0, writeInterval: 0, json: true};
+ // Validate the newPadId if specified and that a pad with that ID does
+ // not already exist to avoid overwriting it.
+ if (!PadManager.isValidPadId(newPadId)) {
+ console.error("Cannot create a pad with that id as it is invalid");
+ process.exit(1);
+ }
+ PadManager.doesPadExists(newPadId, function(err, exists) {
+ if (exists) {
+ console.error("Cannot create a pad with that id as it already exists");
+ process.exit(1);
+ }
+ });
+ PadManager.getPad(padId, function(err, pad) {
+ oldPad = pad;
+ newPad = new Pad(newPadId);
+ callback();
+ });
+ }, function(callback) {
+ // Clone all Chat revisions
+ var chatHead = oldPad.chatHead;
+ for(var i = 0, curHeadNum = 0; i <= chatHead; i++) {
+ db.db.get("pad:" + padId + ":chat:" + i, function (err, chat) {
+ db.db.set("pad:" + newPadId + ":chat:" + curHeadNum++, chat);
+ console.log("Created: Chat Revision: pad:" + newPadId + ":chat:" + curHeadNum);
+ });
+ }
+ callback();
+ }, function(callback) {
+ // Rebuild Pad from revisions up to and including the new revision head
+ AuthorManager = require("../src/node/db/AuthorManager");
+ Changeset = require("ep_etherpad-lite/static/js/Changeset");
+ // Author attributes are derived from changesets, but there can also be
+ // non-author attributes with specific mappings that changesets depend on
+ // and, AFAICT, cannot be recreated any other way
+ newPad.pool.numToAttrib = oldPad.pool.numToAttrib;
+ for(var curRevNum = 0; curRevNum <= newRevHead; curRevNum++) {
+ db.db.get("pad:" + padId + ":revs:" + curRevNum, function(err, rev) {
+ var newRevNum = ++newPad.head;
+ var newRevId = "pad:" + newPad.id + ":revs:" + newRevNum;
+ db.db.set(newRevId, rev);
+ AuthorManager.addPad(rev.meta.author, newPad.id);
+ newPad.atext = Changeset.applyToAText(rev.changeset, newPad.atext, newPad.pool);
+ console.log("Created: Revision: pad:" + newPad.id + ":revs:" + newRevNum);
+ if (newRevNum == newRevHead) {
+ callback();
+ }
+ });
+ }
+ }, function(callback) {
+ // Add saved revisions up to the new revision head
+ console.log(newPad.head);
+ var newSavedRevisions = [];
+ for(var i in oldPad.savedRevisions) {
+ savedRev = oldPad.savedRevisions[i]
+ if (savedRev.revNum <= newRevHead) {
+ newSavedRevisions.push(savedRev);
+ console.log("Added: Saved Revision: " + savedRev.revNum);
+ }
+ }
+ newPad.savedRevisions = newSavedRevisions;
+ callback();
+ }, function(callback) {
+ // Save the source pad
+ db.db.set("pad:"+newPadId, newPad, function(err) {
+ console.log("Created: Source Pad: pad:" + newPadId);
+ newPad.saveToDatabase();
+ callback();
+ });
+ }
+], function (err) {
+ if(err) throw err;
+ else {
+ console.info("finished");
+ process.exit(0);
+ }
+});