support for tikz externalize

make copy of main file as output.tex for tikz externalize
This commit is contained in:
Brian Gough 2017-03-16 16:55:53 +00:00
parent a602629406
commit 3bd919b3eb
4 changed files with 113 additions and 1 deletions

View file

@ -8,6 +8,7 @@ logger = require "logger-sharelatex"
Metrics = require "./Metrics" Metrics = require "./Metrics"
child_process = require "child_process" child_process = require "child_process"
DraftModeManager = require "./DraftModeManager" DraftModeManager = require "./DraftModeManager"
TikzManager = require "./TikzManager"
fs = require("fs") fs = require("fs")
fse = require "fs-extra" fse = require "fs-extra"
os = require("os") os = require("os")
@ -42,6 +43,12 @@ module.exports = CompileManager =
else else
callback() callback()
createTikzFileIfRequired = (callback) ->
if TikzManager.needsOutputFile(request.rootResourcePath, request.resources)
TikzManager.injectOutputFile compileDir, request.rootResourcePath, callback
else
callback()
# set up environment variables for chktex # set up environment variables for chktex
env = {} env = {}
# only run chktex on LaTeX files (not knitr .Rtex files or any others) # only run chktex on LaTeX files (not knitr .Rtex files or any others)
@ -54,7 +61,8 @@ module.exports = CompileManager =
if request.check is 'validate' if request.check is 'validate'
env['CHKTEX_VALIDATE'] = 1 env['CHKTEX_VALIDATE'] = 1
injectDraftModeIfRequired (error) -> # apply a series of file modifications/creations for draft mode and tikz
async.series [injectDraftModeIfRequired, createTikzFileIfRequired], (error) ->
return callback(error) if error? return callback(error) if error?
timer = new Metrics.Timer("run-compile") timer = new Metrics.Timer("run-compile")
# find the image tag to log it as a metric, e.g. 2015.1 (convert . to - for graphite) # find the image tag to log it as a metric, e.g. 2015.1 (convert . to - for graphite)

View file

@ -50,6 +50,8 @@ module.exports = ResourceWriter =
should_delete = false should_delete = false
if path == "output.pdf" or path == "output.dvi" or path == "output.log" if path == "output.pdf" or path == "output.dvi" or path == "output.log"
should_delete = true should_delete = true
if path == "output.tex" # created by TikzManager if present in output files
should_delete = true
if should_delete if should_delete
jobs.push (callback) -> ResourceWriter._deleteFileIfNotDirectory Path.join(basePath, path), callback jobs.push (callback) -> ResourceWriter._deleteFileIfNotDirectory Path.join(basePath, path), callback

View file

@ -0,0 +1,37 @@
fs = require "fs"
Path = require "path"
logger = require "logger-sharelatex"
# for \tikzexternalize to work the main file needs to match the
# jobname. Since we set the -jobname to output, we have to create a
# copy of the main file as 'output.tex'.
module.exports = TikzManager =
needsOutputFile: (rootResourcePath, resources) ->
# if there's already an output.tex file, we don't want to touch it
for resource in resources
if resource.path is "output.tex"
return false
# if there's no output.tex, see if we are using tikz/pgf in the main file
for resource in resources
if resource.path is rootResourcePath
return TikzManager._includesTikz (resource)
# otherwise false
return false
_includesTikz: (resource) ->
# check if we are loading tikz or pgf
content = resource.content.slice(0,4096)
if content.indexOf("\\usepackage{tikz") >= 0
return true
else if content.indexOf("\\usepackage{pgf") >= 0
return true
else
return false
injectOutputFile: (compileDir, mainFile, callback = (error) ->) ->
fs.readFile Path.join(compileDir, mainFile), "utf8", (error, content) ->
return callback(error) if error?
logger.log compileDir: compileDir, mainFile: mainFile, "copied file to ouput.tex for tikz"
# use wx flag to ensure that output file does not already exist
fs.writeFile Path.join(compileDir, "output.tex"), content, {flag:'wx'}, callback

View file

@ -0,0 +1,65 @@
SandboxedModule = require('sandboxed-module')
sinon = require('sinon')
require('chai').should()
modulePath = require('path').join __dirname, '../../../app/js/TikzManager'
describe 'TikzManager', ->
beforeEach ->
@TikzManager = SandboxedModule.require modulePath, requires:
"fs": @fs = {}
"logger-sharelatex": @logger = {log: () ->}
describe "needsOutputFile", ->
it "should return true if there is a usepackage{tikz}", ->
@TikzManager.needsOutputFile("main.tex", [
{ path: 'foo.tex' },
{ path: 'main.tex', content:'foo \\usepackage{tikz}' }
]).should.equal true
it "should return true if there is a usepackage{pgf}", ->
@TikzManager.needsOutputFile("main.tex", [
{ path: 'foo.tex'},
{ path: 'main.tex', content:'foo \\usepackage{pgf}' }
]).should.equal true
it "should return false if there is no usepackage{tikz} or {pgf}", ->
@TikzManager.needsOutputFile("main.tex", [
{ path: 'foo.tex' },
{ path: 'main.tex', content:'foo \\usepackage{bar}' }
]).should.equal false
it "should return false if there is already an output.tex file", ->
@TikzManager.needsOutputFile("main.tex", [
{ path: 'foo.tex' },
{ path: 'main.tex' },
{ path: 'output.tex' }
]).should.equal false
describe "injectOutputFile", ->
beforeEach ->
@rootDir = "/mock"
@filename = "filename.tex"
@callback = sinon.stub()
@content = '''
\\documentclass{article}
\\usepackage{tikz}
\\begin{document}
Hello world
\\end{document}
'''
@fs.readFile = sinon.stub().callsArgWith(2, null, @content)
@fs.writeFile = sinon.stub().callsArg(3)
@TikzManager.injectOutputFile @rootDir, @filename, @callback
it "should read the file", ->
@fs.readFile
.calledWith("#{@rootDir}/#{@filename}", "utf8")
.should.equal true
it "should write out the same file as output.tex", ->
@fs.writeFile
.calledWith("#{@rootDir}/output.tex", @content, {flag: 'wx'})
.should.equal true
it "should call the callback", ->
@callback.called.should.equal true