mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Add flags option to request JSON
Adds a `flags` parameter to the request JSON, appearing under the `compile.options` key (alongside such stalwarts as `compiler`, `timeout`, etc.). This is primarily to support `-file-line-error` as an option, but could have other uses as well. `flags` should be an array of strings, or absent. If supplied, the listed arguments are added to the base latexmk command.
This commit is contained in:
parent
4ccaa3bf2f
commit
1ddf9283f2
6 changed files with 82 additions and 38 deletions
|
@ -93,6 +93,7 @@ module.exports = CompileManager =
|
||||||
compiler: request.compiler
|
compiler: request.compiler
|
||||||
timeout: request.timeout
|
timeout: request.timeout
|
||||||
image: request.imageName
|
image: request.imageName
|
||||||
|
flags: request.flags
|
||||||
environment: env
|
environment: env
|
||||||
}, (error, output, stats, timings) ->
|
}, (error, output, stats, timings) ->
|
||||||
# request was for validation only
|
# request was for validation only
|
||||||
|
@ -130,7 +131,7 @@ module.exports = CompileManager =
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
OutputCacheManager.saveOutputFiles outputFiles, compileDir, (error, newOutputFiles) ->
|
OutputCacheManager.saveOutputFiles outputFiles, compileDir, (error, newOutputFiles) ->
|
||||||
callback null, newOutputFiles
|
callback null, newOutputFiles
|
||||||
|
|
||||||
stopCompile: (project_id, user_id, callback = (error) ->) ->
|
stopCompile: (project_id, user_id, callback = (error) ->) ->
|
||||||
compileName = getCompileName(project_id, user_id)
|
compileName = getCompileName(project_id, user_id)
|
||||||
LatexRunner.killLatex compileName, callback
|
LatexRunner.killLatex compileName, callback
|
||||||
|
|
|
@ -8,27 +8,27 @@ ProcessTable = {} # table of currently running jobs (pids or docker container n
|
||||||
|
|
||||||
module.exports = LatexRunner =
|
module.exports = LatexRunner =
|
||||||
runLatex: (project_id, options, callback = (error) ->) ->
|
runLatex: (project_id, options, callback = (error) ->) ->
|
||||||
{directory, mainFile, compiler, timeout, image, environment} = options
|
{directory, mainFile, compiler, timeout, image, environment, flags} = options
|
||||||
compiler ||= "pdflatex"
|
compiler ||= "pdflatex"
|
||||||
timeout ||= 60000 # milliseconds
|
timeout ||= 60000 # milliseconds
|
||||||
|
|
||||||
logger.log directory: directory, compiler: compiler, timeout: timeout, mainFile: mainFile, environment: environment, "starting compile"
|
logger.log directory: directory, compiler: compiler, timeout: timeout, mainFile: mainFile, environment: environment, flags:flags, "starting compile"
|
||||||
|
|
||||||
# We want to run latexmk on the tex file which we will automatically
|
# We want to run latexmk on the tex file which we will automatically
|
||||||
# generate from the Rtex/Rmd/md file.
|
# generate from the Rtex/Rmd/md file.
|
||||||
mainFile = mainFile.replace(/\.(Rtex|md|Rmd)$/, ".tex")
|
mainFile = mainFile.replace(/\.(Rtex|md|Rmd)$/, ".tex")
|
||||||
|
|
||||||
if compiler == "pdflatex"
|
if compiler == "pdflatex"
|
||||||
command = LatexRunner._pdflatexCommand mainFile
|
command = LatexRunner._pdflatexCommand mainFile, flags
|
||||||
else if compiler == "latex"
|
else if compiler == "latex"
|
||||||
command = LatexRunner._latexCommand mainFile
|
command = LatexRunner._latexCommand mainFile, flags
|
||||||
else if compiler == "xelatex"
|
else if compiler == "xelatex"
|
||||||
command = LatexRunner._xelatexCommand mainFile
|
command = LatexRunner._xelatexCommand mainFile, flags
|
||||||
else if compiler == "lualatex"
|
else if compiler == "lualatex"
|
||||||
command = LatexRunner._lualatexCommand mainFile
|
command = LatexRunner._lualatexCommand mainFile, flags
|
||||||
else
|
else
|
||||||
return callback new Error("unknown compiler: #{compiler}")
|
return callback new Error("unknown compiler: #{compiler}")
|
||||||
|
|
||||||
if Settings.clsi?.strace
|
if Settings.clsi?.strace
|
||||||
command = ["strace", "-o", "strace", "-ff"].concat(command)
|
command = ["strace", "-o", "strace", "-ff"].concat(command)
|
||||||
|
|
||||||
|
@ -63,31 +63,32 @@ module.exports = LatexRunner =
|
||||||
else
|
else
|
||||||
CommandRunner.kill ProcessTable[id], callback
|
CommandRunner.kill ProcessTable[id], callback
|
||||||
|
|
||||||
_latexmkBaseCommand: (Settings?.clsi?.latexmkCommandPrefix || []).concat([
|
_latexmkBaseCommand: (flags) ->
|
||||||
"latexmk", "-cd", "-f", "-jobname=output", "-auxdir=$COMPILE_DIR", "-outdir=$COMPILE_DIR",
|
args = ["latexmk", "-cd", "-f", "-jobname=output", "-auxdir=$COMPILE_DIR", "-outdir=$COMPILE_DIR", "-synctex=1","-interaction=batchmode"]
|
||||||
"-synctex=1","-interaction=batchmode"
|
if flags
|
||||||
])
|
args = args.concat(flags)
|
||||||
|
(Settings?.clsi?.latexmkCommandPrefix || []).concat(args)
|
||||||
|
|
||||||
_pdflatexCommand: (mainFile) ->
|
_pdflatexCommand: (mainFile, flags) ->
|
||||||
LatexRunner._latexmkBaseCommand.concat [
|
LatexRunner._latexmkBaseCommand(flags).concat [
|
||||||
"-pdf",
|
"-pdf",
|
||||||
Path.join("$COMPILE_DIR", mainFile)
|
Path.join("$COMPILE_DIR", mainFile)
|
||||||
]
|
]
|
||||||
|
|
||||||
_latexCommand: (mainFile) ->
|
_latexCommand: (mainFile, flags) ->
|
||||||
LatexRunner._latexmkBaseCommand.concat [
|
LatexRunner._latexmkBaseCommand(flags).concat [
|
||||||
"-pdfdvi",
|
"-pdfdvi",
|
||||||
Path.join("$COMPILE_DIR", mainFile)
|
Path.join("$COMPILE_DIR", mainFile)
|
||||||
]
|
]
|
||||||
|
|
||||||
_xelatexCommand: (mainFile) ->
|
_xelatexCommand: (mainFile, flags) ->
|
||||||
LatexRunner._latexmkBaseCommand.concat [
|
LatexRunner._latexmkBaseCommand(flags).concat [
|
||||||
"-xelatex",
|
"-xelatex",
|
||||||
Path.join("$COMPILE_DIR", mainFile)
|
Path.join("$COMPILE_DIR", mainFile)
|
||||||
]
|
]
|
||||||
|
|
||||||
_lualatexCommand: (mainFile) ->
|
_lualatexCommand: (mainFile, flags) ->
|
||||||
LatexRunner._latexmkBaseCommand.concat [
|
LatexRunner._latexmkBaseCommand(flags).concat [
|
||||||
"-lualatex",
|
"-lualatex",
|
||||||
Path.join("$COMPILE_DIR", mainFile)
|
Path.join("$COMPILE_DIR", mainFile)
|
||||||
]
|
]
|
||||||
|
|
|
@ -12,7 +12,7 @@ module.exports = RequestParser =
|
||||||
|
|
||||||
compile = body.compile
|
compile = body.compile
|
||||||
compile.options ||= {}
|
compile.options ||= {}
|
||||||
|
|
||||||
try
|
try
|
||||||
response.compiler = @_parseAttribute "compiler",
|
response.compiler = @_parseAttribute "compiler",
|
||||||
compile.options.compiler,
|
compile.options.compiler,
|
||||||
|
@ -33,6 +33,10 @@ module.exports = RequestParser =
|
||||||
response.check = @_parseAttribute "check",
|
response.check = @_parseAttribute "check",
|
||||||
compile.options.check,
|
compile.options.check,
|
||||||
type: "string"
|
type: "string"
|
||||||
|
response.flags = @_parseAttribute "flags",
|
||||||
|
compile.options.flags,
|
||||||
|
default: [],
|
||||||
|
type: "object"
|
||||||
|
|
||||||
# The syncType specifies whether the request contains all
|
# The syncType specifies whether the request contains all
|
||||||
# resources (full) or only those resources to be updated
|
# resources (full) or only those resources to be updated
|
||||||
|
@ -68,7 +72,7 @@ module.exports = RequestParser =
|
||||||
originalRootResourcePath = rootResourcePath
|
originalRootResourcePath = rootResourcePath
|
||||||
sanitizedRootResourcePath = RequestParser._sanitizePath(rootResourcePath)
|
sanitizedRootResourcePath = RequestParser._sanitizePath(rootResourcePath)
|
||||||
response.rootResourcePath = RequestParser._checkPath(sanitizedRootResourcePath)
|
response.rootResourcePath = RequestParser._checkPath(sanitizedRootResourcePath)
|
||||||
|
|
||||||
for resource in response.resources
|
for resource in response.resources
|
||||||
if resource.path == originalRootResourcePath
|
if resource.path == originalRootResourcePath
|
||||||
resource.path = sanitizedRootResourcePath
|
resource.path = sanitizedRootResourcePath
|
||||||
|
|
|
@ -13,7 +13,7 @@ describe "CompileManager", ->
|
||||||
"./ResourceWriter": @ResourceWriter = {}
|
"./ResourceWriter": @ResourceWriter = {}
|
||||||
"./OutputFileFinder": @OutputFileFinder = {}
|
"./OutputFileFinder": @OutputFileFinder = {}
|
||||||
"./OutputCacheManager": @OutputCacheManager = {}
|
"./OutputCacheManager": @OutputCacheManager = {}
|
||||||
"settings-sharelatex": @Settings =
|
"settings-sharelatex": @Settings =
|
||||||
path:
|
path:
|
||||||
compilesDir: "/compiles/dir"
|
compilesDir: "/compiles/dir"
|
||||||
synctexBaseDir: -> "/compile"
|
synctexBaseDir: -> "/compile"
|
||||||
|
@ -108,6 +108,7 @@ describe "CompileManager", ->
|
||||||
compiler: @compiler = "pdflatex"
|
compiler: @compiler = "pdflatex"
|
||||||
timeout: @timeout = 42000
|
timeout: @timeout = 42000
|
||||||
imageName: @image = "example.com/image"
|
imageName: @image = "example.com/image"
|
||||||
|
flags: @flags = ["-file-line-error"]
|
||||||
@env = {}
|
@env = {}
|
||||||
@Settings.compileDir = "compiles"
|
@Settings.compileDir = "compiles"
|
||||||
@compileDir = "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}"
|
@compileDir = "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}"
|
||||||
|
@ -117,7 +118,7 @@ describe "CompileManager", ->
|
||||||
@OutputCacheManager.saveOutputFiles = sinon.stub().callsArgWith(2, null, @build_files)
|
@OutputCacheManager.saveOutputFiles = sinon.stub().callsArgWith(2, null, @build_files)
|
||||||
@DraftModeManager.injectDraftMode = sinon.stub().callsArg(1)
|
@DraftModeManager.injectDraftMode = sinon.stub().callsArg(1)
|
||||||
@TikzManager.checkMainFile = sinon.stub().callsArg(3, false)
|
@TikzManager.checkMainFile = sinon.stub().callsArg(3, false)
|
||||||
|
|
||||||
describe "normally", ->
|
describe "normally", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@CompileManager.doCompile @request, @callback
|
@CompileManager.doCompile @request, @callback
|
||||||
|
@ -135,6 +136,7 @@ describe "CompileManager", ->
|
||||||
compiler: @compiler
|
compiler: @compiler
|
||||||
timeout: @timeout
|
timeout: @timeout
|
||||||
image: @image
|
image: @image
|
||||||
|
flags: @flags
|
||||||
environment: @env
|
environment: @env
|
||||||
})
|
})
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
@ -146,15 +148,15 @@ describe "CompileManager", ->
|
||||||
|
|
||||||
it "should return the output files", ->
|
it "should return the output files", ->
|
||||||
@callback.calledWith(null, @build_files).should.equal true
|
@callback.calledWith(null, @build_files).should.equal true
|
||||||
|
|
||||||
it "should not inject draft mode by default", ->
|
it "should not inject draft mode by default", ->
|
||||||
@DraftModeManager.injectDraftMode.called.should.equal false
|
@DraftModeManager.injectDraftMode.called.should.equal false
|
||||||
|
|
||||||
describe "with draft mode", ->
|
describe "with draft mode", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@request.draft = true
|
@request.draft = true
|
||||||
@CompileManager.doCompile @request, @callback
|
@CompileManager.doCompile @request, @callback
|
||||||
|
|
||||||
it "should inject the draft mode header", ->
|
it "should inject the draft mode header", ->
|
||||||
@DraftModeManager.injectDraftMode
|
@DraftModeManager.injectDraftMode
|
||||||
.calledWith(@compileDir + "/" + @rootResourcePath)
|
.calledWith(@compileDir + "/" + @rootResourcePath)
|
||||||
|
@ -173,6 +175,7 @@ describe "CompileManager", ->
|
||||||
compiler: @compiler
|
compiler: @compiler
|
||||||
timeout: @timeout
|
timeout: @timeout
|
||||||
image: @image
|
image: @image
|
||||||
|
flags: @flags
|
||||||
environment: {'CHKTEX_OPTIONS': '-nall -e9 -e10 -w15 -w16', 'CHKTEX_EXIT_ON_ERROR':1, 'CHKTEX_ULIMIT_OPTIONS': '-t 5 -v 64000'}
|
environment: {'CHKTEX_OPTIONS': '-nall -e9 -e10 -w15 -w16', 'CHKTEX_EXIT_ON_ERROR':1, 'CHKTEX_ULIMIT_OPTIONS': '-t 5 -v 64000'}
|
||||||
})
|
})
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
@ -191,6 +194,7 @@ describe "CompileManager", ->
|
||||||
compiler: @compiler
|
compiler: @compiler
|
||||||
timeout: @timeout
|
timeout: @timeout
|
||||||
image: @image
|
image: @image
|
||||||
|
flags: @flags
|
||||||
environment: @env
|
environment: @env
|
||||||
})
|
})
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
@ -297,7 +301,7 @@ describe "CompileManager", ->
|
||||||
@CommandRunner.run
|
@CommandRunner.run
|
||||||
.calledWith(
|
.calledWith(
|
||||||
"#{@project_id}-#{@user_id}",
|
"#{@project_id}-#{@user_id}",
|
||||||
['/opt/synctex', "pdf", synctex_path, @page, @h, @v],
|
['/opt/synctex', "pdf", synctex_path, @page, @h, @v],
|
||||||
"#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}",
|
"#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}",
|
||||||
@Settings.clsi.docker.image,
|
@Settings.clsi.docker.image,
|
||||||
60000,
|
60000,
|
||||||
|
@ -330,7 +334,7 @@ describe "CompileManager", ->
|
||||||
@directory = "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}"
|
@directory = "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}"
|
||||||
@file_path = "$COMPILE_DIR/#{@file_name}"
|
@file_path = "$COMPILE_DIR/#{@file_name}"
|
||||||
@command =[ "texcount", "-nocol", "-inc", @file_path, "-out=" + @file_path + ".wc"]
|
@command =[ "texcount", "-nocol", "-inc", @file_path, "-out=" + @file_path + ".wc"]
|
||||||
|
|
||||||
@CommandRunner.run
|
@CommandRunner.run
|
||||||
.calledWith("#{@project_id}-#{@user_id}", @command, @directory, @image, @timeout, {})
|
.calledWith("#{@project_id}-#{@user_id}", @command, @directory, @image, @timeout, {})
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
|
@ -59,3 +59,21 @@ describe "LatexRunner", ->
|
||||||
mainFile = command.slice(-1)[0]
|
mainFile = command.slice(-1)[0]
|
||||||
mainFile.should.equal "$COMPILE_DIR/main-file.tex"
|
mainFile.should.equal "$COMPILE_DIR/main-file.tex"
|
||||||
|
|
||||||
|
describe "with a flags option", ->
|
||||||
|
beforeEach ->
|
||||||
|
@LatexRunner.runLatex @project_id,
|
||||||
|
directory: @directory
|
||||||
|
mainFile: @mainFile
|
||||||
|
compiler: @compiler
|
||||||
|
image: @image
|
||||||
|
timeout: @timeout = 42000
|
||||||
|
flags: ["-file-line-error", "-halt-on-error"]
|
||||||
|
@callback
|
||||||
|
|
||||||
|
it "should include the flags in the command", ->
|
||||||
|
command = @CommandRunner.run.args[0][1]
|
||||||
|
flags = command.filter (arg) ->
|
||||||
|
(arg == "-file-line-error") || (arg == "-halt-on-error")
|
||||||
|
flags.length.should.equal 2
|
||||||
|
flags[0].should.equal "-file-line-error"
|
||||||
|
flags[1].should.equal "-halt-on-error"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
SandboxedModule = require('sandboxed-module')
|
SandboxedModule = require('sandboxed-module')
|
||||||
sinon = require('sinon')
|
sinon = require('sinon')
|
||||||
require('chai').should()
|
require('chai').should()
|
||||||
|
expect = require('chai').expect
|
||||||
modulePath = require('path').join __dirname, '../../../app/js/RequestParser'
|
modulePath = require('path').join __dirname, '../../../app/js/RequestParser'
|
||||||
tk = require("timekeeper")
|
tk = require("timekeeper")
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ describe "RequestParser", ->
|
||||||
resources: []
|
resources: []
|
||||||
@RequestParser = SandboxedModule.require modulePath, requires:
|
@RequestParser = SandboxedModule.require modulePath, requires:
|
||||||
"settings-sharelatex": @settings = {}
|
"settings-sharelatex": @settings = {}
|
||||||
|
|
||||||
afterEach ->
|
afterEach ->
|
||||||
tk.reset()
|
tk.reset()
|
||||||
|
|
||||||
|
@ -55,7 +56,7 @@ describe "RequestParser", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
delete @validRequest.compile.options.compiler
|
delete @validRequest.compile.options.compiler
|
||||||
@RequestParser.parse @validRequest, (error, @data) =>
|
@RequestParser.parse @validRequest, (error, @data) =>
|
||||||
|
|
||||||
it "should set the compiler to pdflatex by default", ->
|
it "should set the compiler to pdflatex by default", ->
|
||||||
@data.compiler.should.equal "pdflatex"
|
@data.compiler.should.equal "pdflatex"
|
||||||
|
|
||||||
|
@ -66,6 +67,21 @@ describe "RequestParser", ->
|
||||||
it "should set the imageName", ->
|
it "should set the imageName", ->
|
||||||
@data.imageName.should.equal "basicImageName/here:2017-1"
|
@data.imageName.should.equal "basicImageName/here:2017-1"
|
||||||
|
|
||||||
|
describe "with flags set", ->
|
||||||
|
beforeEach ->
|
||||||
|
@validRequest.compile.options.flags = ["-file-line-error"]
|
||||||
|
@RequestParser.parse @validRequest, (error, @data) =>
|
||||||
|
|
||||||
|
it "should set the flags attribute", ->
|
||||||
|
expect(@data.flags).to.deep.equal ["-file-line-error"]
|
||||||
|
|
||||||
|
describe "with flags not specified", ->
|
||||||
|
beforeEach ->
|
||||||
|
@RequestParser.parse @validRequest, (error, @data) =>
|
||||||
|
|
||||||
|
it "it should have an empty flags list", ->
|
||||||
|
expect(@data.flags).to.deep.equal []
|
||||||
|
|
||||||
describe "without a timeout specified", ->
|
describe "without a timeout specified", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
delete @validRequest.compile.options.timeout
|
delete @validRequest.compile.options.timeout
|
||||||
|
@ -88,7 +104,7 @@ describe "RequestParser", ->
|
||||||
|
|
||||||
it "should set the timeout (in milliseconds)", ->
|
it "should set the timeout (in milliseconds)", ->
|
||||||
@data.timeout.should.equal @validRequest.compile.options.timeout * 1000
|
@data.timeout.should.equal @validRequest.compile.options.timeout * 1000
|
||||||
|
|
||||||
describe "with a resource without a path", ->
|
describe "with a resource without a path", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
delete @validResource.path
|
delete @validResource.path
|
||||||
|
@ -175,7 +191,7 @@ describe "RequestParser", ->
|
||||||
|
|
||||||
it "should return the url in the parsed response", ->
|
it "should return the url in the parsed response", ->
|
||||||
@data.resources[0].url.should.equal @url
|
@data.resources[0].url.should.equal @url
|
||||||
|
|
||||||
describe "with a resource with a content attribute", ->
|
describe "with a resource with a content attribute", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@validResource.content = @content = "Hello world"
|
@validResource.content = @content = "Hello world"
|
||||||
|
@ -185,7 +201,7 @@ describe "RequestParser", ->
|
||||||
|
|
||||||
it "should return the content in the parsed response", ->
|
it "should return the content in the parsed response", ->
|
||||||
@data.resources[0].content.should.equal @content
|
@data.resources[0].content.should.equal @content
|
||||||
|
|
||||||
describe "without a root resource path", ->
|
describe "without a root resource path", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
delete @validRequest.compile.rootResourcePath
|
delete @validRequest.compile.rootResourcePath
|
||||||
|
@ -225,13 +241,13 @@ describe "RequestParser", ->
|
||||||
}
|
}
|
||||||
@RequestParser.parse @validRequest, @callback
|
@RequestParser.parse @validRequest, @callback
|
||||||
@data = @callback.args[0][1]
|
@data = @callback.args[0][1]
|
||||||
|
|
||||||
it "should return the escaped resource", ->
|
it "should return the escaped resource", ->
|
||||||
@data.rootResourcePath.should.equal @goodPath
|
@data.rootResourcePath.should.equal @goodPath
|
||||||
|
|
||||||
it "should also escape the resource path", ->
|
it "should also escape the resource path", ->
|
||||||
@data.resources[0].path.should.equal @goodPath
|
@data.resources[0].path.should.equal @goodPath
|
||||||
|
|
||||||
describe "with a root resource path that has a relative path", ->
|
describe "with a root resource path that has a relative path", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@validRequest.compile.rootResourcePath = "foo/../../bar.tex"
|
@validRequest.compile.rootResourcePath = "foo/../../bar.tex"
|
||||||
|
|
Loading…
Reference in a new issue