Skip to content

Commit

Permalink
Merge pull request #682 from intersystems/v0.9.x-fix-enable-download-ipm
Browse files Browse the repository at this point in the history
Fix miscellaneous problems in `enable`
  • Loading branch information
isc-tleavitt authored Jan 6, 2025
2 parents 4ebd3d8 + 3683bd0 commit e780e02
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 26 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased - 0.9.2+snapshot]
### Fixed
- #682 When enabling IPM in a namespace using local IPM caches, check for existence of `<iris-root>/lib/ipm/` beforing querying it.
- #682 Use more standard wording of mapping when enabling IPM
- #681 Convert specified namespaces to upper case for `enable` and `unmap` commands.
- #680, #683 Always export static files (README.md, LICENSE, requirements.txt, CHANGELOG.md) if existent

### Changed
- #682 When downloading IPM via the `enable` command from a remote registry, allow user to pass in the registry name (or get the only existent one), instead of the deployment enabled registry.

## [0.9.1] - 2024-12-18

### Added
Expand Down
56 changes: 30 additions & 26 deletions src/cls/IPM/Main.cls
Original file line number Diff line number Diff line change
Expand Up @@ -655,23 +655,24 @@ generate /my/path -export 00000,PacketName2,IgnorePacket2^00000,PacketName3,Igno
<modifier name="allow-upgrade" description="If specified, will also check for IPM version in specified namespaces and upgrade if version is lower than the target version. By default, this modifier is not ste and will not allow upgrade." />
<modifier name="map" aliases="m" description="If specified, will map IPM code from the current namespace-default code database rather than installing a separate copy." />
<modifier name="repos" aliases="r" description="If specified, will map repository settings across namespaces. Must be used together with -map." />
<modifier name="remote" value="true" description="If specified, will use fetch IPM versions from this remote repository. If this is omitted and multiple remote repositories are present, an error will occur." />
<modifier name="quiet" aliases="q" description="Quiet mode. By default, this modifier is not set and will display the contents onto the terminal/caller command line." />
<modifier name="preview" aliases="p" description="Preview what will be changed without actually making the changes." />
<modifier name="community" description="If specified, will reset repository to the community repository and map IPM to all namespaces along with the repository settings. This is functionaly equivalent to &quot;repo -delete-all&quot;, &quot;repo -reset-defaults&quot;, and &quot;enable -map -repos -globally&quot;. With this modifier, all other modifiers will be ignored."/>
<!-- Examples -->
<example description="Make IPM available in all namespaces (including %SYS) by mapping the version in the current namespace default routine database. Namespace-specific installation will override this.">
enable -map -globally
</example>
<example description="Install IPM version 0.3.4 in quiet mode in namespaces: NS1, NS2, NS3.">
enable -v 0.3.4 -q -ns NS1,NS2,NS3
<example description="Install IPM version 0.3.4 from the remote registry namd &quot;registry&quot; in quiet mode in namespaces: NS1, NS2, NS3.">
enable -v 0.3.4 -q -ns NS1,NS2,NS3 -remote registry
</example>
<example description="Install IPM in all non-%SYS explicit namespaces, and select version later in terminal prompt menu.">
<example description="Install IPM in all non-%SYS explicit namespaces, and select version later in terminal prompt menu. This works if there is only 1 remote repository configured.">
enable -globally
</example>
<example description="User wants to get the latest version of IPM from the registry server, and install it in all non-%SYS explicit namespaces.">
<example description="User wants to get the latest version of IPM from the registry server, and install it in all non-%SYS explicit namespaces. This works if there is only 1 remote repository configured.">
enable -v latest -globally
</example>
<example description="Install or upgrade IPM to latest IPM version in namespaces: NS1, NS2, NS3.">
<example description="Install or upgrade IPM to latest IPM version in namespaces: NS1, NS2, NS3. This works if there is only 1 remote repository configured.">
enable -v latest -allow-upgrade NS1,NS2,NS3
</example>
<example description="Reset repository to the community repository and map IPM to all namespaces along with the repository settings.">
Expand Down Expand Up @@ -2874,6 +2875,7 @@ ClassMethod EnableIPM(ByRef pCommandInfo)
Set namespaces = $$$ucase(namespaces)
Set allowUpgrade = $$$HasModifier(pCommandInfo,"allow-upgrade")
Set mapRepos = $$$HasModifier(pCommandInfo,"repos")
Set remoteName = $$$GetModifier(pCommandInfo,"remote")
Set useLocal = 1 // var to store the final decision of whether to use local manifest or get from server
Set targetVersion = "" // var to store the final version of IPM to be installed
Kill targetNamespaces // multi-dim array to store the final namespaces that need to install IPM
Expand Down Expand Up @@ -2931,11 +2933,11 @@ ClassMethod EnableIPM(ByRef pCommandInfo)
Continue
}
If 'quiet {
Write !,"Mapping %IPM package in "_namespace_" equivalently to "_initNamespace
Write !,"Mapping %IPM package in "_initNamespace_" equivalently to "_namespace
}
$$$ThrowOnError(##class(%IPM.Utils.Build).MapPackageEquivalently("%IPM",initNamespace,namespace))
If 'quiet {
Write !,"Mapping %IPM.* routines in "_namespace_" equivalently to "_initNamespace
Write !,"Mapping %IPM.* routines in "_initNamespace_" equivalently to "_namespace
}
$$$ThrowOnError(##class(%IPM.Utils.Build).MapRoutineEquivalently("%IPM.*",initNamespace,,namespace))
}
Expand Down Expand Up @@ -2967,7 +2969,7 @@ ClassMethod EnableIPM(ByRef pCommandInfo)
Continue
}
If 'quiet {
Write !,"Mapping IPM repository in "_namespace_" equivalently to "_initNamespace
Write !,"Mapping IPM repository in "_initNamespace_" equivalently to "_namespace
}
For suffix = "D", "S", "I" {
$$$ThrowOnError(##class(%IPM.Utils.Build).MapGlobalEquivalently("IPM.Repo.Definition"_suffix, initNamespace, namespace))
Expand Down Expand Up @@ -2995,23 +2997,25 @@ ClassMethod EnableIPM(ByRef pCommandInfo)
Set sc = statement.%PrepareClassQuery("%File", "FileSet")
$$$ThrowOnError(sc)
// Valid IPM installation manifest should be of format: ipm-0.0.1.xml
Set resultSet = statement.%Execute(XMLDir, "ipm-*.xml")
If (resultSet.%SQLCODE < 0) {
$$$ThrowSQLIfError(resultSet.%SQLCODE,resultSet.%Message)
}
Kill ipmLocalArray // multi-dim array to store local ipm manifests; ipmLocalArray(<version>)=<fileName>
Kill menuList // menu to let user choose which version of local ipm to install (if not in quiet mode and no version is specified)
While resultSet.%Next(.sc) {
$$$ThrowOnError(sc)
Set fileName = resultSet.%Get("Name")
If (resultSet.%Get("Type") = "F") {
// get the exact version string from filename
Set exactIPMVer = $Piece($Piece(fileName, "ipm-", 2, *), ".xml", 1, *-1)
Set ipmLocalArray(exactIPMVer) = fileName
Set menuList($Increment(menuList)) = exactIPMVer_" (local version)"
If ##class(%File).DirectoryExists(XMLDir) {
Set resultSet = statement.%Execute(XMLDir, "ipm-*.xml")
If (resultSet.%SQLCODE < 0) {
$$$ThrowSQLIfError(resultSet.%SQLCODE,resultSet.%Message)
}
Kill ipmLocalArray // multi-dim array to store local ipm manifests; ipmLocalArray(<version>)=<fileName>
Kill menuList // menu to let user choose which version of local ipm to install (if not in quiet mode and no version is specified)
While resultSet.%Next(.sc) {
$$$ThrowOnError(sc)
Set fileName = resultSet.%Get("Name")
If (resultSet.%Get("Type") = "F") {
// get the exact version string from filename
Set exactIPMVer = $Piece($Piece(fileName, "ipm-", 2, *), ".xml", 1, *-1)
Set ipmLocalArray(exactIPMVer) = fileName
Set menuList($Increment(menuList)) = exactIPMVer_" (local version)"
}
}
$$$ThrowOnError(sc)
}
$$$ThrowOnError(sc)

If ('$DATA(menuList) && localOnly) {
$$$ThrowOnError($$$ERROR($$$GeneralError,"No ipm-<version>.xml installer file is found locally in directory: "__XMLDir))
Expand Down Expand Up @@ -3057,7 +3061,7 @@ ClassMethod EnableIPM(ByRef pCommandInfo)
Set localIPMCount = $Get(menuList, 0)
If 'localOnly {
// Add remote version options to menuList
Set server = ##class(%IPM.Repo.Remote.Definition).DeploymentServerOpen(1,,.sc)
Set server = ##class(%IPM.Repo.Remote.Definition).GetOne(remoteName, .sc)
$$$ThrowOnError(sc)
If $IsObject(server) {
Set latestVersion = server.GetPackageService().GetLatestModuleVersion($$$IPMModuleName)
Expand Down Expand Up @@ -3128,7 +3132,7 @@ ClassMethod EnableIPM(ByRef pCommandInfo)

// 4. Now that we got all the namespaces that need to install IPM, do the actual installation
If 'useLocal {
Set server = ##class(%IPM.Repo.Remote.Definition).DeploymentServerOpen(1,,.sc)
Set server = ##class(%IPM.Repo.Remote.Definition).GetOne(remoteName, .sc)
$$$ThrowOnError(sc)
If $IsObject(server) {
Set packageService = server.GetPackageService()
Expand All @@ -3137,7 +3141,7 @@ ClassMethod EnableIPM(ByRef pCommandInfo)
Set ipmRef.Name = $$$IPMModuleName
If (targetVersion = "latest") {
// convert latest to semantic version so that it can be undestood by ModuleInfo class
Set server = ##class(%IPM.Repo.Remote.Definition).DeploymentServerOpen(1,,.sc)
Set server = ##class(%IPM.Repo.Remote.Definition).GetOne(remoteName, .sc)
$$$ThrowOnError(sc)
If $IsObject(server) {
Set targetVersion = server.GetPackageService().GetLatestModuleVersion($$$IPMModuleName)
Expand Down
23 changes: 23 additions & 0 deletions src/cls/IPM/Repo/Definition.cls
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,29 @@ SELECT Name FROM %IPM_Repo.Definition
ORDER BY %IPM_Repo.Definition_SortOrder(ID) DESC
}

/// If a name is provided, return the repo of this type with the name
/// Otherwise, return the only repo of this type in the system
/// If there are multiple repos (or no repos) of this type, return an error
ClassMethod GetOne(name As %String = "", Output sc As %Status) As %IPM.Repo.Definition
{
If $Get(name) '= "" {
Quit ..ServerDefinitionKeyOpen(name, , .sc)
}
Set tablename = $$$comClassKeyGet($classname(), $$$cCLASSsqlqualifiednameQ)
Set query = "SELECT id FROM " _ tablename // should be safe from SQL injection, since $classname() is safe
Set rs = ##class(%SQL.Statement).%ExecDirect(, query)
$$$ThrowSQLIfError(rs.%SQLCODE, rs.%Message)
Set list = ""
While rs.%Next() {
Set list = list _ $lb(rs.%Get("id"))
}
If $ListLength(list) = 1 {
Quit ..%OpenId($ListGet(list, 1), , .sc)
}
Set sc = $$$ERROR($$$GeneralError, "Unable to find a unique repo of type " _ $CLASSNAME())
Quit ""
}

Storage Default
{
<Data name="RepoDefinitionDefaultData">
Expand Down

0 comments on commit e780e02

Please sign in to comment.