diff --git a/CHANGELOG.md b/CHANGELOG.md index ba6c7705..91c42f8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,25 @@ 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.10.5] - Unreleased + +### Added + +### Changed +- #885: Always synchronously load dependencies and let each module do multi-threading as needed +to load using multicompile instead of trying to do own multi-threading of item load which causes +lock contention by bypassing IRIS compiler. + +### Deprecated +- #885: `-synchronous` flag since loading dependencies synchronously is now the default behavior. + +### Removed + +### Fixed + +### Security + + ## [0.10.4] - 2025-10-21 ### Added diff --git a/module.xml b/module.xml index defbb43f..e6153cca 100644 --- a/module.xml +++ b/module.xml @@ -1,49 +1,57 @@ - - ZPM - 0.10.4-SNAPSHOT - IPM - InterSystems Package Manager (IPM) provides development tools and infrastructure for defining, building, distributing, and installing modules and applications. - Package Manager - - InterSystems Corporation - - module - src - - - - - - - - - - - - ${verbose} - + + + ZPM + 0.10.5-SNAPSHOT + IPM + InterSystems Package Manager (IPM) provides development tools and + infrastructure for defining, building, distributing, and installing modules and + applications. + Package Manager + + InterSystems Corporation + + module + src + + + + + + + + + + + + ${verbose} + - - + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - + + + + \ No newline at end of file diff --git a/src/cls/IPM/CLI.cls b/src/cls/IPM/CLI.cls index 16f72791..5a0662ca 100644 --- a/src/cls/IPM/CLI.cls +++ b/src/cls/IPM/CLI.cls @@ -401,7 +401,9 @@ ClassMethod %HelpForCommandExamples( /// Parses a command, validating it based on the Commands XData block and structuring output as follows: /// pCommandInfo = "" /// pCommandInfo("modifiers","") = "" +/// pCommandInfo("modifiers","","deprecated") = 0/1 /// pCommandInfo("parameters","") = "" +/// pCommandInfo("parameters","","deprecated") = 0/1 /// pCommandInfo("data","") = "" ClassMethod %ParseCommandInput( pCommandString As %String, @@ -651,6 +653,25 @@ ClassMethod %ParseCommandInput( set tState = tPreEscapeState } } + + // Add in deprecated info to parameters and modifiers + set tCommandName = $get(pCommandInfo) + if (tCommandName '= "") { + for tType="parameters","modifiers" { + set tKey = "" + while 1 { + set tKey = $order(pCommandInfo(tType,tKey)) + if (tKey = "") { + quit + } + // Only include deprecated subscript if command is deprecated + set tIsDeprecated = $get(tCommandStructure(tCommandName,tType,tKey,"deprecated"),0) + if tIsDeprecated { + set pCommandInfo(tType,tKey,"deprecated") = 1 + } + } + } + } if ($get(pCommandInfo) '= "") { set commandName = pCommandInfo for i=1:1 { diff --git a/src/cls/IPM/CLI/Commands.cls b/src/cls/IPM/CLI/Commands.cls index 5906f410..79f0c2ef 100644 --- a/src/cls/IPM/CLI/Commands.cls +++ b/src/cls/IPM/CLI/Commands.cls @@ -48,6 +48,9 @@ XData Schema [ Internal, MimeType = application/xml ] + + + @@ -92,16 +95,19 @@ XData Schema [ Internal, MimeType = application/xml ] - + + + + - + @@ -159,7 +165,7 @@ XData Schema [ Internal, MimeType = application/xml ] } -/// Turns the Comomand XData block into a subscripted array as follows: +/// Turns the Command XData block into a subscripted array as follows: /// pCommandStructure(1, "") = "" /// pCommandStructure("") -> /// "description" = describes the command @@ -173,11 +179,13 @@ XData Schema [ Internal, MimeType = application/xml ] /// "aliases" = aliases for the modifier /// "description" = describes the modifier /// "required" = whether or not modifier is required for the command +/// "deprecated" = whether or not modifier is deprecated for the command /// "trailing" = whether modifier is a trailing modifier /// "parameters": /// "": /// "description" = description of parameter /// "required" = is parameter required +/// "deprecated" = whether or not parameter is deprecated for the command ClassMethod %GetOneCommandStructure(Output pCommandStructure) [ CodeMode = objectgenerator ] { #define DefaultGroup "-" @@ -315,9 +323,10 @@ ClassMethod %GetOneCommandStructure(Output pCommandStructure) [ CodeMode = objec do %code.WriteLine(" Set pCommandStructure("_tName_","_$$$QUOTE(tMap(tCommChild))_") = "_tDescContent) } } else { - // Common: name, required, description + // Common to bother modifier and parameter set tChildName = $$$QUOTE(tMap(tCommChild,"a","name")) set tRequired = $case($get(tMap(tCommChild,"a","required")),"true":1,:0) + set tDeprecated = $case($get(tMap(tCommChild,"a","deprecated")),"true":1,:0) if (tMap(tCommChild) = "modifier") { // Also: aliases, value, valueList @@ -337,17 +346,19 @@ ClassMethod %GetOneCommandStructure(Output pCommandStructure) [ CodeMode = objec do %code.WriteLine(" Set pCommandStructure("_tName_",""modifiers"","_tChildName_",""group"") = "_tGroupName) do %code.WriteLine(" Set pCommandStructure("_tName_",""modifiers"","_tChildName_",""value"") = "_$case(tValue,"true":1,:0)) do %code.WriteLine(" Set pCommandStructure("_tName_",""modifiers"","_tChildName_",""required"") = "_tRequired) + do %code.WriteLine(" Set pCommandStructure("_tName_",""modifiers"","_tChildName_",""deprecated"") = "_tDeprecated) do:(tDesc'=$$$empty) %code.WriteLine(" Set pCommandStructure("_tName_",""modifiers"","_tChildName_",""description"") = "_tDesc) do:(tValueList'=$$$empty) %code.WriteLine(" Set pCommandStructure("_tName_",""modifiers"","_tChildName_",""valueList"") = "_tValueList) do:(tDataAlias'=$$$empty) %code.WriteLine(" Set pCommandStructure("_tName_",""modifiers"","_tChildName_",""dataAlias"") = "_tDataAlias) do:(tDataValue'=$$$empty) %code.WriteLine(" Set pCommandStructure("_tName_",""modifiers"","_tChildName_",""dataValue"") = "_tDataValue) - } elseif (tMap(tCommChild) = "parameter") { + } elseif (tMap(tCommChild) = "parameter") { // Also: example set tExample = $$$QUOTE($get(tMap(tCommChild,"a","example"))) set tTrailing = $case($get(tMap(tCommChild,"a","trailing")),"true":1,:0) do %code.WriteLine(" Set pCommandStructure("_tName_",""parameters"",$i(pCommandStructure("_tName_",""parameters""))) = "_tChildName) do %code.WriteLine(" Set pCommandStructure("_tName_",""parameters"","_tChildName_",""trailing"") = "_tTrailing) do %code.WriteLine(" Set pCommandStructure("_tName_",""parameters"","_tChildName_",""required"") = "_tRequired) + do %code.WriteLine(" Set pCommandStructure("_tName_",""parameters"","_tChildName_",""deprecated"") = "_tDeprecated) do:(tDesc'=$$$empty) %code.WriteLine(" Set pCommandStructure("_tName_",""parameters"","_tChildName_",""description"") = "_tDesc) do:(tExample'=$$$empty) %code.WriteLine(" Set pCommandStructure("_tName_",""parameters"","_tChildName_",""example"") = "_tExample) } diff --git a/src/cls/IPM/General/InstallContext.cls b/src/cls/IPM/General/InstallContext.cls deleted file mode 100644 index 9ab5cdc3..00000000 --- a/src/cls/IPM/General/InstallContext.cls +++ /dev/null @@ -1,72 +0,0 @@ -Include %IPM.Common - -Class %IPM.General.InstallContext Extends %IPM.General.Singleton -{ - -/// If set to 1, calls to %Get must return an instance of this class created in the current namespace; a new instance will be created if none exists. -Parameter NAMESPACESCOPE As BOOLEAN = 1; - -Property DependencyGraph [ MultiDimensional, Private ]; - -Property CacheTempIndex As %Integer [ Private ]; - -Method SetGraph(ByRef pDependencyGraph) -{ - kill ..DependencyGraph - merge ..DependencyGraph = pDependencyGraph -} - -Method SetCacheTempIndex(pIndex As %Integer = "") -{ - set ..CacheTempIndex = pIndex -} - -Method GetModuleList() As %List -{ - set tList = "" - set tModuleName = "" - for { - set tModuleName = $order(..DependencyGraph(tModuleName)) - if (tModuleName = "") { - quit - } - set tList = tList_$listbuild(tModuleName) - } - quit tList -} - -Method ModuleIsDependency(pModuleName As %String) As %Boolean -{ - quit ($data(..DependencyGraph(pModuleName)) > 0) -} - -Method GetPendingModuleList() As %List -{ - if (..CacheTempIndex = "") { - quit "" - } - - // The caller should have the temp global locked, but just in case... - merge tGraph = $$$ZPMTempLoadGraph(..CacheTempIndex) - - set tList = "" - set tModuleName = "" - for { - set tModuleName = $order(tGraph(tModuleName)) - if (tModuleName = "") { - quit - } - set tList = tList_$listbuild(tModuleName) - } - quit tList -} - -Method ModuleIsPending(pModuleName As %String) As %Boolean -{ - if (..CacheTempIndex = "") { - quit 0 - } - quit ($data($$$ZPMTempLoadGraph(..CacheTempIndex,pModuleName)) > 0) -} - -} diff --git a/src/cls/IPM/Lifecycle/Base.cls b/src/cls/IPM/Lifecycle/Base.cls index 08a87c14..a0f3137c 100644 --- a/src/cls/IPM/Lifecycle/Base.cls +++ b/src/cls/IPM/Lifecycle/Base.cls @@ -900,10 +900,6 @@ Method %Compile(ByRef pParams) As %Status $$$ThrowOnError(##class(%Studio.SourceControl.Interface).SourceControlCreate()) } - // Load dependencies correctly for the requested phases. (This will be a no-op in most cases.) - set tSC = ..Module.LoadDependencies(..PhaseList,.pParams) - $$$ThrowOnError(tSC) - // Compile items within the module that are compilable using OnPhase set orderedResourceList = ..Module.GetOrderedResourceList() set tKey = "" @@ -1018,13 +1014,6 @@ Method %Compile(ByRef pParams) As %Status } set tNoCompileLock = '$get(pParams("NoLock")) - if $$$IsISCWorker && 'tNoCompileLock { - // Customized locking - takes out shared locks on dependencies to avoid conflicts between parallel module loads. - set tSC = ##class(%IPM.Utils.LockManager).LockClassesRecursive(.tLockManager,.tCompileArray,.tLockedClasses) - $$$ThrowOnError(tSC) - set tNoCompileLock = 1 - } - // Actually do the compile if $data(tCompileArray)>1 { set tCompiledSomething = 1 @@ -1078,10 +1067,6 @@ Method %Test(ByRef pParams) As %Status { set tSC = $$$OK try { - // Load dependencies correctly for the requested phases. (This will be a no-op in most cases.) - set tSC = ..Module.LoadDependencies(..PhaseList,.pParams) - $$$ThrowOnError(tSC) - set orderedResourceList = ..Module.GetOrderedResourceList() set tKey = "" for { @@ -1129,7 +1114,7 @@ Method %Export( } set tExportDependencies = $get(pParams("ExportDependencies"), ..#EXPORTDEPENDENCIES) - set tSC = ..Module.GetResolvedReferences(.tResourceArray, tExportDependencies,..PhaseList,1,.pDependencyGraph) + set tSC = ..Module.GetResolvedReferences(.tResourceArray, tExportDependencies,..PhaseList,.pDependencyGraph) if $$$ISERR(tSC) { quit } @@ -1308,10 +1293,6 @@ Method %Verify(ByRef pParams) As %Status } } - // Load dependencies correctly for the requested phases. (This will be a no-op in most cases.) - set tSC = ..Module.LoadDependencies(..PhaseList,.pParams) - $$$ThrowOnError(tSC) - set orderedResourceList = ..Module.GetOrderedResourceList() set tKey = "" for { @@ -1592,7 +1573,7 @@ Method %MakeDeployed(ByRef pParams) As %Status // Default implementation: see which resources are expicitly flagged with Deploy = true. // Build an array of those, then mark them as deployed. - $$$ThrowOnError(..Module.GetResolvedReferences(.tResourceArray,tLockedDependencies,..PhaseList,1,.pDependencyGraph)) + $$$ThrowOnError(..Module.GetResolvedReferences(.tResourceArray,tLockedDependencies,..PhaseList,.pDependencyGraph)) set tModuleKey = "" for { diff --git a/src/cls/IPM/Main.cls b/src/cls/IPM/Main.cls index 20dabff2..519bd733 100644 --- a/src/cls/IPM/Main.cls +++ b/src/cls/IPM/Main.cls @@ -287,7 +287,7 @@ load C:\module\root\path -env C:\path\to\env1.json;C:\path\to\env2.json - + @@ -364,7 +364,6 @@ run C:\Temp\MyCommands.json, where contents of the file are as follows: "latest": "" }, "custom_modifiers": { - "NoMapping": 1, "Deploy.Parameter": "TESTDEPLOY" } } @@ -411,7 +410,7 @@ install -env /path/to/env1.json;/path/to/env2.json example-package - + @@ -925,6 +924,9 @@ ClassMethod ShellInternal( // Parse command $$$ThrowOnError(..%ParseCommandInput(tCommand,.tParsedCommandInfo)) + // Warn for deprecated parameters/modifiers + do ..WarnOnDeprecatedModifiersOrParameters(.tParsedCommandInfo) + // Merge defaults first so they can be overwritten by commands do ..GetNamespaceDefaultModifiers(.tDefaultArray) merge tCommandInfo("data") = tDefaultArray @@ -1007,6 +1009,22 @@ ClassMethod ShellInternal( } } +/// Warn for deprecated parameters/modifiers +ClassMethod WarnOnDeprecatedModifiersOrParameters(ByRef pCommandInfo) [ Internal, Private ] +{ + for key = "modifiers", "parameters" { + set name = "" + for { + set name = $order(pCommandInfo(key,name)) + quit:name="" + if ($get(pCommandInfo(key,name,"deprecated"),0)) { + set singularKey = $zconvert($extract(key,1),"U") _ $extract(key,2,*-1) + write !,$$$FormattedLine($$$Yellow, $$$FormatText("WARNING: %1 '%2' is deprecated and will be removed in future versions. Run 'help ' to view further details.",singularKey,name)),! + } + } + } +} + ClassMethod DisplayError(pStatus As %Status) { if $$$ISERR(pStatus) { @@ -2150,7 +2168,6 @@ ClassMethod Load(ByRef pCommandInfo) [ Internal ] // if the path is to a directory (not a file) and it is not a URL, it must be absolute $$$ThrowStatus($$$ERROR($$$GeneralError,"The specified path must be absolute.")) } - set tSynchronous = $$$HasModifier(pCommandInfo,"synchronous") set tForce = $$$HasModifier(pCommandInfo,"force") merge tParams = pCommandInfo("data") // In the case of an update command, pCommandInfo has already been populated in ..Update(). The relevant information was then moved to tParams via the merge command above. @@ -2200,7 +2217,7 @@ ClassMethod Load(ByRef pCommandInfo) [ Internal ] set tTargetDirectory = $get(tTargetDirectory, tDirectoryName) set dotModules = ##class(%File).NormalizeDirectory(".modules", tTargetDirectory) set tmpRepoMgr = ##class(%IPM.General.TempLocalRepoManager).%New(dotModules, 1) - set tSC = ##class(%IPM.Utils.Module).LoadNewModule(tTargetDirectory, .tParams, , tSynchronous) + set tSC = ##class(%IPM.Utils.Module).LoadNewModule(tTargetDirectory, .tParams) set tSC = $$$ADDSC(tSC, tmpRepoMgr.CleanUp()) $$$ThrowOnError(tSC) } @@ -2249,7 +2266,6 @@ ClassMethod Install(ByRef pCommandInfo) [ Internal ] set tVersion = $get(pCommandInfo("parameters","version")) set tKeywords = $$$GetModifier(pCommandInfo,"keywords") - set tSynchronous = $$$HasModifier(pCommandInfo,"synchronous") set tForce = $$$HasModifier(pCommandInfo,"force") set tSearchCriteria = ##class(%IPM.Repo.SearchCriteria).%New() @@ -2299,7 +2315,7 @@ ClassMethod Install(ByRef pCommandInfo) [ Internal ] $$$ThrowStatus($$$ERROR($$$GeneralError, "Deployed package '" _ tModuleName _ "' " _ tResult.VersionString _ " not supported on this platform " _ platformVersion _ ".")) } } - $$$ThrowOnError(##class(%IPM.Utils.Module).LoadQualifiedReference(tResult, .tParams, , tSynchronous)) + $$$ThrowOnError(##class(%IPM.Utils.Module).LoadQualifiedReference(tResult, .tParams)) } } else { set tPrefix = "" diff --git a/src/cls/IPM/Repo/Filesystem/Definition.cls b/src/cls/IPM/Repo/Filesystem/Definition.cls index 49d3b7dc..b99b7d67 100644 --- a/src/cls/IPM/Repo/Filesystem/Definition.cls +++ b/src/cls/IPM/Repo/Filesystem/Definition.cls @@ -51,11 +51,7 @@ Method RootSet(%val) As %Status /// Returns a client to interact with this server. Method GetPackageService() As %IPM.Repo.IPackageService { - set tService = ##class(%IPM.Repo.Filesystem.PackageService).%New(..Root) - if '$$$IsISCWorker && tService.IsAvailable() { - $$$ThrowOnError(..BuildCache()) - } - quit tService + return ##class(%IPM.Repo.Filesystem.PackageService).%New(..Root) } /// Handles modifiers/data attributes provided from the package manager shell. @@ -119,7 +115,7 @@ Trigger RootChanged [ Event = UPDATE, Foreach = row/object ] } Method BuildCache( - pPurge As %Boolean = {'$$$IsISCWorker}, + pPurge As %Boolean = 1, pVerbose As %Integer = 0, pAutoDetectDepth As %Boolean = 0) As %Status { diff --git a/src/cls/IPM/Storage/Module.cls b/src/cls/IPM/Storage/Module.cls index aceaf000..d271279c 100644 --- a/src/cls/IPM/Storage/Module.cls +++ b/src/cls/IPM/Storage/Module.cls @@ -537,16 +537,7 @@ ClassMethod ExecutePhases( // Report timing subject to parameter; overall timing if only one phase has yet been tracked in context // (e.g., set up in multithreaded load) and more than one phase is to be executed. set tTiming = $get(pParams("Timing"),0) - set tOverallTiming = tTiming && ($listlength(tPhases) > 1) && ($listlength($get($$$ZPMHandledModules($namespace,pModuleName))) < 2) - - // Subscript by namespace to handle application build and integration testing processes, which may - // load a module in a different namespace (and call ExecutePhases there) at a lower stack level than the - // initial call to ExecutePhases - if '$data($$$ZPMHandledModules($namespace)) { - new $$$ZPMHandledModules - } else { - set $$$ZPMHandledModules($namespace,pModuleName) = $get($$$ZPMHandledModules($namespace,pModuleName))_tPhases - } + set tOverallTiming = tTiming && ($listlength(tPhases) > 1) // Execute resolved phases in sequence set tLifecycle.PhaseList = tPhases @@ -806,67 +797,45 @@ ClassMethod HasScope( quit $listfind(tPhases, scopeItem) > 0 } -Method LoadDependencies( - pPhaseList As %List, - ByRef pParams) As %Status -{ - set tSC = $$$OK - try { - set tVerbose = $get(pParams("Verbose")) - - if '$data(pParams("qstruct")) { - set qstruct = "ck"_$select(tVerbose:"d",1:"-d") - } else { - merge qstruct = pParams("qstruct") - } - - // Resolve and validate dependencies - set tReloadSnapshots = +$get(pParams("UpdateSnapshots")) - set tPermitDowngrade = +$get(pParams("PermitDowngrade")) - set tSC = ..BuildDependencyGraph(.tDependencyGraph,,tReloadSnapshots,.qstruct,pPhaseList,,,,,,tPermitDowngrade) - if $$$ISERR(tSC) { - quit - } - - if $data(tDependencyGraph) { - set tOptimizeInstalled = 'tReloadSnapshots - write:tVerbose !,"Dependencies:" - set tModuleLoop = "" - for { - set tModuleLoop = $order(tDependencyGraph(tModuleLoop),1,tValue) - quit:tModuleLoop="" - - if (tOptimizeInstalled) && '$data($$$ZPMHandledModules($namespace,tModuleLoop)) { - // Optimize for exact version matches that are already installed. - if ##class(%IPM.Storage.Module).NameExists(tModuleLoop) { - set tMod = ##class(%IPM.Storage.Module).NameOpen(tModuleLoop,,.tSC) - $$$ThrowOnError(tSC) - if (tMod.VersionString = $listget(tValue,3)) { - set $list(tValue,2) = "" - set $list(tDependencyGraph(tModuleLoop),2) = "" - } - } - } - - set tServer = $case($listget(tValue,2),"":" (installed)",:" @ "_$listget(tValue,2)) - write:tVerbose !,tModuleLoop," ",$listget(tValue,3),tServer - } - - // Download dependencies. - kill tParams - merge tParams("qstruct") = qstruct - merge tParams = pParams - set tSC = ##class(%IPM.Utils.Module).LoadDependencies(.tDependencyGraph,.tParams) - if $$$ISERR(tSC) { - quit - } - } - } catch e { - set tSC = e.AsStatus() - } - quit tSC -} - +/// Builds a dependency graph for this module, recursively resolving dependencies to the specified depth. +/// The dependency graph is returned in pDependencyGraph, which is an array where the keys are module names and the values are lists of three items: +///
    +///
  • Depth in the dependency tree (1 for direct dependencies, 2 for dependencies of dependencies, etc.)
  • +///
  • Server from which the module will be (or was) obtained; empty string if already installed
  • +///
  • Version string of the module to be installed
  • +///
