combine the resource state and resource list
to prevent them getting out of sync
This commit is contained in:
@@ -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)
|
|
||||||
@@ -11,10 +11,11 @@ module.exports = ResourceStateManager =
|
|||||||
# incremental update to be allowed.
|
# incremental update to be allowed.
|
||||||
#
|
#
|
||||||
# The initial value is passed in and stored on a full
|
# 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
|
# 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
|
# An incremental compile can only update existing files with new
|
||||||
# content. The sync state identifier must change if any docs or
|
# content. The sync state identifier must change if any docs or
|
||||||
@@ -22,7 +23,7 @@ module.exports = ResourceStateManager =
|
|||||||
|
|
||||||
SYNC_STATE_FILE: ".project-sync-state"
|
SYNC_STATE_FILE: ".project-sync-state"
|
||||||
|
|
||||||
saveProjectStateHash: (state, basePath, callback) ->
|
saveProjectStateHash: (state, resources, basePath, callback = (error) ->) ->
|
||||||
stateFile = Path.join(basePath, @SYNC_STATE_FILE)
|
stateFile = Path.join(basePath, @SYNC_STATE_FILE)
|
||||||
if not state? # remove the file if no state passed in
|
if not state? # remove the file if no state passed in
|
||||||
logger.log state:state, basePath:basePath, "clearing sync state"
|
logger.log state:state, basePath:basePath, "clearing sync state"
|
||||||
@@ -33,14 +34,18 @@ module.exports = ResourceStateManager =
|
|||||||
return callback()
|
return callback()
|
||||||
else
|
else
|
||||||
logger.log state:state, basePath:basePath, "writing sync state"
|
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)
|
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?
|
return callback(err) if err?
|
||||||
logger.log state:state, oldState: oldState, basePath:basePath, stateMatches: !(state isnt oldState), "checking sync state"
|
[resourceList..., oldState] = result?.toString()?.split("\n") or []
|
||||||
if state isnt oldState
|
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")
|
return callback new Errors.FilesOutOfSyncError("invalid state for incremental update")
|
||||||
else
|
else
|
||||||
callback(null)
|
resources = ({path: path} for path in resourceList)
|
||||||
|
callback(null, resources)
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ async = require "async"
|
|||||||
mkdirp = require "mkdirp"
|
mkdirp = require "mkdirp"
|
||||||
OutputFileFinder = require "./OutputFileFinder"
|
OutputFileFinder = require "./OutputFileFinder"
|
||||||
ResourceStateManager = require "./ResourceStateManager"
|
ResourceStateManager = require "./ResourceStateManager"
|
||||||
ResourceListManager = require "./ResourceListManager"
|
|
||||||
Metrics = require "./Metrics"
|
Metrics = require "./Metrics"
|
||||||
logger = require "logger-sharelatex"
|
logger = require "logger-sharelatex"
|
||||||
settings = require("settings-sharelatex")
|
settings = require("settings-sharelatex")
|
||||||
@@ -17,24 +16,20 @@ module.exports = ResourceWriter =
|
|||||||
syncResourcesToDisk: (request, basePath, callback = (error, resourceList) ->) ->
|
syncResourcesToDisk: (request, basePath, callback = (error, resourceList) ->) ->
|
||||||
if request.syncType is "incremental"
|
if request.syncType is "incremental"
|
||||||
logger.log project_id: request.project_id, user_id: request.user_id, "incremental sync"
|
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?
|
return callback(error) if error?
|
||||||
ResourceListManager.loadResourceList basePath, (error, resourceList) ->
|
ResourceWriter._removeExtraneousFiles resourceList, basePath, (error) =>
|
||||||
return callback(error) if 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?
|
return callback(error) if error?
|
||||||
ResourceWriter.saveIncrementalResourcesToDisk request.project_id, request.resources, basePath, (error) ->
|
callback(null, resourceList)
|
||||||
return callback(error) if error?
|
|
||||||
callback(null, resourceList)
|
|
||||||
else
|
else
|
||||||
logger.log project_id: request.project_id, user_id: request.user_id, "full sync"
|
logger.log project_id: request.project_id, user_id: request.user_id, "full sync"
|
||||||
@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?
|
||||||
ResourceStateManager.saveProjectStateHash request.syncState, basePath, (error) ->
|
ResourceStateManager.saveProjectStateHash request.syncState, request.resources, basePath, (error) ->
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
ResourceListManager.saveResourceList request.resources, basePath, (error) =>
|
callback(null, request.resources)
|
||||||
return callback(error) if error?
|
|
||||||
callback(null, request.resources)
|
|
||||||
|
|
||||||
saveIncrementalResourcesToDisk: (project_id, resources, basePath, callback = (error) ->) ->
|
saveIncrementalResourcesToDisk: (project_id, resources, basePath, callback = (error) ->) ->
|
||||||
@_createDirectory basePath, (error) =>
|
@_createDirectory basePath, (error) =>
|
||||||
@@ -81,7 +76,7 @@ module.exports = ResourceWriter =
|
|||||||
should_delete = true
|
should_delete = true
|
||||||
if path.match(/^output\./) or path.match(/\.aux$/) or path.match(/^cache\//) # knitr cache
|
if path.match(/^output\./) or path.match(/\.aux$/) or path.match(/^cache\//) # knitr cache
|
||||||
should_delete = false
|
should_delete = false
|
||||||
if path in ['.project-resource-list', '.project-sync-state']
|
if path == '.project-sync-state'
|
||||||
should_delete = false
|
should_delete = false
|
||||||
if path == "output.pdf" or path == "output.dvi" or path == "output.log" or path == "output.xdv"
|
if path == "output.pdf" or path == "output.dvi" or path == "output.log" or path == "output.xdv"
|
||||||
should_delete = true
|
should_delete = true
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ 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 = {}
|
|
||||||
"./ResourceStateManager": @ResourceStateManager = {}
|
"./ResourceStateManager": @ResourceStateManager = {}
|
||||||
"wrench": @wrench = {}
|
"wrench": @wrench = {}
|
||||||
"./UrlCache" : @UrlCache = {}
|
"./UrlCache" : @UrlCache = {}
|
||||||
@@ -34,9 +33,7 @@ describe "ResourceWriter", ->
|
|||||||
@ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3)
|
@ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3)
|
||||||
@ResourceWriter._removeExtraneousFiles = sinon.stub().callsArg(2)
|
@ResourceWriter._removeExtraneousFiles = sinon.stub().callsArg(2)
|
||||||
@ResourceStateManager.checkProjectStateHashMatches = sinon.stub().callsArg(2)
|
@ResourceStateManager.checkProjectStateHashMatches = sinon.stub().callsArg(2)
|
||||||
@ResourceStateManager.saveProjectStateHash = sinon.stub().callsArg(2)
|
@ResourceStateManager.saveProjectStateHash = sinon.stub().callsArg(3)
|
||||||
@ResourceListManager.saveResourceList = sinon.stub().callsArg(2)
|
|
||||||
@ResourceListManager.loadResourceList = sinon.stub().callsArg(1)
|
|
||||||
@ResourceWriter.syncResourcesToDisk({
|
@ResourceWriter.syncResourcesToDisk({
|
||||||
project_id: @project_id
|
project_id: @project_id
|
||||||
syncState: @syncState = "0123456789abcdef"
|
syncState: @syncState = "0123456789abcdef"
|
||||||
@@ -54,14 +51,9 @@ describe "ResourceWriter", ->
|
|||||||
.calledWith(@project_id, resource, @basePath)
|
.calledWith(@project_id, resource, @basePath)
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
it "should store the sync state", ->
|
it "should store the sync state and resource list", ->
|
||||||
@ResourceStateManager.saveProjectStateHash
|
@ResourceStateManager.saveProjectStateHash
|
||||||
.calledWith(@syncState, @basePath)
|
.calledWith(@syncState, @resources, @basePath)
|
||||||
.should.equal true
|
|
||||||
|
|
||||||
it "should save the resource list", ->
|
|
||||||
@ResourceListManager.saveResourceList
|
|
||||||
.calledWith(@resources, @basePath)
|
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
it "should call the callback", ->
|
it "should call the callback", ->
|
||||||
@@ -74,10 +66,8 @@ describe "ResourceWriter", ->
|
|||||||
]
|
]
|
||||||
@ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3)
|
@ResourceWriter._writeResourceToDisk = sinon.stub().callsArg(3)
|
||||||
@ResourceWriter._removeExtraneousFiles = sinon.stub().callsArg(2)
|
@ResourceWriter._removeExtraneousFiles = sinon.stub().callsArg(2)
|
||||||
@ResourceStateManager.checkProjectStateHashMatches = sinon.stub().callsArg(2)
|
@ResourceStateManager.checkProjectStateHashMatches = sinon.stub().callsArgWith(2, null, @resources)
|
||||||
@ResourceStateManager.saveProjectStateHash = sinon.stub().callsArg(2)
|
@ResourceStateManager.saveProjectStateHash = sinon.stub().callsArg(3)
|
||||||
@ResourceListManager.saveResourceList = sinon.stub().callsArg(2)
|
|
||||||
@ResourceListManager.loadResourceList = sinon.stub().callsArgWith(1, null, @resources)
|
|
||||||
@ResourceWriter.syncResourcesToDisk({
|
@ResourceWriter.syncResourcesToDisk({
|
||||||
project_id: @project_id,
|
project_id: @project_id,
|
||||||
syncType: "incremental",
|
syncType: "incremental",
|
||||||
|
|||||||
Reference in New Issue
Block a user