store the resource list in a file

This commit is contained in:
Brian Gough 2017-08-17 14:53:35 +01:00
parent c0ed71f65c
commit 8415ea2f71
5 changed files with 46 additions and 9 deletions

View file

@ -31,7 +31,8 @@ module.exports = CompileManager =
timer = new Metrics.Timer("write-to-disk") timer = new Metrics.Timer("write-to-disk")
logger.log project_id: request.project_id, user_id: request.user_id, "syncing resources to disk" logger.log project_id: request.project_id, user_id: request.user_id, "syncing resources to disk"
ResourceWriter.syncResourcesToDisk request, compileDir, (error) -> ResourceWriter.syncResourcesToDisk request, compileDir, (error, resourceList) ->
# NOTE: resourceList is insecure, it should only be used to exclude files from the output list
if error? and error instanceof Errors.FilesOutOfSyncError if error? and error instanceof Errors.FilesOutOfSyncError
logger.warn project_id: request.project_id, user_id: request.user_id, "files out of sync, please retry" logger.warn project_id: request.project_id, user_id: request.user_id, "files out of sync, please retry"
return callback(error) return callback(error)
@ -40,15 +41,17 @@ module.exports = CompileManager =
return callback(error) return callback(error)
logger.log project_id: request.project_id, user_id: request.user_id, time_taken: Date.now() - timer.start, "written files to disk" logger.log project_id: request.project_id, user_id: request.user_id, time_taken: Date.now() - timer.start, "written files to disk"
timer.done() timer.done()
# FIXME - for incremental compiles we don't want to inject this multiple times
injectDraftModeIfRequired = (callback) -> injectDraftModeIfRequired = (callback) ->
if request.draft if request.draft
DraftModeManager.injectDraftMode Path.join(compileDir, request.rootResourcePath), callback DraftModeManager.injectDraftMode Path.join(compileDir, request.rootResourcePath), callback
else else
callback() callback()
# FIXME - for incremental compiles we may need to update output.tex every time
createTikzFileIfRequired = (callback) -> createTikzFileIfRequired = (callback) ->
if TikzManager.needsOutputFile(request.rootResourcePath, request.resources) if TikzManager.needsOutputFile(request.rootResourcePath, resourceList)
TikzManager.injectOutputFile compileDir, request.rootResourcePath, callback TikzManager.injectOutputFile compileDir, request.rootResourcePath, callback
else else
callback() callback()
@ -94,7 +97,7 @@ module.exports = CompileManager =
error.validate = "fail" error.validate = "fail"
# compile was killed by user, was a validation, or a compile which failed validation # compile was killed by user, was a validation, or a compile which failed validation
if error?.terminated or error?.validate if error?.terminated or error?.validate
OutputFileFinder.findOutputFiles request.resources, compileDir, (err, outputFiles) -> OutputFileFinder.findOutputFiles resourceList, compileDir, (err, outputFiles) ->
return callback(err) if err? return callback(err) if err?
callback(error, outputFiles) # return output files so user can check logs callback(error, outputFiles) # return output files so user can check logs
return return
@ -114,7 +117,7 @@ module.exports = CompileManager =
if stats?["latex-runs"] > 0 and timings?["cpu-time"] > 0 if stats?["latex-runs"] > 0 and timings?["cpu-time"] > 0
Metrics.timing("run-compile-cpu-time-per-pass", timings["cpu-time"] / stats["latex-runs"]) Metrics.timing("run-compile-cpu-time-per-pass", timings["cpu-time"] / stats["latex-runs"])
OutputFileFinder.findOutputFiles request.resources, compileDir, (error, outputFiles) -> OutputFileFinder.findOutputFiles resourceList, compileDir, (error, outputFiles) ->
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

View file

@ -0,0 +1,24 @@
Path = require "path"
fs = require "fs"
mkdirp = require "mkdirp"
logger = require "logger-sharelatex"
settings = require("settings-sharelatex")
module.exports = ResourceListManager =
# This file is a list of the input files for the project, one per
# line, used to identify output files (i.e. files not on this list)
# when the incoming request is incremental.
RESOURCE_LIST_FILE: ".project-resource-list"
saveResourceList: (resources, basePath, callback = (error) ->) ->
resourceListFile = Path.join(basePath, @RESOURCE_LIST_FILE)
resourceList = (resource.path for resource in resources)
fs.writeFile resourceListFile, resourceList.join("\n"), callback
loadResourceList: (basePath, callback = (error) ->) ->
resourceListFile = Path.join(basePath, @RESOURCE_LIST_FILE)
fs.readFile resourceListFile, (err, resourceList) ->
return callback(err) if err?
resources = ({path: path} for path in resourceList?.toString()?.split("\n") or [])
callback(null, resources)

View file

