1
0
mirror of https://github.com/sasjs/server.git synced 2026-01-08 07:00:04 +00:00

feat: add support for R stored programs

This commit is contained in:
2022-09-06 21:52:21 +05:00
parent b9d032f148
commit d6651bbdbe
13 changed files with 277 additions and 88 deletions

View File

@@ -4,9 +4,9 @@ import { createFolder, fileExists, folderExists, isWindows } from '@sasjs/utils'
import { RunTimeType } from './verifyEnvVariables'
export const getDesktopFields = async () => {
const { SAS_PATH, NODE_PATH, PYTHON_PATH } = process.env
const { SAS_PATH, NODE_PATH, PYTHON_PATH, RSCRIPT_PATH } = process.env
let sasLoc, nodeLoc, pythonLoc
let sasLoc, nodeLoc, pythonLoc, rscriptLoc
if (process.runTimes.includes(RunTimeType.SAS)) {
sasLoc = SAS_PATH ?? (await getSASLocation())
@@ -20,7 +20,11 @@ export const getDesktopFields = async () => {
pythonLoc = PYTHON_PATH ?? (await getPythonLocation())
}
return { sasLoc, nodeLoc, pythonLoc }
if (process.runTimes.includes(RunTimeType.R)) {
rscriptLoc = RSCRIPT_PATH ?? (await getRScriptLocation())
}
return { sasLoc, nodeLoc, pythonLoc, rscriptLoc }
}
const getDriveLocation = async (): Promise<string> => {
@@ -117,3 +121,25 @@ const getPythonLocation = async (): Promise<string> => {
return targetName
}
const getRScriptLocation = async (): Promise<string> => {
const validator = async (filePath: string) => {
if (!filePath) return 'Path to RScript executable is required.'
if (!(await fileExists(filePath))) {
return 'No file found at provided path.'
}
return true
}
const defaultLocation = isWindows() ? 'C:\\Rscript' : '/usr/bin/Rscript'
const targetName = await getString(
'Please enter full path to a Rscript executable: ',
validator,
defaultLocation
)
return targetName
}

View File

@@ -5,7 +5,7 @@ import { RunTimeType } from '.'
export const getRunTimeAndFilePath = async (programPath: string) => {
const ext = path.extname(programPath)
// If programPath (_program) is provided with a ".sas", ".js" or ".py" extension
// If programPath (_program) is provided with a ".sas", ".js", ".py" or ".r" extension
// we should use that extension to determine the appropriate runTime
if (ext && Object.values(RunTimeType).includes(ext.slice(1) as RunTimeType)) {
const runTime = ext.slice(1)

View File

@@ -29,12 +29,14 @@ export const setProcessVariables = async () => {
process.sasLoc = process.env.SAS_PATH
process.nodeLoc = process.env.NODE_PATH
process.pythonLoc = process.env.PYTHON_PATH
process.rscriptLoc = process.env.RSCRIPT_PATH
} else {
const { sasLoc, nodeLoc, pythonLoc } = await getDesktopFields()
const { sasLoc, nodeLoc, pythonLoc, rscriptLoc } = await getDesktopFields()
process.sasLoc = sasLoc
process.nodeLoc = nodeLoc
process.pythonLoc = pythonLoc
process.rscriptLoc = rscriptLoc
}
const { SASJS_ROOT } = process.env

View File

@@ -157,3 +157,30 @@ export const generateFileUploadPythonCode = async (
return uploadCode
}
/**
* Generates the R code that references uploaded files in the concurrent request
* @param filesNamesMap object that maps hashed file names and original file names
* @param sessionFolder name of the folder that is created for the purpose of files in concurrent request
* @returns generated python code
*/
export const generateFileUploadRCode = async (
filesNamesMap: FilenamesMap,
sessionFolder: string
) => {
let uploadCode = ''
let fileCount = 0
const sessionFolderList: string[] = await listFilesInFolder(sessionFolder)
sessionFolderList.forEach(async (fileName) => {
if (fileName.includes('req_file')) {
fileCount++
uploadCode += `\n._WEBIN_FILENAME${fileCount} <- '${filesNamesMap[fileName].originalName}'`
uploadCode += `\n._WEBIN_NAME${fileCount} <- '${filesNamesMap[fileName].fieldName}'`
}
})
uploadCode += `\n._WEBIN_FILE_COUNT <- ${fileCount}`
return uploadCode
}

View File

@@ -34,7 +34,8 @@ export enum LOG_FORMAT_MORGANType {
export enum RunTimeType {
SAS = 'sas',
JS = 'js',
PY = 'py'
PY = 'py',
R = 'r'
}
export enum ReturnCode {
@@ -253,7 +254,8 @@ const verifyRUN_TIMES = (): string[] => {
const verifyExecutablePaths = () => {
const errors: string[] = []
const { RUN_TIMES, SAS_PATH, NODE_PATH, PYTHON_PATH, MODE } = process.env
const { RUN_TIMES, SAS_PATH, NODE_PATH, PYTHON_PATH, RSCRIPT_PATH, MODE } =
process.env
if (MODE === ModeType.Server) {
const runTimes = RUN_TIMES?.split(',')
@@ -269,6 +271,10 @@ const verifyExecutablePaths = () => {
if (runTimes?.includes(RunTimeType.PY) && !PYTHON_PATH) {
errors.push(`- PYTHON_PATH is required for ${RunTimeType.PY} run time`)
}
if (runTimes?.includes(RunTimeType.R) && !RSCRIPT_PATH) {
errors.push(`- RSCRIPT_PATH is required for ${RunTimeType.R} run time`)
}
}
return errors