Source Control 2
From CacheWiki
|
Source Control 2 |
|
| Back |
This version of source control for Caché inherits of the default class and add functionalities:
- can control either class code or routine code
- contains a method to build the whole project from the file sources
- source control can shut off (in production mode)
- source files can be modified outside Caché without calculating a checksum (case of xml export)
We use it with CVS version 2.2.
Include macros
/// Contenu de ^["USER"]MPLSources
/// ^["USER"]MySources(0,InternalName)= save date time in Horolog format
/// ^["USER"]MySources(1,InternalName)= save date time in ODBC format
/// ^["USER"]MySources(2,InternalName)= $LB( user , ? )
Class Roche.SourceControl Extends %Studio.SourceControl.Base [ ProcedureBlock ]
{
/// Check this routine/class/csp file into source control.
Method CheckIn(InternalName As %String, Description As %String) As %Status
{
q ..ExportSource(InternalName)
}
/// Check this routine/class/csp file out of source control.
Method CheckOut(InternalName As %String, Description As %String) As %Status
{
q ..ImportSource(InternalName)
}
/// Compare two date times in Horolog format
/// returns -1 if dh1<dh2, 0 if dh1=dh2 and 1 if dh1>dh2
ClassMethod DTCompare(dh1, dh2) As %Integer
{
s d1=+dh1
s d2=+dh2
q:d1<d2 -1
q:d1>d2 1
s d1=$P(dh1,",",2)
s d2=$P(dh2,",",2)
q:d1<d2 -1
q:d1>d2 1
q 0
}
/// Export the whole project to file. Use it in terminal window
ClassMethod ExportProject(projectName)
{
s class=""
f {
s class=$O(^oddPROJECT(projectName,"Items",class))
q:class=""
s ext=$O(^oddPROJECT(projectName,"Items",class,""))
i ext'="MAC" s class=class_"."_ext
w class," -> ",..ExportSource(class,1),!
}
}
/// Export a routine in RSA format to a file
ClassMethod ExportRoutine(routName, extension, fileName) As %Status
{
s path=$P(fileName,"\",1,$L(fileName,"\")-1)
d ##class(%File).CreateDirectoryChain(path)
i '##class(%File).DirectoryExists(path) w !,"Path ",path," not created, skipping import" q $$$OK
k ^%utility($J)
s ^%utility($J,1)=routName
s ^%utility($J,2)=""
q $$rsave^%Wr("."_extension,fileName_":(""RWN"")","Source Control Export","Cache",0,0,1)
}
/// Export a source code
ClassMethod ExportSource(InternalName As %String, force = 0) As %Status
{
// verify that source control is allowed on this server
s sc=$G(^["USER"]MySources("sourcecontrol"),0)
q:sc=0 $$$OK
//InternalName: [package] . [classe] . CLS
s filename=..GetClassFileName(InternalName)
q:filename="" $$$OK
i 'force
{
//quit if the file time is the same as the time we backed up for this source
q:##class(%RoutineMgr).TS(InternalName)=$G(^["USER"]MPLSources(1,InternalName)) $$$OK
}
s className=$P(InternalName,".",1,$L(InternalName,".")-1), ext=$P(InternalName,".",$L(InternalName,"."))
i ext="CLS"
{ //export in CDL for classes
s sc=$SYSTEM.OBJ.ExportCDL(className,filename,"-d")
}
else
{
i ext="PRJ"
{
//export project in XML
s sc=$SYSTEM.OBJ.Export(InternalName,filename)
}
else
{
//export routines in RSA
d ..ExportRoutine(InternalName,ext,filename)
s sc=$$$OK
}
}
i $$$ISOK(sc)
{
w !,"Exported '",InternalName,"' to file '",filename,"'"
s ^["USER"]MPLSources(0,InternalName)=##class(%File).GetFileDateModified(filename)
s ^["USER"]MPLSources(1,InternalName)=##class(%RoutineMgr).TS(InternalName)
}
else
{
w "Error ExportSource: "_sc,!
d DecomposeStatus^%apiOBJ(sc,,"d")
}
q $$$OK
}
Method ExternalName(InternalName As %String) As %String
{
q ..GetClassFileName(InternalName)
}
/// Returns the path and filename to export a source
/// <u>Argument:</u> InternalName: name of the class as [package] . [classe] . [extension]
/// <u>Retour</u> Path and filename as:<br>
/// Root path: from de ^["USER"]MySources("base")
/// / [Directory from extension] cls, mac, int
/// / [Directory from package]
/// / [Class Name].txt
ClassMethod GetClassFileName(InternalName As %String) As %String
{
s name=$P(InternalName,".",1,$L(InternalName,".")-1),ext=$ZCONVERT($P(InternalName,".",$L(InternalName,".")),"l")
q:name="" ""
s fileExt=".txt"
i ext="cls" s fileExt=".cdl"
i ext="prj" s fileExt=".xml"
s filename=ext_"\"_$TRANSLATE(name,".","\")_fileExt
q $G(^["USER"]MySources("base"),"D:\")_filename
}
Method GetStatus(InternalName As %String, ByRef IsInSourceControl As %Boolean, ByRef Editable As %Boolean, ByRef IsCheckedOut As %Boolean, ByRef UserCheckedOut As %String) As %Status
{
s Editable=0,IsCheckedOut=0,UserCheckedOut=""
s filename=..ExternalName(InternalName)
s IsInSourceControl=(filename'=""&&(##class(%File).Exists(filename)))
i 'IsInSourceControl s Editable=1 q $$$OK
s UserCheckedOut=..Username
s Editable=1
q ..ImportSource(InternalName)
}
/// Import all classes and sources related to a project from files. Run it from terminal
ClassMethod ImportProject(projectName)
{
s class=""
f {
s class=$O(^oddPROJECT(projectName,"Items",class))
q:class=""
s ext=$O(^oddPROJECT(projectName,"Items",class,""))
i ext'="MAC" s class=class_"."_ext
w class," -> ",..ImportSource(class,1),!
}
}
/// Import a routine from a RSA formatted file
ClassMethod ImportRoutine(fileName) As %Status
{
i '##class(%File).Exists(fileName) w !,"File ",fileName," not found, skipping import" q $$$OK
//args: file,mode "Cache", selection: 0=all, overwrite: 2:always, compile: 1=yes, syntax, backup, showstat, langmode, pasting: 0:=no message
q $$rload^%Wr(fileName,"Cache",0,2,1,1,0,0)
}
ClassMethod ImportSource(InternalName As %String, force = 0) As %Status
{
i 'force
{
//verify source control is enabled on this server
s sc=$G(^["USER"]MPLSources("sourcecontrol"),0)
q:sc=0 $$$OK
}
//System file, continue
i $E(InternalName,1)="%" q $$$OK
s filename=..GetClassFileName(InternalName)
q:filename="" $$$OK
//file doen't exist, quit
i '##class(%File).Exists(filename) w !,"File ",filename," not found, skipping import" q $$$OK
i 'force
{
s comp=..DTCompare(##class(%File).GetFileDateModified(filename),$G(^["USER"]MySources(0,InternalName)))
i comp=0
{
w !,InternalName,"same version, skipping import"
q $$$OK
}
i comp<0
{
w !,InternalName,"file older, skipping import"
q $$$OK
}
}
//loading
s ext=$P(InternalName,".",$L(InternalName,"."))
i (ext="CLS")||(ext="PRJ")
{ //import a class
s sc=$SYSTEM.OBJ.Load(filename,"k-l-d") //-l-d
}
else
{
//import a routine
s sc=..ImportRoutine(filename)
}
i $$$ISOK(sc)
{
w !,"Imported '",InternalName,"' from file '",filename,"'"
s ^["USER"]MySources(0,InternalName)=##class(%File).GetFileDateModified(filename)
s ^["USER"]MySources(1,InternalName)=##class(%RoutineMgr).TS(InternalName)
}
else
{
w "ImportSource Error: "_sc,!
d DecomposeStatus^%apiOBJ(sc,.errors,"d")
}
q sc
}
Method IsInSourceControl(InternalName As %String) As %Boolean
{
q 1
}
/// Export the file if modified after compilation
Method OnAfterCompile(InternalName As %String) As %Status
{
q ..ExportSource(InternalName)
}
Method OnAfterSave(InternalName As %String, Object As %RegisteredObject) As %Status
{
q ..ExportSource(InternalName)
}
Method OnBeforeLoad(InternalName As %String) As %Status
{
q ..ImportSource(InternalName)
}
}