Interface for Source Control

= Interface for Source Control =

Introduction
Because our team is not skilled in subversion yet I have choosed not to integrate subversion into Studio at the moment For beginners could be more easy to use TortoiseSvn as a user friendly GUI for subversion communication. So, all I need is to force Studio to behave as a normal source editor, I mean store or classes and routines to local filesystem (and treat this local repository as a PRIMARY source, NOT DB) and then use third party user friedly software for revision controlling. For that purpose I created Interface, which serves for adding/deleting CLS and MAC files to/from Project. Thx a lot to Daniel Kutac from Intersystems CZ for help and hints :)

Include file
  <![CDATA[ /*		Include file */	#Include %sySite #Define RevisionControl #define PATHSEPARATOR	$s($$$ISWINDOWS:"\",1:"/1") #Define ERREXIT goto exit:($$$ISERR(sc)) #Define DBERRCHECK if ( (SQLCODE '= 0) && (SQLCODE '= 100) ) { set sc = $$$ERROR($$$GeneralError, $SYSTEM.SQL.SQLCODE(SQLCODE)) goto exit } #Define DBERRCHECK0 if ( (SQLCODE '= 0)) { set sc = $$$ERROR($$$GeneralError, $SYSTEM.SQL.SQLCODE(SQLCODE)) goto exit } #Define COMMIT if $TLEVEL TCOMMIT #Define ROLLBACK if $TLEVEL TROLLBACK 1 #Define ROLLBACKALL if $TLEVEL TROLLBACK #Define FILENAMEFROMPATH(%a) $List($Listfromstring(%a, $$$PATHSEPARATOR), -1) #Define CATCH(%a) set sc = %a.AsStatus s:($ze="") $ze=""_e.Code  d BACK^%ETN  $$$ERREXIT #Define EXCEP(%a) d:($$$ISERR(%a)) ##class(%Exception.StatusException).CreateFromStatus(%a) //ERRCODES #Define ERRBASE 100000 #Define DIRECTORYNOTCREATED ($$$ERRBASE + 1) #Define BADARGUMENT	($$$ERRBASE + 2) ]]> 
 * 1) IfNDef RevisionControl
 * 1) EndIf

Interface, class file
   <![CDATA[ This is a very simple interface for item project manipulation (MAC and CSP) files. You can export them, import them. Please see the first section of class variables. Probably you would to change them. Warning: This class should not be a member of your project! created by: jan.vlasak@aposteriori.cz for public use change log: -> version: 0.1, basic features, export/import of project items]]> RevisionControl %RegisteredObject 61215,32643.41447</TimeCreated>

<Property name="version">  Version of class</Description> <Type>%String</Type> <InitialExpression>"0.1"</InitialExpression> <Private>1</Private> </Property>

<UDLText name="T"> <Content><![CDATA[ //-

]]></Content> </UDLText>

<Property name="pathSeparator">  Path separator</Description> <Type>%String</Type> <InitialExpression>$$$PATHSEPARATOR</InitialExpression> <Private>1</Private> </Property>

<Property name="repoLocalPath">  Default path to repository on filesystem (root, without name of namespace)</Description> <Type>%String</Type> <InitialExpression>"d:\@Repo"</InitialExpression> <Private>1</Private> </Property>

<Property name="charset">  Charset used for export</Description> <Type>%String</Type> <InitialExpression>"CP1250"</InitialExpression> <Private>1</Private> </Property>

<Property name="projectName">  Name of watched project</Description> <InitialExpression>"Project"</InitialExpression> <Private>1</Private> </Property>

<UDLText name="T"> <Content><![CDATA[ //-

]]></Content> </UDLText>

<Property name="repoLocalDir">  Directory where items are exported (is setted in %OnNew)</Description> <Type>%String</Type> <Private>1</Private> </Property>

<Property name="currNamespace">  Name of current nameSpace</Description> <Type>%String</Type> <Private>1</Private> </Property>

<Method name="GetVersion">  Get version of class</Description> <ReturnType>%String</ReturnType> <Implementation><![CDATA[	q ..version ]]></Implementation> </Method>

