Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use cross-spawn instead of child_process and introduce _W32 placeholders #2015

Merged
merged 16 commits into from
Apr 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@
"env": {}
}
],
"markdownDescription": "Define LaTeX compiling tools to be used in recipes.\nEach tool is labeled by its `name`. When invoked, `command` is spawned with arguments defined in `args` and environment variables defined in `env`. Typically no spaces should appear in each argument unless in paths.\nPlaceholders `%DOC%`, `%DOCFILE%`, `%DOC_EXT`, `%DOCFILE_EXT%`, `%DIR%`, `%TMPDIR%` and `%OUTDIR%` are available. For details, please visit https://github.com/James-Yu/LaTeX-Workshop/wiki/Compile#latex-recipes."
"markdownDescription": "Define LaTeX compiling tools to be used in recipes.\nEach tool is labeled by its `name`. When invoked, `command` is spawned with arguments defined in `args` and environment variables defined in `env`. Typically no spaces should appear in each argument unless in paths.\nPlaceholders `%DOC%`, `%DOC_W32%, %DOC_EXT%`, `%DOC_EXT_W32%`, `%DOCFILE%`, `%DOCFILE_EXT%`, `%DIR%`, `%DIR_W32%`, `%TMPDIR%` and `%OUTDIR%`, `%OUTDIR_W32%` are available. For details, please visit https://github.com/James-Yu/LaTeX-Workshop/wiki/Compile#latex-recipes."
},
"latex-workshop.latex.magic.args": {
"type": "array",
Expand Down
54 changes: 16 additions & 38 deletions src/components/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import * as vscode from 'vscode'
import * as path from 'path'
import * as fs from 'fs-extra'
import * as cp from 'child_process'
import * as cs from 'cross-spawn'
import * as tmp from 'tmp'
import * as pdfjsLib from 'pdfjs-dist'
import {Mutex} from '../lib/await-semaphore'
import {replaceArgumentPlaceholders} from '../utils/utils'

import {Extension} from '../main'

Expand Down Expand Up @@ -96,11 +98,11 @@ export class Builder {
}

if (rootFile !== undefined) {
args = args.map(this.replaceArgumentPlaceholders(rootFile, this.tmpDir))
args = args.map(replaceArgumentPlaceholders(rootFile, this.tmpDir))
}
this.extension.logger.addLogMessage(`Build using the external command: ${command} ${args.length > 0 ? args.join(' '): ''}`)
this.extension.logger.addLogMessage(`cwd: ${wd}`)
this.currentProcess = cp.spawn(command, args, {cwd: wd})
this.currentProcess = cs.spawn(command, args, {cwd: wd})
const pid = this.currentProcess.pid
this.extension.logger.addLogMessage(`External build process spawned. PID: ${pid}.`)

Expand Down Expand Up @@ -205,17 +207,15 @@ export class Builder {
// This was supposed to create the outputDir as latexmk does not
// take care of it (neither does any of latex command). If the
//output directory does not exist, the latex commands simply fail.
if (this.extension.manager.rootDir !== undefined) {
const rootDir = this.extension.manager.rootDir
let outDir = this.extension.manager.getOutDir(rootFile)
if (!path.isAbsolute(outDir)) {
outDir = path.resolve(this.extension.manager.rootDir, outDir)
}
this.extension.manager.getIncludedTeX().forEach(file => {
const relativePath = path.dirname(file.replace(rootDir, '.'))
fs.ensureDirSync(path.resolve(outDir, relativePath))
})
const rootDir = path.dirname(rootFile)
let outDir = this.extension.manager.getOutDir(rootFile)
if (!path.isAbsolute(outDir)) {
outDir = path.resolve(rootDir, outDir)
}
this.extension.manager.getIncludedTeX(rootFile).forEach(file => {
const relativePath = path.dirname(file.replace(rootDir, '.'))
fs.ensureDirSync(path.resolve(outDir, relativePath))
})
this.buildInitiator(rootFile, languageId, recipe, releaseBuildMutex)
} catch (e) {
this.extension.buildInfo.buildEnded()
Expand Down Expand Up @@ -260,7 +260,7 @@ export class Builder {
command += ' ' + args[0]
}
this.extension.logger.addLogMessage(`cwd: ${path.dirname(rootFile)}`)
this.currentProcess = cp.spawn(command, [], {cwd: path.dirname(rootFile), env: envVars, shell: true})
this.currentProcess = cs.spawn(command, [], {cwd: path.dirname(rootFile), env: envVars, shell: true})
} else {
let workingDirectory: string
if (steps[index].command === 'latexmk' && rootFile === this.extension.manager.localRootFile && this.extension.manager.rootDir) {
Expand All @@ -269,7 +269,7 @@ export class Builder {
workingDirectory = path.dirname(rootFile)
}
this.extension.logger.addLogMessage(`cwd: ${workingDirectory}`)
this.currentProcess = cp.spawn(steps[index].command, steps[index].args, {cwd: workingDirectory, env: envVars})
this.currentProcess = cs.spawn(steps[index].command, steps[index].args, {cwd: workingDirectory, env: envVars})
}
const pid = this.currentProcess.pid
this.extension.logger.addLogMessage(`LaTeX build process spawned. PID: ${pid}.`)
Expand Down Expand Up @@ -462,13 +462,13 @@ export class Builder {
}
}
if (step.args) {
step.args = step.args.map(this.replaceArgumentPlaceholders(rootFile, this.tmpDir))
step.args = step.args.map(replaceArgumentPlaceholders(rootFile, this.tmpDir))
}
if (step.env) {
Object.keys(step.env).forEach( v => {
const e = step.env && step.env[v]
if (step.env && e) {
step.env[v] = this.replaceArgumentPlaceholders(rootFile, this.tmpDir)(e)
step.env[v] = replaceArgumentPlaceholders(rootFile, this.tmpDir)(e)
}
})
}
Expand Down Expand Up @@ -524,28 +524,6 @@ export class Builder {

return [texCommand, bibCommand]
}

replaceArgumentPlaceholders(rootFile: string, tmpDir: string): (arg: string) => string {
return (arg: string) => {
const docker = vscode.workspace.getConfiguration('latex-workshop').get('docker.enabled')

const rootFileParsed = path.parse(rootFile)
const docfile = rootFileParsed.name
const docfileExt = rootFileParsed.base
const dir = path.normalize(rootFileParsed.dir).split(path.sep).join('/')
const doc = path.join(dir, docfile)
const docExt = path.join(dir, docfileExt)
const outDir = this.extension.manager.getOutDir(rootFile)

return arg.replace(/%DOC%/g, docker ? docfile : doc)
.replace(/%DOC_EXT%/g, docker ? docfileExt : docExt)
.replace(/%DOCFILE_EXT%/g, docfileExt)
.replace(/%DOCFILE%/g, docfile)
.replace(/%DIR%/g, dir)
.replace(/%TMPDIR%/g, tmpDir)
.replace(/%OUTDIR%/g, outDir)
}
}
}

interface ProcessEnv {
Expand Down
16 changes: 7 additions & 9 deletions src/components/locator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as fs from 'fs'
import * as path from 'path'
import * as cp from 'child_process'
import * as synctexjs from './synctex'
import {replaceArgumentPlaceholders} from '../utils/utils'

import {Extension} from '../main'
import {ClientRequest} from '../../viewer/components/protocol'
Expand Down Expand Up @@ -431,16 +432,13 @@ export class Locator {
const configuration = vscode.workspace.getConfiguration('latex-workshop')
const command = configuration.get('view.pdf.external.synctex.command') as string
let args = configuration.get('view.pdf.external.synctex.args') as string[]
const rootFileParsed = path.parse(rootFile)
const docfile = rootFileParsed.name
const dir = path.normalize(rootFileParsed.dir).split(path.sep).join('/')
const doc = path.join(dir, docfile)
if (args) {
args = args.map(arg => arg.replace(/%DOC%/g, doc)
.replace(/%DOCFILE%/g, docfile)
.replace(/%PDF%/g, pdfFile)
.replace(/%LINE%/g, line.toString())
.replace(/%TEX%/g, texFile))
args = args.map(arg => {
return replaceArgumentPlaceholders(rootFile, this.extension.builder.tmpDir)(arg)
.replace(/%PDF%/g, pdfFile)
.replace(/%LINE%/g, line.toString())
.replace(/%TEX%/g, texFile)
})
}
this.extension.manager.setEnvVar()
cp.spawn(command, args)
Expand Down
12 changes: 2 additions & 10 deletions src/components/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export class Manager {
* Returns the output directory developed according to the input tex path
* and 'latex.outDir' config. If undefined is passed in, the default root
* file is used. If there is not root file, './' is output.
* The return path always uses `/` even on Windows
*/
getOutDir(texPath?: string) {
if (texPath === undefined) {
Expand All @@ -80,19 +81,10 @@ export class Manager {
return './'
}

const texPathParsed = path.parse(texPath)
const docfile = texPathParsed.name
const dir = path.normalize(texPathParsed.dir).split(path.sep).join('/')
const doc = path.join(dir, docfile)
const configuration = vscode.workspace.getConfiguration('latex-workshop')
const docker = configuration.get('docker.enabled')
const outDir = configuration.get('latex.outDir') as string
const out = outDir.replace(/%DOC%/g, docker ? docfile : doc)
.replace(/%DOCFILE%/g, docfile)
.replace(/%DIR%/g, docker ? './' : dir)
.replace(/%TMPDIR%/g, this.extension.builder.tmpDir)
const out = utils.replaceArgumentPlaceholders(texPath, this.extension.builder.tmpDir)(outDir)
return path.normalize(out).split(path.sep).join('/')

}

get rootDir() {
Expand Down
4 changes: 2 additions & 2 deletions src/components/texdoc.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as vscode from 'vscode'
import * as cp from 'child_process'
import * as cs from 'cross-spawn'
import {Extension} from 'src/main'

export class TeXDoc {
Expand All @@ -14,7 +14,7 @@ export class TeXDoc {
const texdocPath = configuration.get('texdoc.path') as string
const texdocArgs = Object.assign([], configuration.get('texdoc.args') as string[])
texdocArgs.push(pkg)
const proc = cp.spawn(texdocPath, texdocArgs)
const proc = cs.spawn(texdocPath, texdocArgs)

let stdout = ''
proc.stdout.on('data', newStdout => {
Expand Down
4 changes: 2 additions & 2 deletions src/components/viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as vscode from 'vscode'
import * as fs from 'fs'
import * as ws from 'ws'
import * as path from 'path'
import * as cp from 'child_process'
import * as cs from 'cross-spawn'
import {sleep} from '../utils/utils'

import {Extension} from '../main'
Expand Down Expand Up @@ -229,7 +229,7 @@ export class Viewer {
args = args.map(arg => arg.replace('%PDF%', pdfFile))
}
this.extension.manager.setEnvVar()
cp.spawn(command, args, {cwd: path.dirname(sourceFile), detached: true})
cs.spawn(command, args, {cwd: path.dirname(sourceFile), detached: true})
this.extension.logger.addLogMessage(`Open external viewer for ${pdfFile}`)
}

Expand Down
14 changes: 4 additions & 10 deletions src/providers/latexformatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as os from 'os'

import { Extension } from '../main'
import {Mutex} from '../lib/await-semaphore'
import {replaceArgumentPlaceholders} from '../utils/utils'

const fullRange = (doc: vscode.TextDocument) => doc.validateRange(new vscode.Range(0, 0, Number.MAX_VALUE, Number.MAX_VALUE))

Expand Down Expand Up @@ -129,19 +130,12 @@ export class LaTexFormatter {
const temporaryFile = documentDirectory + path.sep + '__latexindent_temp.tex'
fs.writeFileSync(temporaryFile, textToFormat)

const fileNameParsed = path.parse(document.fileName)
const docfile = fileNameParsed.name
const dir = path.normalize(fileNameParsed.dir).split(path.sep).join('/')
const doc = path.join(dir, docfile)
// generate command line arguments
const args = this.formatterArgs.map(arg => arg
// taken from ../components/builder.ts
.replace(/%DOC%/g, useDocker ? docfile : doc)
.replace(/%DOCFILE%/g, docfile)
.replace(/%DIR%/g, useDocker ? '.' : dir)
const args = this.formatterArgs.map(arg => { return replaceArgumentPlaceholders(document.fileName, this.extension.builder.tmpDir)(arg)
// latexformatter.ts specific tokens
.replace(/%TMPFILE%/g, useDocker ? path.basename(temporaryFile) : temporaryFile.split(path.sep).join('/'))
.replace(/%INDENT%/g, indent))
.replace(/%INDENT%/g, indent)
})

this.extension.logger.addLogMessage(`Formatting with command ${this.formatter} ${args}`)
this.extension.manager.setEnvVar()
Expand Down
35 changes: 35 additions & 0 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as vscode from 'vscode'
import * as path from 'path'
import * as fs from 'fs'
import * as iconv from 'iconv-lite'
Expand Down Expand Up @@ -128,3 +129,37 @@ export function svgToDataUrl(xml: string): string {
const b64Start = 'data:image/svg+xml;base64,'
return b64Start + svg64
}

export function replaceArgumentPlaceholders(rootFile: string, tmpDir: string): (arg: string) => string {
return (arg: string) => {
const configuration = vscode.workspace.getConfiguration('latex-workshop')
const docker = configuration.get('docker.enabled')

const rootFileParsed = path.parse(rootFile)
const docfile = rootFileParsed.name
const docfileExt = rootFileParsed.base
const dirW32 = path.normalize(rootFileParsed.dir)
const dir = dirW32.split(path.sep).join('/')
const docW32 = path.join(dirW32, docfile)
const doc = docW32.split(path.sep).join('/')
const docExtW32 = path.join(dirW32, docfileExt)
const docExt = docExtW32.split(path.sep).join('/')

const expandPlaceHolders = (a: string): string => {
return a.replace(/%DOC%/g, docker ? docfile : doc)
.replace(/%DOC_W32%/g, docker ? docfile : docW32)
.replace(/%DOC_EXT%/g, docker ? docfileExt : docExt)
.replace(/%DOC_EXT_W32%/g, docker ? docfileExt : docExtW32)
.replace(/%DOCFILE_EXT%/g, docfileExt)
.replace(/%DOCFILE%/g, docfile)
.replace(/%DIR%/g, docker ? './' : dir)
.replace(/%DIR_W32%/g, docker ? './' : dirW32)
.replace(/%TMPDIR%/g, tmpDir)

}
const outDirW32 = path.normalize(expandPlaceHolders(configuration.get('latex.outDir') as string))
const outDir = outDirW32.split(path.sep).join('/')
return expandPlaceHolders(arg).replace(/%OUTDIR%/g, outDir).replace(/%OUTDIR_W32%/g, outDirW32)

}
}
Loading