Permalink
Switch branches/tags
Nothing to show
Find file Copy path
506 lines (458 sloc) 18 KB
<?xml version="1.0" encoding="UTF-8"?>
<Export generator="Cache" version="25">
<Class name="MDX2JSON.Installer">
<TimeCreated>63481,77165.410085</TimeCreated>
<XData name="Install">
<Description>
See generated code in zsetup+1^MDX2JSON.Installer.1
todo add optional parameter WEBAPP to Alter web app name if it needs to have another then namespace name</Description>
<XMLNamespace>INSTALLER</XMLNamespace>
<Data><![CDATA[
<Manifest>
<IfNotDef Var="Namespace">
<Var Name="Namespace" Value="MDX2JSON"/>
<Log Text="Set namespace to ${Namespace}" Level="0"/>
</IfNotDef>
<IfNotDef Var="Import">
<Var Name="Import" Value="1"/>
<Log Text="Set Import to 1" Level="0"/>
</IfNotDef>
<Role Name="MDX2JSONSettings" Description="Role to access and set default MDX2JSON settings for an App"/>
<If Condition='(##class(Config.Namespaces).Exists("${Namespace}")=0)'>
<Log Text="Creating namespace ${Namespace}" Level="0"/>
<Namespace Name="${Namespace}" Create="yes" Code="${Namespace}" Ensemble="" Data="${Namespace}">
<Configuration>
<Database Name="${Namespace}" Dir="${MGRDIR}/${Namespace}" Create="yes" MountRequired="true" Resource="%DB_${Namespace}" PublicPermissions="RW" MountAtStartup="true"/>
</Configuration>
</Namespace>
<Log Text="End Creating namespace ${Namespace}" Level="0"/>
</If>
<Namespace Name="${Namespace}" Create="no">
<If Condition="${Import}">
<IfDef Var="SourceDir">
<Log Text="SourceDir defined - offline install from ${SourceDir}" Level="0"/>
<Import File="${SourceDir}"/>
</IfDef>
<IfNotDef Var="SourceDir">
<Log Text="SourceDir undefined - online install from GitHub" Level="0"/>
<RunInstall Class="MDX2JSON.Installer" Method="DownloadFromGitHub"/>
</IfNotDef>
</If>
<If Condition='(##class(Security.Applications).Exists("/"_"${Namespace}")=0)'>
<Log Text="Creating web application /${Namespace}" Level="0"/>
<!-- This method creates conflits with web-server. Kept for reference purposes. See ##class(%EnsembleMgr).createPortalApp()
<CSPApplication Url="/${Namespace}" Directory="" AuthenticationMethods="64" IsNamespaceDefault="false" />-->
<RunInstall Class="MDX2JSON.Installer" Method="CreateWebApp"/>
</If>
</Namespace>
<If Condition='(##class(Config.Namespaces).Exists("%All")=0)'>
<Log Text="Creating namespace %All" Level="0"/>
<Namespace Name="%All" Create="yes" Code="CACHETEMP" Data="CACHETEMP" Ensemble="0">
<Configuration>
<Log Text="Mapping MDX2JSON package to %All namespace" Level="0"/>
<ClassMapping From="${Namespace}" Package="MDX2JSON"/>
<GlobalMapping From="${Namespace}" Global="MDX2JSON"/>
</Configuration>
</Namespace>
</If>
<Log Text="Mapping MDX2JSON package to Samples namespace" Level="0"/>
<If Condition='##class(Config.Namespaces).Exists("Samples")'>
<Namespace Name="Samples" Create="no" Code="SAMPLES" Data="SAMPLES" Ensemble="0">
<Configuration>
<ClassMapping From="${Namespace}" Package="MDX2JSON"/>
<GlobalMapping From="${Namespace}" Global="MDX2JSON"/>
</Configuration>
</Namespace>
</If>
<!--<RunInstall Class="MDX2JSON.Installer" Method="createrole" />-->
<IfDef Var="User" >
<IfDef Var="Password">
<User Username="${User}" Namespace="${Namespace}" PasswordVar="Password" Roles="MDX2JSON" Enabled="true" Comment="MDX2JSON user" Fullname="MDX2JSON user"/>
</IfDef>
<IfNotDef Var="Password">
<Log Text="You specified username but not a password" Level="0"/>
</IfNotDef>
</IfDef>
</Manifest>
]]></Data>
</XData>
<Method name="setup">
<Description>
This is a method generator whose code is generated by XGL.
Main setup method
Set pVars("User")="web"
Set pVars("Password")="dsweb"
Set pVars("Namespace")="TEMP3"
Set pVars("Import")=1
Set pVars("SourceDir")="C:\temp\MDX2JSON\MDX2JSON"
Do ##class(MDX2JSON.Installer).setup(.pVars)</Description>
<Internal>1</Internal>
<ClassMethod>1</ClassMethod>
<CodeMode>objectgenerator</CodeMode>
<FormalSpec><![CDATA[&pVars,pLogLevel:%Integer=0,pInstaller:%Installer.Installer]]></FormalSpec>
<ReturnType>%Status</ReturnType>
<Implementation><![CDATA[ Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "Install")
]]></Implementation>
</Method>
<Method name="CreateWebApp">
<ClassMethod>1</ClassMethod>
<FormalSpec>pVars,pLogLevel,tInstaller</FormalSpec>
<ReturnType>%Status</ReturnType>
<Implementation><![CDATA[
Set Namespace=tInstaller.Evaluate("${Namespace}")
Do tInstaller.PushNS("%SYS")
Do ##class(Security.System).GetInstallationSecuritySetting(.security)
If (security="None") {
Set cspProperties("AutheEnabled") = $$$AutheUnauthenticated
} Else {
Set cspProperties("AutheEnabled") = $$$AutheCache // Password
}
Set cspProperties("NameSpace") = Namespace
Set cspProperties("IsNameSpaceDefault") = $$$YES
Set cspProperties("DispatchClass") = "MDX2JSON.REST"
Set tSC = ##class(Security.Applications).Create("/"_Namespace, .cspProperties)
Do tInstaller.PopNS()
If $$$ISERR(tSC) Throw ##class(%Installer.Exception).CreateFromStatus(tSC)
Quit $$$OK
]]></Implementation>
</Method>
<Method name="DownloadFromGitHub">
<ClassMethod>1</ClassMethod>
<FormalSpec>pVars,pLogLevel,tInstaller</FormalSpec>
<ReturnType>%Status</ReturnType>
<Implementation><![CDATA[
Set Namespace=tInstaller.Evaluate("${Namespace}")
Do tInstaller.PushNS("%SYS")
Set tSC = ..Update(Namespace, "intersystems-ru", "Cache-MDX2JSON", "master")
Do tInstaller.PopNS()
If $$$ISERR(tSC) Throw ##class(%Installer.Exception).CreateFromStatus(tSC)
quit $$$OK
]]></Implementation>
</Method>
<Method name="Update">
<Description><![CDATA[
Downloads and compiles GitHub repository.<br>
<b>Owner</b> - The name of the repository owner.<br>
<b>Repository</b> - The name of the repository.<br>
<b>Branch</b> - The name of the commit/branch/tag. If skipped the repository’s default branch (usually master) would be used.<br>
<b>Username</b> - GitHub user, who has access to repository. Optional for public repositories.<br>
<b>Password</b> - GitHub password, corresponding to Username. Optional for public repositories.<br>
Note, that with Username, you can make up to 5,000 requests per hour.
For unauthenticated requests, the rate limit allows to make up to 60 requests per hour.
Unauthenticated requests are associated with an IP address.<br>
<b>Namespace</b> - Namespace, where to download and compile repository.<br>
For example in the repository: https://github.com/intersystems-ru/Cache-MDX2JSON<br>
Owner - intersystems-ru, Repository - Cache-MDX2JSON.<br> ]]></Description>
<ClassMethod>1</ClassMethod>
<FormalSpec>Namespace=$Namespace,Owner:%String="intersystems-ru",Repository:%String="Cache-MDX2JSON",Branch:%String,Username:%String,Password:%String</FormalSpec>
<ReturnType>%Status</ReturnType>
<Implementation><![CDATA[
Set namespace = $Namespace
Set SSLConfig = "GitHub"
Zn "%SYS"
Do:'##class(Security.SSLConfigs).Exists(SSLConfig) ##class(Security.SSLConfigs).Create(SSLConfig)
Set req=##class(%Net.HttpRequest).%New()
Set req.Https=1
Set req.SSLConfiguration=SSLConfig
Set req.Server="api.github.com"
Set req.Location = "repos/" _ Owner _ "/" _ Repository _ "/contents" // as described in https://developer.github.com/v3/repos/
Do:$d(Branch) req.SetParam("ref",Branch) // if omitted the repository’s default branch (usually master) would be used
Do req.SetHeader("Accept","application/vnd.github.v3+json") // we want to receive API v3
If ($d(Username) && $d(Password)) { // supply Username and Passwor, if both are provided. GitHub accept Basic Auth
Set req.Username = Username // https://developer.github.com/v3/auth/
Set req.Password = Password
}
Set links = ##class(%ListOfDataTypes).%New()
Set st = ..ProcessDirectory("",req,.links)
Return:$$$ISERR(st) st
Zn Namespace
Set st = ..DownloadFiles(links,req,.list)
Set st2 = $system.OBJ.CompileList(.list)
Zn namespace
Return $$$ADDSC(st, st2)
]]></Implementation>
</Method>
<Method name="ProcessDirectory">
<Description><![CDATA[
Process one directory of GitHub repository. Recursive.<br>
<b>Path</b> -Internal repository path. Root is empty string<br>
<b>Request</b> - Authenticated/Set %Net.HttpRequest object.<br>
<b>Links</b> - List of links to raw files (which satisfy <b>IsCacheFile</b> conditions) from repository.<br>]]></Description>
<ClassMethod>1</ClassMethod>
<FormalSpec><![CDATA[Path:%String="",Request:%Net.HttpRequest,&Links:%ListOfDataTypes]]></FormalSpec>
<ReturnType>%Status</ReturnType>
<Implementation><![CDATA[
Set location = Request.Location
Set Request.Location = Request.Location _ Path
Set st = Request.Get(,,$$$NO)
Return:$$$ISERR(st) st
Return:(Request.HttpResponse.StatusCode = 404) $$$ERROR($$$GeneralError,"Repository doesn't exist OR you don't have access")
Return:((Request.HttpResponse.StatusCode = 403) && (Request.HttpResponse.GetHeader("X-RATELIMIT-REMAINING")=0)) $$$ERROR($$$GeneralError,"API rate limit exceeded. Try logging in.")
Return:(Request.HttpResponse.StatusCode '= 200) $$$ERROR($$$GeneralError,"Received " _ Request.HttpResponse.StatusCode _ " status, expected 200")
#dim objects As List of %ZEN.proxyObject
#dim obj As %ZEN.proxyObject
Set st = ##class(%ZEN.Auxiliary.jsonProvider).%ConvertJSONToObject(Request.HttpResponse.Data,,.objects,1)
Return:$$$ISERR(st) st
For i = 1:1:objects.Count() {
Set obj = objects.GetAt(i)
If (obj.type = "dir") {
Set st = ..ProcessDirectory("/"_obj.name,Request,.Links)
Return:$$$ISERR(st) st
} ElseIf (obj.type = "file") {
Do:..IsCacheFile(obj) Links.Insert(obj."download_url")
} Else {
// obj.type = "symlink" or obj.type = "submodule"
}
}
Set Request.Location = location // to keep track of where in the repository tree we are
Return $$$OK
]]></Implementation>
</Method>
<Method name="IsCacheFile">
<Description>
Check that incoming file is the one you need.</Description>
<ClassMethod>1</ClassMethod>
<FormalSpec>File:%ZEN.proxyObject</FormalSpec>
<ReturnType>%Boolean</ReturnType>
<Implementation><![CDATA[
Set extensions = ",xml,cls,csp,csr,mac,int,bas,inc,gbl,prj,obj,pkg,gof,"
Return:($L(File.name,".")=1) 0 //no extension
Set File.Extension = $P(File.name,".",$L(File.name,"."))
Return $F(extensions,","_$ZCVT(File.Extension,"l")_",")
]]></Implementation>
</Method>
<Method name="DownloadFiles">
<Description><![CDATA[
Download list of files on https://raw.githubusercontent.com/ server.<br>
<b>Links</b> - List of links to raw files.<br>
<b>Request</b> - Authenticated/Set %Net.HttpRequest object.<br>
<b>loadedlist</b> - Returns an array of the items loaded. ]]></Description>
<ClassMethod>1</ClassMethod>
<FormalSpec>Links:%ListOfDataTypes,Request:%Net.HttpRequest,*Items</FormalSpec>
<ReturnType>%Status</ReturnType>
<Implementation><![CDATA[
Kill Items
Set Request.Server = "raw.githubusercontent.com"
Set st = $$$OK
For i = 1:1:Links.Count() {
Set streq = Request.Get($e(Links.GetAt(i),35,*)) // Remove "https://raw.githubusercontent.com/" from URL.
Set:$$$ISERR(streq) st=$$$ADDSC(st, streq)
Set binarystream = Request.HttpResponse.Data
Do binarystream.Rewind() // just in case
Set stream=##class(%GlobalCharacterStream).%New() //translating binary stream into character stream
While 'binarystream.AtEnd {
Do stream.Write(binarystream.Read())
}
Do stream.Rewind()
Set stload = $system.OBJ.LoadStream(stream,"",.error,.items,,,,"UTF8")
Set:$$$ISERR(stload) st=$$$ADDSC(st, stload)
Merge Items = items // Does not overwrite existing array keys: Items(itemname)=""
}
Set Request.Server="api.github.com"
Return st
]]></Implementation>
</Method>
<Method name="Uninstall">
<Description>
Wrapper method. Uninstalls MDX2JSON (deletes MDX2JSON and %All namespaces, DBs, web apps)</Description>
<ClassMethod>1</ClassMethod>
<FormalSpec>NamespaceList="%All,MDX2JSON"</FormalSpec>
<Implementation><![CDATA[
For i=1:1:$L(NamespaceList,",") {
Set Namespace = $P(NamespaceList,",",i)
Write "Start deleting " _ Namespace,!
Write $System.Status.GetErrorText(..DeleteNamespace(Namespace))
Write "End deleting " _ Namespace,!
Write "Start deleting roles",!
Write $System.Status.GetErrorText(..DeleteAccess("%DB_MDX2JSON"))
Write "End deleting roles"
}
]]></Implementation>
</Method>
<Method name="DeleteAccess">
<Description><![CDATA[
Delete <var>Role</var> (and resource)]]></Description>
<ClassMethod>1</ClassMethod>
<FormalSpec>Role="%DB_MDX2JSON"</FormalSpec>
<ReturnType>%Status</ReturnType>
<Implementation><![CDATA[
New $Namespace
Set $Namespace = "%SYS"
Set st = $$$OK
Set st = ##class(Security.Resources).Delete(Role)
Set st = $$$ADDSC(st, ##class(Security.Roles).Delete(Role))
Return st
]]></Implementation>
</Method>
<Method name="DeleteNamespace">
<Description><![CDATA[
Delete <var>Namespace</var>, related web apps and databases]]></Description>
<ClassMethod>1</ClassMethod>
<FormalSpec>Namespace=$Namespace</FormalSpec>
<ReturnType>%Status</ReturnType>
<Implementation><![CDATA[
// Based on %CSP.UI.Portal.Dialog.NamespaceDelete:SaveData and
// %CSP.UI.Portal.Dialog.DatabaseDelete:Delete
Try {
New $Namespace
Set $Namespace = "%SYS"
Set st = $$$OK
If ##Class(Config.Namespaces).Exists(Namespace,.NamespaceObj) {
// Get databases names
Set Routines = NamespaceObj.Routines
Set Globals = NamespaceObj.Globals
Kill NamespaceObj
// Remove Ensemble namespace
If ((##class(%Library.EnsembleMgr).IsEnsembleInstalled() || ##class(%Library.EnsembleMgr).IsHealthShareInstalled())) {
Set st1 = ##class(%Library.EnsembleMgr).DisableNamespace(Namespace)
Set st = $$$ADDSC(st, st1)
}
Set st1 = ..DeleteWebApps(Namespace)
Set st = $$$ADDSC(st, st1)
Set st1 = ..DeletePackageMappings("", Routines)
Set st = $$$ADDSC(st, st1)
Set st1 = ..DeleteGlobalMappings("", Globals)
Set st = $$$ADDSC(st, st1)
Set st1 = ##class(Config.Namespaces).Delete(Namespace)
Set st = $$$ADDSC(st, st1)
Set st1 = ..DeleteDatabase(Routines)
Set st = $$$ADDSC(st, st1)
If Globals'=Routines {
Set st1 = ..DeleteDatabase(Globals)
Set st = $$$ADDSC(st, st1)
}
} Else {
Set st = $$$ERROR($$$GeneralError, "Namespace " _ Namespace _ " does not exist")
}
} Catch ex {
Set st = $$$ADDSC(st, ex.AsStatus())
}
Return st
]]></Implementation>
</Method>
<Method name="DeleteDatabase">
<Description><![CDATA[
Delete all webapps in a <var>Namespace</var>, also dele]]></Description>
<ClassMethod>1</ClassMethod>
<FormalSpec>Database:%String="MDX2JSON"</FormalSpec>
<ReturnType>%Status</ReturnType>
<Implementation><![CDATA[
New $Namespace
Set $Namespace = "%SYS"
Set st = $$$OK
Try {
If ##Class(Config.Databases).Get(Database,.Properties) {
Set Directory = $G(Properties("Directory"))
Set st1 = ##class(SYS.Database).DismountDatabase(Directory)
Set st = $$$ADDSC(st, st1)
Set st1 = ##class(Config.Databases).Delete(Database)
Set st = $$$ADDSC(st, st1)
Set st1 = ##class(SYS.Database).DeleteDatabase(Directory)
Set st = $$$ADDSC(st, st1)
Do ##class(%File).RemoveDirectoryTree(Directory)
Set st = $$$ADDSC(st, %objlasterror)
} Else {
Set st = $$$ERROR($$$GeneralError, "Database " _ Database _ " does not exist")
}
} Catch(ex) {
Set st = $$$ADDSC(st ,ex.AsStatus())
}
Return st
]]></Implementation>
</Method>
<Method name="DeleteWebApps">
<Description><![CDATA[
Delete all webapps in a <var>Namespace</var>, also dele]]></Description>
<ClassMethod>1</ClassMethod>
<FormalSpec>Namespace:%String="MDX2JSON",ClearPath:%Boolean=0</FormalSpec>
<ReturnType>%Status</ReturnType>
<Implementation><![CDATA[
New $Namespace
Set $Namespace = "%SYS"
Set st = $$$OK
Try {
#Dim rs As %SQL.StatementResult
Set rs = ##class(%SQL.Statement).%ExecDirect(,"SELECT Name, Path FROM Security.Applications WHERE NameSpace = ?", Namespace)
While rs.%Next() {
Set st1 = ##class(Security.Applications).Delete(rs.Name)
Set st = $$$ADDSC(st, st1)
If ((ClearPath) && (rs.Path'="")) {
Do ##class(%File).RemoveDirectoryTree(rs.Path)
Set st = $$$ADDSC(st, %objlasterror)
}
}
} Catch(ex) {
Set st = $$$ADDSC(st, ex.AsStatus())
}
Return st
]]></Implementation>
</Method>
<Method name="DeletePackageMappings">
<Description><![CDATA[
Delete all mappings of <var>Package</var> in <var>Database</var> from all Namespaces]]></Description>
<ClassMethod>1</ClassMethod>
<FormalSpec>Package:%String="",Database:%String="MDX2JSON"</FormalSpec>
<ReturnType>%Status</ReturnType>
<Implementation><![CDATA[
New $Namespace
Set $Namespace = "%SYS"
Set st = $$$OK
Try {
#Dim rs As %SQL.StatementResult
Set rs = ##class(%SQL.Statement).%ExecDirect(,"SELECT Namespace FROM Config.MapPackages WHERE Name %STARTSWITH ? AND Database = ?", Package, Database)
While rs.%Next() {
Set st1 = ##Class(Config.MapPackages).Delete(rs.%Get("Namespace"), Database)
Set st = $$$ADDSC(st, st1)
Set st1 = ..ActivateConfiguration(rs.Namespace)
Set st = $$$ADDSC(st, st1)
}
} Catch(ex) {
Set st = $$$ADDSC(st, ex.AsStatus())
}
Return st
]]></Implementation>
</Method>
<Method name="DeleteGlobalMappings">
<Description><![CDATA[
Delete all mappings of <var>Global</var> in <var>Database</var> from all Namespaces]]></Description>
<ClassMethod>1</ClassMethod>
<FormalSpec>Global:%String="",Database:%String="MDX2JSON"</FormalSpec>
<ReturnType>%Status</ReturnType>
<Implementation><![CDATA[
New $Namespace
Set $Namespace = "%SYS"
Set st = $$$OK
Try {
#Dim rs As %SQL.StatementResult
Set rs = ##class(%SQL.Statement).%ExecDirect(,"SELECT Namespace FROM Config.MapGlobals WHERE Name %STARTSWITH ? AND Database = ?", Global, Database)
While rs.%Next() {
Set st1 = ##Class(Config.MapGlobals).Delete(rs.Namespace, Database)
Set st = $$$ADDSC(st, st1)
Set st1 = ..ActivateConfiguration(rs.Namespace)
Set st = $$$ADDSC(st, st1)
}
} Catch(ex) {
Set st = $$$ADDSC(st, ex.AsStatus())
}
Return st
]]></Implementation>
</Method>
<Method name="ActivateConfiguration">
<Description><![CDATA[
Activate a configuration in a <var>Namespace</var>]]></Description>
<ClassMethod>1</ClassMethod>
<FormalSpec>Namespace:%String</FormalSpec>
<ReturnType>%Status</ReturnType>
<Implementation><![CDATA[
Set st = $$$OK
Set Namespace=$ZCVT(Namespace,"U")
Set st = ##Class(Config.CPF).Write()
Return:$$$ISERR(st) st
Set st = ##Class(Config.Map).MoveToActive(Namespace)
Return:$$$ISERR(st) st
Set st = ##Class(Config.Namespaces).Load(Namespace)
Return st
]]></Implementation>
</Method>
</Class>
</Export>