diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9c8d5dea..e1c2ab57 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.9.1] - 2024-12-18
+
+### Added
+- #663 Added support for mapping of repository settings along with, or in addition to, IPM package and routines
+- #663 Added functionality to always unmap repository settings when IPM package and routines are unmapped
+- #663 Added support for unmapping of repository settings alone
+- #663 Added support for `enable -community`, which resets repository settings to default and maps IPM along with repo settings globally
+
+### Fixed
+- #663 Improved error output and instructions in the language extension when "zpm" is run from a namespace without IPM
+
## [0.9.0] - 2024-12-16
### Added
diff --git a/README.md b/README.md
index c65ec88b..9f897600 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,29 @@
-# ObjectScript Package Manager Client - ZPM
+# InterSystems Package Manager - IPM
-Helps to install ObjectScript classes and routines, globals, Embedded Python modules, CSP and Frontend packages, and any files into InterSystems IRIS published on the official [ZPM Registry](https://pm.community.intersystems.com/packages/-/all) or private ZPM registry of your own.
+Helps to install ObjectScript classes and routines, globals, Embedded Python modules, CSP and Frontend packages, and any files into InterSystems IRIS published on the official [Registry](https://pm.community.intersystems.com/packages/-/all) or private registry of your own.
## Documentation
* [The official documenation in the wiki](https://github.com/intersystems-community/zpm/wiki/)
* [Articles on the InterSystems Developer Community](https://community.intersystems.com/tags/objectscript-package-manager-zpm)
* [Videos on YouTube](https://www.youtube.com/playlist?list=PLKb2cBVphNQRcmxt4LtYDyLJEPfF4X4-4)
+## Compatibility Note
+With the release of IPM v0.9.0 on Dec 2024, IPM is no longer mapped across namespaces.
+This is an intentional change so that users can have different IPM versions and configurations in different namespaces.
+If you install IPM on an instance without the legacy 0.7.x version, IPM is only installed to the current namespace.
+
+* To retain the old behavior where %IPM routines and classes mapped across all namespaces, run `zpm "enable -map -globally`. This is automatically performed when upgrading from a legacy version and can be undone by running `zpm "unmap -globally"`.
+* You can optionally choose to map IPM repositories across namespaces with `zpm "enable -map -repos -namespaces NS1,NS2,NS3` or `zpm "enable -map -repos -globally`. Repositories are only mapped if %IPM classes and routines are also mapped from the same namespace.
+* As a convenience command, `zpm "enable -community"` will make IPM behave essentially the same as legacy versions (v0.7.x) by setting up the the community registry and maping %IPM routines and classes, as well IPM repository settings to all namespaces.
## Installing ObjectScript Package Manager Client:
0. Use one-liner in terminal call or programmatically:
```
-s r=##class(%Net.HttpRequest).%New(),r.Server="pm.community.intersystems.com",r.SSLConfiguration="ISC.FeatureTracker.SSL.Config" d r.Get("/packages/zpm/latest/installer"),$system.OBJ.LoadStream(r.HttpResponse.Data,"c")
+s version="latest" s r=##class(%Net.HttpRequest).%New(),r.Server="pm.community.intersystems.com",r.SSLConfiguration="ISC.FeatureTracker.SSL.Config" d r.Get("/packages/zpm/"_version_"/installer"),$system.OBJ.LoadStream(r.HttpResponse.Data,"c")
```
+**If you want the legacy behavior of mapping IPM classes, routines, and repository settings to all namespaces, run `zpm "enable -community"` after installing IPM. See `zpm "help enable"` for details.**
+**In a CI script, for deterministic behavior, you should replace version="latest" with the IPM version you wish to use.**
OR:
@@ -65,4 +75,4 @@ Here is the [alternative supported folder structure.](https://openexchange.inter
## Support and Collaboration
ObjectScript Package Manager is a community supported project and thus open to collaboration via Pull Requests.
-Issues and feature requests [are very welcome](https://github.com/intersystems-community/zpm/issues)
\ No newline at end of file
+Issues and feature requests [are very welcome](https://github.com/intersystems-community/zpm/issues)
diff --git a/src/cls/IPM/Main.cls b/src/cls/IPM/Main.cls
index df96edb8..e478bfb7 100644
--- a/src/cls/IPM/Main.cls
+++ b/src/cls/IPM/Main.cls
@@ -654,8 +654,10 @@ generate /my/path -export 00000,PacketName2,IgnorePacket2^00000,PacketName3,Igno
+
+
enable -map -globally
@@ -672,15 +674,21 @@ generate /my/path -export 00000,PacketName2,IgnorePacket2^00000,PacketName3,Igno
enable -v latest -allow-upgrade NS1,NS2,NS3
+
+ enable -community
+
+ Unmap %IPM package and routines in specified namespaces.
Unmap %IPM package and routines in specified namespaces. Will Skip non-mapped namespaces.
+ If repository settings are mapped, will also unmap repository settings.
+
unmap -ns NS1,NS2,NS3
@@ -2803,9 +2811,12 @@ ZPM(pArgs...)
Set found = 0
While rs.%Next() {
Set $Namespace = $Zstrip(rs.%Get("Nsp"), "<>WC")
- If $System.CLS.IsMthd("%IPM.Main", "Shell") {
+ // Some I4H containers come with %IPM.Main but the "version" command doesn't work ?!
+ If $System.CLS.IsMthd("%IPM.Main", "Shell") && ($Namespace '= "HSLIB") && ($Namespace '= "HSSYS") {
Write !, "Change namepace to one of the following to run the ""zpm"" command"
Do ##class(%IPM.Main).Shell("version")
+ Write !, "If you want to map IPM globally, switch to one of the namespaces above and run: zpm ""enable -map -globally""."
+ Write !, "If you want to reset repository and map IPM globally along with repository settings, switch to one of the namespaces above and run: zpm ""enable -community""."
Set found = 1
Quit
}
@@ -2840,6 +2851,19 @@ ClassMethod EnableIPM(ByRef pCommandInfo)
Write !,($namespace)_"> "_$$$FormattedLine($$$Green,$$$IPMModuleName_" ")_modDef.VersionString
}
+ If $$$HasModifier(pCommandInfo,"community") {
+ For cmd = "repo -delete-all", "repo -reset-defaults", "enable -map -repos -globally" {
+ Write !!, "RUNNING command: """, cmd, """"
+ Do ..ShellInternal(cmd, .exc)
+ If exc '= $$$NULLOREF {
+ Write !, $$$FormattedLine($$$Red, $$$FormatText("Error running command ""%1"" - %2", cmd, exc.DisplayString()))
+ } Else {
+ Write !, $$$FormattedLine($$$Green, $$$FormatText("Command ""%1"" finished successfull", cmd))
+ }
+ }
+ Return
+ }
+
Set quiet = $$$HasModifier(pCommandInfo,"quiet")
Set preview = $$$HasModifier(pCommandInfo,"preview")
Set map = $$$HasModifier(pCommandInfo,"map")
@@ -2848,6 +2872,7 @@ ClassMethod EnableIPM(ByRef pCommandInfo)
Set version = $$$GetModifier(pCommandInfo, "version")
Set namespaces = $$$GetModifier(pCommandInfo, "namespaces")
Set allowUpgrade = $$$HasModifier(pCommandInfo,"allow-upgrade")
+ Set mapRepos = $$$HasModifier(pCommandInfo,"repos")
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
@@ -2866,6 +2891,9 @@ ClassMethod EnableIPM(ByRef pCommandInfo)
If map && 'globally && (namespaces = "") {
$$$ThrowOnError($$$ERROR($$$GeneralError,"If mapping from the current namespace's routine database with -map, must specify either -globally or a list of namespaces with -ns"))
}
+ If ('map) && (mapRepos) {
+ $$$ThrowOnError($$$ERROR($$$GeneralError,"Cannot specify -repos without -map"))
+ }
If map {
If globally {
@@ -2884,13 +2912,15 @@ ClassMethod EnableIPM(ByRef pCommandInfo)
} Else {
Set namespaces = $ListFromString(namespaces)
}
+
+ // First try to map IPM itself
Set pointer = 0
While $ListNext(namespaces,pointer,namespace) {
Set namespace = $Zstrip(namespace, "<>WC")
Set $Namespace = namespace
If ..IPMInstalled() {
If 'quiet || preview {
- Write !,"Skipping "_namespace_" - IPM already installed."
+ Write !,"Skipping IPM mapping of "_namespace_" - IPM already installed."
}
Continue
}
@@ -2908,6 +2938,42 @@ ClassMethod EnableIPM(ByRef pCommandInfo)
}
$$$ThrowOnError(##class(%IPM.Utils.Build).MapRoutineEquivalently("%IPM.*",initNamespace,,namespace))
}
+
+ // Then try to map repositories if -repos is specified
+ If mapRepos {
+ Do ..GetMapInfo(.isMappedFrom)
+ Set pointer = 0
+ While $ListNext(namespaces,pointer,namespace) {
+ Set namespace = $ZStrip(namespace, "<>WC")
+ // If IPM is not mapped from source namespace, skip repo mapping
+ If $Get(isMappedFrom(namespace)) '= initNamespace {
+ If 'quiet || preview {
+ Write !,"Skipping repository mapping of "_namespace_" - IPM not mapped from source namespace."
+ }
+ Continue
+ }
+ // If repository are already present, also skip repo mapping avoid override
+ Set $Namespace = namespace
+ If $Data(^IPM.Repo.DefinitionD) \ 2 {
+ If 'quiet || preview {
+ Write !,"Skipping repository mapping of "_namespace_" - IPM repositories found."
+ }
+ Continue
+ }
+ Set $Namespace = initNamespace
+ If preview {
+ Write !,"Would add IPM repository mappings to "_namespace
+ Continue
+ }
+ If 'quiet {
+ Write !,"Mapping IPM repository in "_namespace_" equivalently to "_initNamespace
+ }
+ For suffix = "D", "S", "I" {
+ $$$ThrowOnError(##class(%IPM.Utils.Build).MapGlobalEquivalently("IPM.Repo.Definition"_suffix, initNamespace, namespace))
+ }
+ }
+ }
+
Set $Namespace = initNamespace
If preview {
Write !,"Preview mode; no configuration changes were made."
@@ -3141,6 +3207,7 @@ ClassMethod UnmapIPM(ByRef pCommandInfo)
Set globally = $$$HasModifier(pCommandInfo,"globally")
Set namespaces = $ListFromString($$$GetModifier(pCommandInfo,"namespaces"), ",")
Set verbose = '$$$HasModifier(pCommandInfo,"quiet")
+ set reposOnly = $$$HasModifier(pCommandInfo,"repos-only")
// Sanity check
If (globally && (namespaces '= "")) {
$$$ThrowOnError($$$ERROR($$$GeneralError,"Cannot specify namespaces and global unmap flag at the same time."))
@@ -3161,7 +3228,11 @@ ClassMethod UnmapIPM(ByRef pCommandInfo)
}
}
If verbose {
- Write !,"Will attempt to unmap %IPM package and routines from: "_ $ListToString(namespaces, ", ")
+ If reposOnly {
+ Write !,"Will attempt to unmap IPM repository settings from: "_ $ListToString(namespaces, ", ")
+ } Else {
+ Write !,"Will attempt to unmap IPM package, routines, and repository settings from: "_ $ListToString(namespaces, ", ")
+ }
}
// Gather namespaces where %IPM is mapped into
@@ -3176,11 +3247,21 @@ ClassMethod UnmapIPM(ByRef pCommandInfo)
}
Continue
}
+
If verbose {
- Write !,"Unmapping %IPM package and routines from "_ns_" (mapped from "_src_")"
+ Write !,"Unmapping repository settings from "_ns_" (mapped from "_src_")"
+ }
+ For suffix = "D", "S", "I" {
+ $$$ThrowOnError(##class(%IPM.Utils.Module).RemoveGlobalMapping(ns, "IPM.Repo.Definition"_suffix))
+ }
+
+ If 'reposOnly {
+ If verbose {
+ Write !,"Unmapping IPM package and routines from "_ns_" (mapped from "_src_")"
+ }
+ $$$ThrowOnError(##class(%IPM.Utils.Module).RemovePackageMapping(ns, "%IPM"))
+ $$$ThrowOnError(##class(%IPM.Utils.Module).RemoveRoutineMapping(ns, "%IPM.*"))
}
- $$$ThrowOnError(##class(%IPM.Utils.Module).RemovePackageMapping(ns, "%IPM"))
- $$$ThrowOnError(##class(%IPM.Utils.Module).RemoveRoutineMapping(ns, "%IPM.*"))
}
}