blob: 0abef26645e146e033308466f7be41aa024709e5 [file] [log] [blame]
# 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