Merge pull request #188 from overleaf/jpa-bump-dev-env-3-3-2-testing
[misc] bump the dev-env to 3.3.2
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
"prettier/standard"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2017
|
||||
"ecmaVersion": 2018
|
||||
},
|
||||
"plugins": [
|
||||
"mocha",
|
||||
|
||||
17
.github/dependabot.yml
vendored
Normal file
17
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
pull-request-branch-name:
|
||||
# Separate sections of the branch name with a hyphen
|
||||
# Docker images use the branch name and do not support slashes in tags
|
||||
# https://github.com/overleaf/google-ops/issues/822
|
||||
# https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#pull-request-branch-nameseparator
|
||||
separator: "-"
|
||||
|
||||
# Block informal upgrades -- security upgrades use a separate queue.
|
||||
# https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#open-pull-requests-limit
|
||||
open-pull-requests-limit: 0
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -11,3 +11,6 @@ db.sqlite-wal
|
||||
db.sqlite-shm
|
||||
config/*
|
||||
npm-debug.log
|
||||
|
||||
# managed by dev-environment$ bin/update_build_scripts
|
||||
.npmrc
|
||||
|
||||
@@ -15,12 +15,10 @@ FROM base as app
|
||||
#wildcard as some files may not be in all repos
|
||||
COPY package*.json npm-shrink*.json /app/
|
||||
|
||||
RUN npm install --quiet
|
||||
RUN npm ci --quiet
|
||||
|
||||
COPY . /app
|
||||
|
||||
|
||||
|
||||
FROM base
|
||||
|
||||
COPY --from=app /app /app
|
||||
|
||||
131
Jenkinsfile
vendored
131
Jenkinsfile
vendored
@@ -1,131 +0,0 @@
|
||||
String cron_string = BRANCH_NAME == "master" ? "@daily" : ""
|
||||
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
environment {
|
||||
GIT_PROJECT = "clsi"
|
||||
JENKINS_WORKFLOW = "clsi-sharelatex"
|
||||
TARGET_URL = "${env.JENKINS_URL}blue/organizations/jenkins/${JENKINS_WORKFLOW}/detail/$BRANCH_NAME/$BUILD_NUMBER/pipeline"
|
||||
GIT_API_URL = "https://api.github.com/repos/overleaf/${GIT_PROJECT}/statuses/$GIT_COMMIT"
|
||||
}
|
||||
|
||||
triggers {
|
||||
pollSCM('* * * * *')
|
||||
cron(cron_string)
|
||||
}
|
||||
|
||||
stages {
|
||||
|
||||
stage('Install') {
|
||||
steps {
|
||||
withCredentials([usernamePassword(credentialsId: 'GITHUB_INTEGRATION', usernameVariable: 'GH_AUTH_USERNAME', passwordVariable: 'GH_AUTH_PASSWORD')]) {
|
||||
sh "curl $GIT_API_URL \
|
||||
--data '{ \
|
||||
\"state\" : \"pending\", \
|
||||
\"target_url\": \"$TARGET_URL\", \
|
||||
\"description\": \"Your build is underway\", \
|
||||
\"context\": \"ci/jenkins\" }' \
|
||||
-u $GH_AUTH_USERNAME:$GH_AUTH_PASSWORD"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'make build'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Linting') {
|
||||
steps {
|
||||
sh 'DOCKER_COMPOSE_FLAGS="-f docker-compose.ci.yml" make format'
|
||||
sh 'DOCKER_COMPOSE_FLAGS="-f docker-compose.ci.yml" make lint'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Unit Tests') {
|
||||
steps {
|
||||
sh 'DOCKER_COMPOSE_FLAGS="-f docker-compose.ci.yml" make test_unit'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Acceptance Tests') {
|
||||
steps {
|
||||
sh 'DOCKER_COMPOSE_FLAGS="-f docker-compose.ci.yml" make test_acceptance'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Package and docker push') {
|
||||
steps {
|
||||
sh 'echo ${BUILD_NUMBER} > build_number.txt'
|
||||
sh 'touch build.tar.gz' // Avoid tar warning about files changing during read
|
||||
sh 'DOCKER_COMPOSE_FLAGS="-f docker-compose.ci.yml" make tar'
|
||||
|
||||
withCredentials([file(credentialsId: 'gcr.io_overleaf-ops', variable: 'DOCKER_REPO_KEY_PATH')]) {
|
||||
sh 'docker login -u _json_key --password-stdin https://gcr.io/overleaf-ops < ${DOCKER_REPO_KEY_PATH}'
|
||||
}
|
||||
sh 'DOCKER_REPO=gcr.io/overleaf-ops make publish'
|
||||
sh 'docker logout https://gcr.io/overleaf-ops'
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
stage('Publish to s3') {
|
||||
steps {
|
||||
sh 'echo ${BRANCH_NAME}-${BUILD_NUMBER} > build_number.txt'
|
||||
withAWS(credentials:'S3_CI_BUILDS_AWS_KEYS', region:"${S3_REGION_BUILD_ARTEFACTS}") {
|
||||
s3Upload(file:'build.tar.gz', bucket:"${S3_BUCKET_BUILD_ARTEFACTS}", path:"${JOB_NAME}/${BUILD_NUMBER}.tar.gz")
|
||||
}
|
||||
withAWS(credentials:'S3_CI_BUILDS_AWS_KEYS', region:"${S3_REGION_BUILD_ARTEFACTS}") {
|
||||
// The deployment process uses this file to figure out the latest build
|
||||
s3Upload(file:'build_number.txt', bucket:"${S3_BUCKET_BUILD_ARTEFACTS}", path:"${JOB_NAME}/latest")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
sh 'DOCKER_COMPOSE_FLAGS="-f docker-compose.ci.yml" make test_clean'
|
||||
sh 'make clean'
|
||||
}
|
||||
|
||||
success {
|
||||
withCredentials([usernamePassword(credentialsId: 'GITHUB_INTEGRATION', usernameVariable: 'GH_AUTH_USERNAME', passwordVariable: 'GH_AUTH_PASSWORD')]) {
|
||||
sh "curl $GIT_API_URL \
|
||||
--data '{ \
|
||||
\"state\" : \"success\", \
|
||||
\"target_url\": \"$TARGET_URL\", \
|
||||
\"description\": \"Your build succeeded!\", \
|
||||
\"context\": \"ci/jenkins\" }' \
|
||||
-u $GH_AUTH_USERNAME:$GH_AUTH_PASSWORD"
|
||||
}
|
||||
}
|
||||
|
||||
failure {
|
||||
mail(from: "${EMAIL_ALERT_FROM}",
|
||||
to: "${EMAIL_ALERT_TO}",
|
||||
subject: "Jenkins build failed: ${JOB_NAME}:${BUILD_NUMBER}",
|
||||
body: "Build: ${BUILD_URL}")
|
||||
withCredentials([usernamePassword(credentialsId: 'GITHUB_INTEGRATION', usernameVariable: 'GH_AUTH_USERNAME', passwordVariable: 'GH_AUTH_PASSWORD')]) {
|
||||
sh "curl $GIT_API_URL \
|
||||
--data '{ \
|
||||
\"state\" : \"failure\", \
|
||||
\"target_url\": \"$TARGET_URL\", \
|
||||
\"description\": \"Your build failed\", \
|
||||
\"context\": \"ci/jenkins\" }' \
|
||||
-u $GH_AUTH_USERNAME:$GH_AUTH_PASSWORD"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The options directive is for configuration that applies to the whole job.
|
||||
options {
|
||||
// we'd like to make sure remove old builds, so we don't fill up our storage!
|
||||
buildDiscarder(logRotator(numToKeepStr:'50'))
|
||||
|
||||
// And we'd really like to be sure that this build doesn't hang forever, so let's time it out after:
|
||||
timeout(time: 30, unit: 'MINUTES')
|
||||
}
|
||||
}
|
||||
6
Makefile
6
Makefile
@@ -25,13 +25,13 @@ clean:
|
||||
docker rmi gcr.io/overleaf-ops/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER)
|
||||
|
||||
format:
|
||||
$(DOCKER_COMPOSE) run --rm test_unit npm run format
|
||||
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format
|
||||
|
||||
format_fix:
|
||||
$(DOCKER_COMPOSE) run --rm test_unit npm run format:fix
|
||||
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent format:fix
|
||||
|
||||
lint:
|
||||
$(DOCKER_COMPOSE) run --rm test_unit npm run lint
|
||||
$(DOCKER_COMPOSE) run --rm test_unit npm run --silent lint
|
||||
|
||||
test: format lint test_unit test_acceptance
|
||||
|
||||
|
||||
19
app.js
19
app.js
@@ -134,17 +134,16 @@ const staticServer = ForbidSymlinks(express.static, Settings.path.compilesDir, {
|
||||
}
|
||||
})
|
||||
|
||||
app.get('/project/:project_id/user/:user_id/build/:build_id/output/*', function(
|
||||
req,
|
||||
res,
|
||||
next
|
||||
) {
|
||||
app.get(
|
||||
'/project/:project_id/user/:user_id/build/:build_id/output/*',
|
||||
function (req, res, next) {
|
||||
// for specific build get the path from the OutputCacheManager (e.g. .clsi/buildId)
|
||||
req.url =
|
||||
`/${req.params.project_id}-${req.params.user_id}/` +
|
||||
OutputCacheManager.path(req.params.build_id, `/${req.params[0]}`)
|
||||
return staticServer(req, res, next)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
app.get('/project/:project_id/build/:build_id/output/*', function (
|
||||
req,
|
||||
@@ -208,7 +207,7 @@ if (Settings.processLifespanLimitMs) {
|
||||
function runSmokeTest() {
|
||||
if (Settings.processTooOld) return
|
||||
logger.log('running smoke tests')
|
||||
smokeTest.triggerRun(err => {
|
||||
smokeTest.triggerRun((err) => {
|
||||
if (err) logger.error({ err }, 'smoke tests failed')
|
||||
setTimeout(runSmokeTest, 30 * 1000)
|
||||
})
|
||||
@@ -301,12 +300,12 @@ loadHttpServer.post('/state/maint', function(req, res, next) {
|
||||
const port =
|
||||
__guard__(
|
||||
Settings.internal != null ? Settings.internal.clsi : undefined,
|
||||
x => x.port
|
||||
(x) => x.port
|
||||
) || 3013
|
||||
const host =
|
||||
__guard__(
|
||||
Settings.internal != null ? Settings.internal.clsi : undefined,
|
||||
x1 => x1.host
|
||||
(x1) => x1.host
|
||||
) || 'localhost'
|
||||
|
||||
const loadTcpPort = Settings.internal.load_balancer_agent.load_port
|
||||
@@ -314,7 +313,7 @@ const loadHttpPort = Settings.internal.load_balancer_agent.local_port
|
||||
|
||||
if (!module.parent) {
|
||||
// Called directly
|
||||
app.listen(port, host, error => {
|
||||
app.listen(port, host, (error) => {
|
||||
if (error) {
|
||||
logger.fatal({ error }, `Error starting CLSI on ${host}:${port}`)
|
||||
} else {
|
||||
|
||||
@@ -116,7 +116,7 @@ module.exports = CompileController = {
|
||||
compile: {
|
||||
status,
|
||||
error: (error != null ? error.message : undefined) || error,
|
||||
outputFiles: outputFiles.map(file => ({
|
||||
outputFiles: outputFiles.map((file) => ({
|
||||
url:
|
||||
`${Settings.apis.clsi.url}/project/${request.project_id}` +
|
||||
(request.user_id != null
|
||||
@@ -197,17 +197,21 @@ module.exports = CompileController = {
|
||||
const v = parseFloat(req.query.v)
|
||||
const { project_id } = req.params
|
||||
const { user_id } = req.params
|
||||
return CompileManager.syncFromPdf(project_id, user_id, page, h, v, function(
|
||||
error,
|
||||
codePositions
|
||||
) {
|
||||
return CompileManager.syncFromPdf(
|
||||
project_id,
|
||||
user_id,
|
||||
page,
|
||||
h,
|
||||
v,
|
||||
function (error, codePositions) {
|
||||
if (error != null) {
|
||||
return next(error)
|
||||
}
|
||||
return res.json({
|
||||
code: codePositions
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
wordcount(req, res, next) {
|
||||
|
||||
@@ -61,7 +61,7 @@ module.exports = CompileManager = {
|
||||
}
|
||||
return LockManager.runWithLock(
|
||||
lockFile,
|
||||
releaseLock => CompileManager.doCompile(request, releaseLock),
|
||||
(releaseLock) => CompileManager.doCompile(request, releaseLock),
|
||||
callback
|
||||
)
|
||||
})
|
||||
@@ -120,7 +120,7 @@ module.exports = CompileManager = {
|
||||
}
|
||||
}
|
||||
|
||||
const createTikzFileIfRequired = callback =>
|
||||
const createTikzFileIfRequired = (callback) =>
|
||||
TikzManager.checkMainFile(
|
||||
compileDir,
|
||||
request.rootResourcePath,
|
||||
@@ -177,9 +177,9 @@ module.exports = CompileManager = {
|
||||
request.imageName != null
|
||||
? request.imageName.match(/:(.*)/)
|
||||
: undefined,
|
||||
x1 => x1[1]
|
||||
(x1) => x1[1]
|
||||
),
|
||||
x => x.replace(/\./g, '-')
|
||||
(x) => x.replace(/\./g, '-')
|
||||
) || 'default'
|
||||
if (!request.project_id.match(/^[0-9a-f]{24}$/)) {
|
||||
tag = 'other'
|
||||
@@ -206,9 +206,7 @@ module.exports = CompileManager = {
|
||||
// request was for validation only
|
||||
let metric_key, metric_value
|
||||
if (request.check === 'validate') {
|
||||
const result = (error != null
|
||||
? error.code
|
||||
: undefined)
|
||||
const result = (error != null ? error.code : undefined)
|
||||
? 'fail'
|
||||
: 'pass'
|
||||
error = new Error('validation')
|
||||
@@ -339,7 +337,7 @@ module.exports = CompileManager = {
|
||||
proc.on('error', callback)
|
||||
|
||||
let stderr = ''
|
||||
proc.stderr.setEncoding('utf8').on('data', chunk => (stderr += chunk))
|
||||
proc.stderr.setEncoding('utf8').on('data', (chunk) => (stderr += chunk))
|
||||
|
||||
return proc.on('close', function (code) {
|
||||
if (code === 0) {
|
||||
@@ -360,7 +358,7 @@ module.exports = CompileManager = {
|
||||
if (err != null) {
|
||||
return callback(err)
|
||||
}
|
||||
const allDirs = Array.from(files).map(file => Path.join(root, file))
|
||||
const allDirs = Array.from(files).map((file) => Path.join(root, file))
|
||||
return callback(null, allDirs)
|
||||
})
|
||||
},
|
||||
@@ -512,7 +510,7 @@ module.exports = CompileManager = {
|
||||
const timeout = 60 * 1000 // increased to allow for large projects
|
||||
const compileName = getCompileName(project_id, user_id)
|
||||
const compileGroup = 'synctex'
|
||||
CompileManager._checkFileExists(directory, 'output.synctex.gz', error => {
|
||||
CompileManager._checkFileExists(directory, 'output.synctex.gz', (error) => {
|
||||
if (error) {
|
||||
return callback(error)
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ logger.info('using docker runner')
|
||||
const usingSiblingContainers = () =>
|
||||
__guard__(
|
||||
Settings != null ? Settings.path : undefined,
|
||||
x => x.sandboxedCompilesHostDir
|
||||
(x) => x.sandboxedCompilesHostDir
|
||||
) != null
|
||||
|
||||
let containerMonitorTimeout
|
||||
@@ -77,8 +77,8 @@ module.exports = DockerRunner = {
|
||||
const volumes = {}
|
||||
volumes[directory] = '/compile'
|
||||
|
||||
command = Array.from(command).map(arg =>
|
||||
__guardMethod__(arg.toString(), 'replace', o =>
|
||||
command = Array.from(command).map((arg) =>
|
||||
__guardMethod__(arg.toString(), 'replace', (o) =>
|
||||
o.replace('$COMPILE_DIR', '/compile')
|
||||
)
|
||||
)
|
||||
@@ -121,7 +121,9 @@ module.exports = DockerRunner = {
|
||||
{ err: error, project_id },
|
||||
'error running container so destroying and retrying'
|
||||
)
|
||||
return DockerRunner.destroyContainer(name, null, true, function(error) {
|
||||
return DockerRunner.destroyContainer(name, null, true, function (
|
||||
error
|
||||
) {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
@@ -149,8 +151,10 @@ module.exports = DockerRunner = {
|
||||
return container.kill(function (error) {
|
||||
if (
|
||||
error != null &&
|
||||
__guardMethod__(error != null ? error.message : undefined, 'match', o =>
|
||||
o.match(/Cannot kill container .* is not running/)
|
||||
__guardMethod__(
|
||||
error != null ? error.message : undefined,
|
||||
'match',
|
||||
(o) => o.match(/Cannot kill container .* is not running/)
|
||||
)
|
||||
) {
|
||||
logger.warn(
|
||||
@@ -231,7 +235,7 @@ module.exports = DockerRunner = {
|
||||
containerReturned = true
|
||||
__guard__(
|
||||
options != null ? options.HostConfig : undefined,
|
||||
x => (x.SecurityOpt = null)
|
||||
(x) => (x.SecurityOpt = null)
|
||||
) // small log line
|
||||
logger.log({ err, exitCode, options }, 'docker container has exited')
|
||||
return callbackIfFinished()
|
||||
@@ -357,16 +361,13 @@ module.exports = DockerRunner = {
|
||||
_fingerprintContainer(containerOptions) {
|
||||
// Yay, Hashing!
|
||||
const json = JSON.stringify(containerOptions)
|
||||
return crypto
|
||||
.createHash('md5')
|
||||
.update(json)
|
||||
.digest('hex')
|
||||
return crypto.createHash('md5').update(json).digest('hex')
|
||||
},
|
||||
|
||||
startContainer(options, volumes, attachStreamHandler, callback) {
|
||||
return LockManager.runWithLock(
|
||||
options.name,
|
||||
releaseLock =>
|
||||
(releaseLock) =>
|
||||
// Check that volumes exist before starting the container.
|
||||
// When a container is started with volume pointing to a
|
||||
// non-existent directory then docker creates the directory but
|
||||
@@ -409,7 +410,7 @@ module.exports = DockerRunner = {
|
||||
})
|
||||
const jobs = []
|
||||
for (const vol in volumes) {
|
||||
;(vol => jobs.push(cb => checkVolume(vol, cb)))(vol)
|
||||
;((vol) => jobs.push((cb) => checkVolume(vol, cb)))(vol)
|
||||
}
|
||||
return async.series(jobs, callback)
|
||||
},
|
||||
@@ -519,7 +520,7 @@ module.exports = DockerRunner = {
|
||||
|
||||
container.modem.demuxStream(stream, stdout, stderr)
|
||||
|
||||
stream.on('error', err =>
|
||||
stream.on('error', (err) =>
|
||||
logger.error(
|
||||
{ err, container_id: containerId },
|
||||
'error reading from container stream'
|
||||
@@ -592,7 +593,7 @@ module.exports = DockerRunner = {
|
||||
}
|
||||
return LockManager.runWithLock(
|
||||
containerName,
|
||||
releaseLock =>
|
||||
(releaseLock) =>
|
||||
DockerRunner._destroyContainer(
|
||||
containerId || containerName,
|
||||
shouldForce,
|
||||
@@ -659,13 +660,16 @@ module.exports = DockerRunner = {
|
||||
if (callback == null) {
|
||||
callback = function (error) {}
|
||||
}
|
||||
return dockerode.listContainers({ all: true }, function(error, containers) {
|
||||
return dockerode.listContainers({ all: true }, function (
|
||||
error,
|
||||
containers
|
||||
) {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
const jobs = []
|
||||
for (const container of Array.from(containers || [])) {
|
||||
;(container =>
|
||||
;((container) =>
|
||||
DockerRunner.examineOldContainer(container, function (
|
||||
err,
|
||||
name,
|
||||
@@ -676,7 +680,7 @@ module.exports = DockerRunner = {
|
||||
// strip the / prefix
|
||||
// the LockManager uses the plain container name
|
||||
name = name.slice(1)
|
||||
return jobs.push(cb =>
|
||||
return jobs.push((cb) =>
|
||||
DockerRunner.destroyContainer(name, id, false, () => cb())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -96,13 +96,13 @@ module.exports = LatexRunner = {
|
||||
}
|
||||
const runs =
|
||||
__guard__(
|
||||
__guard__(output != null ? output.stderr : undefined, x1 =>
|
||||
__guard__(output != null ? output.stderr : undefined, (x1) =>
|
||||
x1.match(/^Run number \d+ of .*latex/gm)
|
||||
),
|
||||
x => x.length
|
||||
(x) => x.length
|
||||
) || 0
|
||||
const failed =
|
||||
__guard__(output != null ? output.stdout : undefined, x2 =>
|
||||
__guard__(output != null ? output.stdout : undefined, (x2) =>
|
||||
x2.match(/^Latexmk: Errors/m)
|
||||
) != null
|
||||
? 1
|
||||
@@ -122,21 +122,21 @@ module.exports = LatexRunner = {
|
||||
stderr != null
|
||||
? stderr.match(/Percent of CPU this job got: (\d+)/m)
|
||||
: undefined,
|
||||
x3 => x3[1]
|
||||
(x3) => x3[1]
|
||||
) || 0
|
||||
timings['cpu-time'] =
|
||||
__guard__(
|
||||
stderr != null
|
||||
? stderr.match(/User time.*: (\d+.\d+)/m)
|
||||
: undefined,
|
||||
x4 => x4[1]
|
||||
(x4) => x4[1]
|
||||
) || 0
|
||||
timings['sys-time'] =
|
||||
__guard__(
|
||||
stderr != null
|
||||
? stderr.match(/System time.*: (\d+.\d+)/m)
|
||||
: undefined,
|
||||
x5 => x5[1]
|
||||
(x5) => x5[1]
|
||||
) || 0
|
||||
// record output files
|
||||
LatexRunner.writeLogOutput(project_id, directory, output, () => {
|
||||
@@ -153,7 +153,7 @@ module.exports = LatexRunner = {
|
||||
// internal method for writing non-empty log files
|
||||
function _writeFile(file, content, cb) {
|
||||
if (content && content.length > 0) {
|
||||
fs.writeFile(file, content, err => {
|
||||
fs.writeFile(file, content, (err) => {
|
||||
if (err) {
|
||||
logger.error({ project_id, file }, 'error writing log file') // don't fail on error
|
||||
}
|
||||
@@ -202,7 +202,7 @@ module.exports = LatexRunner = {
|
||||
return (
|
||||
__guard__(
|
||||
Settings != null ? Settings.clsi : undefined,
|
||||
x => x.latexmkCommandPrefix
|
||||
(x) => x.latexmkCommandPrefix
|
||||
) || []
|
||||
).concat(args)
|
||||
},
|
||||
|
||||
@@ -37,7 +37,7 @@ module.exports = CommandRunner = {
|
||||
} else {
|
||||
callback = _.once(callback)
|
||||
}
|
||||
command = Array.from(command).map(arg =>
|
||||
command = Array.from(command).map((arg) =>
|
||||
arg.toString().replace('$COMPILE_DIR', directory)
|
||||
)
|
||||
logger.log({ project_id, command, directory }, 'running command')
|
||||
@@ -58,7 +58,7 @@ module.exports = CommandRunner = {
|
||||
const proc = spawn(command[0], command.slice(1), { cwd: directory, env })
|
||||
|
||||
let stdout = ''
|
||||
proc.stdout.setEncoding('utf8').on('data', data => (stdout += data))
|
||||
proc.stdout.setEncoding('utf8').on('data', (data) => (stdout += data))
|
||||
|
||||
proc.on('error', function (err) {
|
||||
logger.err(
|
||||
|
||||
@@ -99,13 +99,16 @@ module.exports = OutputCacheManager = {
|
||||
(Settings.clsi != null ? Settings.clsi.archive_logs : undefined) ||
|
||||
(Settings.clsi != null ? Settings.clsi.strace : undefined)
|
||||
) {
|
||||
OutputCacheManager.archiveLogs(outputFiles, compileDir, buildId, function(
|
||||
err
|
||||
) {
|
||||
OutputCacheManager.archiveLogs(
|
||||
outputFiles,
|
||||
compileDir,
|
||||
buildId,
|
||||
function (err) {
|
||||
if (err != null) {
|
||||
return logger.warn({ err }, 'erroring archiving log files')
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// make the new cache directory
|
||||
@@ -280,7 +283,7 @@ module.exports = OutputCacheManager = {
|
||||
// we can get the build time from the first part of the directory name DDDD-RRRR
|
||||
// DDDD is date and RRRR is random bytes
|
||||
const dirTime = parseInt(
|
||||
__guard__(dir.split('-'), x => x[0]),
|
||||
__guard__(dir.split('-'), (x) => x[0]),
|
||||
16
|
||||
)
|
||||
const age = currentTime - dirTime
|
||||
|
||||
@@ -44,7 +44,7 @@ module.exports = OutputFileFinder = {
|
||||
if (!incomingResources[file]) {
|
||||
outputFiles.push({
|
||||
path: file,
|
||||
type: __guard__(file.match(/\.([^\.]+)$/), x => x[1])
|
||||
type: __guard__(file.match(/\.([^\.]+)$/), (x) => x[1])
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ module.exports = OutputFileFinder = {
|
||||
|
||||
const proc = spawn('find', args)
|
||||
let stdout = ''
|
||||
proc.stdout.setEncoding('utf8').on('data', chunk => (stdout += chunk))
|
||||
proc.stdout.setEncoding('utf8').on('data', (chunk) => (stdout += chunk))
|
||||
proc.on('error', callback)
|
||||
return proc.on('close', function (code) {
|
||||
if (code !== 0) {
|
||||
|
||||
@@ -77,7 +77,7 @@ module.exports = OutputFileOptimiser = {
|
||||
const timer = new Metrics.Timer('qpdf')
|
||||
const proc = spawn('qpdf', args)
|
||||
let stdout = ''
|
||||
proc.stdout.setEncoding('utf8').on('data', chunk => (stdout += chunk))
|
||||
proc.stdout.setEncoding('utf8').on('data', (chunk) => (stdout += chunk))
|
||||
callback = _.once(callback) // avoid double call back for error and close event
|
||||
proc.on('error', function (err) {
|
||||
logger.warn({ err, args }, 'qpdf failed')
|
||||
|
||||
@@ -50,7 +50,7 @@ module.exports = ProjectPersistenceManager = {
|
||||
if (callback == null) {
|
||||
callback = function (error) {}
|
||||
}
|
||||
const job = cb =>
|
||||
const job = (cb) =>
|
||||
db.Project.findOrCreate({ where: { project_id } })
|
||||
.spread((project, created) =>
|
||||
project
|
||||
@@ -74,8 +74,8 @@ module.exports = ProjectPersistenceManager = {
|
||||
return callback(error)
|
||||
}
|
||||
logger.log({ project_ids }, 'clearing expired projects')
|
||||
const jobs = Array.from(project_ids || []).map(project_id =>
|
||||
(project_id => callback =>
|
||||
const jobs = Array.from(project_ids || []).map((project_id) =>
|
||||
((project_id) => (callback) =>
|
||||
ProjectPersistenceManager.clearProjectFromCache(project_id, function (
|
||||
err
|
||||
) {
|
||||
@@ -91,7 +91,7 @@ module.exports = ProjectPersistenceManager = {
|
||||
}
|
||||
return CompileManager.clearExpiredProjects(
|
||||
ProjectPersistenceManager.EXPIRY_TIMEOUT,
|
||||
error => callback()
|
||||
(error) => callback()
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -148,7 +148,7 @@ module.exports = ProjectPersistenceManager = {
|
||||
callback = function (error) {}
|
||||
}
|
||||
logger.log({ project_id }, 'clearing project from database')
|
||||
const job = cb =>
|
||||
const job = (cb) =>
|
||||
db.Project.destroy({ where: { project_id } })
|
||||
.then(() => cb())
|
||||
.error(cb)
|
||||
@@ -166,10 +166,10 @@ module.exports = ProjectPersistenceManager = {
|
||||
const q = {}
|
||||
q[db.op.lt] = keepProjectsFrom
|
||||
return db.Project.findAll({ where: { lastAccessed: q } })
|
||||
.then(projects =>
|
||||
.then((projects) =>
|
||||
cb(
|
||||
null,
|
||||
projects.map(project => project.project_id)
|
||||
projects.map((project) => project.project_id)
|
||||
)
|
||||
)
|
||||
.error(cb)
|
||||
|
||||
@@ -56,7 +56,9 @@ module.exports = ResourceStateManager = {
|
||||
})
|
||||
} else {
|
||||
logger.log({ state, basePath }, 'writing sync state')
|
||||
const resourceList = Array.from(resources).map(resource => resource.path)
|
||||
const resourceList = Array.from(resources).map(
|
||||
(resource) => resource.path
|
||||
)
|
||||
return fs.writeFile(
|
||||
stateFile,
|
||||
[...Array.from(resourceList), `stateHash:${state}`].join('\n'),
|
||||
@@ -86,7 +88,7 @@ module.exports = ResourceStateManager = {
|
||||
)
|
||||
}
|
||||
const array =
|
||||
__guard__(result != null ? result.toString() : undefined, x =>
|
||||
__guard__(result != null ? result.toString() : undefined, (x) =>
|
||||
x.split('\n')
|
||||
) || []
|
||||
const adjustedLength = Math.max(array.length, 1)
|
||||
@@ -102,7 +104,7 @@ module.exports = ResourceStateManager = {
|
||||
new Errors.FilesOutOfSyncError('invalid state for incremental update')
|
||||
)
|
||||
} else {
|
||||
const resources = Array.from(resourceList).map(path => ({ path }))
|
||||
const resources = Array.from(resourceList).map((path) => ({ path }))
|
||||
return callback(null, resources)
|
||||
}
|
||||
})
|
||||
@@ -116,7 +118,7 @@ module.exports = ResourceStateManager = {
|
||||
}
|
||||
for (file of Array.from(resources || [])) {
|
||||
for (const dir of Array.from(
|
||||
__guard__(file != null ? file.path : undefined, x => x.split('/'))
|
||||
__guard__(file != null ? file.path : undefined, (x) => x.split('/'))
|
||||
)) {
|
||||
if (dir === '..') {
|
||||
return callback(new Error('relative path in resource file list'))
|
||||
@@ -129,8 +131,8 @@ module.exports = ResourceStateManager = {
|
||||
seenFile[file] = true
|
||||
}
|
||||
const missingFiles = Array.from(resources)
|
||||
.filter(resource => !seenFile[resource.path])
|
||||
.map(resource => resource.path)
|
||||
.filter((resource) => !seenFile[resource.path])
|
||||
.map((resource) => resource.path)
|
||||
if ((missingFiles != null ? missingFiles.length : undefined) > 0) {
|
||||
logger.err(
|
||||
{ missingFiles, basePath, allFiles, resources },
|
||||
|
||||
@@ -109,13 +109,13 @@ module.exports = ResourceWriter = {
|
||||
if (callback == null) {
|
||||
callback = function (error) {}
|
||||
}
|
||||
return this._createDirectory(basePath, error => {
|
||||
return this._createDirectory(basePath, (error) => {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
const jobs = Array.from(resources).map(resource =>
|
||||
(resource => {
|
||||
return callback =>
|
||||
const jobs = Array.from(resources).map((resource) =>
|
||||
((resource) => {
|
||||
return (callback) =>
|
||||
this._writeResourceToDisk(project_id, resource, basePath, callback)
|
||||
})(resource)
|
||||
)
|
||||
@@ -127,17 +127,17 @@ module.exports = ResourceWriter = {
|
||||
if (callback == null) {
|
||||
callback = function (error) {}
|
||||
}
|
||||
return this._createDirectory(basePath, error => {
|
||||
return this._createDirectory(basePath, (error) => {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
return this._removeExtraneousFiles(resources, basePath, error => {
|
||||
return this._removeExtraneousFiles(resources, basePath, (error) => {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
const jobs = Array.from(resources).map(resource =>
|
||||
(resource => {
|
||||
return callback =>
|
||||
const jobs = Array.from(resources).map((resource) =>
|
||||
((resource) => {
|
||||
return (callback) =>
|
||||
this._writeResourceToDisk(
|
||||
project_id,
|
||||
resource,
|
||||
@@ -242,7 +242,7 @@ module.exports = ResourceWriter = {
|
||||
should_delete = true
|
||||
}
|
||||
if (should_delete) {
|
||||
return jobs.push(callback =>
|
||||
return jobs.push((callback) =>
|
||||
ResourceWriter._deleteFileIfNotDirectory(
|
||||
Path.join(basePath, path),
|
||||
callback
|
||||
@@ -303,7 +303,9 @@ module.exports = ResourceWriter = {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
return fs.mkdir(Path.dirname(path), { recursive: true }, function(error) {
|
||||
return fs.mkdir(Path.dirname(path), { recursive: true }, function (
|
||||
error
|
||||
) {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ module.exports = ForbidSymlinks = function(staticFn, root, options) {
|
||||
const basePath = Path.resolve(root)
|
||||
return function (req, res, next) {
|
||||
let file, project_id, result
|
||||
const path = __guard__(url.parse(req.url), x => x.pathname)
|
||||
const path = __guard__(url.parse(req.url), (x) => x.pathname)
|
||||
// check that the path is of the form /project_id_or_name/path/to/file.log
|
||||
if ((result = path.match(/^\/?([a-zA-Z0-9_-]+)\/(.*)/))) {
|
||||
project_id = result[1]
|
||||
|
||||
@@ -42,7 +42,10 @@ module.exports = TikzManager = {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
return SafeReader.readFile(path, 65536, 'utf8', function(error, content) {
|
||||
return SafeReader.readFile(path, 65536, 'utf8', function (
|
||||
error,
|
||||
content
|
||||
) {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ module.exports = UrlCache = {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
const jobs = Array.from(urls || []).map(url =>
|
||||
(url => callback =>
|
||||
const jobs = Array.from(urls || []).map((url) =>
|
||||
((url) => (callback) =>
|
||||
UrlCache._clearUrlFromCache(project_id, url, function (error) {
|
||||
if (error != null) {
|
||||
logger.error(
|
||||
@@ -98,7 +98,7 @@ module.exports = UrlCache = {
|
||||
return UrlFetcher.pipeUrlToFileWithRetry(
|
||||
url,
|
||||
UrlCache._cacheFilePathForUrl(project_id, url),
|
||||
error => {
|
||||
(error) => {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
@@ -106,7 +106,7 @@ module.exports = UrlCache = {
|
||||
project_id,
|
||||
url,
|
||||
lastModified,
|
||||
error => {
|
||||
(error) => {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
@@ -153,14 +153,7 @@ module.exports = UrlCache = {
|
||||
},
|
||||
|
||||
_cacheFileNameForUrl(project_id, url) {
|
||||
return (
|
||||
project_id +
|
||||
':' +
|
||||
crypto
|
||||
.createHash('md5')
|
||||
.update(url)
|
||||
.digest('hex')
|
||||
)
|
||||
return project_id + ':' + crypto.createHash('md5').update(url).digest('hex')
|
||||
},
|
||||
|
||||
_cacheFilePathForUrl(project_id, url) {
|
||||
@@ -197,7 +190,9 @@ module.exports = UrlCache = {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
return UrlCache._deleteUrlCacheFromDisk(project_id, url, function(error) {
|
||||
return UrlCache._deleteUrlCacheFromDisk(project_id, url, function (
|
||||
error
|
||||
) {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
@@ -226,9 +221,9 @@ module.exports = UrlCache = {
|
||||
if (callback == null) {
|
||||
callback = function (error, urlDetails) {}
|
||||
}
|
||||
const job = cb =>
|
||||
const job = (cb) =>
|
||||
db.UrlCache.findOne({ where: { url, project_id } })
|
||||
.then(urlDetails => cb(null, urlDetails))
|
||||
.then((urlDetails) => cb(null, urlDetails))
|
||||
.error(cb)
|
||||
return dbQueue.queue.push(job, callback)
|
||||
},
|
||||
@@ -237,7 +232,7 @@ module.exports = UrlCache = {
|
||||
if (callback == null) {
|
||||
callback = function (error) {}
|
||||
}
|
||||
const job = cb =>
|
||||
const job = (cb) =>
|
||||
db.UrlCache.findOrCreate({ where: { url, project_id } })
|
||||
.spread((urlDetails, created) =>
|
||||
urlDetails
|
||||
@@ -253,7 +248,7 @@ module.exports = UrlCache = {
|
||||
if (callback == null) {
|
||||
callback = function (error) {}
|
||||
}
|
||||
const job = cb =>
|
||||
const job = (cb) =>
|
||||
db.UrlCache.destroy({ where: { url, project_id } })
|
||||
.then(() => cb(null))
|
||||
.error(cb)
|
||||
@@ -264,12 +259,12 @@ module.exports = UrlCache = {
|
||||
if (callback == null) {
|
||||
callback = function (error, urls) {}
|
||||
}
|
||||
const job = cb =>
|
||||
const job = (cb) =>
|
||||
db.UrlCache.findAll({ where: { project_id } })
|
||||
.then(urlEntries =>
|
||||
.then((urlEntries) =>
|
||||
cb(
|
||||
null,
|
||||
urlEntries.map(entry => entry.url)
|
||||
urlEntries.map((entry) => entry.url)
|
||||
)
|
||||
)
|
||||
.error(cb)
|
||||
|
||||
@@ -62,6 +62,6 @@ module.exports = {
|
||||
return sequelize
|
||||
.sync()
|
||||
.then(() => logger.log('db sync complete'))
|
||||
.catch(err => console.log(err, 'error syncing'))
|
||||
.catch((err) => console.log(err, 'error syncing'))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
clsi
|
||||
--acceptance-creds=None
|
||||
--data-dirs=cache,compiles,db
|
||||
--dependencies=
|
||||
--docker-repos=gcr.io/overleaf-ops
|
||||
--env-add=
|
||||
--env-pass-through=TEXLIVE_IMAGE
|
||||
--language=es
|
||||
--node-version=10.21.0
|
||||
--public-repo=True
|
||||
--script-version=2.1.0
|
||||
--script-version=3.3.2
|
||||
|
||||
@@ -10,6 +10,7 @@ services:
|
||||
command: npm run test:unit:_run
|
||||
environment:
|
||||
NODE_ENV: test
|
||||
NODE_OPTIONS: "--unhandled-rejections=strict"
|
||||
|
||||
|
||||
test_acceptance:
|
||||
@@ -25,6 +26,7 @@ services:
|
||||
POSTGRES_HOST: postgres
|
||||
MOCHA_GREP: ${MOCHA_GREP}
|
||||
NODE_ENV: test
|
||||
NODE_OPTIONS: "--unhandled-rejections=strict"
|
||||
TEXLIVE_IMAGE:
|
||||
command: npm run test:acceptance:_run
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ services:
|
||||
environment:
|
||||
MOCHA_GREP: ${MOCHA_GREP}
|
||||
NODE_ENV: test
|
||||
command: npm run test:unit
|
||||
NODE_OPTIONS: "--unhandled-rejections=strict"
|
||||
command: npm run --silent test:unit
|
||||
|
||||
test_acceptance:
|
||||
build:
|
||||
@@ -35,5 +36,6 @@ services:
|
||||
MOCHA_GREP: ${MOCHA_GREP}
|
||||
LOG_LEVEL: ERROR
|
||||
NODE_ENV: test
|
||||
command: npm run test:acceptance
|
||||
NODE_OPTIONS: "--unhandled-rejections=strict"
|
||||
command: npm run --silent test:acceptance
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
"execMap": {
|
||||
"js": "npm run start"
|
||||
},
|
||||
|
||||
"watch": [
|
||||
"app/js/",
|
||||
"app.js",
|
||||
|
||||
705
package-lock.json
generated
705
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@
|
||||
"test:unit:_run": "mocha --recursive --reporter spec $@ test/unit/js",
|
||||
"test:unit": "npm run test:unit:_run -- --grep=$MOCHA_GREP",
|
||||
"nodemon": "nodemon --config nodemon.json",
|
||||
"lint": "node_modules/.bin/eslint .",
|
||||
"lint": "node_modules/.bin/eslint --max-warnings 0 .",
|
||||
"format": "node_modules/.bin/prettier-eslint $PWD'/**/*.js' --list-different",
|
||||
"format:fix": "node_modules/.bin/prettier-eslint $PWD'/**/*.js' --write"
|
||||
},
|
||||
@@ -28,7 +28,7 @@
|
||||
"heapdump": "^0.3.15",
|
||||
"lockfile": "^1.0.4",
|
||||
"lodash": "^4.17.15",
|
||||
"logger-sharelatex": "^1.9.1",
|
||||
"logger-sharelatex": "^2.2.0",
|
||||
"lynx": "0.2.0",
|
||||
"metrics-sharelatex": "^2.6.0",
|
||||
"mysql": "^2.18.1",
|
||||
@@ -59,7 +59,7 @@
|
||||
"eslint-plugin-react": "^7.19.0",
|
||||
"eslint-plugin-standard": "^4.0.1",
|
||||
"mocha": "^7.1.0",
|
||||
"prettier": "^1.19.1",
|
||||
"prettier": "^2.0.0",
|
||||
"prettier-eslint-cli": "^5.0.0",
|
||||
"sandboxed-module": "^2.0.3",
|
||||
"sinon": "~9.0.1",
|
||||
|
||||
@@ -24,7 +24,7 @@ const ChildProcess = require('child_process')
|
||||
const ClsiApp = require('./helpers/ClsiApp')
|
||||
const logger = require('logger-sharelatex')
|
||||
const Path = require('path')
|
||||
const fixturePath = path => {
|
||||
const fixturePath = (path) => {
|
||||
if (path.slice(0, 3) === 'tmp') {
|
||||
return '/tmp/clsi_acceptance_tests' + path.slice(3)
|
||||
}
|
||||
@@ -50,8 +50,8 @@ const convertToPng = function(pdfPath, pngPath, callback) {
|
||||
console.log(command)
|
||||
const convert = ChildProcess.exec(command)
|
||||
const stdout = ''
|
||||
convert.stdout.on('data', chunk => console.log('STDOUT', chunk.toString()))
|
||||
convert.stderr.on('data', chunk => console.log('STDERR', chunk.toString()))
|
||||
convert.stdout.on('data', (chunk) => console.log('STDOUT', chunk.toString()))
|
||||
convert.stderr.on('data', (chunk) => console.log('STDERR', chunk.toString()))
|
||||
return convert.on('exit', () => callback())
|
||||
}
|
||||
|
||||
@@ -66,11 +66,11 @@ const compare = function(originalPath, generatedPath, callback) {
|
||||
)} ${diff_file}`
|
||||
)
|
||||
let stderr = ''
|
||||
proc.stderr.on('data', chunk => (stderr += chunk))
|
||||
proc.stderr.on('data', (chunk) => (stderr += chunk))
|
||||
return proc.on('exit', () => {
|
||||
if (stderr.trim() === '0 (0)') {
|
||||
// remove output diff if test matches expected image
|
||||
fs.unlink(diff_file, err => {
|
||||
fs.unlink(diff_file, (err) => {
|
||||
if (err) {
|
||||
throw err
|
||||
}
|
||||
@@ -89,8 +89,8 @@ const checkPdfInfo = function(pdfPath, callback) {
|
||||
}
|
||||
const proc = ChildProcess.exec(`pdfinfo ${fixturePath(pdfPath)}`)
|
||||
let stdout = ''
|
||||
proc.stdout.on('data', chunk => (stdout += chunk))
|
||||
proc.stderr.on('data', chunk => console.log('STDERR', chunk.toString()))
|
||||
proc.stdout.on('data', (chunk) => (stdout += chunk))
|
||||
proc.stderr.on('data', (chunk) => console.log('STDERR', chunk.toString()))
|
||||
return proc.on('exit', () => {
|
||||
if (stdout.match(/Optimized:\s+yes/)) {
|
||||
return callback(null, true)
|
||||
@@ -136,14 +136,14 @@ const comparePdf = function(project_id, example_dir, callback) {
|
||||
return convertToPng(
|
||||
`tmp/${project_id}.pdf`,
|
||||
`tmp/${project_id}-generated.png`,
|
||||
error => {
|
||||
(error) => {
|
||||
if (error != null) {
|
||||
throw error
|
||||
}
|
||||
return convertToPng(
|
||||
`examples/${example_dir}/output.pdf`,
|
||||
`tmp/${project_id}-source.png`,
|
||||
error => {
|
||||
(error) => {
|
||||
if (error != null) {
|
||||
throw error
|
||||
}
|
||||
@@ -163,7 +163,7 @@ const comparePdf = function(project_id, example_dir, callback) {
|
||||
}
|
||||
)
|
||||
} else {
|
||||
return compareMultiplePages(project_id, error => {
|
||||
return compareMultiplePages(project_id, (error) => {
|
||||
if (error != null) {
|
||||
throw error
|
||||
}
|
||||
@@ -178,7 +178,12 @@ const comparePdf = function(project_id, example_dir, callback) {
|
||||
)
|
||||
}
|
||||
|
||||
const downloadAndComparePdf = function(project_id, example_dir, url, callback) {
|
||||
const downloadAndComparePdf = function (
|
||||
project_id,
|
||||
example_dir,
|
||||
url,
|
||||
callback
|
||||
) {
|
||||
if (callback == null) {
|
||||
callback = function (error) {}
|
||||
}
|
||||
@@ -212,8 +217,9 @@ describe('Example Documents', function() {
|
||||
fsExtra.remove(fixturePath('tmp'), done)
|
||||
})
|
||||
|
||||
return Array.from(fs.readdirSync(fixturePath('examples'))).map(example_dir =>
|
||||
(example_dir =>
|
||||
return Array.from(fs.readdirSync(fixturePath('examples'))).map(
|
||||
(example_dir) =>
|
||||
((example_dir) =>
|
||||
describe(example_dir, function () {
|
||||
before(function () {
|
||||
return (this.project_id = Client.randomId() + '_' + example_dir)
|
||||
@@ -231,10 +237,15 @@ describe('Example Documents', function() {
|
||||
error ||
|
||||
__guard__(
|
||||
body != null ? body.compile : undefined,
|
||||
x => x.status
|
||||
(x) => x.status
|
||||
) === 'failure'
|
||||
) {
|
||||
console.log('DEBUG: error', error, 'body', JSON.stringify(body))
|
||||
console.log(
|
||||
'DEBUG: error',
|
||||
error,
|
||||
'body',
|
||||
JSON.stringify(body)
|
||||
)
|
||||
return done(new Error('Compile failed'))
|
||||
}
|
||||
const pdf = Client.getOutputFile(body, 'pdf')
|
||||
@@ -260,10 +271,15 @@ describe('Example Documents', function() {
|
||||
error ||
|
||||
__guard__(
|
||||
body != null ? body.compile : undefined,
|
||||
x => x.status
|
||||
(x) => x.status
|
||||
) === 'failure'
|
||||
) {
|
||||
console.log('DEBUG: error', error, 'body', JSON.stringify(body))
|
||||
console.log(
|
||||
'DEBUG: error',
|
||||
error,
|
||||
'body',
|
||||
JSON.stringify(body)
|
||||
)
|
||||
return done(new Error('Compile failed'))
|
||||
}
|
||||
const pdf = Client.getOutputFile(body, 'pdf')
|
||||
|
||||
@@ -56,7 +56,7 @@ describe('Timed out compile', function() {
|
||||
})
|
||||
|
||||
return it('should return the log output file name', function () {
|
||||
const outputFilePaths = this.body.compile.outputFiles.map(x => x.path)
|
||||
const outputFilePaths = this.body.compile.outputFiles.map((x) => x.path)
|
||||
return outputFilePaths.should.include('output.log')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -35,9 +35,7 @@ const Server = {
|
||||
getFile() {},
|
||||
|
||||
randomId() {
|
||||
return Math.random()
|
||||
.toString(16)
|
||||
.slice(2)
|
||||
return Math.random().toString(16).slice(2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,7 +336,7 @@ describe('Url Caching', function() {
|
||||
]
|
||||
}
|
||||
|
||||
return Client.compile(this.project_id, this.request, error => {
|
||||
return Client.compile(this.project_id, this.request, (error) => {
|
||||
if (error != null) {
|
||||
throw error
|
||||
}
|
||||
|
||||
@@ -23,9 +23,7 @@ module.exports = Client = {
|
||||
host: Settings.apis.clsi.url,
|
||||
|
||||
randomId() {
|
||||
return Math.random()
|
||||
.toString(16)
|
||||
.slice(2)
|
||||
return Math.random().toString(16).slice(2)
|
||||
},
|
||||
|
||||
compile(project_id, data, callback) {
|
||||
@@ -64,7 +62,7 @@ module.exports = Client = {
|
||||
const app = express()
|
||||
app.use(express.static(directory))
|
||||
console.log('starting test server on', port, host)
|
||||
return app.listen(port, host).on('error', error => {
|
||||
return app.listen(port, host).on('error', (error) => {
|
||||
console.error('error starting server:', error.message)
|
||||
return process.exit(1)
|
||||
})
|
||||
@@ -130,7 +128,7 @@ module.exports = Client = {
|
||||
entities = entities.concat(
|
||||
fs
|
||||
.readdirSync(`${baseDirectory}/${directory}/${entity}`)
|
||||
.map(subEntity => {
|
||||
.map((subEntity) => {
|
||||
if (subEntity === 'main.tex') {
|
||||
rootResourcePath = `${entity}/${subEntity}`
|
||||
}
|
||||
|
||||
@@ -35,10 +35,10 @@ module.exports = {
|
||||
return app.listen(
|
||||
__guard__(
|
||||
Settings.internal != null ? Settings.internal.clsi : undefined,
|
||||
x => x.port
|
||||
(x) => x.port
|
||||
),
|
||||
'localhost',
|
||||
error => {
|
||||
(error) => {
|
||||
if (error != null) {
|
||||
throw error
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ const _ = require('lodash')
|
||||
const concurentCompiles = 5
|
||||
const totalCompiles = 50
|
||||
|
||||
const buildUrl = path =>
|
||||
const buildUrl = (path) =>
|
||||
`http://${Settings.internal.clsi.host}:${Settings.internal.clsi.port}/${path}`
|
||||
|
||||
const mainTexContent = fs.readFileSync('./bulk.tex', 'utf-8')
|
||||
@@ -74,12 +74,12 @@ ${bodyContent}
|
||||
)
|
||||
}
|
||||
|
||||
const jobs = _.map(__range__(1, totalCompiles, true), i => cb =>
|
||||
const jobs = _.map(__range__(1, totalCompiles, true), (i) => (cb) =>
|
||||
makeRequest(i, cb)
|
||||
)
|
||||
|
||||
const startTime = new Date()
|
||||
async.parallelLimit(jobs, concurentCompiles, err => {
|
||||
async.parallelLimit(jobs, concurentCompiles, (err) => {
|
||||
if (err != null) {
|
||||
console.error(err)
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
const request = require('request')
|
||||
const Settings = require('settings-sharelatex')
|
||||
|
||||
const buildUrl = path =>
|
||||
const buildUrl = (path) =>
|
||||
`http://${Settings.internal.clsi.host}:${Settings.internal.clsi.port}/${path}`
|
||||
|
||||
const url = buildUrl(`project/smoketest-${process.pid}/compile`)
|
||||
|
||||
module.exports = {
|
||||
sendNewResult(res) {
|
||||
this._run(error => this._sendResponse(res, error))
|
||||
this._run((error) => this._sendResponse(res, error))
|
||||
},
|
||||
sendLastResult(res) {
|
||||
this._sendResponse(res, this._lastError)
|
||||
},
|
||||
triggerRun(cb) {
|
||||
this._run(error => {
|
||||
this._run((error) => {
|
||||
this._lastError = error
|
||||
cb(error)
|
||||
})
|
||||
|
||||
@@ -115,7 +115,7 @@ describe('CompileController', function() {
|
||||
compile: {
|
||||
status: 'success',
|
||||
error: null,
|
||||
outputFiles: this.output_files.map(file => {
|
||||
outputFiles: this.output_files.map((file) => {
|
||||
return {
|
||||
url: `${this.Settings.apis.clsi.url}/project/${this.project_id}/build/${file.build}/output/${file.path}`,
|
||||
path: file.path,
|
||||
|
||||
@@ -374,7 +374,7 @@ describe('CompileManager', function() {
|
||||
this.column = 3
|
||||
this.file_name = 'main.tex'
|
||||
this.child_process.execFile = sinon.stub()
|
||||
return (this.Settings.path.synctexBaseDir = project_id =>
|
||||
return (this.Settings.path.synctexBaseDir = (project_id) =>
|
||||
`${this.Settings.path.compilesDir}/${this.project_id}-${this.user_id}`)
|
||||
})
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ describe('LockManager', function() {
|
||||
this.callback = sinon.stub()
|
||||
return this.LockManager.runWithLock(
|
||||
'lock-one',
|
||||
releaseLock =>
|
||||
(releaseLock) =>
|
||||
setTimeout(() => releaseLock(null, 'hello', 'world'), 100),
|
||||
|
||||
(err, ...args) => {
|
||||
@@ -59,7 +59,7 @@ describe('LockManager', function() {
|
||||
this.callback2 = sinon.stub()
|
||||
this.LockManager.runWithLock(
|
||||
'lock-one',
|
||||
releaseLock =>
|
||||
(releaseLock) =>
|
||||
setTimeout(() => releaseLock(null, 'hello', 'world', 'one'), 100),
|
||||
|
||||
(err, ...args) => {
|
||||
@@ -68,7 +68,7 @@ describe('LockManager', function() {
|
||||
)
|
||||
return this.LockManager.runWithLock(
|
||||
'lock-two',
|
||||
releaseLock =>
|
||||
(releaseLock) =>
|
||||
setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 200),
|
||||
|
||||
(err, ...args) => {
|
||||
@@ -100,7 +100,7 @@ describe('LockManager', function() {
|
||||
this.callback2 = sinon.stub()
|
||||
this.LockManager.runWithLock(
|
||||
'lock',
|
||||
releaseLock =>
|
||||
(releaseLock) =>
|
||||
setTimeout(() => releaseLock(null, 'hello', 'world', 'one'), 100),
|
||||
|
||||
(err, ...args) => {
|
||||
@@ -109,7 +109,7 @@ describe('LockManager', function() {
|
||||
)
|
||||
return this.LockManager.runWithLock(
|
||||
'lock',
|
||||
releaseLock =>
|
||||
(releaseLock) =>
|
||||
setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 200),
|
||||
|
||||
(err, ...args) => {
|
||||
@@ -154,7 +154,7 @@ describe('LockManager', function() {
|
||||
}
|
||||
this.LockManager.runWithLock(
|
||||
'lock',
|
||||
releaseLock =>
|
||||
(releaseLock) =>
|
||||
setTimeout(
|
||||
() => releaseLock(null, 'hello', 'world', 'one'),
|
||||
1100
|
||||
@@ -167,7 +167,7 @@ describe('LockManager', function() {
|
||||
)
|
||||
return this.LockManager.runWithLock(
|
||||
'lock',
|
||||
releaseLock =>
|
||||
(releaseLock) =>
|
||||
setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 100),
|
||||
|
||||
(err, ...args) => {
|
||||
@@ -211,7 +211,7 @@ describe('LockManager', function() {
|
||||
}
|
||||
this.LockManager.runWithLock(
|
||||
'lock',
|
||||
releaseLock =>
|
||||
(releaseLock) =>
|
||||
setTimeout(
|
||||
() => releaseLock(null, 'hello', 'world', 'one'),
|
||||
1500
|
||||
@@ -224,7 +224,7 @@ describe('LockManager', function() {
|
||||
)
|
||||
return this.LockManager.runWithLock(
|
||||
'lock',
|
||||
releaseLock =>
|
||||
(releaseLock) =>
|
||||
setTimeout(() => releaseLock(null, 'hello', 'world', 'two'), 100),
|
||||
|
||||
(err, ...args) => {
|
||||
|
||||
@@ -738,7 +738,7 @@ describe('DockerRunner', function() {
|
||||
this.DockerRunner.MAX_CONTAINER_AGE = oneHourInMilliseconds
|
||||
this.listContainers.callsArgWith(1, null, this.containers)
|
||||
this.DockerRunner.destroyContainer = sinon.stub().callsArg(3)
|
||||
return this.DockerRunner.destroyOldContainers(error => {
|
||||
return this.DockerRunner.destroyOldContainers((error) => {
|
||||
this.callback(error)
|
||||
return done()
|
||||
})
|
||||
@@ -785,7 +785,7 @@ describe('DockerRunner', function() {
|
||||
return this.DockerRunner._destroyContainer(
|
||||
this.containerId,
|
||||
false,
|
||||
err => {
|
||||
(err) => {
|
||||
this.Docker.prototype.getContainer.callCount.should.equal(1)
|
||||
this.Docker.prototype.getContainer
|
||||
.calledWith(this.containerId)
|
||||
@@ -799,7 +799,7 @@ describe('DockerRunner', function() {
|
||||
return this.DockerRunner._destroyContainer(
|
||||
this.containerId,
|
||||
true,
|
||||
err => {
|
||||
(err) => {
|
||||
this.fakeContainer.remove.callCount.should.equal(1)
|
||||
this.fakeContainer.remove
|
||||
.calledWith({ force: true })
|
||||
@@ -813,7 +813,7 @@ describe('DockerRunner', function() {
|
||||
return this.DockerRunner._destroyContainer(
|
||||
this.containerId,
|
||||
false,
|
||||
err => {
|
||||
(err) => {
|
||||
this.fakeContainer.remove.callCount.should.equal(1)
|
||||
this.fakeContainer.remove
|
||||
.calledWith({ force: false })
|
||||
@@ -827,7 +827,7 @@ describe('DockerRunner', function() {
|
||||
return this.DockerRunner._destroyContainer(
|
||||
this.containerId,
|
||||
false,
|
||||
err => {
|
||||
(err) => {
|
||||
expect(err).to.equal(null)
|
||||
return done()
|
||||
}
|
||||
@@ -850,7 +850,7 @@ describe('DockerRunner', function() {
|
||||
return this.DockerRunner._destroyContainer(
|
||||
this.containerId,
|
||||
false,
|
||||
err => {
|
||||
(err) => {
|
||||
expect(err).to.equal(null)
|
||||
return done()
|
||||
}
|
||||
@@ -874,7 +874,7 @@ describe('DockerRunner', function() {
|
||||
return this.DockerRunner._destroyContainer(
|
||||
this.containerId,
|
||||
false,
|
||||
err => {
|
||||
(err) => {
|
||||
expect(err).to.not.equal(null)
|
||||
expect(err).to.equal(this.fakeError)
|
||||
return done()
|
||||
@@ -894,7 +894,7 @@ describe('DockerRunner', function() {
|
||||
})
|
||||
|
||||
it('should get the container', function (done) {
|
||||
return this.DockerRunner.kill(this.containerId, err => {
|
||||
return this.DockerRunner.kill(this.containerId, (err) => {
|
||||
this.Docker.prototype.getContainer.callCount.should.equal(1)
|
||||
this.Docker.prototype.getContainer
|
||||
.calledWith(this.containerId)
|
||||
@@ -904,14 +904,14 @@ describe('DockerRunner', function() {
|
||||
})
|
||||
|
||||
it('should try to force-destroy the container', function (done) {
|
||||
return this.DockerRunner.kill(this.containerId, err => {
|
||||
return this.DockerRunner.kill(this.containerId, (err) => {
|
||||
this.fakeContainer.kill.callCount.should.equal(1)
|
||||
return done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should not produce an error', function (done) {
|
||||
return this.DockerRunner.kill(this.containerId, err => {
|
||||
return this.DockerRunner.kill(this.containerId, (err) => {
|
||||
expect(err).to.equal(undefined)
|
||||
return done()
|
||||
})
|
||||
@@ -932,7 +932,7 @@ describe('DockerRunner', function() {
|
||||
})
|
||||
|
||||
return it('should not produce an error', function (done) {
|
||||
return this.DockerRunner.kill(this.containerId, err => {
|
||||
return this.DockerRunner.kill(this.containerId, (err) => {
|
||||
expect(err).to.equal(undefined)
|
||||
return done()
|
||||
})
|
||||
@@ -953,7 +953,7 @@ describe('DockerRunner', function() {
|
||||
})
|
||||
|
||||
return it('should produce an error', function (done) {
|
||||
return this.DockerRunner.kill(this.containerId, err => {
|
||||
return this.DockerRunner.kill(this.containerId, (err) => {
|
||||
expect(err).to.not.equal(undefined)
|
||||
expect(err).to.equal(this.fakeError)
|
||||
return done()
|
||||
|
||||
@@ -144,7 +144,7 @@ describe('LatexRunner', function() {
|
||||
return it('should include the flags in the command', function () {
|
||||
const command = this.CommandRunner.run.args[0][1]
|
||||
const flags = command.filter(
|
||||
arg => arg === '-file-line-error' || arg === '-halt-on-error'
|
||||
(arg) => arg === '-file-line-error' || arg === '-halt-on-error'
|
||||
)
|
||||
flags.length.should.equal(2)
|
||||
flags[0].should.equal('-file-line-error')
|
||||
|
||||
@@ -126,10 +126,7 @@ describe('OutputFileOptimiser', function() {
|
||||
.stub()
|
||||
.withArgs(this.fd)
|
||||
.yields(null, 100, Buffer.from('hello /Linearized 1'))
|
||||
this.fs.close = sinon
|
||||
.stub()
|
||||
.withArgs(this.fd)
|
||||
.yields(null)
|
||||
this.fs.close = sinon.stub().withArgs(this.fd).yields(null)
|
||||
return this.OutputFileOptimiser.checkIfPDFIsOptimised(
|
||||
this.src,
|
||||
this.callback
|
||||
|
||||
@@ -109,7 +109,7 @@ describe('ProjectPersistenceManager', function() {
|
||||
})
|
||||
|
||||
it('should clear each expired project', function () {
|
||||
return Array.from(this.project_ids).map(project_id =>
|
||||
return Array.from(this.project_ids).map((project_id) =>
|
||||
this.ProjectPersistenceManager.clearProjectFromCache
|
||||
.calledWith(project_id)
|
||||
.should.equal(true)
|
||||
|
||||
@@ -78,7 +78,7 @@ describe('ResourceWriter', function() {
|
||||
})
|
||||
|
||||
it('should write each resource to disk', function () {
|
||||
return Array.from(this.resources).map(resource =>
|
||||
return Array.from(this.resources).map((resource) =>
|
||||
this.ResourceWriter._writeResourceToDisk
|
||||
.calledWith(this.project_id, resource, this.basePath)
|
||||
.should.equal(true)
|
||||
@@ -139,7 +139,7 @@ describe('ResourceWriter', function() {
|
||||
})
|
||||
|
||||
it('should write each resource to disk', function () {
|
||||
return Array.from(this.resources).map(resource =>
|
||||
return Array.from(this.resources).map((resource) =>
|
||||
this.ResourceWriter._writeResourceToDisk
|
||||
.calledWith(this.project_id, resource, this.basePath)
|
||||
.should.equal(true)
|
||||
|
||||
@@ -342,7 +342,7 @@ describe('UrlCache', function() {
|
||||
})
|
||||
|
||||
it('should clear the cache for each url in the project', function () {
|
||||
return Array.from(this.urls).map(url =>
|
||||
return Array.from(this.urls).map((url) =>
|
||||
this.UrlCache._clearUrlFromCache
|
||||
.calledWith(this.project_id, url)
|
||||
.should.equal(true)
|
||||
|
||||
@@ -40,7 +40,7 @@ describe('UrlFetcher', function() {
|
||||
|
||||
it('should call pipeUrlToFile', function (done) {
|
||||
this.UrlFetcher.pipeUrlToFile.callsArgWith(2)
|
||||
this.UrlFetcher.pipeUrlToFileWithRetry(this.url, this.path, err => {
|
||||
this.UrlFetcher.pipeUrlToFileWithRetry(this.url, this.path, (err) => {
|
||||
expect(err).to.equal(undefined)
|
||||
this.UrlFetcher.pipeUrlToFile.called.should.equal(true)
|
||||
done()
|
||||
@@ -50,7 +50,7 @@ describe('UrlFetcher', function() {
|
||||
it('should call pipeUrlToFile multiple times on error', function (done) {
|
||||
const error = new Error("couldn't download file")
|
||||
this.UrlFetcher.pipeUrlToFile.callsArgWith(2, error)
|
||||
this.UrlFetcher.pipeUrlToFileWithRetry(this.url, this.path, err => {
|
||||
this.UrlFetcher.pipeUrlToFileWithRetry(this.url, this.path, (err) => {
|
||||
expect(err).to.equal(error)
|
||||
this.UrlFetcher.pipeUrlToFile.callCount.should.equal(3)
|
||||
done()
|
||||
@@ -60,7 +60,7 @@ describe('UrlFetcher', function() {
|
||||
it('should call pipeUrlToFile twice if only 1 error', function (done) {
|
||||
this.UrlFetcher.pipeUrlToFile.onCall(0).callsArgWith(2, 'error')
|
||||
this.UrlFetcher.pipeUrlToFile.onCall(1).callsArgWith(2)
|
||||
this.UrlFetcher.pipeUrlToFileWithRetry(this.url, this.path, err => {
|
||||
this.UrlFetcher.pipeUrlToFileWithRetry(this.url, this.path, (err) => {
|
||||
expect(err).to.equal(undefined)
|
||||
this.UrlFetcher.pipeUrlToFile.callCount.should.equal(2)
|
||||
done()
|
||||
@@ -167,7 +167,7 @@ describe('UrlFetcher', function() {
|
||||
|
||||
describe('with non success status code', function () {
|
||||
beforeEach(function (done) {
|
||||
this.UrlFetcher.pipeUrlToFile(this.url, this.path, err => {
|
||||
this.UrlFetcher.pipeUrlToFile(this.url, this.path, (err) => {
|
||||
this.callback(err)
|
||||
return done()
|
||||
})
|
||||
@@ -188,7 +188,7 @@ describe('UrlFetcher', function() {
|
||||
|
||||
return describe('with error', function () {
|
||||
beforeEach(function (done) {
|
||||
this.UrlFetcher.pipeUrlToFile(this.url, this.path, err => {
|
||||
this.UrlFetcher.pipeUrlToFile(this.url, this.path, (err) => {
|
||||
this.callback(err)
|
||||
return done()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user