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.*")) } }