class Dependabot::Uv::Requirement
def self.parse(obj)
def self.parse(obj) return ["=", Uv::Version.new(obj.to_s)] if obj.is_a?(Gem::Version) line = obj.to_s if (matches = PARENS_PATTERN.match(line)) line = matches[1] end unless (matches = PATTERN.match(line)) msg = "Illformed requirement [#{obj.inspect}]" raise BadRequirementError, msg end return DefaultRequirement if matches[:op] == ">=" && matches[:version] == "0" [matches[:op] || "=", Uv::Version.new(T.must(matches[:version]))] end
def self.requirements_array(requirement_string)
def self.requirements_array(requirement_string) return [new(nil)] if requirement_string.nil? if (matches = PARENS_PATTERN.match(requirement_string)) requirement_string = matches[1] end T.must(requirement_string).strip.split(OR_SEPARATOR).map do |req_string| new(req_string.strip) end end
def convert_caret_req(req_string)
Poetry uses ^ requirements
def convert_caret_req(req_string) version = req_string.gsub(/^\^/, "") parts = version.split(".") parts.fill(0, parts.length...3) first_non_zero = parts.find { |d| d != "0" } first_non_zero_index = first_non_zero ? parts.index(first_non_zero) : parts.count - 1 upper_bound = parts.map.with_index do |part, i| if i < first_non_zero_index then part elsif i == first_non_zero_index then (part.to_i + 1).to_s # .dev has lowest precedence: https://packaging.python.org/en/latest/specifications/version-specifiers/#summary-of-permitted-suffixes-and-relative-ordering elsif i > first_non_zero_index && i == 2 then "0.dev" else 0 end end.join(".") [">= #{version}", "< #{upper_bound}"] end
def convert_python_constraint_to_ruby_constraint(req_string)
def convert_python_constraint_to_ruby_constraint(req_string) return nil if req_string.nil? return nil if req_string == "*" req_string = req_string.gsub("~=", "~>") req_string = req_string.gsub(/(?<=\d)[<=>].*\Z/, "") if req_string.match?(/~[^>]/) then convert_tilde_req(req_string) elsif req_string.start_with?("^") then convert_caret_req(req_string) elsif req_string.include?(".*") then convert_wildcard(req_string) else req_string end end
def convert_tilde_req(req_string)
Poetry uses ~ requirements.
def convert_tilde_req(req_string) version = req_string.gsub(/^~\>?/, "") parts = version.split(".") parts << "0" if parts.count < 3 "~> #{parts.join('.')}" end
def convert_wildcard(req_string)
def convert_wildcard(req_string) # NOTE: This isn't perfect. It replaces the "!= 1.0.*" case with # "!= 1.0.0". There's no way to model this correctly in Ruby :'( quoted_ops = OPS.keys.sort_by(&:length).reverse .map { |k| Regexp.quote(k) }.join("|") op = req_string.match(/\A\s*(#{quoted_ops})?/) .captures.first.to_s&.strip exact_op = ["", "=", "==", "==="].include?(op) req_string.strip .split(".") .first(req_string.split(".").index { |s| s.include?("*") } + 1) .join(".") .gsub(/\*(?!$)/, "0") .gsub(/\*$/, "0.dev") .tap { |s| exact_op ? s.gsub!(/^(?<!!)=*/, "~>") : s } end
def exact?
def exact? return false unless @requirements.size == 1 %w(= == ===).include?(@requirements[0][0]) end
def initialize(*requirements)
def initialize(*requirements) requirements = requirements.flatten.flat_map do |req_string| next if req_string.nil? # Standard python doesn't support whitespace in requirements, but Poetry does. req_string = req_string.gsub(/(\d +)([<=>])/, '\1,\2') req_string.split(",").map(&:strip).map do |r| convert_python_constraint_to_ruby_constraint(r) end end super(requirements) end
def satisfied_by?(version)
def satisfied_by?(version) version = Uv::Version.new(version.to_s) requirements.all? { |op, rv| (OPS[op] || OPS["="]).call(version, rv) } end