| # Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with this |
| # work for additional information regarding copyright ownership. The ASF |
| # licenses this file to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| # License for the specific language governing permissions and limitations under |
| # the License. |
| |
| autoload :Hpricot, 'hpricot' |
| |
| module Buildr #:nodoc: |
| |
| # Search best artifact version from remote repositories |
| module ArtifactSearch |
| extend self |
| |
| def include(method = nil) |
| (@includes ||= []).tap { push method if method } |
| end |
| |
| def exclude(method = nil) |
| (@excludes ||= []).tap { push method if method } |
| end |
| |
| # TODO: return the url for best matching repo |
| def best_version(spec, *methods) |
| spec = Artifact.to_hash(spec) |
| spec[:version] = requirement = VersionRequirement.create(spec[:version]) |
| select = lambda do |candidates| |
| candidates.find { |candidate| requirement.satisfied_by?(candidate) } |
| end |
| result = nil |
| methods = search_methods if methods.empty? |
| if requirement.composed? |
| until result || methods.empty? |
| method = methods.shift |
| type = method.keys.first |
| from = method[type] |
| if (include.empty? || !(include & [:all, type, from]).empty?) && |
| (exclude & [:all, type, from]).empty? |
| if from.respond_to?(:call) |
| versions = from.call(spec.dup) |
| else |
| versions = send("#{type}_versions", spec.dup, *from) |
| end |
| result = select[versions] |
| end |
| end |
| end |
| result ||= requirement.default |
| raise "Could not find #{Artifact.to_spec(spec)}" + |
| "\n You may need to use an specific version instead of a requirement" unless result |
| spec.merge :version => result |
| end |
| |
| def requirement?(spec) |
| VersionRequirement.requirement?(spec[:version]) |
| end |
| |
| private |
| def search_methods |
| [].tap do |
| push :runtime => [Artifact.list] |
| push :local => Buildr.repositories.local |
| Buildr.repositories.remote.each { |remote| push :remote => remote } |
| push :mvnrepository => [] |
| end |
| end |
| |
| def depend_version(spec) |
| spec[:version][/[\w\.]+/] |
| end |
| |
| def runtime_versions(spec, artifacts) |
| spec_classif = spec.values_at(:group, :id, :type) |
| artifacts.inject([]) do |in_memory, str| |
| candidate = Artifact.to_hash(str) |
| if spec_classif == candidate.values_at(:group, :id, :type) |
| in_memory << candidate[:version] |
| end |
| in_memory |
| end |
| end |
| |
| def local_versions(spec, repo) |
| path = (spec[:group].split(/\./) + [spec[:id]]).flatten.join('/') |
| Dir[File.expand_path(path + "/*", repo)].map { |d| d.pathmap("%f") }.sort.reverse |
| end |
| |
| def remote_versions(art, base, from = :metadata, fallback = true) |
| path = (art[:group].split(/\./) + [art[:id]]).flatten.join('/') |
| base ||= "https://repo1.maven.org/maven2" |
| uris = {:metadata => "#{base}/#{path}/maven-metadata.xml"} |
| uris[:listing] = "#{base}/#{path}/" if base =~ /^https?:/ |
| xml = nil |
| until xml || uris.empty? |
| begin |
| xml = URI.read(uris.delete(from)) |
| rescue URI::NotFoundError => e |
| from = fallback ? uris.keys.first : nil |
| end |
| end |
| return [] unless xml |
| doc = Hpricot(xml) |
| case from |
| when :metadata then |
| doc.search("versions/version").map(&:innerHTML).reverse |
| when :listing then |
| doc.search("a[@href]").inject([]) { |vers, a| |
| vers << a.innerHTML.chop if a.innerHTML[-1..-1] == '/' |
| vers |
| }.sort.reverse |
| else |
| fail "Don't know how to parse #{from}: \n#{xml.inspect}" |
| end |
| end |
| |
| def mvnrepository_versions(art) |
| uri = "http://www.mvnrepository.com/artifact/#{art[:group]}/#{art[:id]}" |
| xml = begin |
| URI.read(uri) |
| rescue URI::NotFoundError => e |
| puts e.class, e |
| return [] |
| end |
| doc = Hpricot(xml) |
| doc.search("table.grid/tr/td[1]/a").map(&:innerHTML) |
| end |
| |
| end # ArtifactSearch |
| end |