mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
[web] Fetch and parse compile log files asynchronously (#6220)
GitOrigin-RevId: 91b4c3551b705e7c07205b1bced3ae4768b10edb
This commit is contained in:
parent
74b76c853d
commit
439ba17bd5
3 changed files with 98 additions and 57 deletions
|
@ -11,13 +11,18 @@ export const buildFileList = (outputFiles, clsiServerId) => {
|
||||||
params.set('clsiserverid', clsiServerId)
|
params.set('clsiserverid', clsiServerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const queryString = params.toString()
|
||||||
|
|
||||||
const allFiles = []
|
const allFiles = []
|
||||||
|
|
||||||
// filter out ignored files and set some properties
|
// filter out ignored files and set some properties
|
||||||
for (const file of outputFiles.values()) {
|
for (const file of outputFiles.values()) {
|
||||||
if (!ignoreFiles.includes(file.path)) {
|
if (!ignoreFiles.includes(file.path)) {
|
||||||
file.main = file.path.startsWith('output.')
|
file.main = file.path.startsWith('output.')
|
||||||
file.url += `?${params}`
|
|
||||||
|
if (queryString.length) {
|
||||||
|
file.url += `?${queryString}`
|
||||||
|
}
|
||||||
|
|
||||||
allFiles.push(file)
|
allFiles.push(file)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,15 @@
|
||||||
import getMeta from '../../../utils/meta'
|
import getMeta from '../../../utils/meta'
|
||||||
import HumanReadableLogs from '../../../ide/human-readable-logs/HumanReadableLogs'
|
import HumanReadableLogs from '../../../ide/human-readable-logs/HumanReadableLogs'
|
||||||
import BibLogParser from '../../../ide/log-parser/bib-log-parser'
|
import BibLogParser from '../../../ide/log-parser/bib-log-parser'
|
||||||
import { buildFileList } from './file-list'
|
|
||||||
import { v4 as uuid } from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
|
|
||||||
const searchParams = new URLSearchParams(window.location.search)
|
const searchParams = new URLSearchParams(window.location.search)
|
||||||
|
|
||||||
export const handleOutputFiles = async (projectId, data) => {
|
export const handleOutputFiles = async (outputFiles, projectId, data) => {
|
||||||
const result = {}
|
const result = {}
|
||||||
|
|
||||||
const outputFiles = new Map()
|
|
||||||
const pdfDownloadDomain = data.pdfDownloadDomain ?? ''
|
const pdfDownloadDomain = data.pdfDownloadDomain ?? ''
|
||||||
|
|
||||||
for (const outputFile of data.outputFiles) {
|
|
||||||
outputFiles.set(outputFile.path, outputFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
const outputFile = outputFiles.get('output.pdf')
|
const outputFile = outputFiles.get('output.pdf')
|
||||||
|
|
||||||
if (outputFile) {
|
if (outputFile) {
|
||||||
|
@ -46,18 +40,19 @@ export const handleOutputFiles = async (projectId, data) => {
|
||||||
result.pdfDownloadUrl = `/download/project/${projectId}/build/${outputFile.build}/output/output.pdf?${params}`
|
result.pdfDownloadUrl = `/download/project/${projectId}/build/${outputFile.build}/output/output.pdf?${params}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = new URLSearchParams({
|
return result
|
||||||
compileGroup: data.compileGroup,
|
}
|
||||||
})
|
|
||||||
|
|
||||||
if (data.clsiServerId) {
|
export const handleLogFiles = async (outputFiles, data, signal) => {
|
||||||
params.set('clsiserverid', data.clsiServerId)
|
const pdfDownloadDomain = data.pdfDownloadDomain ?? ''
|
||||||
}
|
|
||||||
|
|
||||||
result.logEntries = {
|
const result = {
|
||||||
errors: [],
|
log: null,
|
||||||
warnings: [],
|
logEntries: {
|
||||||
typesetting: [],
|
errors: [],
|
||||||
|
warnings: [],
|
||||||
|
typesetting: [],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
function accumulateResults(newEntries, type) {
|
function accumulateResults(newEntries, type) {
|
||||||
|
@ -80,38 +75,49 @@ export const handleOutputFiles = async (projectId, data) => {
|
||||||
const logFile = outputFiles.get('output.log')
|
const logFile = outputFiles.get('output.log')
|
||||||
|
|
||||||
if (logFile) {
|
if (logFile) {
|
||||||
const response = await fetch(`${pdfDownloadDomain}${logFile.url}?${params}`)
|
try {
|
||||||
|
const response = await fetch(`${pdfDownloadDomain}${logFile.url}`, {
|
||||||
|
signal,
|
||||||
|
})
|
||||||
|
|
||||||
const log = await response.text()
|
result.log = await response.text()
|
||||||
|
|
||||||
result.log = log
|
const { errors, warnings, typesetting } = HumanReadableLogs.parse(
|
||||||
|
result.log,
|
||||||
|
{
|
||||||
|
ignoreDuplicates: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const { errors, warnings, typesetting } = HumanReadableLogs.parse(log, {
|
accumulateResults({ errors, warnings, typesetting })
|
||||||
ignoreDuplicates: true,
|
} catch (e) {
|
||||||
})
|
console.warn(e) // ignore failure to fetch/parse the log file, but log a warning
|
||||||
|
}
|
||||||
accumulateResults({ errors, warnings, typesetting })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const blgFile = outputFiles.get('output.blg')
|
const blgFile = outputFiles.get('output.blg')
|
||||||
|
|
||||||
if (blgFile) {
|
if (blgFile) {
|
||||||
const response = await fetch(`${pdfDownloadDomain}${blgFile.url}?${params}`)
|
|
||||||
|
|
||||||
const log = await response.text()
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { errors, warnings } = new BibLogParser(log, {
|
const response = await fetch(`${pdfDownloadDomain}${blgFile.url}`, {
|
||||||
maxErrors: 100,
|
signal,
|
||||||
}).parse()
|
})
|
||||||
accumulateResults({ errors, warnings }, 'BibTeX:')
|
|
||||||
|
const log = await response.text()
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { errors, warnings } = new BibLogParser(log, {
|
||||||
|
maxErrors: 100,
|
||||||
|
}).parse()
|
||||||
|
accumulateResults({ errors, warnings }, 'BibTeX:')
|
||||||
|
} catch (e) {
|
||||||
|
// BibLog parsing errors are ignored
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// BibLog parsing errors are ignored
|
console.warn(e) // ignore failure to fetch/parse the log file, but log a warning
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.fileList = buildFileList(outputFiles, data.clsiServerId)
|
|
||||||
|
|
||||||
result.logEntries.all = [
|
result.logEntries.all = [
|
||||||
...result.logEntries.errors,
|
...result.logEntries.errors,
|
||||||
...result.logEntries.warnings,
|
...result.logEntries.warnings,
|
||||||
|
|
|
@ -16,11 +16,13 @@ import DocumentCompiler from '../../features/pdf-preview/util/compiler'
|
||||||
import { send, sendMBSampled } from '../../infrastructure/event-tracking'
|
import { send, sendMBSampled } from '../../infrastructure/event-tracking'
|
||||||
import {
|
import {
|
||||||
buildLogEntryAnnotations,
|
buildLogEntryAnnotations,
|
||||||
|
handleLogFiles,
|
||||||
handleOutputFiles,
|
handleOutputFiles,
|
||||||
} from '../../features/pdf-preview/util/output-files'
|
} from '../../features/pdf-preview/util/output-files'
|
||||||
import { useIdeContext } from './ide-context'
|
import { useIdeContext } from './ide-context'
|
||||||
import { useProjectContext } from './project-context'
|
import { useProjectContext } from './project-context'
|
||||||
import { useEditorContext } from './editor-context'
|
import { useEditorContext } from './editor-context'
|
||||||
|
import { buildFileList } from '../../features/pdf-preview/util/file-list'
|
||||||
|
|
||||||
export const CompileContext = createContext()
|
export const CompileContext = createContext()
|
||||||
|
|
||||||
|
@ -214,37 +216,61 @@ export function CompileProvider({ children }) {
|
||||||
// note: this should _only_ run when `data` changes,
|
// note: this should _only_ run when `data` changes,
|
||||||
// the other dependencies must all be static
|
// the other dependencies must all be static
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const abortController = new AbortController()
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
if (data.clsiServerId) {
|
if (data.clsiServerId) {
|
||||||
setClsiServerId(data.clsiServerId) // set in scope, for PdfSynctexController
|
setClsiServerId(data.clsiServerId) // set in scope, for PdfSynctexController
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.outputFiles) {
|
if (data.outputFiles) {
|
||||||
handleOutputFiles(projectId, data).then(result => {
|
const outputFiles = new Map()
|
||||||
setLogEntryAnnotations(
|
|
||||||
buildLogEntryAnnotations(result.logEntries.all, ide.fileTreeManager)
|
for (const outputFile of data.outputFiles) {
|
||||||
)
|
outputFiles.set(outputFile.path, outputFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the PDF URLs
|
||||||
|
handleOutputFiles(outputFiles, projectId, data).then(result => {
|
||||||
if (data.status === 'success') {
|
if (data.status === 'success') {
|
||||||
setPdfDownloadUrl(result.pdfDownloadUrl)
|
setPdfDownloadUrl(result.pdfDownloadUrl)
|
||||||
setPdfUrl(result.pdfUrl)
|
setPdfUrl(result.pdfUrl)
|
||||||
}
|
}
|
||||||
setLogEntries(result.logEntries)
|
|
||||||
setFileList(result.fileList)
|
|
||||||
setRawLog(result.log)
|
|
||||||
|
|
||||||
// sample compile stats for real users
|
setFileList(buildFileList(outputFiles, data.clsiServerId))
|
||||||
if (!window.user.alphaProgram && data.status === 'success') {
|
|
||||||
sendMBSampled(
|
// handle log files
|
||||||
'compile-result',
|
// asynchronous (TODO: cancel on new compile?)
|
||||||
{
|
setLogEntryAnnotations(null)
|
||||||
errors: result.logEntries.errors.length,
|
setLogEntries(null)
|
||||||
warnings: result.logEntries.warnings.length,
|
setRawLog(null)
|
||||||
typesetting: result.logEntries.typesetting.length,
|
|
||||||
newPdfPreview: true, // TODO: is this useful?
|
handleLogFiles(outputFiles, data, abortController.signal).then(
|
||||||
},
|
result => {
|
||||||
0.01
|
setRawLog(result.log)
|
||||||
)
|
setLogEntries(result.logEntries)
|
||||||
}
|
setLogEntryAnnotations(
|
||||||
|
buildLogEntryAnnotations(
|
||||||
|
result.logEntries.all,
|
||||||
|
ide.fileTreeManager
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// sample compile stats for real users
|
||||||
|
if (!window.user.alphaProgram && data.status === 'success') {
|
||||||
|
sendMBSampled(
|
||||||
|
'compile-result',
|
||||||
|
{
|
||||||
|
errors: result.logEntries.errors.length,
|
||||||
|
warnings: result.logEntries.warnings.length,
|
||||||
|
typesetting: result.logEntries.typesetting.length,
|
||||||
|
newPdfPreview: true, // TODO: is this useful?
|
||||||
|
},
|
||||||
|
0.01
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,6 +324,10 @@ export function CompileProvider({ children }) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
abortController.abort()
|
||||||
|
}
|
||||||
}, [
|
}, [
|
||||||
data,
|
data,
|
||||||
ide,
|
ide,
|
||||||
|
|
Loading…
Reference in a new issue