<Method name="%OnNew">  Constructor. Local repository is created here (even if exist)</Description> <FormalSpec>initvalue:%CacheString</FormalSpec> <Private>1</Private> <ProcedureBlock>1</ProcedureBlock> <ReturnType>%Status</ReturnType> <ServerOnly>1</ServerOnly> <Implementation><![CDATA[ try {		set sc = $$$OK //get current namespace set ..currNamespace = $zutil(5) //create directory for export/import items set ..repoLocalDir = ..repoLocalPath _ ..pathSeparator _ ..currNamespace _ ..pathSeparator _ ..projectName set created = ##class(%File).CreateDirectoryChain(..repoLocalDir) if ( created = 0 ) {			set sc = $$$ERROR($$$DIRECTORYNOTCREATED, "Dir: " _ ..repoLocalDir) $$$EXCEP(sc) }		//-	}	catch e	{ $$$CATCH(e) }

exit q sc ]]></Implementation> </Method>

<Method name="ExportOne">  Export obj (class, macro, etc.) to filesystem as one XML file</Description> <FormalSpec>itemName:%String</FormalSpec> <ReturnType>%Status</ReturnType> <Implementation><![CDATA[ try {		set sc = $$$OK set exportFilePath = ..ExternalName(itemName) set sc = ##class(%SYSTEM.OBJ).Export(itemName, exportFilePath, "", "", ..charset) $$$EXCEP(sc) }	catch e	{ $$$CATCH(e) }

exit q sc ]]></Implementation> </Method>

<Method name="ExportAll">  Export all items in project to dir individually</Description> <ReturnType>%Status</ReturnType> <Implementation><![CDATA[ set sc = $$$OK try {		set sc = ..GetItemsInProject(.names, .types, .exportName) $$$EXCEP(sc) for i = 1: 1: exportName.Count {			set sc = ..ExportOne( exportName.GetAt(i) ) $$$EXCEP(sc) }	}	catch e	{ $$$CATCH(e) }

exit q sc ]]></Implementation> </Method>

<Method name="GetItemsInProject">  Get array of items in project (just CLS/MAC items)</Description> <FormalSpec>*itemName:%ArrayOfDataTypes,*itemType:%ArrayOfDataTypes,*exportName:%ArrayOfDataTypes</FormalSpec> <Private>1</Private> <ReturnType>%Status</ReturnType> <Implementation><![CDATA[ try {		set sc = $$$OK set itemName = ##class(%ArrayOfDataTypes).%New set itemType = ##class(%ArrayOfDataTypes).%New set exportName = ##class(%ArrayOfDataTypes).%New set r = ##class(%Library.ResultSet).%New("%Studio.Project:ProjectItemsList") set sc = r.Execute(..projectName) $$$EXCEP(sc) set i = 0 while ( r.Next(.sc)) {			$$$EXCEP(sc) set id = r.Data("ID") set name = r.Data("Name") set type = r.Data("Type") set inSourceControl = r.Data("InSourceControl") //not used yet if (type = "CLS") || (type = "MAC") {				set i = i + 1 set sc = itemName.SetAt(name, i)				$$$EXCEP(sc) set sc = itemType.SetAt(type, i)				$$$EXCEP(sc) if ( type = "MAC" ) {					set sc = exportName.SetAt( name, i ) $$$EXCEP(sc) }				else {					set sc = exportName.SetAt( name _ "." _ type, i ) $$$EXCEP(sc) }			} //end of if (type = "CLS") || (type = "MAC") } //end of while }	catch e	{ $$$CATCH(e) }

exit q sc ]]></Implementation> </Method>

<Method name="ImportOne"> <![CDATA[ Import one XML into namespace/project It takes few seconds to reload the project]]></Description> <FormalSpec>itemName:%String,importToProject:%Boolean=1</FormalSpec> <ReturnType>%Status</ReturnType> <Implementation><![CDATA[ try {			set sc = $System.OBJ.Load(..ExternalName(itemName), "-ck") //c = compile, k = dont delete int files $$$EXCEP(sc) if ( importToProject ) {			set project = ##class(%Studio.Project).%OpenId(..projectName, 1, .sc) $$$EXCEP(sc) set sc = project.AddItem(itemName) $$$EXCEP(sc) set sc = project.%Save $$$EXCEP(sc) }	}	catch e	{ $$$CATCH(e) } exit q sc ]]></Implementation> </Method>

<Method name="ImportAll"> <![CDATA[ Import all XML files from local repository  dont call this method twice  Firt kill this instance and then you can call it again.]]></Description> <FormalSpec>*files:%ArrayOfDataTypes,importToProject:%Boolean=1,withDeleteAll:%Boolean=1</FormalSpec> <ReturnType>%Status</ReturnType> <Implementation><![CDATA[ set sc = $$$OK try {		TSTART if ( withDeleteAll ) {			set sc = ..DeleteAll $$$EXCEP(sc) }		set files = ##class(%ArrayOfDataTypes).%New /// first, we must make an array of filenames located there set r = ##class(%Library.ResultSet).%New("%Library.File:FileSet") set sc = r.Execute(..repoLocalDir, "*.xml", "name") $$$EXCEP(sc) set i = 0 while (r.Next(.sc)) {			$$$EXCEP(sc) set i = i + 1 set sc = files.SetAt(r.Data("Name"), i)		} //-		for i = 1: 1: files.Count {			set filePath = files.GetAt(i) set fileName = $$$FILENAMEFROMPATH(filePath) //I want do delete .xml file extension set count = ##class(%Utility).Replace(fileName, ".xml", "", 0, .internalName) /// no replace :(			if ( count = 0 )			{				set sc = $$$ERROR($$$GeneralError, "No replace for filename: " _ fileName)				$$$EXCEP(sc)			}			set sc = ..ImportOne(internalName, importToProject)			$$$EXCEP(sc)		}	}	catch e	{		$$$CATCH(e)	}

exit if $$$ISERR(sc) {		$$$ROLLBACKALL }	else {		$$$COMMIT }

q sc ]]></Implementation> </Method>

<Method name="DeleteOne"> <![CDATA[ Delete one item in project/namespace We can manage only MAC/CLS items, others you have to manage manually]]></Description> <FormalSpec>itemName:%String,itemType:%String,removeFromProject:%Boolean=1</FormalSpec> <ReturnType>%Status</ReturnType> <Implementation><![CDATA[ try {		set sc = $$$OK if ( itemType = "CLS" ) {			d:(removeFromProject) ##class(%Studio.Project).DeleteItem(itemName) set sc = ##class(%SYSTEM.OBJ).Delete(itemName, "", "") $$$EXCEP(sc) }		elseif ( itemType = "MAC" ) {			d:(removeFromProject) ##class(%Studio.Project).DeleteItem(itemName) set sc = ##class(%Library.Routine).Delete(itemName) $$$EXCEP(sc) }		else {			set sc = $$$ERROR($$$BADARGUMENT, "type: " _ itemName) $$$EXCEP(sc) }	}	catch e	{ $$$CATCH(e) } exit q sc ]]></Implementation> </Method>

<Method name="DeleteAll"> <![CDATA[ Delete all items in project (not project itself) We can manage only MAC/CLS items, others you have to manage manually]]></Description> <ReturnType>%Status</ReturnType> <Implementation><![CDATA[ set sc = $$$OK try {		TSTART set sc = ..GetItemsInProject(.names, .types, .internalNames) $$$EXCEP(sc) for i = 1: 1: internalNames.Count {			set item = internalNames.GetAt(i) set type = types.GetAt(i) set sc = ..DeleteOne(item, type) $$$EXCEP(sc) }	}	catch e	{ $$$CATCH(e) }

exit if $$$ISERR(sc) {		$$$ROLLBACKALL }	else {		$$$COMMIT }

q sc ]]></Implementation> </Method>

<Method name="ExternalName"> <Description> Convert the internal name, e.g. TEST.MAC to an external name that is used to export the routine/class/csp item. This is often a filename to write the file out to.</Description> <FormalSpec>internalName:%String,fullPath:%Boolean=1</FormalSpec> <Private>1</Private> <ReturnType>%String</ReturnType> <Implementation><![CDATA[ // replace slashes in (csp,..) internalname by underscores set internalName = $tr(internalName,"/\","__") set len = $l(internalName, ".") set type = $zcvt($p(internalName, ".", len),"L") set external = $p(internalName,".", 1, len - 1) _ "." _ type _ ".xml" set:(fullPath) external = ..repoLocalDir _ ..pathSeparator _ external q external ]]></Implementation> </Method> </Class> </Export>