文章
· 五月 24, 2023 阅读大约需 4 分钟

使用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文件, SourceDirNamespace是传入的参数。导入文件要在一个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文件

Using the Manifest

在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
讨论 (1)1
登录或注册以继续