mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-20 15:36:16 -04:00
restructure: move bin/ and tests/ to src/
Also add symlinks from the old `bin/` and `tests/` locations to avoid breaking scripts and other tools. Motivations: * Scripts and tests no longer have to do dubious things like: require('ep_etherpad-lite/node_modules/foo') to access packages installed as dependencies in `src/package.json`. * Plugins can access the backend test helper library in a non-hacky way: require('ep_etherpad-lite/tests/backend/common') * We can delete the top-level `package.json` without breaking our ability to lint the files in `bin/` and `tests/`. Deleting the top-level `package.json` has downsides: It will cause `npm` to print warnings whenever plugins are installed, npm will no longer be able to enforce a plugin's peer dependency on ep_etherpad-lite, and npm will keep deleting the `node_modules/ep_etherpad-lite` symlink that points to `../src`. But there are significant upsides to deleting the top-level `package.json`: It will drastically speed up plugin installation because `npm` doesn't have to recursively walk the dependencies in `src/package.json`. Also, deleting the top-level `package.json` avoids npm's horrible dependency hoisting behavior (where it moves stuff from `src/node_modules/` to the top-level `node_modules/` directory). Dependency hoisting causes numerous mysterious problems such as silent failures in `npm outdated` and `npm update`. Dependency hoisting also breaks plugins that do: require('ep_etherpad-lite/node_modules/foo')
This commit is contained in:
parent
efde0b787a
commit
2ea8ea1275
146 changed files with 191 additions and 1161 deletions
84
src/bin/rebuildPad.js
Normal file
84
src/bin/rebuildPad.js
Normal file
|
@ -0,0 +1,84 @@
|
|||
'use strict';
|
||||
|
||||
/*
|
||||
This is a repair tool. It rebuilds an old pad at a new pad location up to a
|
||||
known "good" revision.
|
||||
*/
|
||||
|
||||
// As of v14, Node.js does not exit when there is an unhandled Promise rejection. Convert an
|
||||
// unhandled rejection into an uncaught exception, which does cause Node.js to exit.
|
||||
process.on('unhandledRejection', (err) => { throw err; });
|
||||
|
||||
if (process.argv.length !== 4 && process.argv.length !== 5) {
|
||||
throw new Error('Use: node bin/repairPad.js $PADID $REV [$NEWPADID]');
|
||||
}
|
||||
|
||||
const padId = process.argv[2];
|
||||
const newRevHead = process.argv[3];
|
||||
const newPadId = process.argv[4] || `${padId}-rebuilt`;
|
||||
|
||||
(async () => {
|
||||
const db = require('../node/db/DB');
|
||||
await db.init();
|
||||
|
||||
const PadManager = require('../node/db/PadManager');
|
||||
const Pad = require('../node/db/Pad').Pad;
|
||||
// Validate the newPadId if specified and that a pad with that ID does
|
||||
// not already exist to avoid overwriting it.
|
||||
if (!PadManager.isValidPadId(newPadId)) {
|
||||
throw new Error('Cannot create a pad with that id as it is invalid');
|
||||
}
|
||||
const exists = await PadManager.doesPadExist(newPadId);
|
||||
if (exists) throw new Error('Cannot create a pad with that id as it already exists');
|
||||
|
||||
const oldPad = await PadManager.getPad(padId);
|
||||
const newPad = new Pad(newPadId);
|
||||
|
||||
// Clone all Chat revisions
|
||||
const chatHead = oldPad.chatHead;
|
||||
await Promise.all([...Array(chatHead + 1).keys()].map(async (i) => {
|
||||
const chat = await db.get(`pad:${padId}:chat:${i}`);
|
||||
await db.set(`pad:${newPadId}:chat:${i}`, chat);
|
||||
console.log(`Created: Chat Revision: pad:${newPadId}:chat:${i}`);
|
||||
}));
|
||||
|
||||
// Rebuild Pad from revisions up to and including the new revision head
|
||||
const AuthorManager = require('../node/db/AuthorManager');
|
||||
const Changeset = require('../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 (let curRevNum = 0; curRevNum <= newRevHead; curRevNum++) {
|
||||
const rev = await db.get(`pad:${padId}:revs:${curRevNum}`);
|
||||
if (!rev || !rev.meta) throw new Error('The specified revision number could not be found.');
|
||||
const newRevNum = ++newPad.head;
|
||||
const newRevId = `pad:${newPad.id}:revs:${newRevNum}`;
|
||||
await Promise.all([
|
||||
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}`);
|
||||
}
|
||||
|
||||
// Add saved revisions up to the new revision head
|
||||
console.log(newPad.head);
|
||||
const newSavedRevisions = [];
|
||||
for (const savedRev of oldPad.savedRevisions) {
|
||||
if (savedRev.revNum <= newRevHead) {
|
||||
newSavedRevisions.push(savedRev);
|
||||
console.log(`Added: Saved Revision: ${savedRev.revNum}`);
|
||||
}
|
||||
}
|
||||
newPad.savedRevisions = newSavedRevisions;
|
||||
|
||||
// Save the source pad
|
||||
await db.set(`pad:${newPadId}`, newPad);
|
||||
|
||||
console.log(`Created: Source Pad: pad:${newPadId}`);
|
||||
await newPad.saveToDatabase();
|
||||
|
||||
await db.shutdown();
|
||||
console.info('finished');
|
||||
})();
|
Loading…
Add table
Add a link
Reference in a new issue