apm_dependency_check_new (public)
apm_dependency_check_new -repository_array repository_array \ -package_keys package_keys
Defined in packages/acs-tcl/tcl/apm-install-procs.tcl
Checks dependencies and finds out which packages are required to install the requested packages. In case some packages cannot be installed due to failed dependencies, it returns which packages out of the requested can be installed, and which packages, either originally requested or required by those, could not be installed, and why.
- Switches:
- -repository_array (required)
- Name of an array in the caller's namespace containing the repository of available packages as returned by apm_get_package_repository.
- -package_keys (required)
- The list of package_keys of the packages requested to be installed.
- Returns:
- An array list with the following elements:
- status: 'ok' or 'failed'.
- install: If status is 'ok', this is the complete list of packages that need to be installed, in the order in which they need to be installed. If status is 'failed', the list of packages that can be installed.
- failed: If status is 'failed', an array list keyed by package_key of 2-tuples of (required-uri, required-version) of requirements that could not be satisfied.
- packages: The list of package_keys of the packages touched upon, either because they were originally requested, or because they were required. If status is 'ok', will be identical to 'install'.
- See Also:
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
Source code: upvar 1 $repository_array repository array set result { status failed install {} failed {} packages {} } # 'pending_packages' is an array keyed by package_key with a value of 1 for each package pending installation # When dependencies have been met, the entry will be unset array set pending_packages [list] foreach package_key $package_keys { set pending_packages($package_key) 1 } # 'installed_packages' is an array keyed by package_key with a value of 1 for each package # whose dependencies have been met and is ready to be installed array set installed_packages [list] # 'provided' will keep track of what we've provided with the currently installed packages # combined with the packages which we're already able to install apm_get_installed_provides -array provided # 'required' will keep track of unsatisfied dependencies # keyed by (service-uri) and will contain the largest version number required array set required [list] # 'required_by' will keep track of unsatisfied dependencies # keyed by (service-uri) and will contain the largest version number required array set required_by [list] # Just to get us started set updated_p 1 ns_log notice "apm_dependency_check_new: STARTING DEPENDENCY CHECK [array names pending_packages]" # Outer loop tries to find a package from the repository to add if # we're stuck because of unsatisfied dependencies while { $updated_p } { # Keep looping over pending_package_keys, trying to add packages # So long as we've added another, try looping again, as there may be cross-dependencies while { $updated_p && [array size pending_packages] > 0 } { set updated_p 0 # Try to add a package from foreach package_key [array names pending_packages] { if {![info exists repository($package_key)]} continue set version $repository($package_key) set satisfied_p 1 foreach req [concat [dict get $version embeds] [dict get $version extends] [dict get $version requires]] { lassign $req req_uri req_version if { ![info exists provided($req_uri)] || [apm_version_names_compare $provided($req_uri) $req_version] == -1 } { ns_log Debug "apm_dependency_check_new: $package_key embeds, extends or requires $req_uri $req_version => failed" set satisfied_p 0 # Mark this as a requirement if { ![info exists required($req_uri)] || [apm_version_names_compare $required($req_uri) $req_version] == -1 } { set required($req_uri) $req_version } } else { ns_log Debug "apm_dependency_check_new: $package_key embeds, extends or requires $req_uri $req_version => OK" } } if { $satisfied_p } { # Record as set to go set installed_packages($package_key) 1 # Remove from pending list unset pending_packages($package_key) # Add to install-list, as this is important for ordering the installation of packages correctly lappend result(install) $package_key # Add to list of packages touched lappend result(packages) $package_key # Record what this package provides, and remove it from the required list, if appropriate foreach prov [dict get $version provides] { lassign $prov prov_uri prov_version # If what we provide is not already provided, or the alredady provided version is # less than what we provide, record this new provision if { ![info exists provided($prov_uri)] || [apm_version_names_compare $provided($prov_uri) $prov_version] == -1 } { set provided($prov_uri) $prov_version } # If what we provide is required, and the required version is less than what we provide, # drop the requirement if { [info exists required($prov_uri)] && [apm_version_names_compare $required($prov_uri) $prov_version] <= 0 } { unset required($prov_uri) } } # Another package has been added, so repeat set updated_p 1 } } } # Inner loop completed. Either we're done, or there are packages that have dependencies # not currently on the pending_package_keys list. set updated_p 0 if { [array size pending_packages] > 0 } { # There are packages that have unsatisfied dependencies # Those unmet requirements will be registered in the 'required' array # Let's find a package which satisfies at least one of the requirements in 'required' foreach package_key [array names repository] { if { [info exists pending_packages($package_key)] || [info exists installed_packages($package_key)] } { # Packages already on the pending list, or already verified ok won't help us any continue } if {![info exists repository($package_key)]} { ns_log notice "package $package_key is apparently missing" set pending_packages($package_key) 1 set updated_p 1 break } set version $repository($package_key) ns_log Debug "apm_dependency_check_new: Considering $package_key: $version" # Let's see if this package provides anything we need foreach prov [dict get $version provides] { lassign $prov prov_uri prov_version if { [info exists required($prov_uri)] && [apm_version_names_compare $required($prov_uri) $prov_version] <= 0 } { ns_log Debug "apm_dependency_check_new: Adding $package_key, as it provides $prov_uri $prov_version" # If this package provides something that's required in a version high enough # add it to the pending list set pending_packages($package_key) 1 # We've changed something set updated_p 1 # Let's try for another go at installing packages break } } # Break all the way back to installing pending packages again if { $updated_p } { break } } } } if { [array size pending_packages] == 0 } { set result(status) ok } else { set result(status) failed array set failed [list] # There were problems, now be helpful # Find out which packages couldn't be installed and why foreach package_key [array names pending_packages] { # Add to touched packages lappend result(packages) $package_key if {![info exists repository($package_key)]} { lappend failed($package_key) [list Unknown "package $package_key"] continue } set version $repository($package_key) # Find unsatisfied requirements foreach req [concat [dict get $version embeds] [dict get $version extends] [dict get $version requires]] { lassign $req req_uri req_version if { ![info exists provided($req_uri)] || [apm_version_names_compare $provided($req_uri) $req_version] == -1 } { lappend failed($package_key) [list $req_uri $req_version] if { [info exists provided($req_uri)] } { ns_log Debug "apm_dependency_check_new: Failed dependency: $package_key embeds/extends/requires $req_uri $req_version, but we only provide $provided($req_uri)" } else { ns_log Debug "apm_dependency_check_new: Failed dependency: $package_key embeds/extends/requires $req_uri $req_version, but we don't have it" } } } } set result(failed) [array get failed] } return [array get result]Generic XQL file: packages/acs-tcl/tcl/apm-install-procs.xql
PostgreSQL XQL file: packages/acs-tcl/tcl/apm-install-procs-postgresql.xql
Oracle XQL file: packages/acs-tcl/tcl/apm-install-procs-oracle.xql