a7c2403c4a
- Add QuartoRunner.js: runs `quarto render --to typst --output output.pdf`, using Typst (bundled with Quarto >= 1.4) so no separate LaTeX install needed - Swap LatexRunner for QuartoRunner in CompileManager; remove latexmk-specific stats, fdb metrics, and performance sampling that no longer apply - Add 'quarto' to VALID_COMPILERS in RequestParser and set it as the default; change default rootResourcePath from main.tex to main.qmd - Add 'quarto' to safeCompilers and set it as the default in web settings - Replace with-texlive Dockerfile stage with with-quarto (Quarto deb install); add Quarto to the default final stage as well Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
103 lines
2.5 KiB
JavaScript
103 lines
2.5 KiB
JavaScript
import Path from 'node:path'
|
|
import { promisify } from 'node:util'
|
|
import logger from '@overleaf/logger'
|
|
import CommandRunner from './CommandRunner.js'
|
|
import fs from 'node:fs'
|
|
|
|
// Maps currently-running Quarto jobs: compileName → PID (or docker container id)
|
|
const ProcessTable = {}
|
|
|
|
function runQuarto(compileName, options, callback) {
|
|
const {
|
|
directory,
|
|
mainFile,
|
|
image,
|
|
environment,
|
|
compileGroup,
|
|
timings,
|
|
} = options
|
|
const timeout = options.timeout || 60000
|
|
|
|
logger.debug({ directory, timeout, mainFile, compileGroup }, 'starting quarto compile')
|
|
|
|
const command = _buildQuartoCommand(mainFile)
|
|
|
|
ProcessTable[compileName] = CommandRunner.run(
|
|
compileName,
|
|
command,
|
|
directory,
|
|
image,
|
|
timeout,
|
|
environment || {},
|
|
compileGroup,
|
|
null,
|
|
function (error, output) {
|
|
delete ProcessTable[compileName]
|
|
if (error) return callback(error)
|
|
_writeLogOutput(compileName, directory, output, () => {
|
|
callback(null, output)
|
|
})
|
|
}
|
|
)
|
|
}
|
|
|
|
function _buildQuartoCommand(mainFile) {
|
|
// Use Typst as the PDF engine — it is bundled with Quarto (>= 1.4) and
|
|
// does not require a separate LaTeX installation.
|
|
return [
|
|
'quarto',
|
|
'render',
|
|
Path.join('$COMPILE_DIR', mainFile),
|
|
'--to', 'typst',
|
|
'--output', 'output.pdf',
|
|
]
|
|
}
|
|
|
|
function _writeLogOutput(compileName, directory, output, callback) {
|
|
if (!output) return callback()
|
|
|
|
function _writeFile(file, content, cb) {
|
|
if (content && content.length > 0) {
|
|
fs.unlink(file, () => {
|
|
fs.writeFile(file, content, { flag: 'wx' }, err => {
|
|
if (err) {
|
|
logger.error({ err, compileName, file }, 'error writing log file')
|
|
}
|
|
cb()
|
|
})
|
|
})
|
|
} else {
|
|
cb()
|
|
}
|
|
}
|
|
|
|
_writeFile(Path.join(directory, 'output.stdout'), output.stdout, () => {
|
|
_writeFile(Path.join(directory, 'output.stderr'), output.stderr, () => {
|
|
callback()
|
|
})
|
|
})
|
|
}
|
|
|
|
function isRunning(compileName) {
|
|
return ProcessTable[compileName] != null
|
|
}
|
|
|
|
function killQuarto(compileName, callback) {
|
|
logger.debug({ compileName }, 'killing running quarto compile')
|
|
if (!isRunning(compileName)) {
|
|
logger.warn({ compileName }, 'no such compile to kill')
|
|
return callback(null)
|
|
}
|
|
CommandRunner.kill(ProcessTable[compileName], callback)
|
|
}
|
|
|
|
export default {
|
|
isRunning,
|
|
runQuarto,
|
|
killQuarto,
|
|
promises: {
|
|
runQuarto: promisify(runQuarto),
|
|
killQuarto: promisify(killQuarto),
|
|
},
|
|
}
|