From 8803762081e2beccdc274af41703497d1674722e Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Thu, 16 Mar 2017 16:55:53 +0000 Subject: [PATCH] support for tikz externalize make copy of main file as output.tex for tikz externalize --- app/coffee/CompileManager.coffee | 10 ++++- app/coffee/ResourceWriter.coffee | 2 + app/coffee/TikzManager.coffee | 37 ++++++++++++++++ test/unit/coffee/TikzManager.coffee | 65 +++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 app/coffee/TikzManager.coffee create mode 100644 test/unit/coffee/TikzManager.coffee diff --git a/app/coffee/CompileManager.coffee b/app/coffee/CompileManager.coffee index 0a1ea9d..e4cb452 100644 --- a/app/coffee/CompileManager.coffee +++ b/app/coffee/CompileManager.coffee @@ -8,6 +8,7 @@ logger = require "logger-sharelatex" Metrics = require "./Metrics" child_process = require "child_process" DraftModeManager = require "./DraftModeManager" +TikzManager = require "./TikzManager" fs = require("fs") fse = require "fs-extra" os = require("os") @@ -42,6 +43,12 @@ module.exports = CompileManager = else callback() + createTikzFileIfRequired = (callback) -> + if TikzManager.needsOutputFile(request.rootResourcePath, request.resources) + TikzManager.injectOutputFile compileDir, request.rootResourcePath, callback + else + callback() + # set up environment variables for chktex env = {} # 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' 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? timer = new Metrics.Timer("run-compile") # find the image tag to log it as a metric, e.g. 2015.1 (convert . to - for graphite) diff --git a/app/coffee/ResourceWriter.coffee b/app/coffee/ResourceWriter.coffee index 16000cb..a7da588 100644 --- a/app/coffee/ResourceWriter.coffee +++ b/app/coffee/ResourceWriter.coffee @@ -50,6 +50,8 @@ module.exports = ResourceWriter = should_delete = false if path == "output.pdf" or path == "output.dvi" or path == "output.log" should_delete = true + if path == "output.tex" # created by TikzManager if present in output files + should_delete = true if should_delete jobs.push (callback) -> ResourceWriter._deleteFileIfNotDirectory Path.join(basePath, path), callback diff --git a/app/coffee/TikzManager.coffee b/app/coffee/TikzManager.coffee new file mode 100644 index 0000000..a7f29e9 --- /dev/null +++ b/app/coffee/TikzManager.coffee @@ -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 diff --git a/test/unit/coffee/TikzManager.coffee b/test/unit/coffee/TikzManager.coffee new file mode 100644 index 0000000..859c392 --- /dev/null +++ b/test/unit/coffee/TikzManager.coffee @@ -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