@ -4,6 +4,7 @@ fs = require "fs"
async = require "async" async = require "async"
mkdirp = require "mkdirp" mkdirp = require "mkdirp"
OutputFileFinder = require "./OutputFileFinder" OutputFileFinder = require "./OutputFileFinder"
ResourceListManager = require "./ResourceListManager"
Metrics = require "./Metrics" Metrics = require "./Metrics"
Errors = require "./Errors" Errors = require "./Errors"
logger = require "logger-sharelatex" logger = require "logger-sharelatex"
@ -13,16 +14,22 @@ parallelFileDownloads = settings.parallelFileDownloads or 1
module.exports = ResourceWriter = module.exports = ResourceWriter =
syncResourcesToDisk: (request, basePath, callback = (error) ->) -> syncResourcesToDisk: (request, basePath, callback = (error, resourceList) ->) ->
if request.syncType is "incremental" if request.syncType is "incremental"
ResourceWriter.checkSyncState request.syncState, basePath, (error, syncStateOk) -> ResourceWriter.checkSyncState request.syncState, basePath, (error, syncStateOk) ->
logger.log syncState: request.syncState, result:syncStateOk, "checked state on incremental request" logger.log syncState: request.syncState, result:syncStateOk, "checked state on incremental request"
return callback new Errors.FilesOutOfSyncError("invalid state for incremental update") if not syncStateOk return callback new Errors.FilesOutOfSyncError("invalid state for incremental update") if not syncStateOk
ResourceWriter.saveIncrementalResourcesToDisk request.project_id, request.resources, basePath, callback ResourceWriter.saveIncrementalResourcesToDisk request.project_id, request.resources, basePath, (error) ->
return callback(error) if error?
ResourceListManager.loadResourceList basePath, callback
else else
@saveAllResourcesToDisk request.project_id, request.resources, basePath, (error) -> @saveAllResourcesToDisk request.project_id, request.resources, basePath, (error) ->
return callback(error) if error? return callback(error) if error?
ResourceWriter.storeSyncState request.syncState, basePath, callback ResourceWriter.storeSyncState request.syncState, basePath, (error) ->
return callback(error) if error?
ResourceListManager.saveResourceList request.resources, basePath, (error) =>
return callback(error) if error?
callback(null, request.resources)
# The sync state is an identifier which must match for an # The sync state is an identifier which must match for an
# incremental update to be allowed. # incremental update to be allowed.

View file

@ -51,7 +51,7 @@ describe "CompileManager", ->
@env = {} @env = {}
@Settings.compileDir = "compiles" @Settings.compileDir = "compiles"
@compileDir = "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}" @compileDir = "#{@Settings.path.compilesDir}/#{@project_id}-#{@user_id}"
@ResourceWriter.syncResourcesToDisk = sinon.stub().callsArg(2) @ResourceWriter.syncResourcesToDisk = sinon.stub().callsArgWith(2, null, @resources)
@LatexRunner.runLatex = sinon.stub().callsArg(2) @LatexRunner.runLatex = sinon.stub().callsArg(2)
@OutputFileFinder.findOutputFiles = sinon.stub().callsArgWith(2, null, @output_files) @OutputFileFinder.findOutputFiles = sinon.stub().callsArgWith(2, null, @output_files)
@OutputCacheManager.saveOutputFiles = sinon.stub().callsArgWith(2, null, @build_files) @OutputCacheManager.saveOutputFiles = sinon.stub().callsArgWith(2, null, @build_files)

View file

@ -10,6 +10,7 @@ describe "ResourceWriter", ->
"fs": @fs = "fs": @fs =
mkdir: sinon.stub().callsArg(1) mkdir: sinon.stub().callsArg(1)
unlink: sinon.stub().callsArg(1) unlink: sinon.stub().callsArg(1)
"./ResourceListManager": @ResourceListManager = {}
"wrench": @wrench = {} "wrench": @wrench = {}
"./UrlCache" : @UrlCache = {} "./UrlCache" : @UrlCache = {}
"mkdirp" : @mkdirp = sinon.stub().callsArg(1) "mkdirp" : @mkdirp = sinon.stub().callsArg(1)
@ -33,6 +34,8 @@ describe "ResourceWriter", ->
@ResourceWriter._removeExtraneousFiles = sinon.stub().callsArg(2) @ResourceWriter._removeExtraneousFiles = sinon.stub().callsArg(2)
@ResourceWriter.checkSyncState = sinon.stub().callsArg(2) @ResourceWriter.checkSyncState = sinon.stub().callsArg(2)
@ResourceWriter.storeSyncState = sinon.stub().callsArg(2) @ResourceWriter.storeSyncState = sinon.stub().callsArg(2)
@ResourceListManager.saveResourceList = sinon.stub().callsArg(2)
@ResourceListManager.loadResourceList = sinon.stub().callsArg(1)
@ResourceWriter.syncResourcesToDisk({project_id: @project_id, resources: @resources}, @basePath, @callback) @ResourceWriter.syncResourcesToDisk({project_id: @project_id, resources: @resources}, @basePath, @callback)
it "should remove old files", -> it "should remove old files", ->