diff --git a/app/coffee/ResourceListManager.coffee b/app/coffee/ResourceListManager.coffee deleted file mode 100644 index aef2d2f..0000000 --- a/app/coffee/ResourceListManager.coffee +++ /dev/null @@ -1,25 +0,0 @@ -Path = require "path" -fs = require "fs" -logger = require "logger-sharelatex" -settings = require("settings-sharelatex") -SafeReader = require "./SafeReader" - -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) - # limit file to 128K, compile directory is user accessible - SafeReader.readFile resourceListFile, 128*1024, 'utf8', (err, resourceList) -> - return callback(err) if err? - resources = ({path: path} for path in resourceList?.toString()?.split("\n") or []) - callback(null, resources) diff --git a/app/coffee/ResourceStateManager.coffee b/app/coffee/ResourceStateManager.coffee index 946c8b5..7f97405 100644 --- a/app/coffee/ResourceStateManager.coffee +++ b/app/coffee/ResourceStateManager.coffee @@ -11,10 +11,11 @@ module.exports = ResourceStateManager = # incremental update to be allowed. # # The initial value is passed in and stored on a full - # compile. + # compile, along with the list of resources.. # # Subsequent incremental compiles must come with the same value - if - # not they will be rejected with a 409 Conflict response. + # not they will be rejected with a 409 Conflict response. The + # previous list of resources is returned. # # An incremental compile can only update existing files with new # content. The sync state identifier must change if any docs or @@ -22,7 +23,7 @@ module.exports = ResourceStateManager = SYNC_STATE_FILE: ".project-sync-state" - saveProjectStateHash: (state, basePath, callback) -> + saveProjectStateHash: (state, resources, basePath, callback = (error) ->) -> stateFile = Path.join(basePath, @SYNC_STATE_FILE) if not state? # remove the file if no state passed in logger.log state:state, basePath:basePath, "clearing sync state" @@ -33,14 +34,18 @@ module.exports = ResourceStateManager = return callback() else logger.log state:state, basePath:basePath, "writing sync state" - fs.writeFile stateFile, state, {encoding: 'ascii'}, callback + resourceList = (resource.path for resource in resources) + fs.writeFile stateFile, [resourceList..., "stateHash:#{state}"].join("\n"), callback - checkProjectStateHashMatches: (state, basePath, callback) -> + checkProjectStateHashMatches: (state, basePath, callback = (error, resources) ->) -> stateFile = Path.join(basePath, @SYNC_STATE_FILE) - SafeReader.readFile stateFile, 64, 'ascii', (err, oldState) -> + SafeReader.readFile stateFile, 128*1024, 'utf8', (err, result) -> return callback(err) if err? - logger.log state:state, oldState: oldState, basePath:basePath, stateMatches: !(state isnt oldState), "checking sync state" - if state isnt oldState + [resourceList..., oldState] = result?.toString()?.split("\n") or [] + newState = "stateHash:#{state}" + logger.log state:state, oldState: oldState, basePath:basePath, stateMatches: (newState is oldState), "checking sync state" + if newState isnt oldState return callback new Errors.FilesOutOfSyncError("invalid state for incremental update") else - callback(null) + resources = ({path: path} for path in resourceList) + callback(null, resources) diff --git a/app/coffee/ResourceWriter.coffee b/app/coffee/ResourceWriter.coffee index 7c3bc73..55f1508 100644 --- a/app/coffee/ResourceWriter.coffee +++ b/app/coffee/ResourceWriter.coffee @@ -5,7 +5,6 @@ async = require "async" mkdirp = require "mkdirp" OutputFileFinder = require "./OutputFileFinder" ResourceStateManager = require "./ResourceStateManager" -ResourceListManager = require "./ResourceListManager" Metrics = require "./Metrics" logger = require "logger-sharelatex" settings = require("settings-sharelatex") @@ -17,24 +16,20 @@ module.exports = ResourceWriter = syncResourcesToDisk: (request, basePath, callback = (error, resourceList) ->) -> if request.syncType is "incremental" logger.log project_id: request.project_id, user_id: request.user_id, "incremental sync" - ResourceStateManager.checkProjectStateHashMatches request.syncState, basePath, (error) -> + ResourceStateManager.checkProjectStateHashMatches request.syncState, basePath, (error, resourceList) -> return callback(error) if error? - ResourceListManager.loadResourceList basePath, (error, resourceList) -> + ResourceWriter._removeExtraneousFiles resourceList, basePath, (error) => return callback(error) if error? - ResourceWriter._removeExtraneousFiles resourceList, basePath, (error) => + ResourceWriter.saveIncrementalResourcesToDisk request.project_id, request.resources, basePath, (error) -> return callback(error) if error? - ResourceWriter.saveIncrementalResourcesToDisk request.project_id, request.resources, basePath, (error) -> - return callback(error) if error? - callback(null, resourceList) + callback(null, resourceList) else logger.log project_id: request.project_id, user_id: request.user_id, "full sync" @saveAllResourcesToDisk request.project_id, request.resources, basePath, (error) -> return callback(error) if error? - ResourceStateManager.saveProjectStateHash request.syncState, basePath, (error) -> + ResourceStateManager.saveProjectStateHash request.syncState, request.resources, basePath, (error) -> return callback(error) if error? - ResourceListManager.saveResourceList request.resources, basePath, (error) => - return callback(error) if error? - callback(null, request.resources) + callback(null, request.resources) saveIncrementalResourcesToDisk: (project_id, resources, basePath, callback = (error) ->) -> @_createDirectory basePath, (error) => @@ -81,7 +76,7 @@ module.exports = ResourceWriter = should_delete = true if path.match(/^output\./) or path.match(/\.aux$/) or path.match(/^cache\//) # knitr cache should_delete = false - if path in ['.project-resource-list', '.project-sync-state'] + if path == '.project-sync-state' should_delete = false if path == "output.pdf" or path == "output.dvi" or path == "output.log" or path == "output.xdv" should_delete = true diff --git a/test/unit/coffee/ResourceWriterTests.coffee b/test/unit/coffee/ResourceWriterTests.coffee index 0804438..520db6f 100644 --- a/test/unit/coffee/ResourceWriterTests.coffee +++ b/test/unit/coffee/ResourceWriterTests.coffee @@ -10,7 +10,6 @@ describe "ResourceWriter", -> "fs": @fs = mkdir: sinon.stub().callsArg(1) unlink: sinon.stub().callsArg(1) - "./ResourceListManager": @ResourceListManager = {} "./ResourceStateManager": @ResourceStateManager = {} "wrench": @wrench = {} "./UrlCache" : @UrlCache = {} @@ -34,9 +33,7 @@ describe "ResourceWriter", -> @ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3) @ResourceWriter._removeExtraneousFiles = sinon.stub().callsArg(2) @ResourceStateManager.checkProjectStateHashMatches = sinon.stub().callsArg(2) - @ResourceStateManager.saveProjectStateHash = sinon.stub().callsArg(2) - @ResourceListManager.saveResourceList = sinon.stub().callsArg(2) - @ResourceListManager.loadResourceList = sinon.stub().callsArg(1) + @ResourceStateManager.saveProjectStateHash = sinon.stub().callsArg(3) @ResourceWriter.syncResourcesToDisk({ project_id: @project_id syncState: @syncState = "0123456789abcdef" @@ -54,14 +51,9 @@ describe "ResourceWriter", -> .calledWith(@project_id, resource, @basePath) .should.equal true - it "should store the sync state", -> + it "should store the sync state and resource list", -> @ResourceStateManager.saveProjectStateHash - .calledWith(@syncState, @basePath) - .should.equal true - - it "should save the resource list", -> - @ResourceListManager.saveResourceList - .calledWith(@resources, @basePath) + .calledWith(@syncState, @resources, @basePath) .should.equal true it "should call the callback", -> @@ -74,10 +66,8 @@ describe "ResourceWriter", -> ] @ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3) @ResourceWriter._removeExtraneousFiles = sinon.stub().callsArg(2) - @ResourceStateManager.checkProjectStateHashMatches = sinon.stub().callsArg(2) - @ResourceStateManager.saveProjectStateHash = sinon.stub().callsArg(2) - @ResourceListManager.saveResourceList = sinon.stub().callsArg(2) - @ResourceListManager.loadResourceList = sinon.stub().callsArgWith(1, null, @resources) + @ResourceStateManager.checkProjectStateHashMatches = sinon.stub().callsArgWith(2, null, @resources) + @ResourceStateManager.saveProjectStateHash = sinon.stub().callsArg(3) @ResourceWriter.syncResourcesToDisk({ project_id: @project_id, syncType: "incremental",