Skip to content

Commit

Permalink
Easytrieve language script (#154)
Browse files Browse the repository at this point in the history
* Easytrieve language script implementation

Signed-off-by: Dennis Behm <[email protected]>
  • Loading branch information
dennis-behm authored May 22, 2024
1 parent 5b08d82 commit a2c69f9
Show file tree
Hide file tree
Showing 12 changed files with 440 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ The zAppBuild sample provides the following *language* build scripts by default:
* ZunitConfig.groovy
* CRB.groovy
* Transfer.groovy (for transport non-buildable files like JCL or PROC into build libraries and register them as build output)
* Easytrieve.groovy

All language scripts both compile and optionally link-edit programs. The language build scripts are intended to be useful out of the box but depending on the complexity of your applications' build requirements, may require modifications to meet your development team's needs. By following the examples used in the existing language build scripts of keeping all application specific references out of the build scripts and instead using configuration properties with strong default values, the zAppBuild sample can continue to be a generic build solution for all of your specific applications.

Expand Down
45 changes: 45 additions & 0 deletions build-conf/Easytrieve.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Releng properties used by language/Easytrieve.groovy

#
# Comma separated list of required build properties for easytrieve.groovy
easytrieve_requiredBuildProperties=easytrieve_srcPDS,easytrieve_cpyPDS,easytrieve_objPDS,easytrieve_loadPDS,\
easytrieve_compiler,easytrieve_linkEditor,easytrieve_tempOptions,applicationOutputsCollectionName,\
SCEELKED

#
# easytrieve compiler name
# Easytrieve EZTCOM
# IBM Migration Utility: FSYTPA00
easytrieve_compiler=FSYTPA00

#
# linker name
easytrieve_linkEditor=IEWBLINK

#
# easytrieve source data sets
easytrieve_srcPDS=${hlq}.EZT
easytrieve_cpyPDS=${hlq}.MAC
easytrieve_objPDS=${hlq}.OBJ
easytrieve_dbrmPDS=${hlq}.DBRM

#
# easytrieve load data sets
easytrieve_loadPDS=${hlq}.LOAD

#
# List the data sets that need to be created and their creation options
# https://www.ibm.com/docs/en/mufz/5.1?topic=jcl-jcmucl2jtwo-step-translate-link-without-proc
easytrieve_srcDatasets=${easytrieve_srcPDS},${easytrieve_cpyPDS},${easytrieve_objPDS},${easytrieve_dbrmPDS}
easytrieve_srcOptions=cyl space(1,1) lrecl(80) dsorg(PO) recfm(F,B) dsntype(library)

easytrieve_loadDatasets=${easytrieve_loadPDS}
easytrieve_loadOptions=cyl space(1,1) dsorg(PO) recfm(U) blksize(32760) dsntype(library)

easytrieve_tempOptions=cyl space(5,5) unit(vio) blksize(80) lrecl(80) recfm(f,b) new
easytrieve_printTempOptions=cyl space(5,5) unit(vio) blksize(133) lrecl(133) recfm(f,b) new

#
# List of output datasets to document deletions
easytrievel_outputDatasets=${easytrieve_loadPDS}

21 changes: 21 additions & 0 deletions build-conf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ SDSNLOAD | DB2 Load Library. Example: DB2.V9R1M0.SDSNLOAD
SDSNEXIT | DB2 Exit Library. Example: DBC0CFG.SDSNEXIT
SFELLOAD | Optional IDz Load Library. Example: FEL.V14R0M0.SFELLOAD
SBZUSAMP | Optional z/OS Dynamic Test Runner IDz zUnit / WAZI VTP library containing necessary copybooks. Example : FEL.V14R2.SBZUSAMP
EZETLOAD | Easytrieve Load Library. Example for IBM Migration Utility: SYS1.SFSYLOAD

### build.properties
General properties used mainly by `build.groovy` but can also be a place to declare properties used by multiple language scripts.
Expand Down Expand Up @@ -336,6 +337,26 @@ transfer_xmlPDS | Sample dataset for xml members
transfer_dsOptions | BPXWDYN creation options for creating 'source' type data sets
transfer_outputDatasets | List of output datasets to document deletions ** Can be overridden by a file property. ** If used for multiple, use a file property to set transfer_outputDatasets

### Easytrieve.properties
Build properties used by zAppBuild/language/Easytrieve.groovy

Property | Description
--- | ---
easytrieve_requiredBuildProperties | Comma separated list of required build properties for language/Cobol.groovy
easytrieve_srcPDS | Dataset to move Easytrieve source files to from USS
easytrieve_cpyPDS | Dataset to move Easytrieve macros to from USS
easytrieve_objPDS | Dataset to create object decks in from compile step
easytrieve_dbrmPDS | Dataset to create DB2 DBRM modules in from compile step
easytrieve_loadPDS | Dataset to create load modules in from link edit step
easytrieve_srcDataSets | Comma separated list of 'source' type data sets
easytrieve_srcOptions | BPXWDYN creation options for creating 'source' type data sets
easytrieve_loadDatasets | Comma separated list of 'load module' type data sets
easytrieve_loadOptions | BPXWDYN creation options for 'load module' type data sets
easytrieve_tempOptions | BPXWDYN creation options for temporary data sets
easytrieve_outputDatasets | List of output datasets to document deletions ** Can be overridden by a file property.
easytrieve_compiler | MVS program name of the COBOL compiler
easytrieve_linkEditor | MVS program name of the link editor

### language-conf/languageConfigProps01.properties
Sample language configuration properties file used by dbb-zappbuild/utilities/BuildUtilities.groovy.

Expand Down
2 changes: 1 addition & 1 deletion build-conf/build.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
buildPropFiles=${systemDatasets},dependencyReport.properties,Assembler.properties,BMS.properties,\
MFS.properties,PSBgen.properties,DBDgen.properties,ACBgen.properties,Cobol.properties,\
LinkEdit.properties,PLI.properties,REXX.properties,ZunitConfig.properties,Transfer.properties,\
CRB.properties,zCEE3.properties,zCEE2.properties
CRB.properties,zCEE3.properties,zCEE2.properties,Easytrieve.properties

#
# Comma separated list of property files defining system datasets
Expand Down
5 changes: 5 additions & 0 deletions build-conf/datasets.properties
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,10 @@ SBZUSAMP=
# REXX Compiler Data Sets. Example: REXX.V1R4.SFANLMD
SFANLMD=

# Easytrieve Load Library. Example:
# Easytrieve: EZT.PRODUCT.LOADLIB
# IBM Migration Utility: SYS1.SFSYLOAD
EZETLOAD=

# PD Tools Common Component load library. Example : PDTCC.V1R8.SIPVMODA
PDTCCMOD=
1 change: 1 addition & 0 deletions build-conf/defaultzAppBuildConf.properties
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ dbb.scannerMapping = "scannerClass":"DependencyScanner", "languageHint":"C" :: c
dbb.scannerMapping = "scannerClass":"DependencyScanner", "languageHint":"ASM" :: asm, mac
dbb.scannerMapping = "scannerClass":"DependencyScanner", "languageHint":"CPP" :: cpp, hpp
dbb.scannerMapping = "scannerClass":"DependencyScanner", "languageHint":"PLI" :: pli, inc
dbb.scannerMapping = "scannerClass":"DependencyScanner", "languageHint":"EASY" :: ezt, eztm
dbb.scannerMapping = "scannerClass":"ZUnitConfigScanner" :: bzucfg
# Custom mappings
dbb.scannerMapping = "scannerClass":"DependencyScanner", "languageHint":"REXX" :: rexx
Expand Down
273 changes: 273 additions & 0 deletions languages/Easytrieve.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
@groovy.transform.BaseScript com.ibm.dbb.groovy.ScriptLoader baseScript
import com.ibm.dbb.dependency.*
import com.ibm.dbb.build.*
import groovy.transform.*


// define script properties
@Field BuildProperties props = BuildProperties.getInstance()
@Field def buildUtils= loadScript(new File("${props.zAppBuildDir}/utilities/BuildUtilities.groovy"))
@Field def impactUtils= loadScript(new File("${props.zAppBuildDir}/utilities/ImpactUtilities.groovy"))


/***
*
* Sample language script to compile and link Easytrieve source code
*
* https://www.ibm.com/docs/en/mufz/5.1?topic=jcl-jcmucl2jtwo-step-translate-link-without-proc
*
*/

println("** Building ${argMap.buildList.size()} ${argMap.buildList.size() == 1 ? 'file' : 'files'} mapped to ${this.class.getName()}.groovy script")

//verify required build properties
buildUtils.assertBuildProperties(props.easytrieve_requiredBuildProperties)

// create language datasets
def langQualifier = "easytrieve"
buildUtils.createLanguageDatasets(langQualifier)


//sort the build list based on build file rank if provided
List<String> sortedList = buildUtils.sortBuildList(argMap.buildList, 'easytrieve_fileBuildRank')
int currentBuildFileNumber = 1

//iterate through build list

sortedList.each { buildFile ->
println "*** (${currentBuildFileNumber++}/${sortedList.size()}) Building file $buildFile"

// configure dependency resolution and create logical file

String dependencySearch = props.getFileProperty('easytrieve_dependencySearch', buildFile)
SearchPathDependencyResolver dependencyResolver = new SearchPathDependencyResolver(dependencySearch)

// copy source files and dependency files to data sets
buildUtils.copySourceFiles(buildFile, props.easytrieve_srcPDS, 'easytrieve_dependenciesDatasetMapping', null, dependencyResolver)

// Get logical file
LogicalFile logicalFile = buildUtils.createLogicalFile(dependencyResolver, buildFile)


// create mvs commands
String member = CopyToPDS.createMemberName(buildFile)
String needsLinking = props.getFileProperty('easytrieve_linkEdit', buildFile)

File logFile = new File( props.userBuild ? "${props.buildOutDir}/${member}.log" : "${props.buildOutDir}/${member}.ezt.log")
if (logFile.exists())
logFile.delete()

MVSExec compile = createCompileCommand(buildFile, logicalFile, member, logFile)
MVSExec linkEdit
if (needsLinking.toBoolean()) linkEdit = createLinkEditCommand(buildFile, logicalFile, member, logFile)

// execute mvs commands in a mvs job
MVSJob job = new MVSJob()
job.start()

// compile the easytrieve program
int rc = compile.execute()
//int rc = 0
int maxRC = props.getFileProperty('easytrieve_compileMaxRC', buildFile).toInteger()

if (rc > maxRC) {
String errorMsg = "*! The compile return code ($rc) for $buildFile exceeded the maximum return code allowed ($maxRC)"
println(errorMsg)
props.error = "true"
buildUtils.updateBuildResult(errorMsg:errorMsg,logs:["${member}.log":logFile])
}
else {
// if this program needs to be link edited . . .

if (needsLinking.toBoolean()) {
rc = linkEdit.execute()
//rc = 0
maxRC = props.getFileProperty('easytrieve_linkEditMaxRC', buildFile).toInteger()

if (rc > maxRC) {
String errorMsg = "*! The link edit return code ($rc) for $buildFile exceeded the maximum return code allowed ($maxRC)"
println(errorMsg)
props.error = "true"
buildUtils.updateBuildResult(errorMsg:errorMsg,logs:["${member}.log":logFile])
}
else {
// only scan the load module if load module scanning turned on for file
String scanLoadModule = props.getFileProperty('easytrieve_scanLoadModule', buildFile)
if (scanLoadModule && scanLoadModule.toBoolean())
impactUtils.saveStaticLinkDependencies(buildFile, props.linkedit_loadPDS, logicalFile)
}
}

}


// clean up passed DD statements
job.stop()
}

// end script


//********************************************************************
//* Method definitions
//********************************************************************

/*
* createEasytrieveParms - Builds up the EZT compiler parameter list from build and file properties
*/
def createEasytrieveParms(String buildFile, LogicalFile logicalFile) {
def parms = props.getFileProperty('easytrieve_compileParms', buildFile) ?: ""

if (parms.startsWith(','))
parms = parms.drop(1)

if (props.verbose) println "Easytrieve compiler parms for $buildFile = $parms"
return parms
}

/*
* createCompileCommand - creates a MVSExec command for compiling the EZT program (buildFile)
*/
def createCompileCommand(String buildFile, LogicalFile logicalFile, String member, File logFile) {
String parms = createEasytrieveParms(buildFile, logicalFile)
String compiler = props.getFileProperty('easytrieve_compiler', buildFile)

// define the MVSExec command to compile the program
MVSExec compile = new MVSExec().file(buildFile).pgm(compiler).parm(parms)

// add DD statements to the compile command
compile.dd(new DDStatement().name("SYSIN").dsn("${props.easytrieve_srcPDS}($member)").options('shr').report(true))
compile.dd(new DDStatement().name("SYSPRINT").options(props.easytrieve_printTempOptions))
(1..2).toList().each { num ->
compile.dd(new DDStatement().name("SYSUT$num").options(props.easytrieve_tempOptions))
}

// define object dataset allocation
compile.dd(new DDStatement().name("SYSLIN").dsn("${props.easytrieve_objPDS}($member)").options('shr').output(true))

// add a syslib to the compile command
compile.dd(new DDStatement().name("PANDD").dsn(props.easytrieve_cpyPDS).options("shr"))

// add custom concatenation
def easytrieveSyslibConcatenation = props.getFileProperty('easytrieve_easytrieveSyslibConcatenation', buildFile) ?: ""
if (easytrieveSyslibConcatenation) {
def String[] syslibDatasets = easytrieveSyslibConcatenation.split(',');
for (String syslibDataset : syslibDatasets )
compile.dd(new DDStatement().dsn(syslibDataset).options("shr"))
}

// add a tasklib to the compile command with optional concatenations
compile.dd(new DDStatement().name("TASKLIB").dsn(props.EZETLOAD).options("shr"))

// add optional DBRMLIB if build file contains DB2 code
if (buildUtils.isSQL(logicalFile))
compile.dd(new DDStatement().name("DBRMLIB").dsn("$props.easytrieve_dbrmPDS($member)").options('shr').output(true).deployType('DBRM'))

// add a copy command to the compile command to copy the SYSPRINT from the temporary dataset to an HFS log file
compile.copy(new CopyToHFS().ddName("SYSPRINT").file(logFile).hfsEncoding(props.logEncoding))

return compile
}


/*
* createLinkEditCommand - creates a MVSExec command for link editing the EZT object module produced by the compile
*/
def createLinkEditCommand(String buildFile, LogicalFile logicalFile, String member, File logFile) {
String parms = props.getFileProperty('easytrieve_linkEditParms', buildFile)
String linker = props.getFileProperty('easytrieve_linkEditor', buildFile)
String linkEditStream = props.getFileProperty('easytrieve_linkEditStream', buildFile)

// obtain githash for buildfile
String easytrieve_storeSSI = props.getFileProperty('easytrieve_storeSSI', buildFile)
if (easytrieve_storeSSI && easytrieve_storeSSI.toBoolean() && (props.mergeBuild || props.impactBuild || props.fullBuild)) {
String ssi = buildUtils.getShortGitHash(buildFile)
if (ssi != null) parms = parms + ",SSI=$ssi"
}

if (props.verbose) println "*** Link-Edit parms for $buildFile = $parms"

// define the MVSExec command to link edit the program
MVSExec linkedit = new MVSExec().file(buildFile).pgm(linker).parm(parms)

// Assemble linkEditInstream to define SYSIN as instreamData
String sysin_linkEditInstream = ''

// appending configured linkEdit stream if specified
if (linkEditStream) {
sysin_linkEditInstream += " " + linkEditStream.replace("\\n","\n").replace('@{member}',member)
}

// appending IDENTIFY statement to link phase for traceability of load modules
// this adds an IDRU record, which can be retrieved with amblist
def identifyLoad = props.getFileProperty('easytrieve_identifyLoad', buildFile)

if (identifyLoad && identifyLoad.toBoolean()) {
String identifyStatement = buildUtils.generateIdentifyStatement(buildFile, props.easytrieve_loadOptions)
if (identifyStatement != null ) {
sysin_linkEditInstream += identifyStatement
}
}

// appending mq stub according to file flags
if(buildUtils.isMQ(logicalFile)) {
// include mq stub program
// https://www.ibm.com/docs/en/ibm-mq/9.3?topic=files-mq-zos-stub-programs
sysin_linkEditInstream += buildUtils.getMqStubInstruction(logicalFile)
}

// appending debug exit to link instructions
if (props.debug && linkDebugExit!= null) {
sysin_linkEditInstream += " " + linkDebugExit.replace("\\n","\n").replace('@{member}',member)
}

// Define SYSIN dd as instream data
if (sysin_linkEditInstream) {
if (props.verbose) println("*** Generated linkcard input stream: \n $sysin_linkEditInstream")
linkedit.dd(new DDStatement().name("SYSIN").instreamData(sysin_linkEditInstream))
}

// add SYSLIN along the reference to SYSIN if configured through sysin_linkEditInstream
linkedit.dd(new DDStatement().name("SYSLIN").dsn("${props.easytrieve_objPDS}($member)").options('shr'))
if (sysin_linkEditInstream) linkedit.dd(new DDStatement().ddref("SYSIN"))

// add DD statements to the linkedit command
String deployType = buildUtils.getDeployType("easytrieve", buildFile, logicalFile)
linkedit.dd(new DDStatement().name("SYSLMOD").dsn("${props.easytrieve_loadPDS}($member)").options('shr').output(true).deployType(deployType))
linkedit.dd(new DDStatement().name("SYSPRINT").options(props.easytrieve_printTempOptions))
linkedit.dd(new DDStatement().name("SYSUT1").options(props.easytrieve_tempOptions))

// add a syslib to the compile command with optional concatenation
linkedit.dd(new DDStatement().name("SYSLIB").dsn(props.easytrieve_objPDS).options("shr"))

// add custom concatenation
def linkEditSyslibConcatenation = props.getFileProperty('easytrieve_linkEditSyslibConcatenation', buildFile) ?: ""
if (linkEditSyslibConcatenation) {
def String[] syslibDatasets = linkEditSyslibConcatenation.split(',');
for (String syslibDataset : syslibDatasets )
linkedit.dd(new DDStatement().dsn(syslibDataset).options("shr"))
}

linkedit.dd(new DDStatement().dsn(props.SCEELKED).options("shr"))

// Add Debug Dataset to find the debug exit to SYSLIB
if (props.debug && props.SEQAMOD)
linkedit.dd(new DDStatement().dsn(props.SEQAMOD).options("shr"))

if (buildUtils.isCICS(logicalFile))
linkedit.dd(new DDStatement().dsn(props.SDFHLOAD).options("shr"))

if (buildUtils.isIMS(logicalFile))
linkedit.dd(new DDStatement().dsn(props.SDFSRESL).options("shr"))

if (buildUtils.isSQL(logicalFile))
linkedit.dd(new DDStatement().dsn(props.SDSNLOAD).options("shr"))

if (buildUtils.isMQ(logicalFile))
linkedit.dd(new DDStatement().dsn(props.SCSQLOAD).options("shr"))

// add a copy command to the linkedit command to append the SYSPRINT from the temporary dataset to the HFS log file
linkedit.copy(new CopyToHFS().ddName("SYSPRINT").file(logFile).hfsEncoding(props.logEncoding).append(true))

return linkedit
}
1 change: 1 addition & 0 deletions languages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ zAppBuild comes with a number of language specific build scripts. These script
* MFS.groovy
* zCEE3.groovy
* ZunitConfig.groovy
* Easytrieve.groovy

All language scripts both compile and optionally link-edit programs. The language build scripts are intended to be useful out of the box but depending on the complexity of your applications' build requirements, may require modifications to meet your development team's needs. By following the examples used in the existing language build scripts of keeping all application specific references out of the build scripts and instead using configuration properties with strong default values, the zAppBuild sample can continue to be a generic build solution for all of your specific applications.

Expand Down
Loading

0 comments on commit a2c69f9

Please sign in to comment.