使用Manifest
Manifest也许应该被翻译成“清单”, 字典上是这么解释的: 提供船舶及其货物和其他物品、乘客和船员的全面细节的文件,供海关官员使用,比如:飞机上的乘客或货物清单; 一辆货运列车的车厢清单。
在计算机语言中, Manifest可以是各种格式,用的最多的是xml和json,在IRIS中,manifest是xml格式的, 放在objectscript类的XDATA块里。
编写mainfest
IRIS用manifest来做配置。内部工具*%install*, 会读取manifest, 生成真正的objectscript代码来配置IRIS。我们来看个基本的例子。
基本用法
下面的User.Manifest.cls` ,它配置了IRIS的global buff, bbsize等等, 然后还创建了一个命名空间。
Include %occInclude
Class User.Manifest
{
ClassMethod setup(ByRef pVars, pLogLevel As %Integer = 3, pInstaller As %Installer.Installer, pLogger As %Installer.AbstractLogger) As %Status [ CodeMode = objectgenerator, Internal ]
{
Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "MyInstall")
}
XData MyInstall [ XMLNamespace = INSTALLER ]{
<Manifest>
<SystemSetting Name="Config.config.gmheap" Value="50000"/>
<SystemSetting Name="Config.config.locksiz" Value="5000000"/>
<SystemSetting Name="Config.config.routines" Value="256"/>
<SystemSetting Name="Config.config.globals8kb" Value="600"/>
<SystemSetting Name="Config.config.wijdir" Value="/cache/wij"/>
<SystemSetting Name="Config.Journal.CurrentDirectory" Value="/journal1"/>
<SystemSetting Name="Config.Journal.AlternateDirectory" Value="/journal2"/>
<SystemSetting Name="Config.Miscellaneous.EnableLongStrings" Value="1"/>
<Namespace Name="TUOTANTO" Create="yes" Code="TUOTANTO-R" Data="TUOTANTO-D">
<Configuration>
<Database Name="TUOTANTO-R" Create="yes" Dir="/cache/database/TUOTANTO-R"/>
<Database Name="TUOTANTO-D" Create="yes" Dir="/cache/database/TUOTANTO-D"/>
</Configuration>
</Namespace>
</Manifest>
}
}
稍微解释一下代码:
Include %occInclude是必须的setup()用来读取manifest的内容,完成配置工作。用户基本不用修改这个method。mainifest本身的逻辑层次很清楚,要配置什么内容查查文档都可以。上面的manifest只是个示意,真正用起来可以需要非常多的配置项,比如namespace, database的配置,有很多的标签可选。
传参数给manifest
调用manifest的method, 也就是例子里的setup(), 注意第一个参数是ByRef pVars。这是objectscript里常用的By referrence的传参方式。请看下面的例子:
Include %occInclude
Class User.Manifest
{
ClassMethod main(){
Set pVars("Namespace")="MYNAMESPACE"
Set pVars("AnotherKey")= "AnotherValue"
$$$ThrowOnError(..CreateNamespace(.pVars))
}
ClassMethod CreateNamespace(ByRef pVars, pLogLevel As %Integer = 3, pInstaller As %Installer.Installer, pLogger As %Installer.AbstractLogger) As %Status [ CodeMode = objectgenerator, Internal ]{
Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "CreateNamespace")
}
XData CreateNamespace [ XMLNamespace = INSTALLER ]{
<Manifest>
<Log Text="This is the content of ${AnotherKey}" Level="0" />
<Namespace Name="${Namespace}" Create="yes" Code="${Namespace}" Data="${Namespace}" Ensemble="1">
<Configuration>
<Database Name="${Namespace}" Create="yes" Dir="${MGRDIR}/${Namespace}" Resource="%DB_${Namespace}" PublicPermissions="RW" MountAtStartup="true" />
</Configuration>
</Namespace>
</Manifest>
}
}
上面code在main()里定义了一个pVars, 放了两个key-value, 用来调用CreateName()。 定义的namespace在manifest用到了, Anotherkey被用在了log里, 只是一个示意。
注意这个定义: Dir="${MGRDIR}/${Namespace}"。 其中的MGRDIR不需要自己定义。Manifest有一堆自己定义的Variable, 用的最多的是 CFGDIR, CSPDIR, INSTALLDIR, MGRDIR, PORT等等。具体列表见文档。
更多的用法
下面这个例子包括了import文件和copy文件, SourceDir和Namespace是传入的参数。导入文件要在一个namespace的定义里面, 拷贝文件和命名空间无关。
<Manifest>
<Namespace Name="${Namespace}">
<Import File="${SourceDir}/code.xml" Flags="ck" Recurse="1"/>
</Namespace>
<CopyDir Src="${SourceDir}/xslfiles" Target="${CSPDIR}/xslt" IgnoreErrors="0"/>
<CopyFile Src="${SourceDir}/a.html" Target="${CSPDIR}/hcc" IgnoreErrors="0"/>
</Manifest>
CSPApplication
在manifest里定义cspapplication不难,麻烦的是不同的版本使用的标签上会有修改。下面给了一个例子。
<Manifest>
<Namespace Name="flagger">
<CSPApplication CSPZENEnabled="1" LoginClass="/csp/flagger/Flagger.LoginAuth.cls" CustomErrorPage="/csperror.csp" ChangePasswordPage="/csp/flagger/ChangePassword.cls" AutoCompile="1" Url="/csp/flagger" IsNamespaceDefault="1" InboundWebServicesEnabled="1" Recurse="1" AuthenticationMethods="64" DefaultTimeout="900" Directory="${CSPDIR}flagger" UseSessionCookie="2" CookiePath="/csp/flagger/" ServeFiles="1" ServeFilesTimeout="3600"/>
</Namespace>
</Manifest>
调用代码的例子
<Manifest>
<Role Name="${PMGNAMESPACE}" Description="Works User Role for ${PMGNAMESPACE} Namespace" Resources='"_tInstaller.Evaluate("${PMGDbResource}:RW,PMG:RWU")_"' RolesGranted="" />
<!-- set locale -->
<Namespace Name="%SYS" Create="no">
<Log Text="Changing the Locale" Level="0" />
<Invoke Class="Config.NLS.Locales" Method="Install" CheckStatus="true">
<Arg Value="chew" />
</Invoke>
</Namespace>
<Namespace Name="flagger">
<Invoke Class="IRISConfig.Installer" Method="LoadTransactionalData" CheckStatus="true">
<Arg name="pNamespace" Value="${Namespace}"/>
</Invoke>
</Namespace>
</Manifest>
创建User, Role
<Manifest>
<User Username="ISC" PasswordVar="PASSWORD" Roles="%All" Fullname="ISC" Comment=""/>
<Role Name="${PMGNAMESPACE}" Description="Works User Role for ${PMGNAMESPACE} Namespace" Resources='"_tInstaller.Evaluate("${PMGDbResource}:RW,PMG:RWU")_"' RolesGranted="" />
</Manifest>
Nampespace Mapping
<Manifest>
<Namespace Name="FHIRNS">
<Configuration>
<Database Name="FHIRNS"/>
<GlobalMapping Global="%SYS" From="IRISSYS"/>
<GlobalMapping Global="OAuth2.*" From="HSSYS"/>
<GlobalMapping Global="SchemaMap.*" From="HSLIB"/>
<ClassMapping Package="HS" From="HSLIB"/>
<ClassMapping Package="HS.Local" From="HSCUSTOM"/>
<ClassMapping Package="HSMOD" From="HSLIB"/>
<ClassMapping Package="SchemaMap" From="HSLIB"/>
<RoutineMapping Routines="HS.*" From="HSLIB"/>
<RoutineMapping Routines="HSMOD.*" Type="INC" From="HSLIB"/>
<RoutineMapping Routines="HSMOD.*" From="HSLIB"/>
<RoutineMapping Routines="SchemaMap.*" From="HSLIB"/>
</Configuration>
</Namespace>
</Manifest>
其他还有很多的用法。想了解更多,可以看看文档说明里的Tag列表, 和template。
怎么执行cls文件
在Terminal里执行
%SYS>do ##class(MyPackage.MyInstaller).setup()
或者, 带上参数
%SYS>set vars("SourceDir")="c:\myinstaller"
%SYS>set vars("Updated")="Yes"
%SYS>do ##class(MyPackage.MyInstaller).setup(.vars,3)
During IRIS安装?
Export the manifest class as DefaultInstallerClass.xml to the same directory where the InterSystems IRIS install (either .msi, setup_irisdb.exe, or irisinstall) is run. It is imported into %SYS and compiled, and the setup() method is executed.
那么是irisinstall里面的什么语句在执行manifest呢?
# script, 用ISC_INSTALLER_MANIFEST, installer-manifest-example.xml
[root@silent jhvinstall]# cat cache_install.sh
#!/bin/bash
echo -n "Installing Cache..."
ISC_INSTALLER_MANIFEST=$3 ISC_PACKAGE_INSTANCENAME=$1 ISC_PACKAGE_INSTALLDIR=$2 ISC_PACKAGE_UNICODE="Y" ISC_PACKAGE_INITIAL_SECURITY="Minimal" ISC_PACKAGE_MGRUSER="cacheusr" ISC_PACKAGE_MGRGROUP="cacheusr"
ISC_PACKAGE_USER_PASSWORD="sys" ./cinstall_silent
[root@silent jhvinstall]# ./cache_install.sh CACHE6 "/cache/tmpcache6" "/tmp/installer-manifest-example.xml"
Installing Cache...
写一个脚本执行
这里给一个脚本的例子,简短,但内容很丰富。
#!/bin/bash
# Usage install.sh [instanceName] [password]
instanceName=$1
password=$2
DIR=$(pwd)
ClassImportDir=$DIR/install
NameSpace="ENSDEMO"
CspPath="/csp/ensdemo"
SrcDir=$DIR/src/CLS
DirFront=$DIR/src/CSP/csp/demo
irissession $instanceName -U USER <<EOF
SuperUser
$password
do \$system.OBJ.ImportDir("$ClassImportDir","*.cls","cubk",.errors,1)
write "installer导入成功"
Set pVars("DirBin")="$DIR/ENSDEMO"
Set pVars("DirFront")="$DirFront"
Set pVars("NAMESPACE")="$NameSpace"
Do ##class(App.Installer).setup(.pVars)
zn "%SYS"
set props("DeepSeeEnabled")=1
set sc=##class(Security.Applications).Modify("$CspPath", .props)
zn "$NameSpace"
do \$system.OBJ.ImportDir("$SrcDir","*.cls","cubk",.errors,1)
halt
EOF