lib/java/compile.rb in buildr-0.18.0 vs lib/java/compile.rb in buildr-0.19.0
- old
+ new
@@ -1,11 +1,34 @@
+require "core/project"
+require "core/build"
+require "java/artifact"
+require "java/java"
+require "tasks/filter"
+
module Buildr
module Java
+ # Wraps Javac in a task that does all the heavy lifting.
+ #
+ # Accepts multiple source directories that are invoked as prerequisites before compilation.
+ # You can pass a task as a source directory, e.g. compile.from(apt).
+ #
+ # Likewise, classpath dependencies are invoked before compiling. All classpath dependencies
+ # are evaluated as #artifacts, so you can pass artifact specifications and even projects.
+ #
+ # Creates a file task for the target directory, so executing that task as a dependency will
+ # execute the compile task first.
+ #
+ # Compiler options are inherited form a parent task, e.g. the foo:bar:compile task inherits
+ # its options from the foo:compile task. Even if foo is an empty project that does not compile
+ # any classes itself, you can use it to set compile options for all its sub-projects.
+ #
+ # Normally, the project will take care of setting the source and target directory, and you
+ # only need to set options and classpath dependencies. See Project#compile.
class CompileTask < Rake::Task
- # Compiler options, accessible from Compiler#options.
+ # Compiler options, accessible from CompileTask#options.
#
# Supported options are:
# - warnings -- Generate warnings if true (opposite of -nowarn).
# - deprecation -- Output source locations where deprecated APIs are used.
# - source -- Source compatibility with specified release.
@@ -14,41 +37,48 @@
# options, or pass a specific setting as string or array of strings.
# - debug -- Generate debugging info.
# - other -- Array of options to pass to the Java compiler as is.
#
# For example:
- # options.warnings = true
- # options.source = options.target = "1.6"
+ # compile.options.warnings = true
+ # compile.options.source = options.target = "1.6"
class Options
- include Attributes
+ include InheritedAttributes
OPTIONS = [:warnings, :deprecation, :source, :target, :lint, :debug, :other]
# Generate warnings (opposite of -nowarn).
+ attr_accessor :warnings
inherited_attr :warnings
# Output source locations where deprecated APIs are used.
+ attr_accessor :deprecation
inherited_attr :deprecation
# Provide source compatibility with specified release.
+ attr_accessor :source
inherited_attr :source
# Generate class files for specific VM version.
+ attr_accessor :target
inherited_attr :target
# Values to pass to Xlint: string or array. Use true to enable
# Xlint with no values.
+ attr_accessor :lint
inherited_attr :lint
# Generate all debugging info.
+ attr_accessor :debug
inherited_attr :debug
# Array of arguments passed to the Java compiler as is.
+ attr_accessor :other
inherited_attr :other
- def initialize(parent = nil)
+ def initialize(parent = nil) #:nodoc:
@parent = parent
end
- # :nodoc:
- attr_reader :parent
+ attr_reader :parent # :nodoc:
+ # Resets all the options.
def clear()
OPTIONS.each { |name| send "#{name}=", nil }
end
def to_s()
@@ -77,11 +107,11 @@
end
end
- def initialize(*args)
+ def initialize(*args) #:nodoc:
super
parent = Rake::Task["^compile"] if name[":"] # Only if in namespace
if parent && parent.respond_to?(:options)
@options = Options.new(parent.options)
else
@@ -89,211 +119,261 @@
end
@sources = []
@classpath = []
enhance do |task|
- mkpath target, :verbose=>false
+ mkpath target.to_s, :verbose=>false
Java.javac source_files.keys, :sourcepath=>sources.map(&:to_s).select { |source| File.directory?(source) }.uniq,
:classpath=>classpath, :output=>target, :javac_args=>options.javac_args, :name=>task.name
# By touching the target we let other tasks know we did something,
# and also prevent recompiling again for classpath dependencies.
- touch target, :verbose=>false
+ touch target.to_s, :verbose=>false
end
end
# Source directories and files to compile.
attr_accessor :sources
+ # :call-seq:
+ # from(*sources) => self
+ #
# Adds source directories and files to compile, and returns self.
#
# For example:
# compile.from("src/java").into("classes").with("module1.jar")
- def from(*files)
- @sources |= files.flatten
+ def from(*sources)
+ @sources |= sources.flatten
self
end
# Classpath dependencies.
attr_accessor :classpath
+ # :call-seq:
+ # with(*artifacts) => self
+ #
# Adds files and artifacts as classpath dependencies, and returns self.
#
# Calls #artifacts on the arguments, so you can pass artifact specifications,
# tasks, projects, etc. Use this rather than setting the classpath directly.
#
# For example:
# compile.with("module1.jar", "log4j:log4j:jar:1.0", project("foo"))
- def with(*files)
- @classpath |= artifacts(files.flatten).uniq
+ def with(*specs)
+ @classpath |= artifacts(specs.flatten).uniq
self
end
# The target directory for the generated class files.
attr_reader :target
+ # :call-seq:
+ # into(path) => self
+ #
# Sets the target directory and returns self. This will also set the compile task
# as a prerequisite to a file task on the target directory.
#
# For example:
# compile(src_dir).into(target_dir).with(artifacts)
- def into(dir)
- dir = File.expand_path(dir)
- unless @target == dir
- @target = dir
- file(dir).enhance [self]
- end
+ # Both compile.invoke and file(target_dir).invoke will compile the source files.
+ def into(path)
+ path = File.expand_path(path.to_s)
+ @target = file(path).enhance([self]) unless @target && @target.to_s == path
self
end
# Returns the compiler options.
attr_reader :options
+ # :call-seq:
+ # using(options) => self
+ #
# Sets the compiler options from a hash and returns self.
#
# For example:
# compile.using(:warnings=>true, :source=>"1.5")
def using(hash)
hash.each { |k, v| options.send "#{k}=", v }
self
end
- def timestamp()
+ def timestamp() #:nodoc:
# If we compiled successfully, then the target directory reflects that.
# If we didn't, see needed?
- @timestamp ||= (File.exist?(target) ? File.stat(target).mtime : Rake::EARLY)
+ target ? target.timestamp : Rake::EARLY
end
- def needed?()
+ def needed?() #:nodoc:
return false if source_files.empty?
- return true unless File.exist?(target)
+ return true unless File.exist?(target.to_s)
return true if source_files.any? { |j, c| !File.exist?(c) || File.stat(j).mtime > File.stat(c).mtime }
oldest = source_files.map { |j, c| File.stat(c).mtime }.min
return classpath.any? { |path| application[path].timestamp > oldest }
end
- def prerequisites()
+ def prerequisites() #:nodoc:
super + classpath + sources
end
- def invoke_prerequisites()
+ def invoke_prerequisites() #:nodoc:
prerequisites.each { |n| application[n, @scope].invoke }
end
- protected
-
# Returns the files to compile. This list is derived from the list of sources,
# expanding directories into files, and includes only source files that are
# newer than the corresponding class file. Includes all files if one or more
# classpath dependency has been updated.
def source_files()
@source_files ||= @sources.map(&:to_s).inject({}) do |map, source|
raise "Compile task #{name} has source files, but no target directory" unless target
+ target_dir = target.to_s
if File.directory?(source)
base = Pathname.new(source)
- FileList[File.join(source, "**", "*.java")].
- each { |file| map[file] = File.join(target, Pathname.new(file).relative_path_from(base).to_s.ext(".class")) }
+ FileList["#{source}/**/*.java"].
+ each { |file| map[file] = File.join(target_dir, Pathname.new(file).relative_path_from(base).to_s.ext(".class")) }
else
- map[source] = File.join(target, File.basename(source).ext(".class"))
+ map[source] = File.join(target_dir, File.basename(source).ext(".class"))
end
map
end
end
end
+
+ # The resources task is executed by the compile task to copy resource files over
+ # to the target directory. You can enhance this task in the normal way, but mostly
+ # you will use the task's filter.
+ #
+ # For example:
+ # resources.filter.using "Copyright"=>"Acme Inc, 2007"
+ class ResourcesTask < Rake::Task
+
+ # Returns the filter used to copy resources over. See Buildr::Filter.
+ attr_reader :filter
+
+ def initialize(*args) #:nodoc:
+ super
+ @filter = Buildr::filter
+ enhance { filter.run }
+ end
+
+ # :call-seq:
+ # include(*files) => self
+ #
+ # Includes the specified files in the filter and returns self.
+ def include(*files)
+ filter.include *files
+ self
+ end
+
+ # :call-seq:
+ # exclude(*files) => self
+ #
+ # Excludes the specified files in the filter and returns self.
+ def exclude(*files)
+ filter.exclude *files
+ self
+ end
+
+ def prerequisites() #:nodoc:
+ super + filter.sources
+ end
+
+ end
+
end
# Local task to execute the compile task of the current project.
# This task is not itself a compile task.
desc "Compile all projects"
- Project.local_task(task("compile"))
+ Project.local_task("compile") { |name| "Compiling #{name}" }
class Project
- # The source directory. The default is "src".
- inherited_attr :src_dir, "src"
- # The Java source code directory. The default is <src_dir>/main/java.
- inherited_attr :java_src_dir do File.join(src_dir, "main", "java") end
- # The resources source directory. The default is <src_dir>/main/resources.
- inherited_attr :resources_dir do File.join(src_dir, "main", "resources") end
- # The target directory. The default is "target".
- inherited_attr :target_dir, "target"
- # The Java target directory. The default is <target_dir>/classes.
- inherited_attr :java_target_dir do File.join(target_dir, "classes") end
-
+ # :call-seq:
+ # prepare(*prereqs) => task
+ # prepare(*prereqs) { |task| .. } => task
+ #
# The prepare task executes before the #compile task. Use it for pre-compilation
# tasks, e.g. generating source code.
#
# This method returns the project's prepare task. It also accepts a list of
# prerequisites and a block, used to enhance the prepare task.
#
- # By default the prepare task will only generate the #target_dir directory.
- #
# For example:
- # prepare "src/generated"
- # prepare { javacc.run }
- def prepare(*tasks, &block)
- task("prepare").enhance tasks, &block
+ # prepare { schema_to_java }
+ def prepare(*prereqs, &block)
+ task("prepare").enhance prereqs, &block
end
+ # :call-seq:
+ # compile(*sources) => CompileTask
+ # compile(*sources) { |task| .. } => CompileTask
+ #
# The compile task does what its name suggests. This method returns the project's
- # compile task. It also accepts a list of source directories and files to compile
- # (equivalent to calling Java::CompileTask#from on the task), and a block for any
+ # CompileTask. It also accepts a list of source directories and files to compile
+ # (equivalent to calling CompileTask#from on the task), and a block for any
# post-compilation work.
#
- # For more information, see Java::CompileTask.
- #
- # The compile task will pick all the source files in the #java_src_dir directory,
- # and unless specified, compile into the #java_target_dir directory. It will pick
+ # The compile task will pick all the source files in the src/main/java directory,
+ # and unless specified, compile them into the target/classes directory. It will pick
# the default values for compiler options from the parent project's compile task.
#
# For example:
- # compile.options.source = "1.5"
- # compile("src").with("log4j:log4j:jar:1.2")
- # compile { backport(compile.target) }
+ # # Force target compatibility.
+ # compile.options.source = "1.6"
+ # # Include Apt-generated source files.
+ # compile.from apt
+ # # Include Log4J and the api sub-project artifacts.
+ # compile.with "log4j:log4j:jar:1.2", project("api")
+ # # Run the OpenJPA bytecode enhancer after compilation.
+ # compile { open_jpa_enhance }
+ #
+ # For more information, see Java::CompileTask.
def compile(*sources, &block)
task("compile").from(sources).enhance &block
end
- # The resources task executes after compilation, and will copy resources files
+ # :call-seq:
+ # resources(*prereqs) => ResourcesTask
+ # resources(*prereqs) { |task| .. } => ResourcesTask
+ #
+ # The resources task is executed by the compile task to copy resources files
# from the resource directory into the target directory.
#
# This method returns the project's resources task. It also accepts a list of
# prerequisites and a block, used to enhance the resources task.
#
- # By default the resources task copies files from the #resources_dir into the
- # same target directory as the #compile task.
+ # By default the resources task copies files from the src/main/resources into the
+ # same target directory as the #compile task. It does so using a filter that you
+ # can access by calling resources.filter (see Buildr::Filter).
#
- # For more information, see Filter.
- def resources(*tasks, &block)
- task("resources").enhance tasks, &block
+ # For example:
+ # resources.filter.include "config.xml"
+ # resources.filter.using "Copyright"=>"Acme Inc, 2007"
+ def resources(*prereqs, &block)
+ task("resources").enhance prereqs, &block
end
end
Project.on_define do |project|
prepare = task("prepare")
# Resources task is a filter.
- resources = FilterTask.define_task("resources")
+ resources = Java::ResourcesTask.define_task("resources")
+ project.path_to("src/main/resources").tap { |dir| resources.filter.include project.path_to(dir, "*") if File.exist?(dir) }
# Compile task requires prepare and performs resources, if anything compiled.
- compile = Java::CompileTask.define_task("compile"=>prepare) { |task| resources.invoke }
+ compile = Java::CompileTask.define_task("compile"=>[prepare, resources]) { |task| project.resources.invoke }
+ project.path_to("src/main/java").tap { |dir| compile.from dir if File.exist?(dir) }
+ compile.into project.path_to("target/classes")
+ resources.filter.into project.compile.target
project.recursive_task("compile")
+ project.clean { verbose(false) { rm_rf project.path_to("target") } }
project.enhance do |project|
- # For convenience, have the prepare task generate the target directory.
- #directory project.path_to(:target_dir)
- #project.prepare.prerequisites.unshift project.path_to(:target_dir)
- # Use the source directory if exists, and set the target directory is not already set.
- project.compile.from project.path_to(:java_src_dir) if File.exist?(project.path_to(:java_src_dir))
- project.compile.into project.path_to(:java_target_dir) unless project.compile.target
- # Do the same for resources.
- project.resources.include project.path_to(:resources_dir, "*") if File.exists?(project.path_to(:resources_dir))
- project.resources.into project.compile.target unless project.resources.target
- # Now we know what to build/clean.
project.build project.compile.target
- project.clean { verbose(false) { rm_rf project.path_to(:target_dir) } }
end
-
end
end