+///

+/// If pDepth is 1, only direct dependencies are resolved. +/// If it is 2, dependencies of dependencies are also resolved, and so on. +/// If it is 0, dependencies are resolved to any depth. +///

+/// If pForceSnapshotReload is 1, then any cached snapshot of available modules is reloaded from the repository server(s). +///

+/// qstruct is passed to the repository manager to control which repositories are queried. +///

+/// pPhases is a list of lifecycle phases that will be executed for the module. +/// This is used to determine whether scoped dependencies should be considered. +/// If empty, all dependencies are considered. +///

+/// pSubModules is an output parameter that returns a list of submodules that were found. +///

+/// pPass controls whether exact version dependencies (1) or fuzzy version dependencies (2) are processed. +/// The method is typically called twice, once for each pass. +///

+/// pModulePath is used internally to track the path of modules being processed, to detect cyclic dependencies. +///

+/// If pIgnoreInstalledModules is 1, then already-installed modules are not considered when resolving dependencies. +///

+/// pKnownDependencies is a list of modules that are known dependencies of the root module being installed. +/// This is used to avoid considering these modules as already-installed when resolving dependencies. +///

+/// If pPermitDowngrade is 1, then dependencies that require downgrading an already-installed module are permitted. +///

+/// If pCheckNestedScoped is 1, then scoped dependencies of dependencies are checked against the phases of the root module being installed. +///

