Article
Gevorg Arutiunian · Nov 1, 2018 9m read

Utility to compare class and include file definitions between builds

The following code provides information about software builds. Read the original description below for information about the different methods:


///Description
///This class enables developers to compare class and INCLUDE routine definitions between software builds.
///It navigates through all aspects of a class definition and INCLUDE file code and uses a 32 bit crc on 
///each element to produce a checksum for comparison purposes.
///The utility can simply return a checksum value, provides details at certain levels and output the 
///results to a file for comparison if required.
///
///The class has three primary methods
///
///Class (class, details, filename)
///This method will provide a checksum for 1 class
///
///Package (package, details, filename)
///This method will checksum information for all classes that are members of a given package
///
///Namespace (details , filename)
///This method will provide a checksum for all non-system classes in a namespace and a checksum for all 
///INCLUDE files in that namespace.
///This method is recommended as the preferred mechanism for comparing two software definitions in two 
///different namespaces.
///
///The details flag operates with the following values
///0 - No details written, total checksum returned
///1 - Class total written, total checksum returned
///2 - Class total and element total written , total checksum returned
///3 - Class total,element total and named element total written , total checksum returned 

Class objectscript.checkBuild extends (%RegisteredObject, %XML.Adaptor) [ClassType = "", Inheritance = right, ProcedureBlock]
{
    /// Define the crcmode = 7 "A correct 32-bit CRC"
    Parameter CRCMODE = 7;
     
    /// Provides a checksum for 1 class based on summation of 32 bit CRC checking
    /// 
Details ///
0 - No details written, total checksum returned ///
1 - Class total written, total checksum returned ///
2 - Class total and element total written , total checksum returned ///
3 - Class total,element total and named element total written , total checksum returned /// ClassMethod Class(class As %String, details As %Integer = 0, filename As %String = "") As %Integer { //Open the file if requested if filename'="" { set file=..FileOpen(filename) if file="Error" { write "Unable to open file : ",filename quit 0 } } else { set file="" } //Checksum 1 class set ccs=..CheckClass(class,details,file) if file { do ..FileClose(file) } quit ccs } ClassMethod CheckClass(class As %String, details As %Integer = 0, file = "") As %Integer { //Write out a blank line as a seperator followed by the classname if details { do ..Write("Class "_class,file) } //Initialize some iteration variables set (element,name,node,sub,snode)="" set selectivity="" //Initialize checksum totals //class|element|name set cst="0|0|0" //Process Header element checksum for { set element=$order(^oddDEF(class,element)) //Completed header information if (element="")||(element'?.n) { quit } //Eliminate date/timestamp from header - may vary if (element'=63)&&(element'=64)&&(element'=69) { set cst=..Add(cst,$zcrc(^(element),..#CRCMODE)) } } //Write out Header checksum details if wanted if details>1 { do ..Write($char(9)_"Header: "_$piece(cst,"|",2),file) } //Class elements set element("a")="Attributes" set element("f")="Foreign Keys" set element("i")="Indexes" set element("m")="Methods" set element("p")="Parameters" set element("q")="Queries" set element("s")="Storage" set element("t")="Triggers" //Process all other element checksums set element="" //Iterate though the Elements for { //Get next element set element=$order(element(element)) quit:element="" //Reset Element checksum set $piece(cst,"|",2)=0 //Iterate through Named Elements for { //Iterate through named elements set name=$order(^oddDEF(class,element,name)) quit:name="" //Reset Named element Checksum set $piece(cst,"|",3)=0 //Iterate through nodes of Named Elements for { set node=$order(^oddDEF(class,element,name,node)) quit:node="" //Add to checksums if data at this level if ($data(^oddDEF(class,element,name,node))'=10)&&(node'=11) { set cst=..Add(cst,$zcrc(^(node),..#CRCMODE)) } //Iterate through sub-nodes of nodes of Named Elememts for { set sub=$order(^oddDEF(class,element,name,node,sub)) quit:sub="" //Add to checksums if $data(^oddDEF(class,element,name,node,sub))'=10 { set cst=..Add(cst,$zcrc(^(sub),..#CRCMODE)) } //Iterate through storage nodes for { set snode=$order(^oddDEF(class,element,name,node,sub,"V",snode)) quit:snode="" //Add to checksums set cst=..Add(cst,$zcrc(^(snode,21),..#CRCMODE)) //Update selectivity selectivity if selectivity exists in storage definition if $data(^oddDEF(class,"s",name,"M")) { set selectivity="*" } } } } //Write out Named Element checksum details if requested if details>2 { do ..Write($char(9)_$char(9)_name_": "_$piece(cst,"|",3),file) } } //Write out Element checksum details if requested if details>1 { do ..Write($char(9)_element(element)_": "_$piece(cst,"|",2)_selectivity,file) //Reset selectivity indicator to "" set selectivity="" } } //Write out Class checksum details if requested if details { do ..Write($char(9)_"Checksum: "_$piece(cst,"|",1),file) } //Return Class checksum quit $piece(cst,"|",1) } /// Provides a checksum for a package(s) based on summation of 32 bit CRC checking ///
"PackageName" - 1 package ///
"" - All packages in a namespace (excludes % - Sydtem classes) ///
Details ///
0 - No details written, total checksum returned ///
1 - Class total written, total checksum returned ///
2 - Class total and element total written , total checksum returned ///
3 - Class total,element total and named element total written , total checksum returned /// ClassMethod Package(package As %String = "", details As %Integer = 0, filename As %String = "") As %Integer { //Open the file if requested if filename'="" { set file=..FileOpen(filename) if file="Error" { write "Unable to open file : ",filename quit 0 } } else { set file="" } //Checksum Package(s) set pcs=..CheckPackage(package,details,file) //Close the file if file { do ..FileClose(file) } //Return package checksum quit pcs } ClassMethod CheckPackage(package As %String = "", details As %Integer = 0, file As %File = "") As %Integer { //Initiate package anc total checksum set (tcs,pcs)=0 //Eliminate "%" system classes and checksum all packages if package="" if package="" { set package="@" set cpackage=$piece($order(^oddDEF(package)),".",1) } //Iterate through a package/packages(s) sending classes off to CheckClass set class=package for { set class=$order(^oddDEF(class)) if (class="")&&(package="@") { if details { do ..Write(cpackage_": "_pcs,file) do ..Write("",file) } quit } elseif (package'="@")&&($piece(class,".",1)'=package) { if details { do ..Write(package_": "_pcs,file) do ..Write("",file) } quit } elseif (package="@")&&($piece(class,".",1)'=cpackage) { if details { do ..Write(cpackage_": "_pcs,file) do ..Write("",file) } set pcs=0 set cpackage=$piece(class,".",1) } else { set ccs=..CheckClass(class,details,file) set tcs=tcs+ccs set pcs=pcs+ccs } } //Write the package total checksum if details { do ..Write("Checksum: "_tcs,file) } quit tcs } /// Provides a checksum for a Namespace based on summation of 32 bit CRC checking ///
This includes all INCLUDE files for code generation ///
"" - All packages in a namespace (excludes % - Sydtem classes) ///
Details ///
0 - No details written, total checksum returned ///
1 - Class total written, total checksum returned ///
2 - Class total and element total written , total checksum returned ///
3 - Class total,element total and named element total written , total checksum returned /// ClassMethod Namespace(details As %Integer = 0, filename As %String = "") As %Integer { //Open the file if requested if filename'="" { set file=..FileOpen(filename) if file="Error" { write "Unable to open file : ",filename quit 0 } } else { set file="" } //Go through the class packages first set ncs=..CheckPackage("",details,file) //Calculate the INCLUDE files if details { do ..Write("",file) do ..Write("Include Files",file) } //Initialize INCLUDE files checksum set ics=0 set routine="@",line="" for { set routine=$order(^rINC(routine)) quit:routine="" //Initialize INCLUDE ROUTINE checksum set rcs=0 //Iterate through the include file routines for { set line=$order(^rINC(routine,0,line)) quit:line="" set rcs=rcs+$zcrc(^(line),..#CRCMODE) set ics=ics+$zcrc(^(line),..#CRCMODE) set ncs=ncs+$zcrc(^(line),..#CRCMODE) } if details>1 { do ..Write($char(9)_routine_": "_rcs,file) } } //Write out the INCLUDE files checksum if details { do ..Write("Checksum: "_ics,file) } //Write out the Namespace checksum if details { do ..Write("",file) do ..Write("Namespace: "_ncs,file) } //Close the file if file { do ..FileClose(file) } //Return the namespace checksum quit ncs } ClassMethod FileOpen(filename As %String) As %File { set file=##class(%File).%New(filename) set ok=file.Open("WNS") if 'ok { do $system.OBJ.DisplayError(ok) quit "Error" } else { quit file } } ClassMethod FileClose(file As %File) { do file.Close() quit } ClassMethod Write(string As %String, file As %File) { if file { do file.WriteLine(string) } write !,string quit } ClassMethod Add(cst As %String, crc As %Integer) As %String { set $piece(cst,"|",1)=$piece(cst,"|",1)+crc set $piece(cst,"|",2)=$piece(cst,"|",2)+crc set $piece(cst,"|",3)=$piece(cst,"|",3)+crc quit cst } }

Here's a link to the code on GitHub: https://github.com/intersystems-community/code-snippets/blob/master/src/...

0
0 376
Discussion (0)2
Log in or sign up to continue