 			# for invalid build id, return top level
 			return file
 
+	generateBuildId: (callback = (error, buildId) ->) ->
+		# generate a secure build id from Date.now() and 8 random bytes in hex
+		crypto.randomBytes 8, (err, buf) ->
+			return callback(err) if err?
+			random = buf.toString('hex')
+			date = Date.now().toString(16)
+			callback err, "#{date}-#{random}"
+
 	saveOutputFiles: (outputFiles, compileDir, callback = (error) ->) ->
+		OutputCacheManager.generateBuildId (err, buildId) ->
+			return callback(err) if err?
+			OutputCacheManager.saveOutputFilesInBuildDir outputFiles, compileDir, buildId, callback
+
+	saveOutputFilesInBuildDir: (outputFiles, compileDir, buildId, callback = (error) ->) ->
 		# make a compileDir/CACHE_SUBDIR/build_id directory and
 		# copy all the output files into it
 		cacheRoot = Path.join(compileDir, OutputCacheManager.CACHE_SUBDIR)
 		# Put the files into a new cache subdirectory
-		buildId = Date.now().toString(16)
 		cacheDir = Path.join(compileDir, OutputCacheManager.CACHE_SUBDIR, buildId)
 
 		# let file expiry run in the background

logger = require "logger-sharelatex"
_ = require "underscore"
Settings = require "settings-sharelatex"

OutputFileOptimiser = require "./OutputFileOptimiser"

module.exports = OutputCacheManager =
	CACHE_SUBDIR: '.cache/clsi'
	ARCHIVE_SUBDIR: '.archive/clsi'
	BUILD_REGEX: /^[0-9a-f]+$/  # build id is Date.now() converted to hex
	CACHE_LIMIT: 2  # maximum number of cache directories
	CACHE_AGE: 60*60*1000 # up to one hour old


					else
						# pass back the list of new files in the cache
						callback(err, results)

	archiveLogs: (outputFiles, compileDir, buildId, callback = (error) ->) ->
		archiveDir = Path.join(compileDir, OutputCacheManager.ARCHIVE_SUBDIR, buildId)
		logger.log {dir: archiveDir}, "archiving log files for project"
		fse.ensureDir archiveDir, (err) ->
