2017-08-18 05:22:17 -04:00
|
|
|
Path = require "path"
|
|
|
|
fs = require "fs"
|
|
|
|
logger = require "logger-sharelatex"
|
|
|
|
settings = require("settings-sharelatex")
|
|
|
|
Errors = require "./Errors"
|
2017-08-18 06:17:01 -04:00
|
|
|
SafeReader = require "./SafeReader"
|
2017-08-18 05:22:17 -04:00
|
|
|
|
|
|
|
module.exports = ResourceStateManager =
|
|
|
|
|
|
|
|
# The sync state is an identifier which must match for an
|
|
|
|
# incremental update to be allowed.
|
|
|
|
#
|
|
|
|
# The initial value is passed in and stored on a full
|
2017-09-07 06:54:38 -04:00
|
|
|
# compile, along with the list of resources..
|
2017-08-18 05:22:17 -04:00
|
|
|
#
|
|
|
|
# Subsequent incremental compiles must come with the same value - if
|
2017-09-07 06:54:38 -04:00
|
|
|
# not they will be rejected with a 409 Conflict response. The
|
|
|
|
# previous list of resources is returned.
|
2017-08-18 05:22:17 -04:00
|
|
|
#
|
|
|
|
# An incremental compile can only update existing files with new
|
|
|
|
# content. The sync state identifier must change if any docs or
|
|
|
|
# files are moved, added, deleted or renamed.
|
|
|
|
|
|
|
|
SYNC_STATE_FILE: ".project-sync-state"
|
2017-10-02 10:44:00 -04:00
|
|
|
SYNC_STATE_MAX_SIZE: 128*1024
|
2017-08-18 05:22:17 -04:00
|
|
|
|
2017-09-08 08:56:40 -04:00
|
|
|
saveProjectState: (state, resources, basePath, callback = (error) ->) ->
|
2017-08-18 05:22:17 -04:00
|
|
|
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"
|
|
|
|
fs.unlink stateFile, (err) ->
|
|
|
|
if err? and err.code isnt 'ENOENT'
|
|
|
|
return callback(err)
|
|
|
|
else
|
|
|
|
return callback()
|
|
|
|
else
|
|
|
|
logger.log state:state, basePath:basePath, "writing sync state"
|
2017-09-07 06:54:38 -04:00
|
|
|
resourceList = (resource.path for resource in resources)
|
|
|
|
fs.writeFile stateFile, [resourceList..., "stateHash:#{state}"].join("\n"), callback
|
2017-08-18 05:22:17 -04:00
|
|
|
|
2017-09-08 08:56:40 -04:00
|
|
|
checkProjectStateMatches: (state, basePath, callback = (error, resources) ->) ->
|
2017-08-18 05:22:17 -04:00
|
|
|
stateFile = Path.join(basePath, @SYNC_STATE_FILE)
|
2017-10-02 10:44:00 -04:00
|
|
|
size = @SYNC_STATE_MAX_SIZE
|
|
|
|
SafeReader.readFile stateFile, size, 'utf8', (err, result, bytesRead) ->
|
2017-08-18 06:17:01 -04:00
|
|
|
return callback(err) if err?
|
2017-10-02 10:44:00 -04:00
|
|
|
if bytesRead is size
|
|
|
|
logger.error file:stateFile, size:size, bytesRead:bytesRead, "project state file truncated"
|
2017-09-07 06:54:38 -04:00
|
|
|
[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
|
2017-08-18 05:22:17 -04:00
|
|
|
return callback new Errors.FilesOutOfSyncError("invalid state for incremental update")
|
2017-08-18 06:17:01 -04:00
|
|
|
else
|
2017-09-07 06:54:38 -04:00
|
|
|
resources = ({path: path} for path in resourceList)
|
|
|
|
callback(null, resources)
|
2017-09-07 08:51:36 -04:00
|
|
|
|
2017-09-15 08:41:56 -04:00
|
|
|
checkResourceFiles: (resources, allFiles, basePath, callback = (error) ->) ->
|
|
|
|
# check the paths are all relative to current directory
|
|
|
|
for file in resources or []
|
|
|
|
for dir in file?.path?.split('/')
|
|
|
|
if dir == '..'
|
|
|
|
return callback new Error("relative path in resource file list")
|
2017-09-07 08:51:36 -04:00
|
|
|
# check if any of the input files are not present in list of files
|
|
|
|
seenFile = {}
|
|
|
|
for file in allFiles
|
|
|
|
seenFile[file] = true
|
2017-09-26 04:48:09 -04:00
|
|
|
missingFiles = (resource.path for resource in resources when not seenFile[resource.path])
|
|
|
|
if missingFiles?.length > 0
|
|
|
|
logger.err missingFiles:missingFiles, basePath:basePath, allFiles:allFiles, resources:resources, "missing input files for project"
|
|
|
|
return callback new Errors.FilesOutOfSyncError("resource files missing in incremental update")
|
2017-09-07 08:51:36 -04:00
|
|
|
else
|
2017-09-26 04:48:09 -04:00
|
|
|
callback()
|