+/// pSearchList is an output parameter that returns a list of repository servers that were searched. +///

+/// If pIncludeDisplayName is 1, then the display name of each module is included in the output list for informational purposes. Method BuildDependencyGraph( ByRef pDependencyGraph, pDepth As %Integer = 1, @@ -881,7 +850,7 @@ Method BuildDependencyGraph( pPermitDowngrade As %Boolean = 0, pCheckNestedScoped As %Boolean = 0, ByRef pSearchList, - pIncludeDisplayName As %Boolean = 0) As %Status + pIncludeDisplayName As %Boolean = 0) As %Status [ Internal ] { #define EXACT 1 #define FUZZY 2 @@ -896,10 +865,6 @@ Method BuildDependencyGraph( set tRepositoryManager = ##class(%IPM.Repo.Manager).%Get(.tSC) $$$ThrowOnError(tSC) - // Disregard violation of dependencies of pending modules - set tInstallContext = ##class(%IPM.General.InstallContext).%Get(.tSC) - $$$ThrowOnError(tSC) - // May want to pass phases to subsequent calls set tPhases = $case(pCheckNestedScoped, 1: pPhases, : "") for i=1:1:..Dependencies.Count() { @@ -949,9 +914,8 @@ Method BuildDependencyGraph( if 'pIgnoreInstalledModules { // Also apply requirements presented by other installed modules, with the exception of those that are: // * Known as dependencies of the root module being installed (and thus eligible for upgrade) - // * Pending (re)installation // * Already in the dependency graph - set tOtherDeps = pKnownDependencies_tInstallContext.GetPendingModuleList() + set tOtherDeps = pKnownDependencies set tExistingDepKey = "" for { set tExistingDepKey = $order(pDependencyGraph(tExistingDepKey)) @@ -984,13 +948,6 @@ Method BuildDependencyGraph( // The "clean" phase can be used to bypass this (by removing modules from the current namespace) // Forcing an update from disk can also override this, although we ensure that the same module is // not loaded multiple times in a given operation. - set tForceSnapshotReload = pForceSnapshotReload - if tForceSnapshotReload && $data($$$ZPMHandledModules($namespace,tDep.Name),tHandled) { - if $listfind(tHandled,"Activate") { - // If we have already activated the given module, don't do so again. - set tForceSnapshotReload = 0 - } - } if ('pIgnoreInstalledModules) && ..NameExists(tDep.Name) { set tLocalObj = ..NameOpen(tDep.Name,,.tSC) if $$$ISERR(tSC) { @@ -998,7 +955,7 @@ Method BuildDependencyGraph( } set tInstalledVersionValid = tLocalObj.Version.Satisfies(tSearchExpr) && ((tVersion = "") || (tVersion = tLocalObj.VersionString)) - if tInstalledVersionValid && '(tLocalObj.Version.IsSnapshot() && tForceSnapshotReload) { + if tInstalledVersionValid && '(tLocalObj.Version.IsSnapshot() && pForceSnapshotReload) { set tLocalMod = 1 set tDepth = $select(tPreviousDepth=0:pDepth,tPreviousDepth>pDepth:tPreviousDepth,1:pDepth) set pDependencyGraph(tDep.Name) = $listbuild(pDepth,"",tLocalObj.VersionString) @@ -1257,13 +1214,11 @@ ClassMethod GetKnownDependencies(pModuleName As %String) As %List /// @Argument pReferenceArray Array of all module's resources (including resources that compose a resource) that contain the appropriate phase scope.
/// @Argument pLockedDependencies Whether method should be recursively applied to the module's dependencies (true = yes).
/// @Argument pPhases List of IPM lifecycle phases to be applied to the current module.
-/// @Argument pSkipDependencies Whether to skip loading uninstalled dependency modules.
/// @Argument pDependencyGraph Tree of module's dependencies.
Method GetResolvedReferences( Output pReferenceArray, pLockedDependencies As %Boolean = 0, pPhases As %List = "", - pSkipDependencies As %Boolean = 0, ByRef pDependencyGraph) As %Status { set tSC = $$$OK @@ -1275,16 +1230,6 @@ Method GetResolvedReferences( } } - if 'pSkipDependencies { - kill tParams - set tParams("Verbose") = 0 - set tParams("qstruct") = "k" - set tSC = ##class(%IPM.Utils.Module).LoadDependencies(.pDependencyGraph,.tParams) - if $$$ISERR(tSC) { - quit - } - } - set pReferenceArray(..Name, ..Name_".ZPM") = "" set orderedResourceList = ..GetOrderedResourceList() @@ -1328,7 +1273,7 @@ Method GetResolvedReferences( // pLockedDependencies=0 to avoid duplicating effort on nested dependencies; // this loop will already get all of them. - set tSC = tModule.GetResolvedReferences(.pReferenceArray,0,,1) + set tSC = tModule.GetResolvedReferences(.pReferenceArray,0) if $$$ISERR(tSC) { quit } @@ -1466,11 +1411,6 @@ Method %OnValidateObject() As %Status [ Private, ServerOnly = 1 ] quit } - // Pre-check for uniqueness among resources (make sure there are no collisions and report descriptive errors if there are). - // This is simpler than trying to interpret a unique index violation later, and will work in all cases where we're updating modules. - set tInstallContext = ##class(%IPM.General.InstallContext).%Get(.tSC) - $$$ThrowOnError(tSC) - set tSC = $$$OK set orderedResourceList = ..GetOrderedResourceList() set tKey = "" @@ -1486,10 +1426,6 @@ Method %OnValidateObject() As %Status [ Private, ServerOnly = 1 ] if $$$ISERR(tSC) { quit } - if tInstallContext.ModuleIsPending(tOtherResource.Module.Name) { - // %OnAddToSaveSet will correct for this condition. - continue - } if (tResource.Name = tResource.UniqueName) { // Common case: classes, packages, include files, etc. set tMsg = $$$FormatText("Resource '%1' is already defined as part of module '%2'; cannot also be listed in module '%3'",tResource.Name,tOtherResource.Module.Name,..Name) @@ -1549,33 +1485,6 @@ Method %OnAddToSaveSet( set ..Hash = tHash set ..LastModifiedTimestamp = $zdatetime($horolog,3) } - - // Deal with resources moving from a module dependent on the current module that hasn't been reloaded yet - set tInstallContext = ##class(%IPM.General.InstallContext).%Get(.tSC) - $$$ThrowOnError(tSC) - - set tSC = $$$OK - set orderedResourceList = ..GetOrderedResourceList() - set tKey = "" - for { - set tResource = orderedResourceList.GetNext(.tKey) - quit:(tKey="") - - // If it hasn't been saved yet (to account for module renames)... - if (tResource.%Id() = "") && (tResource.UniqueName '= "") { - // ... see if some other resource exists with the same name. - if ##class(%IPM.Storage.ResourceReference).ResourceNameExists(tResource.UniqueName,.tResourceId) { - set tOtherResource = ##class(%IPM.Storage.ResourceReference).%OpenId(tResourceId,,.tSC) - $$$ThrowOnError(tSC) - - if tInstallContext.ModuleIsPending(tOtherResource.Module.Name) { - // Delete the resource. If the pending module still contains it, there will be an error when that module is loaded. - set tSC = ##class(%IPM.Storage.ResourceReference).%DeleteId(tResourceId) - $$$ThrowOnError(tSC) - } - } - } - } } catch e { set tSC = e.AsStatus() } diff --git a/src/cls/IPM/Utils/Module.cls b/src/cls/IPM/Utils/Module.cls index a4fa3ab0..d3abef37 100644 --- a/src/cls/IPM/Utils/Module.cls +++ b/src/cls/IPM/Utils/Module.cls @@ -20,212 +20,16 @@ ClassMethod CreateAndGetSSLConfig(ByRef pProperties) As %String return name } -/// Format of pDependencyGraph: -/// pDependencyGraph("module name") = $ListBuild(,,) -/// pDependencyGraph("module name"," ") = -ClassMethod LoadDependencies( - ByRef pDependencyGraph, - ByRef pParams, - pWorkQueue As %SYSTEM.WorkMgr) -{ - // Suspend the error count to avoid spurious messages about errors being detected in load/compile. - $$$SuspendErrorCount - set tSC = $$$OK - set tLocked = 0 - set tRestoreParams = 0 - try { - set initWorkQueueManager = '$data(pParams("Multicompile","CacheTempIndex"),tCacheTempIndex) || '$isobject($get(pWorkQueue)) - if initWorkQueueManager { - if '$isobject($get(pWorkQueue)) { - // There may be one at a higher stack level. - // Deal with dependencies here, and ensure that previous CacheTempIndex can be restored at the end. - merge tParamBackup = pParams - set tRestoreParams = 1 - } - - if ($get(pParams("Threads")) = 1) || ($tlevel > 0) { - set tNumWorkers = -1 // Disable multithreading. - } else { - set tNumWorkers = $get(pParams("Threads"),1) // Enable multicompile - } - - set pWorkQueue = ##class(%SYSTEM.WorkMgr).Initialize("/multicompile="_tNumWorkers,.tSC) - $$$ThrowOnError(tSC) - - set tModuleName = "" - for { - set tModuleName = $order(pDependencyGraph(tModuleName),1,tData) - quit:tModuleName="" - - // List modules to avoid duplicate loads. - set pParams("Multicompile","ModuleContext",tModuleName) = $listbuild("Activate") - - // Invert dependency graph, subscripts (,) - set tInvertedDependencyGraph(tModuleName) = $list(tData,2,*) - - set tDependentKey = "" - for { - set tDependentKey = $order(pDependencyGraph(tModuleName,tDependentKey)) - quit:tDependentKey="" - - set tInvertedDependencyGraph($piece(tDependentKey," "),tModuleName) = "" - } - } - - set tCacheTempIndex = $increment($$$ZPMTempLoadGraphRoot) - set pParams("Multicompile","CacheTempIndex") = tCacheTempIndex - kill $$$ZPMTempLoadGraph(tCacheTempIndex) - merge $$$ZPMTempLoadGraph(tCacheTempIndex) = tInvertedDependencyGraph - } else { - lock +$$$ZPMTempLoadGraph(tCacheTempIndex):$$$LockTimeout - if $test { - set tLocked = 1 - } else { - $$$ThrowStatus($$$ERROR($$$GeneralError,"Failed to obtain lock on dependency graph.")) - } - merge tInvertedDependencyGraph = $$$ZPMTempLoadGraph(tCacheTempIndex) - } - - // Queue load of modules without uninstalled dependencies. - set tModuleName = "" - for { - set tModuleName = $order(tInvertedDependencyGraph(tModuleName),1,tData) - quit:tModuleName="" - - // Check if ALL subnode modules have no server name in the top level node of those modules - // in the inverted dependency graph (which means they are already installed) - // ONLY want to check on the initial version of the graph because nodes are killed as modules are installed - if initWorkQueueManager { - set tHasUninstalledDependency = 0 - set tSubnode = "" - while 1 { - set tSubnode = $order(tInvertedDependencyGraph(tModuleName, tSubnode)) - if (tSubnode = "") { - quit - } - // Check if subnode exists. If it doesn't, then its already been installed because subnodes are killed - set tSubnodeServerName = $listget($get(tInvertedDependencyGraph(tSubnode)), 1) - if (tSubnodeServerName '= "") { - set tHasUninstalledDependency = 1 - quit - } - } - } else { - set tHasUninstalledDependency = ($data(tInvertedDependencyGraph(tModuleName)) >= 10) - } - // If no uninstalled dependencies remain... - if 'tHasUninstalledDependency { - set $listbuild(tServerName, tVersion, tDeployed, tPlatformVersion) = tData - zkill $$$ZPMTempLoadGraph(tCacheTempIndex,tModuleName) - - // Missing server name indicates that it's already present locally; nothing to do in that case. - if (tServerName '= "") { - if ($tlevel = 0) && ($get(pParams("Multicompile","Verbose"),$get(pParams("Verbose"),0))) { - write !,"Queuing module load: ",tModuleName," ",tVersion," @ ",tServerName - } - set tSC = pWorkQueue.QueueCallback( - "##class("_$classname()_").LoadModuleReference", - "##class("_$classname()_").LoadCompleted", - tServerName, tModuleName, tVersion, $get(tDeployed), $get(tPlatformVersion), .pParams, .pDependencyGraph) - $$$ThrowOnError(tSC) - } else { - // Remove this module from dependencies. - set tDependentKey = "" - for { - set tDependentKey = $order($$$ZPMTempLoadGraph(tCacheTempIndex,tDependentKey)) - quit:tDependentKey="" - - kill $$$ZPMTempLoadGraph(tCacheTempIndex,tDependentKey,tModuleName) - } - } - } - } - if (tLocked) { - lock -$$$ZPMTempLoadGraph(tCacheTempIndex) - set tLocked = 0 - } else { - // Only call WaitForComplete once (!!!) - // Recursive calls will do repeat execution of previously-queued jobs. - set tSC = pWorkQueue.WaitForComplete() - $$$ThrowOnError(tSC) - } - - merge $$$ZPMHandledModules($namespace) = pParams("Multicompile","ModuleContext") - } catch e { - if (e.Name["ZSOAP") { - set tSC = $get(%objlasterror,e.AsStatus()) - } else { - set tSC = e.AsStatus() - } - } - if tRestoreParams { - kill pParams - merge pParams = tParamBackup - } - if (tLocked) { - lock -$$$ZPMTempLoadGraph(tCacheTempIndex) - } - quit tSC -} - -/// Intended to be invoked only as a work queue callback (so %status and %workqueue will be defined) -/// Signature must match LoadModuleReference per work queue manager conventions. -ClassMethod LoadCompleted( - pServerName As %String, - pModuleName As %String, - pVersion As %String, - pDeployed As %String, - pPlatformVersion As %String, - ByRef pParams, - ByRef pDependencyGraph) As %Status -{ - // Suspend the error count to avoid spurious messages about errors being detected in load/compile. - $$$SuspendErrorCount - set tSC = $$$OK - set tLocked = 0 - try { - $$$ThrowOnError(%status) - if $$$ISOK(tSC) && $data(pParams("Multicompile","CacheTempIndex"),tCacheTempIndex) { - // Remove loaded dependency from dependencies subscript. - lock +$$$ZPMTempLoadGraph(tCacheTempIndex):$$$LockTimeout - if $test { - set tLocked = 1 - } else { - $$$ThrowStatus($$$ERROR($$$GeneralError,"Failed to obtain lock on dependency graph.")) - } - set tDependentKey = "" - for { - set tDependentKey = $order($$$ZPMTempLoadGraph(tCacheTempIndex,tDependentKey)) - quit:tDependentKey="" - - kill $$$ZPMTempLoadGraph(tCacheTempIndex,tDependentKey,pModuleName) - } - lock -$$$ZPMTempLoadGraph(tCacheTempIndex) - set tLocked = 0 - - // Schedule load of any other modules that may need to be scheduled. - set tSC = ..LoadDependencies(.pDependencyGraph,.pParams,%workqueue) - } - } catch e { - set tSC = e.AsStatus() - } - if (tLocked) { - lock -$$$ZPMTempLoadGraph(tCacheTempIndex) - } - quit tSC -} - ClassMethod LoadQualifiedReference( pReference As %IPM.Storage.QualifiedModuleInfo, ByRef pParams, - ByRef pDependencyGraph, - pSynchronous As %Boolean = 0) As %Status + ByRef pDependencyGraph) As %Status { set tSC = $$$OK try { #dim tReference As %IPM.Storage.QualifiedModuleInfo set tReference = pReference.%ConstructClone() - set tSC = ..LoadModuleReference(tReference.ServerName, tReference.Name, tReference.VersionString, tReference.Deployed, tReference.PlatformVersion, .pParams, .pDependencyGraph, pSynchronous) + set tSC = ..LoadModuleReference(tReference.ServerName, tReference.Name, tReference.VersionString, tReference.Deployed, tReference.PlatformVersion, .pParams, .pDependencyGraph) } catch e { set tSC = e.AsStatus() } @@ -239,14 +43,11 @@ ClassMethod LoadModuleReference( pDeployed As %Boolean, pPlatformVersion As %String, ByRef pParams, - ByRef pDependencyGraph, - pSynchronous As %Boolean = 0) As %Status + ByRef pDependencyGraph) As %Status { // Keep a reference of the singleton in this process (which can be a new process!), so subsequent .%Get() calls return the same instance set configReference = ##class(%IPM.General.EnvironmentConfig).%Get() - // Suspend the error count to avoid spurious messages about errors being detected in load/compile. - $$$SuspendErrorCount #dim tExpression As %IPM.General.SemanticVersionExpression set tSC = $$$OK try { @@ -263,23 +64,11 @@ ClassMethod LoadModuleReference( merge qstruct = pParams("qstruct") } - // Use % variables that intentionally leak in worker processes, to avoid duplicate work when they go out of scope. - #dim %installcontext As %IPM.General.InstallContext - #dim %manager As %IPM.Repo.Manager - if '$$$IsISCWorker { - new %installcontext - new %manager - } - set %installcontext = ##class(%IPM.General.InstallContext).%Get(.tSC) - $$$ThrowOnError(tSC) - do %installcontext.SetGraph(.pDependencyGraph) - merge tIndex = pParams("Multicompile","CacheTempIndex") - do %installcontext.SetCacheTempIndex(.tIndex) - - set %manager = $select($isobject($get(%manager)):%manager,1:##class(%IPM.Repo.Manager).%Get(.tSC)) + #dim manager As %IPM.Repo.Manager + set manager = ##class(%IPM.Repo.Manager).%Get(.tSC) $$$ThrowOnError(tSC) - set tClient = %manager.CheckServiceCache(pServerName,.tAvailable) + set tClient = manager.CheckServiceCache(pServerName,.tAvailable) if 'tAvailable { set tSC = $$$ERROR($$$GeneralError,$$$FormatText("Repository '%1' is unavailable.",pServerName)) quit @@ -309,7 +98,7 @@ ClassMethod LoadModuleReference( // Ensure requested versions match those required by other modules in the namespace, excluding versions currently being installed // (the requirements of such modules are already known to be satisfied) - set tSC = ..GetRequiredVersionExpression(pModuleName,%installcontext.GetPendingModuleList(),.tExpression,.tSourceList) + set tSC = ..GetRequiredVersionExpression(pModuleName,,.tExpression,.tSourceList) if $$$ISERR(tSC) { quit } @@ -330,7 +119,7 @@ ClassMethod LoadModuleReference( } set dotModules = ##class(%File).NormalizeDirectory(".modules", tDirectory) set tmpRepoMgr = ##class(%IPM.General.TempLocalRepoManager).%New(dotModules, 0) - set tSC = ..LoadModuleFromDirectory(tDirectory,.pParams,tDeveloperMode,pServerName,pSynchronous) + set tSC = ..LoadModuleFromDirectory(tDirectory,.pParams,tDeveloperMode,pServerName) set tSC = $$$ADDSC(tSC, tmpRepoMgr.CleanUp()) } else { set tAsArchive = -1 @@ -364,7 +153,7 @@ ClassMethod LoadModuleReference( do tTmpStream.CopyFromAndSave(tPayload) if (tAsArchive) { - set tSC = ..LoadModuleFromArchive(tModRef.Name,tModRef.VersionString,tTmpStream,.pParams, pServerName,pSynchronous) + set tSC = ..LoadModuleFromArchive(tModRef.Name,tModRef.VersionString,tTmpStream,.pParams, pServerName) } else { // Old format (TODO: officially deprecate): try loading a .xml file @@ -406,8 +195,7 @@ ClassMethod LoadModuleFromArchive( pModuleVersion As %String, pArchiveStream As %Stream.Object, ByRef pParams, - pRepository As %String = "", - pSynchronous As %Boolean = 0) As %Status + pRepository As %String = "") As %Status { set tSC = $$$OK try { @@ -438,7 +226,7 @@ ClassMethod LoadModuleFromArchive( set dotModules = ##class(%File).NormalizeDirectory(".modules", tTargetDirectory) set tmpRepoMgr = ##class(%IPM.General.TempLocalRepoManager).%New(dotModules, 0) - set tSC = ..LoadModuleFromDirectory(tTargetDirectory, .pParams, , pRepository,pSynchronous) + set tSC = ..LoadModuleFromDirectory(tTargetDirectory, .pParams, , pRepository) set tSC = $$$ADDSC(tSC, tmpRepoMgr.CleanUp()) if $$$ISERR(tSC) { quit @@ -453,8 +241,7 @@ ClassMethod LoadModuleFromDirectory( pDirectory As %String, ByRef pParams, pOverrideDeveloperMode As %Boolean = 0, - pRepository As %String = "", - pSynchronous As %Boolean = 0) As %Status + pRepository As %String = "") As %Status { set tSC = $$$OK try { @@ -485,7 +272,7 @@ ClassMethod LoadModuleFromDirectory( merge tParams("AngularArtifact") = pParams("AngularArtifact") merge tParams("EnvFiles") = pParams("EnvFiles") } - set tSC = ..LoadNewModule(pDirectory,.tParams,pRepository,pSynchronous) + set tSC = ..LoadNewModule(pDirectory,.tParams,pRepository) if $$$ISERR(tSC) { quit } @@ -1243,8 +1030,7 @@ ClassMethod ExportDocumentForObject( ClassMethod LoadNewModule( pDirectory As %String, ByRef pParams, - pRepository As %String = "", - pSynchronous As %Boolean = 0) As %Status + pRepository As %String = "") As %Status { set tSC = $$$OK set tInitTLevel = $tlevel @@ -1261,15 +1047,6 @@ ClassMethod LoadNewModule( } set commandLineModuleName = $get(params("ModuleName")) - // Check for valid license key prior to top-level module load - // This may throw an exception. - if '$data($$$ZPMHandledModules($namespace)) { - set tLicenseIsValid = ..CheckLicenseKey() - if 'tLicenseIsValid { - write !,"WARNING: Continuing module load without a valid license." - } - } - // Create a singleton instance for logging of warnings/error messages set tLogManager = ##class(%IPM.General.LogManager).%Get(.tSC) $$$ThrowOnError(tSC) @@ -1336,11 +1113,7 @@ ClassMethod LoadNewModule( set tDisplayName = $piece(tFirstLoaded, ".", 1, *-1) set tModuleName = $$$lcase(tDisplayName) - #dim tInstallContext As %IPM.General.InstallContext - set tInstallContext = ##class(%IPM.General.InstallContext).%Get(.tSC) - $$$ThrowOnError(tSC) - - if foundNewModuleObj && 'tInstallContext.ModuleIsDependency(tModuleName) { + if foundNewModuleObj { // Check that on an update command with -path flag, the module in the path matches the base module specified for update. if (commandLineModuleName '= "") && (newModuleObj.Name '= commandLineModuleName) { set msg = $$$FormatText("The specified path does not contain a module matching the specified module to update. Module in path = %1. Specified module = %2.",newModuleObj.Name,commandLineModuleName) @@ -1385,32 +1158,10 @@ ClassMethod LoadNewModule( tstart } - if '$data($$$ZPMHandledModules($namespace)) { - // The purpose of this NEW command is to make sure that the % variable $$$ZPMHandledModules refers to doesn't leak outside this scope. - // This only happens for the first module to be loaded in a set of dependencies (using zpm "load ..." or zpm "install ...") - // $$$ZPMHandledModules is also used in the ExecutePhases method of %IPM.Storage.Module to - // cover cases where new dependencies are added and a module is compiled without reloading, and in the BuildDependencyGraph - // method to treat installed snapshot versions as installed rather than forcing reload if they have been reloaded - // as part of the same root module operation. - new $$$ZPMHandledModules - set $$$ZPMHandledModules($namespace) = "" //Initialize. - } - merge $$$ZPMHandledModules($namespace) = params("Multicompile","ModuleContext") - $$$ThrowOnError(##class(%IPM.Storage.Module).CheckSystemRequirements(tModuleName)) - if 'tInstallContext.ModuleIsDependency(tModuleName) { - if 'pSynchronous { - // Regular async multi-threaded loading of dependencies - set tSC = tModule.LoadDependencies("",.params) - $$$ThrowOnError(tSC) - } else { - // Temporary custom loading of dependencies in a synchronous - // manner to prevent lock timeouts until lifecycle rework - // is complete (HSIEO-4450) - do ..SyncLoadDependencies(tModule, .params) - } - } + kill params("ModuleName") // Ensure module name is not passed down to dependency loads + do ..LoadDependencies(tModule, .params) set tSC = $system.OBJ.Load(pDirectory_"module.xml",$select(tVerbose:"d",1:"-d"),,.tLoadedList) $$$ThrowOnError(tSC) @@ -1443,18 +1194,13 @@ ClassMethod LoadNewModule( quit tSC } -/// Temporary workaround to synchronously load dependencies. Can be removed once -/// HSIEO-4450 is complete. -ClassMethod SyncLoadDependencies( +/// Load dependencies of a module in a synchronous manner, one at a time, in the correct order. +ClassMethod LoadDependencies( pModule As %IPM.Storage.Module, ByRef pParams) { set isVerbose = $get(pParams("Verbose"),0) - /* - * Call to BuildDependencyGraph copied from %IPM.Storage.Module:LoadDependencies - */ - set reloadSnapshots = +$get(pParams("UpdateSnapshots")) set permitDowngrade = +$get(pParams("PermitDowngrade")) set ignoreInstalled = +$get(pParams("IgnoreInstalled")) @@ -1463,9 +1209,6 @@ ClassMethod SyncLoadDependencies( $$$ThrowOnError(sc) write "Done." - /* This setting is copied from %IPM.Main:Install */ - set pParams("Install") = 1 - do ..ConstructInvertedDependencyGraph(.depdendencyGraph, .invertedDependencyGraph) if isVerbose { write !, "Created inverted dependency graph from dependency graph" @@ -1566,7 +1309,7 @@ ClassMethod CheckLicenseKey() As %Boolean // Limit the number of attempts in case this somehow ends up running in a non-interactive process. #define MaxTries 5 set tValidLicense = ($system.License.GetKeyStatus() '= "Invalid") - while ('tValidLicense) && $$$InProgrammerMode && ('$$$IsISCWorker) && ($increment(tTries) <= $$$MaxTries) { + while ('tValidLicense) && $$$InProgrammerMode && ($increment(tTries) <= $$$MaxTries) { write !!,"Your system has no (valid) license key present" write !,"Copy a valid license key into "_$system.Util.ManagerDirectory() write !,"and then enter 'y' to activate it. Enter 'n' to continue without a license key, " diff --git a/src/inc/IPM/Common.inc b/src/inc/IPM/Common.inc index cadd50bf..2ad75824 100644 --- a/src/inc/IPM/Common.inc +++ b/src/inc/IPM/Common.inc @@ -5,9 +5,6 @@ ROUTINE %IPM.Common [Type=INC] #; Helper for XML import of documents #define ZPMStudioDocumentModule %IPMStudioDocumentModule -#; Local % Variable to track modules already handled for a given end goal -#define ZPMHandledModules %IPMHandledModules - #; Local % Variable to indicate that ^Sources update trigger should not be run for modifications to individual resources #define ZPMDeferModifyResources %IPMDeferModifyResources @@ -38,8 +35,8 @@ ROUTINE %IPM.Common [Type=INC] #; Log levels #define ZPMLogTRACE 0 -#define ZPMLogINFO 1 -#define ZPMLogWARNING 2 +#define ZPMLogINFO 1 +#define ZPMLogWARNING 2 #define ZPMLogERROR 3 #; System method/special variable wrappers diff --git a/tests/integration_tests/Test/PM/Integration/Update.cls b/tests/integration_tests/Test/PM/Integration/Update.cls index 7df68f60..513c2a34 100644 --- a/tests/integration_tests/Test/PM/Integration/Update.cls +++ b/tests/integration_tests/Test/PM/Integration/Update.cls @@ -46,6 +46,7 @@ Method OnBeforeAllTests() As %Status Method TestAllNoErrorModulesNoMirror() { if $system.Mirror.IsMember() { + do $$$AssertSkipped("Skipping test since this is a mirror member") return } // Simple module without dependencies diff --git a/tests/unit_tests/Test/PM/Unit/CLI.cls b/tests/unit_tests/Test/PM/Unit/CLI.cls index 2ea8e973..4130f4fc 100644 --- a/tests/unit_tests/Test/PM/Unit/CLI.cls +++ b/tests/unit_tests/Test/PM/Unit/CLI.cls @@ -55,9 +55,11 @@ Method TestParser() set tResults(tCommands)="list-installed" set tResults(tCommands,"modifiers","tree")="" - set tCommands($increment(tCommands)) = "install SomeModule" + set tCommands($increment(tCommands)) = "install SomeModule -synchronous" set tResults(tCommands)="install" set tResults(tCommands,"parameters","module")="SomeModule" + set tResults(tCommands,"modifiers","synchronous")="" + set tResults(tCommands,"modifiers","synchronous","deprecated")=1 set tCommands($increment(tCommands)) = "install SomeModule 0.0.1-prerelease.42+snapshot" set tResults(tCommands)="install"