lib/buildr/ivy_extension.rb in ivy4r-0.6.0 vs lib/buildr/ivy_extension.rb in ivy4r-0.7.0

- old
+ new

@@ -2,47 +2,55 @@ module Buildr module Ivy # TODO extend extension to download ivy stuff with dependencies automatically -# VERSION = '2.1.0-rc1' + # VERSION = '2.1.0-rc1' class << self def setting(*keys) setting = Buildr.settings.build['ivy'] keys.each { |key| setting = setting[key] unless setting.nil? } setting end -# def version -# setting['version'] || VERSION -# end -# def dependencies -# @dependencies ||= [ -# "org.apache.ivy:ivy:jar:#{version}", -# 'com.jcraft:jsch:jar:1.41', -# 'oro:oro:jar:2.08' -# ] -# end + # def version + # setting['version'] || VERSION + # end + # def dependencies + # @dependencies ||= [ + # "org.apache.ivy:ivy:jar:#{version}", + # 'com.jcraft:jsch:jar:1.41', + # 'oro:oro:jar:2.08' + # ] + # end end class IvyConfig + TARGETS = [:compile, :test, :package] + TYPES = [:conf, :include, :exclude] attr_accessor :extension_dir, :resolved + attr_reader :post_resolve_task_list + # Store the current project and initialize ivy ant wrapper def initialize(project) @project = project if project.parent.nil? @extension_dir = @project.base_dir + @post_resolve_task_list = [] else @extension_dir = @project.parent.ivy.extension_dir @base_ivy = @project.parent.ivy unless own_file? end + @target_config = Hash.new do + |hash, key| hash[key] = {} + end end - + def enabled? @enabled ||= Ivy.setting('enabled') || true end def own_file? @@ -68,14 +76,18 @@ def file_project own_file? ? @project : @base_ivy.file_project end # Returns the artifacts for given configurations as array + # this is a post resolve task. def deps(*confs) configure - pathid = "ivy.deps." + confs.join('.') - ant.cachepath :conf => confs.join(','), :pathid => pathid + confs = confs.reject {|c| c.nil? || c.blank? } + unless confs.empty? + pathid = "ivy.deps." + confs.join('.') + ant.cachepath :conf => confs.join(','), :pathid => pathid + end end # Returns ivy info for configured ivy file using a new ant instance. def info if @base_ivy @@ -107,10 +119,12 @@ if @base_ivy @base_ivy.resolve else unless @resolved @resolved = ant.resolve :file => file + @project.send(:info, "Calling '#{post_resolve_tasks.size}' post_resolve tasks for '#{@project.name}'") + post_resolve_tasks.each { |p| p.call(self) } end end end # Returns the additional infos for the manifest file. @@ -310,67 +324,116 @@ @report_dir = report_dir[0] self end end - # Set the configuration artifacts to use in package tasks like +:war+ or +:ear+. - # <tt>project.ivy.package_conf('server', 'client')</tt> - # or - # <tt>project.ivy.package_conf(['server', 'client'])</tt> - def package_conf(*package_conf) - if package_conf.empty? - @package_conf ||= [Ivy.setting('package.conf') || 'prod'].flatten.uniq - else - @package_conf = [package_conf].flatten.uniq - self - end + # Adds given block as post resolve action that is executed directly after #resolve has been called. + # Yields this ivy config object into block. + # <tt>project.ivy.post_resolve { |ivy| p "all deps:" + ivy.deps('all').join(", ") }</tt> + def post_resolve(&block) + post_resolve_tasks << block if block end - # Sets the includes pattern(s) to use for packages. I.e. - # <tt>project.ivy.package_include(/\.jar/, /\.gz/)</tt> - def package_include(*includes) - if includes.empty? - @package_include ||= [Ivy.setting('package.include') || /\.jar/].flatten.uniq - else - @package_include = [includes].flatten.uniq - self + # Filter artifacts for given configuration with provided filter values, this is a post resolve + # task like #deps. + # <tt>project.ivy.filter('server', 'client', :include => /b.*.jar/, :exclude => [/a\.jar/, /other.*\.jar/])</tt> + def filter(*confs) + filter = confs.last.kind_of?(Hash) ? confs.pop : {} + unless (filter.keys - [:include, :exclude]).empty? + raise ArgumentError, "Invalid filter use :include and/or :exclude only: given #{filter.keys.inspect}" end + includes, excludes = filter[:include] || [], filter[:exclude] || [] + + artifacts = deps(*confs.flatten) + if artifacts + artifacts = artifacts.find_all do |lib| + lib = File.basename(lib) + includes = includes.reject {|i| i.nil? || i.blank? } + should_include = includes.empty? || includes.any? {|include| include === lib } + should_include && !excludes.any? {|exclude| exclude === lib} + end + end + + artifacts end - # Sets the exclude pattern(s) to use for packages. I.e. - # <tt>project.ivy.package_exclude(/\.zip/, /\.tar/)</tt> - def package_exclude(*excludes) - if excludes.empty? - @package_exclude ||= [Ivy.setting('package.exlude') || ''].flatten.uniq + # :call-seq: + # for types: + # project.ivy.include(:compile => [/\.jar/, /\.gz/], :package => 'cglib.jar') + # project.ivy.exclude(:test => 'cglib.jar') + # project.ivy.conf(:compile => 'compile', :test => 'test', :package => 'prod') + # for targets: + # project.ivy.compile(:conf => 'compile', :exclude => /cglib.jar/) + # project.ivy.test(:conf => 'test') + # project.ivy.package(:conf => 'prod', :include => /.*.jar/, :exclude => /cglib.jar/) + # or verbose: + # project.ivy.compile_conf or project.ivy.conf_compile + # project.ivy.compile_include or project.ivy.include_compile + # the same for the other possible options. + # + # Uses #method_missing to handle the options. + # Generic handling of settings for +target+ and +type+. All calls in the form + # <tt>target_type({})</tt> or <tt>type_target({})</tt> are handled via this method see + # #TARGETS #TYPES for more information about valid targets and types. + def method_missing(methodname, *args, &block) + if block.nil? && valid_config_call?(methodname) + target, type = target(methodname), type(methodname) + if target && type + handle_variable(target, type, *args) + elsif target && args.size == 1 && args.last.kind_of?(Hash) + args[0].each { |type, value| handle_variable(target, type, *value) } + self + elsif type && args.size == 1 && args.last.kind_of?(Hash) + args[0].each { |target, value| handle_variable(target, type, *value) } + self + else + raise "Could not recognize config call for method '#{methodname}', args=#{args.inspect}" + end else - @package_exclude = [excludes].flatten.uniq - self + super.method_missing(methodname, *args, &block) end end + + private + def target(targets) + t = targets.to_s.split('_').find { |t| TARGETS.member? t.to_sym } + t ? t.to_sym : nil + end - # Set the configuration artifacts to use for compile tasks, added to <tt>compile.with</tt> - # <tt>project.ivy.compile_conf('server', 'client')</tt> - def compile_conf(*compile_conf) - if compile_conf.empty? - @compile_conf ||= [Ivy.setting('compile.conf') || 'compile'].flatten.uniq - else - @compile_conf = [compile_conf].flatten.uniq - self + def type(types) + t = types.to_s.split('_').find { |t| TYPES.member? t.to_sym } + t ? t.to_sym : nil + end + + def valid_config_call?(method_name) + valid_calls = [] + TYPES.each do|type| + TARGETS.each do|target| + valid_calls << type.to_s << target.to_s << "#{type}_#{target}" << "#{target}_#{type}" + end end + valid_calls.member? method_name.to_s end - # Set the configuration artifacts to use for test tasks, added to <tt>test.compile.with</tt> - # and <tt>test.with</tt>. Note that all artifacts from #compile_conf are added automatically. - # <tt>project.ivy.test_conf('server', 'test')</tt> - def test_conf(*test_conf) - if test_conf.empty? - @test_conf ||= [Ivy.setting('test.conf') || 'test'].flatten.uniq + # Sets a variable for given basename and type to given values. If values are empty returns the + # current value. + # I.e. <tt>handle_variable(:package, :include, /blua.*\.jar/, /da.*\.jar/)</tt> + def handle_variable(target, type, *values) + unless TARGETS.member?(target) && TYPES.member?(type) + raise ArgumentError, "Unknown config value for target #{target.inspect} and type #{type.inspect}" + end + if values.empty? + @target_config[target][type] ||= [Ivy.setting("#{target.to_s}.#{type.to_s}") || ''].flatten.uniq else - @test_conf = [test_conf].flatten.uniq + @target_config[target][type] = [values].flatten.uniq self end end + + def post_resolve_tasks + @base_ivy ? @base_ivy.post_resolve_task_list : post_resolve_task_list + end end =begin rdoc The Ivy Buildr extension adding the new tasks for ivy. @@ -396,28 +459,38 @@ class << self def add_ivy_deps_to_java_tasks(project) resolve_target = project.ivy.file_project.task('ivy:resolve') project.task :compiledeps => resolve_target do - compile_conf = [project.ivy.compile_conf].flatten - project.compile.with project.ivy.deps(compile_conf) - info "Ivy adding compile dependencies '#{compile_conf.join(', ')}' to project '#{project.name}'" + includes = project.ivy.compile_include + excludes = project.ivy.compile_exclude + confs = [project.ivy.compile_conf].flatten + if deps = project.ivy.filter(confs, :include => includes, :exclude => excludes) + project.compile.with deps + info "Ivy adding compile dependencies '#{confs.join(', ')}' to project '#{project.name}'" + end end project.task :compile => "#{project.name}:compiledeps" project.task :testdeps => resolve_target do + includes = project.ivy.test_include + excludes = project.ivy.test_exclude confs = [project.ivy.test_conf, project.ivy.compile_conf].flatten.uniq - project.test.with project.ivy.deps(confs) - info "Ivy adding test dependencies '#{confs.join(', ')}' to project '#{project.name}'" + if deps = project.ivy.filter(confs, :include => includes, :exclude => excludes) + project.test.with deps + info "Ivy adding test dependencies '#{confs.join(', ')}' to project '#{project.name}'" + end end project.task "test:compile" => "#{project.name}:testdeps" project.task :javadocdeps => resolve_target do confs = [project.ivy.test_conf, project.ivy.compile_conf].flatten.uniq - project.javadoc.with project.ivy.deps(confs) - info "Ivy adding javadoc dependencies '#{confs.join(', ')}' to project '#{project.name}'" + if deps = project.ivy.deps(confs) + project.javadoc.with deps + info "Ivy adding javadoc dependencies '#{confs.join(', ')}' to project '#{project.name}'" + end end project.task :javadoc => "#{project.name}:javadocdeps" [project.task(:eclipse), project.task(:idea), project.task(:idea7x)].each do |task| task.prerequisites.each{|p| p.enhance ["#{project.name}:compiledeps", "#{project.name}:testdeps"]} @@ -435,25 +508,20 @@ project.task :build => task end end def add_prod_libs_to_distributeables(project) - includes = project.ivy.package_include - excludes = project.ivy.package_exclude pkgs = project.packages.find_all { |pkg| [:war, :ear].member? pkg.type } pkgs.each do |pkg| name = "#{pkg.name}deps" task = project.task name => project.ivy.file_project.task('ivy:resolve') do + includes = project.ivy.package_include + excludes = project.ivy.package_exclude confs = project.ivy.package_conf - libs = project.ivy.deps(confs).find_all do |lib| - lib = File.basename(lib) - use = includes.any? {|include| include === lib } && !excludes.any? {|exclude| exclude === lib} - verbose "Including '#{lib}' from package '#{pkg}' in project '#{project.name}'" if use - info "Excluding '#{lib}' from package '#{pkg}' in project '#{project.name}'" unless use - use + if deps = project.ivy.filter(confs, :include => includes, :exclude => excludes) + pkg.with :libs => deps + info "Adding production libs from conf '#{confs.join(', ')}' to package '#{pkg.name}' in project '#{project.name}'" end - pkg.with :libs => libs - info "Adding production libs from conf '#{confs.join(', ')}' to package '#{pkg.name}' in project '#{project.name}'" end project.task :build => task end end