UNPKG

zowe-utils

Version:

z/OS : JCL submission and common ftp operations, for NodeJS developers (ZOWE).

161 lines (136 loc) 6.6 kB
const fs = require('fs-extra') const iconvlite = require('iconv-lite') const path = require('path') const uuid = require('uuid-random') const os = require('os') const { execZoweCommand, execFtpCommand } = require('./support_modules/execCommand.js') const mvsNamingConventions = require('./support_modules/mvsNamingConventions.js') const countFileLines = require('./support_modules/countFileLines.js') module.exports = (config) => { const { encoding } = config async function put (source, hostFile, optionsCopy) { const regex = new RegExp('^' + config.user, 'i') if (!regex.test(hostFile)) throw new Error('Can upload to dataset/PDS starting with ' + config.user) if (!mvsNamingConventions(hostFile)) throw new Error('Name doesn\'t adhere to MVS naming conventions!') const options = Object.assign({}, optionsCopy) if (!options) throw new Error('Missing required argument: option') if (!options.sourceType) throw new Error('Missing required option: sourceType') if (options.sourceType !== 'string' && options.sourceType !== 'localFile') { throw new Error('Invalid sourcetype : ' + options.sourceType + ' (Valid sourceTypes: string & localFile)') } let sourceFilePath if (options.sourceType === 'string') { sourceFilePath = path.join(os.tmpdir(), 'zowe_' + uuid()) await fs.writeFile(sourceFilePath, source) } if (options.sourceType === 'localFile') { sourceFilePath = source } const hostFileParenthesisIndex = hostFile.indexOf('(') const hostFileType = hostFileParenthesisIndex === -1 ? 'dataset' : 'pds' if (hostFileType === 'pds') { // create pds library before proceeding const pdsDataSet = hostFile.slice(0, hostFileParenthesisIndex) if (!options.skipList) await checkPds(pdsDataSet) } if (hostFileType === 'dataset') { // if dataset exists delete it const pathInMainframe = await pathExists(hostFile) // console.log(pathInMainframe) if (pathInMainframe) { if (pathInMainframe.dsntp === 'PDS' || pathInMainframe.dsntp === 'LIBRARY') throw new Error('Cannot upload dataset to a PDS!') await del(hostFile) } if (!options.lrecl) options.lrecl = 80 if (!options.size) { // calculate the primary cylinders let totalRows if (options.sourceType === 'string') { const numberOfNewLines = source.match(/\n/g) if (numberOfNewLines) totalRows = numberOfNewLines.length + 1 else totalRows = 1 } else totalRows = await countFileLines(source) + 1 console.log({ totalRows }) // options.size = (Math.ceil(totalRows * options.lrecl / 839940) / 2 + 1) options.size = (Math.ceil(totalRows * options.lrecl / 10000) + 1) options['secondary-space'] = Math.ceil(Math.min(options.size * 0.10, 300)) options.size = Math.min(options.size, 4369) + 'CYL' } options.blksize = 0 let extraOptions = '' for (const key in options) { if (key === 'sourceType' || key === 'binary') continue extraOptions += ' --' + key.toLowerCase() + ' ' + options[key] } await execZoweCommand(`zowe zos-files create data-set-sequential "${hostFile}" ${extraOptions}`, config) } if (options.sourceType === 'string') { await execZoweCommand(`zowe zos-files upload file-to-data-set "${sourceFilePath}" "${hostFile}" --encoding ${encoding}`, config) await fs.remove(sourceFilePath) } else await execFtpCommand(`${options.binary ? 'binary\n' : 'ascii\n'}put "${sourceFilePath}" "${hostFile}"`, config) } async function get (hostFile, localFilePath, { mode = 'single', returnString = false, binary = false, extension = '' } = {}) { const finalLocalFilePath = localFilePath || path.join(os.tmpdir(), 'zowe_' + uuid()) if (mode === 'all') { // const regex = new RegExp('^' + config.user, 'i') // if (!regex.test(hostFile)) throw new Error('Can download PDS libraries starting with ' + config.user) return await execZoweCommand(`zowe zos-files download all-members "${hostFile}" --directory "${finalLocalFilePath}" --encoding ${encoding} --extension '${extension}'`, config) } if (!localFilePath) { // Return a string using zowe await execZoweCommand(`zowe zos-files download data-set "${hostFile}" --file "${finalLocalFilePath}" --encoding ${encoding}`, config) const jsString = await fs.readFile(finalLocalFilePath, 'utf8') await fs.remove(finalLocalFilePath) return jsString } await execFtpCommand(`${binary ? 'binary\n' : 'ascii\n'}get "${hostFile}" "${finalLocalFilePath}"`, config) if (returnString) { const content = await fs.readFile(finalLocalFilePath) const jsString = iconvlite.decode(content, encoding === '875' ? 'ISO-8859-7' : encoding) return jsString } } async function del (hostFile) { if (!(await pathExists(hostFile))) return await execZoweCommand(`zowe zos-files delete data-set "${hostFile}" --for-sure`, config) } async function list (path) { const executionResult = await execZoweCommand(`zowe zos-files list data-set "${path}" --attributes`, config) const items = executionResult.data.apiResponse.items.map(el => { return { dsname: el.dsname, dsntp: el.dsntp } }) return items } async function listPdsMembers (path, pattern = '*') { const executionResult = await execZoweCommand(`zowe zos-files list all-members "${path}" --pattern "${pattern}" --attributes`, config) const items = executionResult.data.apiResponse.items.map(el => { return { dsname: el.member, m4date: el.m4date, mtime: el.mtime, user: el.user } }) return items } // Fails with EDC5003I Truncation of a record occurred during an I/O operation at some members // async function uploadPdsLibrary (localFilePath, pdsDataSet) { // await checkPds(pdsDataSet) // await execZoweCommand(`zowe zos-files upload dir-to-pds "${localFilePath}" "${pdsDataSet}" --encoding ${encoding} `, config) // } async function pathExists (path) { const arrayOfMatches = await list(path) return arrayOfMatches.find(el => el.dsname === path) } async function checkPds (pdsDataSet) { if (!(await pathExists(pdsDataSet))) { await execZoweCommand( `zowe zos-files create data-set-partitioned "${pdsDataSet}" --primary-space 50 --directory-blocks 5000 --block-size 32720` , config) } } return { put, get, del, list, listPdsMembers } }