mirror of
https://github.com/overleaf/overleaf.git
synced 2024-12-12 00:42:18 -05:00
7f48c67512
* Add `unicorn/prefer-node-protocol` * Fix `unicorn/prefer-node-protocol` ESLint errors * Run `npm run format:fix` * Add sandboxed-module sourceTransformers in mocha setups Fix `no such file or directory, open 'node:fs'` in `sandboxed-module` * Remove `node:` in the SandboxedModule requires * Fix new linting errors with `node:` GitOrigin-RevId: 68f6e31e2191fcff4cb8058dd0a6914c14f59926
107 lines
2.9 KiB
JavaScript
107 lines
2.9 KiB
JavaScript
/**
|
|
* Compress changes for projects that have too many text operations.
|
|
*
|
|
* Usage:
|
|
*
|
|
* node tasks/compress_changes.js CSV_FILE
|
|
*
|
|
* where CSV_FILE contains a list of project ids in the first column
|
|
*/
|
|
|
|
const fs = require('node:fs')
|
|
const BPromise = require('bluebird')
|
|
const { History } = require('overleaf-editor-core')
|
|
const { historyStore, chunkStore } = require('..')
|
|
|
|
const CONCURRENCY = 10
|
|
|
|
async function main() {
|
|
const filename = process.argv[2]
|
|
const projectIds = await readCsv(filename)
|
|
const chunks = []
|
|
for (const projectId of projectIds) {
|
|
const chunkIds = await chunkStore.getProjectChunkIds(projectId)
|
|
chunks.push(...chunkIds.map(id => ({ id, projectId })))
|
|
}
|
|
let totalCompressed = 0
|
|
await BPromise.map(
|
|
chunks,
|
|
async chunk => {
|
|
try {
|
|
const history = await getHistory(chunk)
|
|
const numCompressed = compressChanges(history)
|
|
if (numCompressed > 0) {
|
|
await storeHistory(chunk, history)
|
|
console.log(
|
|
`Compressed project ${chunk.projectId}, chunk ${chunk.id}`
|
|
)
|
|
}
|
|
totalCompressed += numCompressed
|
|
} catch (err) {
|
|
console.log(err)
|
|
}
|
|
},
|
|
{ concurrency: CONCURRENCY }
|
|
)
|
|
console.log('CHANGES:', totalCompressed)
|
|
}
|
|
|
|
async function readCsv(filename) {
|
|
const csv = await fs.promises.readFile(filename, 'utf-8')
|
|
const lines = csv.trim().split('\n')
|
|
const projectIds = lines.map(line => line.split(',')[0])
|
|
return projectIds
|
|
}
|
|
|
|
async function getHistory(chunk) {
|
|
const rawHistory = await historyStore.loadRaw(chunk.projectId, chunk.id)
|
|
const history = History.fromRaw(rawHistory)
|
|
return history
|
|
}
|
|
|
|
async function storeHistory(chunk, history) {
|
|
const rawHistory = history.toRaw()
|
|
await historyStore.storeRaw(chunk.projectId, chunk.id, rawHistory)
|
|
}
|
|
|
|
function compressChanges(history) {
|
|
let numCompressed = 0
|
|
for (const change of history.getChanges()) {
|
|
const newOperations = compressOperations(change.operations)
|
|
if (newOperations.length !== change.operations.length) {
|
|
numCompressed++
|
|
}
|
|
change.setOperations(newOperations)
|
|
}
|
|
return numCompressed
|
|
}
|
|
|
|
function compressOperations(operations) {
|
|
if (!operations.length) return []
|
|
|
|
const newOperations = []
|
|
let currentOperation = operations[0]
|
|
for (let operationId = 1; operationId < operations.length; operationId++) {
|
|
const nextOperation = operations[operationId]
|
|
if (currentOperation.canBeComposedWith(nextOperation)) {
|
|
currentOperation = currentOperation.compose(nextOperation)
|
|
} else {
|
|
// currentOperation and nextOperation cannot be composed. Push the
|
|
// currentOperation and start over with nextOperation.
|
|
newOperations.push(currentOperation)
|
|
currentOperation = nextOperation
|
|
}
|
|
}
|
|
newOperations.push(currentOperation)
|
|
|
|
return newOperations
|
|
}
|
|
|
|
main()
|
|
.then(() => {
|
|
process.exit()
|
|
})
|
|
.catch(err => {
|
|
console.error(err)
|
|
process.exit(1)
|
|
})
|