diff --git a/bin/crew b/bin/crew index 4661cc9f8..2b19e6cd5 100755 --- a/bin/crew +++ b/bin/crew @@ -1220,6 +1220,24 @@ def resolve_dependencies dependencies = @pkg.get_deps_list(return_attr: true) + # compare dependency version with required range (if installed) + dependencies&.each do |dep| + dep_name = dep.keys[0] + dep_info = @device[:installed_packages].select { |pkg| pkg[:name] == dep_name }[0] + + # skip if dependency is not installed + + next unless dep_info + + _tags, version_check = dep.values[0] + installed_version = dep_info[:version] + + next unless version_check + + # abort if the range is not fulfilled + abort unless version_check.call(installed_version) + end + # leave only dependency names (remove all package attributes returned by @pkg.get_deps_list) dependencies.map!(&:keys).flatten! diff --git a/lib/const.rb b/lib/const.rb index e32e799e6..086abfc21 100644 --- a/lib/const.rb +++ b/lib/const.rb @@ -4,7 +4,7 @@ require 'etc' require 'open3' OLD_CREW_VERSION ||= defined?(CREW_VERSION) ? CREW_VERSION : '1.0' -CREW_VERSION ||= '1.65.3' unless defined?(CREW_VERSION) && CREW_VERSION == OLD_CREW_VERSION +CREW_VERSION ||= '1.65.4' unless defined?(CREW_VERSION) && CREW_VERSION == OLD_CREW_VERSION # Kernel architecture. KERN_ARCH ||= Etc.uname[:machine] diff --git a/lib/package.rb b/lib/package.rb index e93c00de1..30fe0a09d 100644 --- a/lib/package.rb +++ b/lib/package.rb @@ -122,7 +122,7 @@ class Package end def self.get_deps_list(pkg_name = name, return_attr: false, hash: false, include_build_deps: 'auto', include_self: false, - pkg_tags: [], highlight_build_deps: true, exclude_buildessential: false, top_level: true) + pkg_tags: [], ver_check: nil, highlight_build_deps: true, exclude_buildessential: false, top_level: true) # get_deps_list: get dependencies list of pkg_name (current package by default) # # pkg_name: package to check dependencies, current package by default @@ -160,7 +160,7 @@ class Package end # Parse dependencies recursively. - expanded_deps = deps.uniq.map do |dep, dep_tags| + expanded_deps = deps.uniq.map do |dep, (dep_tags, ver_check)| # Check build dependencies only if building from source is needed/specified. # Do not recursively find :build based build dependencies. next unless (include_build_deps == true && @crew_current_package == pkg_obj.name) || @@ -175,7 +175,7 @@ class Package # Check dependency by calling this function recursively. next \ send( - __method__, dep, pkg_tags: tags, include_self: true, top_level: false, + __method__, dep, pkg_tags: tags, ver_check:, include_self: true, top_level: false, hash:, return_attr:, include_build_deps:, highlight_build_deps:, exclude_buildessential: ) elsif hash && top_level @@ -203,7 +203,7 @@ class Package elsif include_self # Return pkg_name itself if this function is called as a recursive loop (see `expanded_deps`). if return_attr - return [expanded_deps, { pkg_name => pkg_tags }].flatten + return [expanded_deps, { pkg_name => [pkg_tags, ver_check] }].flatten else return [expanded_deps, pkg_name].flatten end @@ -288,8 +288,9 @@ class Package puts tree_view end - def self.depends_on(dependency) + def self.depends_on(dependency, ver_range = nil) @dependencies ||= {} + ver_check = nil dep_tags = [] # Add element in "[ name, [ tag1, tag2, ... ] ]" format. @@ -304,7 +305,30 @@ class Package dep_name = dependency end - @dependencies.store(dep_name, dep_tags) + # Process dependency version range if specified. + # example: + # depends_on name, '>= 1.0' + # + # Operators can be: '>=', '==', '<=', '<', or '>' + if ver_range + operator, target_ver = ver_range.split(' ', 2) + + # lambda for comparing the given range with installed version + ver_check = lambda do |installed_ver| + unless Gem::Version.new(installed_ver).send(operator.to_sym, Gem::Version.new(target_ver)) + # Print error if the range is not fulfilled. + warn <<~EOT.lightred + Package #{name} depends on '#{dep_name}' (#{operator} #{target_ver}), however version '#{installed_ver}' is currently installed :/ + + Run `crew update && crew upgrade` and try again? + EOT + return false + end + return true + end + end + + @dependencies.store(dep_name, [dep_tags, ver_check]) end def self.binary?(architecture) = !@build_from_source && @binary_sha256&.key?(architecture)