1
0
mirror of https://github.com/sasjs/server.git synced 2025-12-10 19:34:34 +00:00
Files
server/api/src/controllers/Execution.ts
sabhas 0c6ccddafd Merge branch 'master' into homepage-sasjs-executor
Conflicts:
	api/src/app.ts
	api/src/routes/index.ts
	api/src/routes/spec/routes.spec.ts
2021-11-01 13:12:52 +00:00

152 lines
3.8 KiB
TypeScript

import path from 'path'
import fs from 'fs'
import { getSessionController } from './'
import { readFile, fileExists, createFile } from '@sasjs/utils'
import { configuration } from '../../package.json'
import { promisify } from 'util'
import { execFile } from 'child_process'
import { Session, TreeNode } from '../types'
import { generateFileUploadSasCode, getTmpFilesFolderPath } from '../utils'
const execFilePromise = promisify(execFile)
export class ExecutionController {
async execute(
program = '',
autoExec?: string,
session?: Session,
vars?: any,
otherArgs?: any,
returnJson?: boolean
) {
if (program) {
if (!(await fileExists(program))) {
throw 'ExecutionController: SAS file does not exist.'
}
program = await readFile(program)
if (vars) {
Object.keys(vars).forEach(
(key: string) => (program = `%let ${key}=${vars[key]};\n${program}`)
)
}
}
const sessionController = getSessionController()
if (!session) {
session = await sessionController.getSession()
session.inUse = true
}
let log = path.join(session.path, 'log.log')
let webout = path.join(session.path, 'webout.txt')
await createFile(webout, '')
program = `
%let sasjsprocessmode=Stored Program;
filename _webout "${webout}";
${program}`
// if no files are uploaded filesNamesMap will be undefined
if (otherArgs && otherArgs.filesNamesMap) {
const uploadSasCode = await generateFileUploadSasCode(
otherArgs.filesNamesMap,
session.path
)
//If sas code for the file is generated it will be appended to the top of sasCode
if (uploadSasCode.length > 0) {
program = `${uploadSasCode}` + program
}
}
const code = path.join(session.path, 'code.sas')
if (!(await fileExists(code))) {
await createFile(code, program)
}
let additionalArgs: string[] = []
if (autoExec) additionalArgs = ['-AUTOEXEC', autoExec]
const { stdout, stderr } = await execFilePromise(configuration.sasPath, [
'-SYSIN',
code,
'-LOG',
log,
'-WORK',
session.path,
...additionalArgs,
process.platform === 'win32' ? '-nosplash' : ''
]).catch((err) => ({ stderr: err, stdout: '' }))
if (await fileExists(log)) log = await readFile(log)
else log = ''
if (await fileExists(webout)) webout = await readFile(webout)
else webout = ''
const debug = Object.keys(vars).find(
(key: string) => key.toLowerCase() === '_debug'
)
let jsonResult
if ((debug && vars[debug] >= 131) || stderr) {
webout = `<html><body>
${webout}
<div style="text-align:left">
<hr /><h2>SAS Log</h2>
<pre>${log}</pre>
</div>
</body></html>`
} else if (returnJson) {
jsonResult = { result: webout, log: log }
}
session.inUse = false
sessionController.deleteSession(session)
return Promise.resolve(jsonResult || webout)
}
buildDirectorytree() {
const root: TreeNode = {
name: 'files',
relativePath: '',
absolutePath: getTmpFilesFolderPath(),
children: []
}
const stack = [root]
while (stack.length) {
const currentNode = stack.pop()
if (currentNode) {
const children = fs.readdirSync(currentNode.absolutePath)
for (let child of children) {
const absoluteChildPath = `${currentNode.absolutePath}/${child}`
const relativeChildPath = `${currentNode.relativePath}/${child}`
const childNode: TreeNode = {
name: child,
relativePath: relativeChildPath,
absolutePath: absoluteChildPath,
children: []
}
currentNode.children.push(childNode)
if (fs.statSync(childNode.absolutePath).isDirectory()) {
stack.push(childNode)
}
}
}
}
return root
}
}