buildr 0.18.0 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,10 +1,68 @@
1
+ 0.19 (4/13/2007)
2
+ * Fixed: Eclipse task correctly handles FileTasks
3
+ * Fixed: Eclipse task output directory is "target/classes" (Project.compile.target) instead of "/target"
4
+ * Added: Set specific file permissions when uploading with SFTP transport with :permission option
5
+ * Fixed: Correctly use JAVA_HOME environment variable, if available, for determining java version
6
+ * Added: ConcatTask and concat: a file task that creates or updates the target file by concatenating all the file prerequisites.
7
+ * Added: Ant module (requires antwrap and rjb Gems), so also added RJB setup module.
8
+ * Added: When zipping you can include the contents of a directory using :as=>".".
9
+ * Added: Convenience apt method returns a file task that generates sources using APT.
10
+ * Added: Convenience open_jpa_enhance method to enhance compiled files.
11
+ * Added: Convenience compile_xml_beans setups the compiler to include XSD-generated XML Beans.
12
+ * Added: Convenience javacc/jjtraa methods return file tasks that generate source files.
13
+ * Added: build is now the default task.
14
+ * Added: jetty:start and jetty:stop tasks to start/stop the server from the console.
15
+ * Added: jetty:use to start Jetty inside the build or hook to an existing server.
16
+ * Added: jetty:setup and jetty:teardown to perform tasks around jetty:use.
17
+ * Added: The local build task will now execute the local test task. So building a project (or sub-project)
18
+ will run the test cases on that project (or sub-project) but not any of its dependencies.
19
+ * Added: ZipTask accepts nested path (i.e. calling path inside a path).
20
+ * Added: package(:war) by defaults picks libraries from the compiler classpath. You can always override by
21
+ passing the :libs option.
22
+ * Changed: Eclipse task now generates library path with M2_REPO variable or project-relative paths
23
+ where appropriate
24
+ * Changed: compile.target (CompileTask) and resources.target (Filter) are now file tasks, not strings.
25
+ So passing the target to someone else will hopefully convience them to invoke or enhance it.
26
+ * Changed: Java related tasks like OpenJPA, XMLBeans, JavaCC all moved to the Buildr::Java module.
27
+ * Changed: Handling of package_as arguments to support JBI packaging.
28
+ * Changed: meta_inf project property is an array accepting filenames (strings) and file tasks.
29
+ * Changed: meta_info by default only includes the LICENSE file from the top-level project.
30
+ * Changed: The WarTask :classes argument is now a directory name, and will include all files in this directory.
31
+ * Changed: WarTask and JarTask accept meta_inf argument.
32
+ * Changed: Behavior of needed? and prerequsities in base Rake::Task. This will probably not affect you,
33
+ but don't be surprised if it disappears (see lib/core/rake_ext.rb for details).
34
+ * Changed: Were previous the test task would link to test.run, it now executes the entire test lifecycle,
35
+ and is the major point for extending the test lifecycle.
36
+ * Changed: test.run is now test.junit.
37
+ * Changed: Ant.define is now Ant.declarative, Ant.execute is now Ant.executable.
38
+ * Changed: The filter method now returns a Filter class that can be used to set a filter, but is not itself
39
+ a task. Instead, it creates a task when setting its target.
40
+ * Changed: Project.resources now returns a ResourceTask that includes, but is not itself a filter, accessed
41
+ using the accessor filter.
42
+ * Changed: UnzipTask eliminated and replaced with Unzip which you now have to run directly by calling extract.
43
+ However, unzip method creates a file task and returns an Unzip object that can be used as a reference to
44
+ that file task.
45
+ * Changed: Attributes is now InheritedAttributes.
46
+ * Changed: The first call to package configures the package task from the options, the second call only returns
47
+ the package task.
48
+ * Removed: :cp argument, always use :classpath.
49
+ * Removed: src_dir, java_src_dir, target_dir, webapp_src_dir and all other premature configuration attributes.
50
+ * Removed: Project tests method deprecated in favor of a single test method; it now accepts an enhancement
51
+ block, not an instance_eval block.
52
+ * Removed: FilterTask is dead.
53
+ * Removed: sub_projects method. Is anyone using this?
54
+ * Fixed: Local buildr.rb not loaded from running from inside a sub-project directory.
55
+ * Fixed: Eclipse task now executed whenever a change is made in the Rakefile, or any file it requires,
56
+ include buildr.rb and task files.
57
+ * Fixed: Circular dependency in release task.
58
+
1
59
  0.18 (3/26/2007)
2
60
  * Added: manifest attribute on project, used by default when packaging JAR/WAR.
3
61
  * Added: default manifest includes build-by, build-jdk and implementation-title.
4
62
  * Added: compile.from(sources) in the same vein as compile.with(classpath)
5
63
  * Added: load all *.rake files form the tasks directory (if exists) for use in the
6
64
  main Rakefile.
7
- * Added: Java.tools returns a reference to tools.jar on JDKs that include it.
65
+ * Added: Java.tools returns a reference to tools.jar on JDKs that include it.
8
66
  * Added: brought back experimental test tasks.
9
67
  * Added: artifacts task to download all artifacts referenced by project (using
10
68
  either artifact or artifacts method).
@@ -36,7 +94,7 @@
36
94
  * Changed: LocalDirectoryTask replaced with Project.local_task.
37
95
  * Changed: projects method accepts multiple names, returning only these project
38
96
  definitions, returns all of them with no arguments.
39
- * Changed: package only defines the essentials once, so you can call package
97
+ * Changed: packge only defines the essentials once, so you can call package
40
98
  on a project to retrieve a specific package by type/id.
41
99
  * Changed: zip task (and jar/war) no longer resolve artifacts for you,
42
100
  must call artifacts directly.
@@ -95,7 +153,7 @@
95
153
  * Changed: moved all code into Buildr module.
96
154
  * Fixed: download breaking when POM not found.
97
155
  * Fixed: compile task fails if classpath is empty.
98
- * Fixed: zip task fails if target directory does not exist.
156
+ * Fixed: zip task fails if target directory does not exist.
99
157
  * Fixed: packaging task does not require build.
100
158
  * Fixed: compiler not showing command when trace is on.
101
159
  * Fixed: zip dependencies were all fucked up.
@@ -107,7 +165,7 @@
107
165
  * Added: prepare, compile and resources accept a block you can use to enhance the task
108
166
  * Changed: ZipTask executes all includes files as prerequisites, and now includes
109
167
  directories correctly
110
- * Changed: Jar/WarTask are now extended using with(options) method
168
+ * Changed: Jar/WarTask are now extended using with(options) method
111
169
  * Changed: JarTask now accepts array of sections (each being a hash) for the manifest,
112
170
  and a proc/method to generate it
113
171
  * Changed: added HighLine to hide password entry on the command line
data/LICENSE CHANGED
@@ -186,7 +186,7 @@
186
186
  same "printed page" as the copyright notice for easier
187
187
  identification within third-party archives.
188
188
 
189
- Copyright 2006, Intalio Inc.
189
+ Copyright 2006-2007, Intalio Inc.
190
190
 
191
191
  Licensed under the Apache License, Version 2.0 (the "License");
192
192
  you may not use this file except in compliance with the License.
data/README CHANGED
@@ -1,4 +1,67 @@
1
+ = Buildr
1
2
 
2
3
  This is Buildr, the build system that doesn't suck.
3
4
 
4
- http://buildr.rubyforge.org/
5
+ http://buildr.rubyforge.org
6
+
7
+ == Get Started
8
+
9
+ === Install Buildr:
10
+ gem install buildr
11
+
12
+ === RTFM:
13
+
14
+ * Buildr documentation: http://buildr.rubyforge.org/rdoc
15
+ * More about Rake: http://docs.rubyrake.org
16
+ * Antwrap documentation: http://antwrap.rubyforge.org
17
+
18
+ === Join Buildr-talk mailing list:
19
+
20
+ * http://groups.google.com/group/buildr-talk
21
+
22
+ Create your own Rakefile and start living the life!
23
+
24
+
25
+ == Where's My Ruby?
26
+
27
+ Buildr needs Ruby 1.8 or later and RubyGems 0.9 or later. All other dependencies are installed when you run:
28
+ gem install buildr
29
+
30
+ === Windows
31
+
32
+ Windows users can get the one-click Ruby installer, which includes the latest version of Ruby and RubyGems:
33
+
34
+ http://rubyinstaller.rubyforge.org
35
+
36
+ === Linux and OS/X
37
+
38
+ If you're running Linux or OS/X you may already have Ruby installed, or you can get it through the usual channels:
39
+ yum install ruby
40
+ apt-get install ruby
41
+ emerge ruby
42
+
43
+ You can get RubyGems here: http://rubyforge.org/frs/?group_id=126
44
+
45
+ To install:
46
+ tar -xz < rubygems-0.9.2.tgz
47
+ cd rubygems-0.9.2
48
+ sudo ruby setup.rb
49
+ sudo gem install rubygems-update
50
+
51
+
52
+ == Living On the Edge
53
+
54
+ You can check the latest sources from SVN:
55
+ svn co svn://www.intalio.org/usr/local/svn/repos/buildr/trunk buildr
56
+ Or browse the SVN repository online: http://blog.intalio.org/viewrep/Buildr
57
+
58
+ To install Buildr locally from source, do:
59
+
60
+ cd buildr
61
+ rake install
62
+
63
+ If the cutting edge doesn't work, make sure to check the CHANGELOG, to see which changes might have broken your build.
64
+
65
+ == License
66
+
67
+ :include:LICENSE
data/lib/buildr.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "highline"
1
2
  # returning(obj)
2
3
  require "facet/kernel/with"
3
4
  # &:symbol goodness.
@@ -17,30 +18,23 @@ require "facet/openobject"
17
18
  require "facets/core/kernel/tap"
18
19
 
19
20
 
21
+ module Kernel #:nodoc:
22
+ def warn_with_color(message)
23
+ warn_without_color HighLine.new.color(message.to_s, :red)
24
+ end
25
+ alias_method_chain :warn, :color
26
+ end
27
+
28
+
20
29
  module Buildr
21
- VERSION = "0.18.0"
30
+ VERSION = "0.19.0"
22
31
  end
23
32
 
24
- $LOAD_PATH.unshift File.join(__DIR__)
25
- require "core/core.rb"
26
- require "core/project.rb"
27
- require "core/artifact.rb"
28
- require "core/build.rb"
29
- require "core/transports.rb"
30
-
31
- require "tasks/download"
32
- require "tasks/filter"
33
- require "tasks/zip"
34
-
35
- require "java/java"
36
- require "java/jetty"
37
- require "java/compile"
38
- require "java/eclipse"
39
- require "java/test"
40
- require "java/javacc"
41
- require "java/openjpa"
42
- require "java/packaging"
43
- require "java/xmlbeans"
33
+
34
+ File.expand_path(__DIR__).tap do |here|
35
+ $LOAD_PATH.unshift here
36
+ Dir[File.expand_path("*/*.rb", __DIR__)].each { |file| require file.sub("#{here}/", "") }
37
+ end
44
38
 
45
39
  include Buildr
46
40
 
@@ -48,13 +42,18 @@ include Buildr
48
42
  # XMLBuilder after we're done enhancing Object.
49
43
  require "builder"
50
44
 
51
- # Load the settings files.
52
- if File.exist?(File.join(ENV["HOME"], "buildr.rb"))
53
- load File.join(ENV["HOME"], "buildr.rb")
54
- end
55
- if File.exist?(File.join(Rake.application.original_dir, "buildr.rb"))
56
- load File.join(Rake.application.original_dir, "buildr.rb")
45
+ module Buildr
46
+ @loaded_features_to_ignore = $LOADED_FEATURES +
47
+ [Pathname.new(File.expand_path(__FILE__)).relative_path_from(Pathname.new(Dir.pwd)).to_s]
57
48
  end
58
49
 
50
+ # Load the settings files.
51
+ [ File.expand_path("buildr.rb", ENV["HOME"]), File.expand_path("buildr.rb") ].each { |file| require file if File.exist?(file) }
52
+
59
53
  #Load local tasks that can be used in the Rakefile.
60
- Dir["#{Dir.pwd}/tasks/*.rake"].each { |ext| load ext }
54
+ Dir["#{Dir.pwd}/tasks/*.rake"].each do |file|
55
+ unless $LOADED_FEATURES.include?(file)
56
+ load file
57
+ $LOADED_FEATURES << file
58
+ end
59
+ end
data/lib/core/build.rb CHANGED
@@ -1,42 +1,51 @@
1
1
  require "open3"
2
-
2
+ require "core/project"
3
3
 
4
4
  module Buildr
5
5
 
6
- BUILD_TASKS = {
7
- :build =>"Build the project",
8
- :clean =>"Clean files generated during a build",
9
- :package =>"Create packages",
10
- :install =>"Install packages created by the project",
11
- :uninstall=>"Remove previously installed packages",
12
- :deploy =>"Deploy packages created by the project"
13
- }
14
-
15
- # Handles the build and clean tasks.
16
- BUILD_TASKS.each { |name, comment| Project.local_task(task(name)).add_comment(comment) }
17
-
18
- Project.on_define do |project|
19
- BUILD_TASKS.each { |name, comment| project.recursive_task name }
6
+ desc "Build the project"
7
+ Project.local_task("build") { |name| "Building #{name}" }
8
+ desc "Clean files generated during a build"
9
+ Project.local_task("clean") { |name| "Cleaning #{name}" }
10
+ desc "Create packages"
11
+ Project.local_task("package") { |name| "Packaging #{name}" }
12
+ desc "Install packages created by the project"
13
+ Project.local_task("install") { |name| "Installing packages from #{name}" }
14
+ desc "Remove previously installed packages"
15
+ Project.local_task("uninstall") { |name| "Uninstalling packages from #{name}" }
16
+ desc "Deploy packages created by the project"
17
+ Project.local_task("deploy") { |name| "Deploying packages from #{name}" }
18
+
19
+ [ :build, :clean, :package, :install, :uninstall, :deploy ].each do |name|
20
+ Project.on_define { |project| project.recursive_task name }
20
21
  end
21
22
 
22
23
  class Project
23
- def build(*args, &block)
24
- task("build").enhance args, &block
24
+
25
+ # :call-seq:
26
+ # build(*prereqs) => task
27
+ # build { |task| .. } => task
28
+ #
29
+ # Returns the project's build task. With arguments or block, also enhances that task.
30
+ def build(*prereqs, &block)
31
+ task("build").enhance prereqs, &block
25
32
  end
26
33
 
27
- def clean(*args, &block)
28
- task("clean").enhance args, &block
34
+ # :call-seq:
35
+ # build(*prereqs) => task
36
+ # build { |task| .. } => task
37
+ #
38
+ # Returns the project's clean task. With arguments or block, also enhances that task.
39
+ def clean(*prereqs, &block)
40
+ task("clean").enhance prereqs, &block
29
41
  end
30
- end
31
42
 
32
- Project.on_define do |project|
33
- # Make sure these tasks are defined in the project.
34
- project.build
35
- project.clean
36
43
  end
37
44
 
45
+ desc "The default task it build"
46
+ task "default"=>"build"
38
47
 
39
- class Release
48
+ class Release #:nodoc:
40
49
 
41
50
  VERSION_NUMBER_PATTERN = /VERSION_NUMBER\s*=\s*(["'])(.*)\1/
42
51
  NEXT_VERSION_PATTERN = /NEXT_VERSION\s*=\s*(["'])(.*)\1/
@@ -48,7 +57,7 @@ module Buildr
48
57
  end
49
58
 
50
59
  def initialize(rakefile = nil)
51
- @rakefile = rakefile || File.read(Rake.application.rakefile)
60
+ @rakefile = rakefile || Rake.application.rakefile
52
61
  end
53
62
 
54
63
  attr_reader :rakefile
@@ -145,7 +154,7 @@ module Buildr
145
154
  stdin.close
146
155
  error = stderr.read
147
156
  fail error unless error.empty?
148
- returning(stdout.read) { |output| puts output if Rake.application.options.trace }
157
+ stdout.read.tap { |output| puts output if Rake.application.options.trace }
149
158
  end
150
159
  end
151
160
 
@@ -153,12 +162,12 @@ module Buildr
153
162
 
154
163
 
155
164
  desc "Make a release"
156
- task("release").tap do |release|
157
- class << release
165
+ task("release").tap do |task|
166
+ class << task
158
167
  def release()
159
168
  @release ||= Release.new
160
169
  end
161
170
  end
162
- release.enhance { release.invoke }
171
+ task.enhance { task.release.invoke }
163
172
  end
164
173
  end
data/lib/core/project.rb CHANGED
@@ -1,20 +1,93 @@
1
+ require "core/rake_ext"
2
+
1
3
  module Buildr
2
4
 
3
- # A project is a convenient mechanism for managing all the tasks
4
- # related to a given project. For complex applications, you may have
5
- # several projects, or sub-projects for each of the modules.
5
+ # An inherited attribute gets its value an accessor with the same name.
6
+ # But if the value is not set, it will obtain a value from the parent,
7
+ # so setting the value in the parent make it accessible to all the children
8
+ # that did not override it.
9
+ module InheritedAttributes
10
+
11
+ class << self
12
+ private
13
+ def included(mod)
14
+ mod.extend(self)
15
+ end
16
+ end
17
+
18
+ # :call-seq:
19
+ # inherited_attr(symbol, default?)
20
+ # inherited_attr(symbol) { |obj| ... }
21
+ #
22
+ # Defines an inherited attribute. The first form can provide a default value
23
+ # for the top-level object, used if the attribute was not set. The second form
24
+ # provides a default value by calling the block.
25
+ #
26
+ # For example:
27
+ # inherited_attr :version
28
+ # inherited_attr :src_dir, "src"
29
+ # inherited_attr(:created_on) { Time.now }
30
+ def inherited_attr(symbol, default = nil, &block)
31
+ block ||= proc { default }
32
+ attr_accessor symbol
33
+ define_method "#{symbol}_with_inheritence" do
34
+ unless value = send("#{symbol}_without_inheritence")
35
+ value = parent ? parent.send(symbol) : self.instance_eval(&block)
36
+ send "#{symbol}=", value
37
+ end
38
+ value
39
+ end
40
+ alias_method_chain symbol, :inheritence
41
+ end
42
+ end
43
+
44
+
45
+ # A project definition is where you define all the tasks associated with
46
+ # the project you're building.
47
+ #
48
+ # The project itself will define several life cycle tasks for you. For example,
49
+ # it automatically creates a compile task that will compile all the source files
50
+ # found in src/main/java into target/classes, a test task that will compile source
51
+ # files from src/test/java and run all the JUnit tests found there, and a build
52
+ # task to compile and then run the tests.
53
+ #
54
+ # You use the project definition to enhance these tasks, for example, telling the
55
+ # compile task which class path dependencies to use. Or telling the project how
56
+ # to package an artifact, e.g. creating a JAR using <tt>package :jar</tt>.
57
+ #
58
+ # You can also define additional tasks that are executed by project tasks,
59
+ # or invoked from rake.
6
60
  #
7
- # A project definition creates its own set of tasks, prefixed with
8
- # the project name. For example, each project has a clean, build
9
- # and deploy task. For project +foo+ the task names are +foo:clean+,
10
- # +foo:build+ and +foo:deploy+.
61
+ # Tasks created by the project are all prefixed with the project name, e.g.
62
+ # the project foo creates the task foo:compile. If foo contains a sub-project bar,
63
+ # the later will define the task foo:bar:compile. Since the compile task is
64
+ # recursive, compiling foo will also compile foo:bar.
11
65
  #
12
- # Projects have properties, some of which they inherit from their
13
- # parent project. Built in tasks use these properties, for example,
14
- # the +clean+ task will remove the target directory specified by
15
- # the +target_dir+ property. The +compile+ tasks uses the compiler
16
- # option: you can set these options on the parent project and they
17
- # will be inherited by all sub-projects.
66
+ # If you run:
67
+ # rake compile
68
+ # from the command line, it will execute the compile task of the current project.
69
+ #
70
+ # Projects and sub-projects follow a directory heirarchy. The Rakefile is assumed to
71
+ # reside in the same directory as the top-level project, and each sub-project is
72
+ # contained in a sub-directory in the same name. For example:
73
+ # /home/foo
74
+ # |__ Rakefile
75
+ # |__ src/main/java
76
+ # |__ foo
77
+ # |__ src/main/java
78
+ #
79
+ # The default structure of each project is assumed to be:
80
+ # src
81
+ # |__main
82
+ # | |__java <-- Source files to compile
83
+ # | |__resources <-- Resources to copy
84
+ # | |__webapp <-- For WARs
85
+ # |__test
86
+ # | |__java <-- Source files to compile (tests)
87
+ # | |__resources <-- Resources to copy (tests)
88
+ # |__target <-- Packages created here
89
+ # | |__classes <-- Generated when compiling
90
+ # | |__test-classes <-- Generated when compiling tests
18
91
  #
19
92
  # You can only define a project once using #define. Afterwards, you
20
93
  # can obtain the project definition using #project. However, when
@@ -24,70 +97,53 @@ module Buildr
24
97
  # are not allowed.
25
98
  #
26
99
  # For example:
27
- # define "project1" do
28
- # self.version = "1.1"
100
+ # define "myapp", :version=>"1.1" do
29
101
  #
30
- # define "module1" do
31
- # package :jar
102
+ # define "wepapp" do
103
+ # compile.with project("myapp:beans")
104
+ # package :war
32
105
  # end
33
106
  #
34
- # define "module2" do
35
- # compile.with project("project1:module1")
107
+ # define "beans" do
108
+ # compile.with DEPENDS
36
109
  # package :jar
37
110
  # end
38
111
  # end
39
112
  #
40
- # projects.map(&:name)
41
- # => [ "project", "project:module1", "project1:module2" ]
42
- # project("project1").sub_projects.map(&:name)
43
- # => [ "project1:module1", "project1:module2" ]
44
- # project("project1:module1").parent.name
45
- # => "project1"
46
- # project("project1:module1").version
47
- # => "1.1"
48
- #
49
- # Each project has a base directory (see #base_dir). By default,
50
- # a top-level project uses the current directory, and each sub-project
51
- # uses a sub-directory relative to the parent project.
52
- #
53
- # For the above example, the directory structure is:
54
- # project1/
55
- # |__Rakefile
56
- # |__module1/
57
- # |__module2/
58
- #
59
- # The project definition tasks a block and executes it in the context of
60
- # the project object. For example:
61
- # define "project1" do
62
- # project.version = "1.1"
63
- # end
64
- # puts project("project1").version
65
- # => "1.1"
113
+ # puts projects.map(&:name)
114
+ # => [ "myapp", "myapp:beans", "myapp:webapp" ]
115
+ # puts project("myapp:webapp").parent.name
116
+ # => "myapp"
117
+ # puts project("myapp:webapp").compile.classpath.map(&:to_spec)
118
+ # => "myapp:myapp-beans:jar:1.1"
66
119
  class Project < Rake::Task
67
120
 
68
121
  class << self
69
122
 
70
123
  # See Buildr#define.
71
- def define(*args, &block)
72
- name, properties = name_and_properties_from_args(*args)
124
+ def define(name, properties, &block) #:nodoc:
73
125
  # Make sure a sub-project is only defined within the parent project,
74
126
  # to prevent silly mistakes that lead to inconsistencies (e.g.
75
127
  # namespaces will be all out of whack).
76
128
  Rake.application.current_scope == name.split(":")[0...-1] or
77
- raise "You can only define a sub project (#{name}) within the definition of its parent process"
129
+ raise "You can only define a sub project (#{name}) within the definition of its parent project"
78
130
 
79
131
  @projects ||= {}
80
132
  raise "You cannot define the same project (#{name}) more than once" if @projects[name]
81
133
  Project.define_task(name).tap do |project|
134
+ # Define the project to prevent duplicate definition.
82
135
  @projects[name] = project
83
- project.enhance { |project| @on_define.each { |callback| callback[project] } } if @on_define
84
136
  # Set the project properties first, actions may use them.
85
- properties.each { |name, value| project.send "#{name}=", value }
86
- # Enhance the project definition with the block.
87
- if block
88
- project.enhance { project.instance_eval &block }
89
- end
90
-
137
+ properties.each { |name, value| project.send "#{name}=", value } if properties
138
+ project.enhance do |project|
139
+ @on_define.each { |callback| callback[project] }
140
+ end if @on_define
141
+ # Enhance the project using the definition block.
142
+ project.enhance { project.instance_eval &block } if block
143
+
144
+ # Top-level project? Invoke the project definition. Sub-project? We don't invoke
145
+ # the project definiton yet (allow project() calls to establish order of evaluation),
146
+ # but must do so before the parent project's definition is done.
91
147
  if project.parent
92
148
  project.parent.enhance { project.invoke }
93
149
  else
@@ -97,103 +153,85 @@ module Buildr
97
153
  end
98
154
 
99
155
  # See Buildr#project.
100
- def project(name)
156
+ def project(name) #:nodoc:
101
157
  @projects && @projects[name] or raise "No such project #{name}"
102
- returning(@projects[name]) { |project| project.invoke }
158
+ @projects[name].tap { |project| project.invoke }
103
159
  end
104
160
 
105
161
  # See Buildr#projects.
106
- def projects(*args)
162
+ def projects(*names) #:nodoc:
107
163
  @projects ||= {}
108
- if args.empty?
164
+ if names.empty?
109
165
  @projects.keys.map { |name| project(name) }.sort_by(&:name)
110
166
  else
111
- args.map { |name| project(name) or raise "No such project #{name}" }.
112
- uniq.sort_by(&:name)
167
+ names.map { |name| project(name) or raise "No such project #{name}" }.uniq.sort_by(&:name)
113
168
  end
114
169
  end
115
170
 
171
+ # :call-seq:
172
+ # clear()
173
+ #
116
174
  # Discard all project definitions.
117
175
  def clear()
118
176
  @projects.clear if @projects
119
177
  end
120
178
 
121
- # Enhances this task into a local task. A local task executes the same
122
- # task on the project in the local directory.
179
+ # :call-seq:
180
+ # local_task(name)
181
+ # local_task(name) { |name| ... }
182
+ #
183
+ # Defines a local task with an optional execution message.
123
184
  #
124
- # For example, if the current directory project is +foo+, then
125
- # +rake build+ executes +rake foo:build+.
185
+ # A local task is a task that executes a task with the same name, defined in the
186
+ # current project, the project's with a base directory that is the same as the
187
+ # current directory.
126
188
  #
127
- # The current directory project is a project with the base directory
128
- # being the same as the current directory. For example:
189
+ # Complicated? Try this:
190
+ # rake build
191
+ # is the same as:
192
+ # rake foo:build
193
+ # But:
129
194
  # cd bar
130
195
  # rake build
131
- # Will execute the +foo:bar:build+ task, after switching to the directory
132
- # of the sub-project +bar+.
133
- def local_task(task)
134
- task = task(task) unless Rake::Task === task
135
- task.enhance do |task|
196
+ # is the same as:
197
+ # rake foo:bar:build
198
+ #
199
+ # The optional block is called with the project name when the task executes
200
+ # and returns a message that, for example "Building project #{name}".
201
+ def local_task(args, &block)
202
+ task args do |task|
136
203
  projects = Project.projects.select { |project| project.base_dir == Rake.application.original_dir }
137
- if verbose && projects.empty?
138
- warn "No projects defined for directory #{Rake.application.original_dir}"
204
+ if projects.empty?
205
+ warn "No projects defined for directory #{Rake.application.original_dir}" if verbose
206
+ else
207
+ projects.each do |project|
208
+ puts block.call(project.name) if block && verbose
209
+ task("#{project.name}:#{task.name}").invoke
210
+ end
139
211
  end
140
- projects.each { |project| task("#{project.name}:#{task.name}").invoke }
141
212
  end
142
- task
143
213
  end
144
214
 
145
- # The Project class defines minimal behavior for new projects.
146
- # Use #on_define to add behavior when defining new projects.
147
- # Whenever a new project is defined, it will yield to the block
148
- # with the project object.
215
+ # :call-seq:
216
+ # on_define() { |project| ... }
217
+ #
218
+ # The Project class defines minimal behavior, only what is documented here.
219
+ # To extend its definition, other modules use Project#on_define to incorporate
220
+ # code called during a new project's definition.
149
221
  #
150
222
  # For example:
151
223
  # # Set the default version of each project to "1.0".
152
- # Project.on_define do |project|
153
- # project.version ||= "1.0"
154
- # end
224
+ # Project.on_define { |project| project.version ||= "1.0" }
155
225
  #
156
- # Keep in mind that the order in which #on_define blocks are
157
- # called is not determined. You cannot depend on a previous
158
- # #on_define to set properties or create new tasks. You would
159
- # want to use the #enhance method instead, by calling it
160
- # from within #on_define.
161
- #
162
- # For example:
163
- # Project.on_define do |project|
164
- # puts "defining"
165
- # project.enhance { puts "defined" }
166
- # end
167
- # define "foo" do
168
- # puts "block"
169
- # end
170
- # => defining
171
- # block
172
- # defined
226
+ # Since each project definition is essentially a task, if you need to do work
227
+ # at the end of the project definition (after the block is executed), you can
228
+ # enhance it from within #on_define.
173
229
  def on_define(&block)
174
230
  (@on_define ||= []) << block if block
175
231
  end
176
232
 
177
- # :nodoc:
178
- def name_and_properties_from_args(*args)
179
- if Hash === args.last
180
- properties = args.pop.dup
181
- else
182
- properties = {}
183
- end
184
- if String === args.first
185
- name = args.shift
186
- else
187
- name = properties.delete(:name)
188
- end
189
- raise ArgumentError, "Expected project name followed by (optional) project properties." unless args.empty?
190
- raise ArgumentError, "Missing project name, this is the first argument to the define method" unless name
191
- [ name, properties ]
192
- end
193
-
194
- # :nodoc:
195
- def warnings()
196
- returning([]) do |msgs|
233
+ def warnings() #:nodoc:
234
+ [].tap do |msgs|
197
235
  msgs << "There are no project definitions in your Rakefile" if @projects.nil? || @projects.empty?
198
236
  # Find all projects that:
199
237
  # * Are referenced but never defined. This is probably a typo.
@@ -204,45 +242,51 @@ module Buildr
204
242
  end
205
243
  end
206
244
 
207
- def scope_name(scope, task_name)
245
+ def scope_name(scope, task_name) #:nodoc:
208
246
  task_name
209
247
  end
210
248
 
211
249
  end
212
250
 
213
- include Attributes
251
+ include InheritedAttributes
214
252
 
215
- # The project name. If this is a sub-project, it will be prefixed
216
- # by the parent project's name. For example, "foo" and "foo:bar".
253
+ # The project name. For example, "foo" for the top-level project, and "foo:bar"
254
+ # for its sub-project.
217
255
  attr_reader :name
218
256
 
219
257
  # The parent project if this is a sub-project.
220
258
  attr_reader :parent
221
259
 
222
- # :nodoc:
223
- def initialize(*args)
260
+ def initialize(*args) #:nodoc:
224
261
  super
225
262
  split = name.split(":")
226
263
  if split.size > 1
227
- # Get parent project, but do not invoke it's definition to
228
- # prevent circular dependencies (it's being invoked right now).
264
+ # Get parent project, but do not invoke it's definition to prevent circular
265
+ # dependencies (it's being invoked right now, so calling project() will fail).
229
266
  @parent = task(split[0...-1].join(":"))
230
267
  raise "No parent project #{split[0...-1].join(":")}" unless @parent && Project === parent
231
268
  end
232
- # We want to lazily evaluate base_dir, but default initialize
233
- # will set it to the current directory.
269
+ # We only need this because each task (and a project is a task) already has
270
+ # a @base_dir variable (and base_dir method), and we want it lazily evaluated.
271
+ # See all the logic that happens when we call base_dir.
234
272
  @base_dir = nil
235
273
  end
236
274
 
237
- # The base directory of this project. The default for a top-level project
238
- # is the same directory that holds the Rakefile. The default for a
239
- # sub-project is a child directory with the same name.
275
+ # :call-seq:
276
+ # base_dir() => path
277
+ #
278
+ # Returns the project's base directory.
240
279
  #
241
- # A project definition can change the base directory using the base_dir
242
- # hash value. Be advised that the base directory and all values that
243
- # depend on it can only be determined after the project is defined.
280
+ # The Rakefile defines top-level project, so it's logical that the top-level project's
281
+ # base directory is the one in which we find the Rakefile. And each sub-project has
282
+ # a base directory that is one level down, with the same name as the sub-project.
283
+ #
284
+ # For example:
285
+ # /home/foo/ <-- base_directory of project "foo"
286
+ # /home/foo/Rakefile <-- builds "foo"
287
+ # /home/foo/bar <-- sub-project "foo:bar"
244
288
  def base_dir()
245
- unless @base_dir
289
+ if @base_dir.nil?
246
290
  if @parent
247
291
  # For sub-project, a good default is a directory in the parent's base_dir,
248
292
  # using the same name as the project.
@@ -257,6 +301,14 @@ module Buildr
257
301
  @base_dir
258
302
  end
259
303
 
304
+ # :call-seq:
305
+ # base_dir = dir
306
+ #
307
+ # Sets the project's base directory. Allows you to specify a base directory by calling
308
+ # this accessor, or with the :base_dir property when calling #define.
309
+ #
310
+ # You can only set the base directory once for a given project, and only before accessing
311
+ # the base directory (for example, by calling #file or #path_to).
260
312
  # Set the base directory. Note: you can only do this once for a project,
261
313
  # and only before accessing the base directory. If you try reading the
262
314
  # value with #base_dir, the base directory cannot be set again.
@@ -265,49 +317,68 @@ module Buildr
265
317
  @base_dir = File.expand_path(dir)
266
318
  end
267
319
 
268
- # Define a new sub-project within this project.
269
- def define(*args, &block)
270
- name, properties = Project.name_and_properties_from_args(*args)
271
- Project.define "#{self.name}:#{name}", properties, &block
272
- end
273
-
274
- # Returns a path made from multiple arguments. Relative paths are turned into
275
- # absolute paths using this project's base directory.
320
+ # :call-seq:
321
+ # path_to(*names) => path
322
+ #
323
+ # Returns a path from a combination of name, relative to the project's base directory.
324
+ # Essentially, joins all the supplied names and expands the path relative to #base_dir.
325
+ # Symbol arguments are converted to paths by calling the attribute accessor on the project.
276
326
  #
277
- # Symbol arguments are converted to paths by calling the attribute accessor
278
- # on the project. For example:
327
+ # For example:
279
328
  #
280
329
  # For example:
281
330
  # path_to("foo", "bar")
282
- # => /projects/project1/foo/bar
283
- # path_to(:target_dir, "foo")
284
- # => /projects/project1/target/foo
331
+ # => /home/project1/foo/bar
285
332
  # path_to("/tmp")
286
333
  # => /tmp
287
- def path_to(*args)
288
- File.expand_path(File.join(args.map { |arg| Symbol === arg ? send(arg) : arg.to_s }), base_dir)
334
+ # path_to(:base_dir, "foo")
335
+ # => /home/project1/foo
336
+ def path_to(*names)
337
+ File.expand_path(File.join(names.map { |name| Symbol === name ? send(name) : name.to_s }), base_dir)
338
+ end
339
+
340
+ # :call-seq:
341
+ # define(name, properties?) { |project| ... } => project
342
+ #
343
+ # Define a new sub-project within this project. See Buildr#define.
344
+ def define(name, properties = nil, &block)
345
+ Project.define "#{self.name}:#{name}", properties, &block
289
346
  end
290
347
 
348
+ # :call-seq:
349
+ # project(name) => project
350
+ #
291
351
  # Same as Buildr#project.
292
352
  def project(name)
293
353
  Project.project(name)
294
354
  end
295
355
 
356
+ # :call-seq:
357
+ # projects(*names) => projects
358
+ #
296
359
  # Same as Buildr#projects.
297
- def projects(*args)
298
- Project.projects(*args)
360
+ def projects(*names)
361
+ Project.projects(*names)
299
362
  end
300
363
 
301
- def sub_projects()
302
- prefix = name + ":"
303
- Project.projects.select { |project| project.name.starts_with?(prefix) }.sort_by(&:name)
304
- end
305
-
306
- # Create or return a file task. This is similar to Rake's file method,
307
- # with the exception that all relative paths are resolved relative to
308
- # the project's base directory.
364
+ # :call-seq:
365
+ # file(path) => Task
366
+ # file(path=>prereqs) => Task
367
+ # file(path) { |task| ... } => Task
368
+ #
369
+ # Creates and returns a new file task in the project. Similar to calling Rake's
370
+ # file method, but the path is expanded relative to the project's base directory,
371
+ # and the task executes in the project's base directory.
309
372
  #
310
- # You can call this from within or outside the project definition.
373
+ # For example:
374
+ # define "foo" do
375
+ # define "bar" do
376
+ # file("src") { ... }
377
+ # end
378
+ # end
379
+ #
380
+ # puts project("foo:bar").file("src").to_s
381
+ # => "/home/foo/bar/src"
311
382
  def file(args, &block)
312
383
  task_name, deps = Rake.application.resolve_args(args)
313
384
  unless task = Rake.application.lookup(task_name, [])
@@ -318,17 +389,41 @@ module Buildr
318
389
  task.enhance deps, &block
319
390
  end
320
391
 
321
- # Create or return a task. This is similar to Rake's task method,
322
- # with the exception that the task is always defined within the project's
323
- # namespace.
392
+ # :call-seq:
393
+ # task(name) => Task
394
+ # task(name=>prereqs) => Task
395
+ # task(name) { |task| ... } => Task
396
+ #
397
+ # Creates and returns a new task in the project. Similar to calling Rake's task
398
+ # method, but prefixes the task name with the project name and executes the task
399
+ # in the project's base directory.
400
+ #
401
+ # For example:
402
+ # define "foo" do
403
+ # task "doda"
404
+ # end
405
+ #
406
+ # puts project("foo").task("doda").name
407
+ # => "foo:doda"
324
408
  #
325
- # If called from within the project definition, it returns a task,
326
- # creating a new one no such task exists. If called from outside the
327
- # project definition, it returns a task and raises an error if the
328
- # task does not exist.
409
+ # When called from within the project definition, creates a new task if the task
410
+ # does not already exist. If called from outside the project definition, returns
411
+ # the named task and raises an exception if the task is not defined.
412
+ #
413
+ # As with Rake's task method, calling this method enhances the task with the
414
+ # prerequisites and optional block.
329
415
  def task(args, &block)
330
416
  task_name, deps = Rake.application.resolve_args(args)
331
- if Rake.application.current_scope == name.split(":")
417
+ if task_name =~ /^:/
418
+ Rake.application.instance_eval do
419
+ scope, @scope = @scope, []
420
+ begin
421
+ Rake::Task.define_task(task_name[1..-1]=>deps, &block)
422
+ ensure
423
+ @scope = scope
424
+ end
425
+ end
426
+ elsif Rake.application.current_scope == name.split(":")
332
427
  Rake::Task.define_task(task_name=>deps, &block)
333
428
  else
334
429
  if task = Rake.application.lookup(task_name, name.split(":"))
@@ -341,33 +436,15 @@ module Buildr
341
436
  end
342
437
  end
343
438
 
344
- # Define a recursive task.
345
- #
346
- # A recursive task executes the task with the same name in the project,
347
- # and in all its sub-projects. In fact, a recursive task actually adds
348
- # itself as a prerequisite on the parent task.
349
- #
350
- # For example:
351
- # define "foo" do
352
- # define "bar" do
353
- # define "baz" do
354
- # end
355
- # end
356
- # end
357
- #
358
- # rake foo:build
359
- # Will execute foo:build, foo:bar:build and foo:baz:build
360
- #
361
- # Inside the bar directory:
362
- # rake build
363
- # Will execute foo:bar:build and foo:baz:build.
439
+ # :call-seq:
440
+ # recursive_task(name=>prereqs) { |task| ... }
364
441
  #
365
- # This method defines a RakeTask. If you need a different type of task,
366
- # define the task first and then call #recursive_task.
442
+ # Define a recursive task. A recursive task executes itself and the same task
443
+ # in all the sub-projects.
367
444
  def recursive_task(args, &block)
368
445
  task_name, deps = Rake.application.resolve_args(args)
369
446
  deps = [deps] unless deps.respond_to?(:to_ary)
370
- returning(task(task_name=>deps)) do |task|
447
+ task(task_name=>deps).tap do |task|
371
448
  if parent
372
449
  Rake.application.lookup(task_name, parent.name.split(":")).enhance [task]
373
450
  #Rake::Task["^#{name}"].enhance([ task ])
@@ -376,7 +453,7 @@ module Buildr
376
453
  end
377
454
  end
378
455
 
379
- def execute()
456
+ def execute() #:nodoc:
380
457
  Rake.application.in_namespace ":#{name}" do
381
458
  # Everything we do inside the project is relative to its working directory.
382
459
  Dir.chdir(base_dir) { super }
@@ -386,73 +463,68 @@ module Buildr
386
463
  end
387
464
 
388
465
  # :call-seq:
389
- # define name { |project| ... }
390
- # define name, properties { |project| ... }
391
- # define properties { |project| ... }
466
+ # define(name, properties?) { |project| ... } => project
392
467
  #
393
468
  # Defines a new project.
394
469
  #
395
- # The first argument is the project name. Each project must have a unique name,
396
- # and you can only define a project once.
470
+ # The first argument is the project name. Each project must have a unique name.
471
+ # For a sub-project, the actual project name is created by prefixing the parent
472
+ # project's name.
397
473
  #
398
- # The second argument contains any number of properties that are set on the
399
- # project. The project must have attribute accessors to support these properties.
400
- # You can also pass the project name in the properties hash.
474
+ # The second argument is optional and contains a hash or properties that are set
475
+ # on the project. You can only use properties that are supported by the project
476
+ # definition, e.g. :group and :version. You can also set these properties from the
477
+ # project definition.
401
478
  #
402
- # The easiest way to define a project and configure its tasks is by passing
403
- # a block. The #define method executes the block in the context of the project.
479
+ # You pass a block that is executed in the context of the project definition.
480
+ # This block is used to define the project and tasks that are part of the project.
481
+ # Do not perform any work inside the project itself, as it will execute each time
482
+ # the Rakefile is loaded. Instead, use it to create and extend tasks that are
483
+ # related to the project.
404
484
  #
405
485
  # For example:
406
486
  # define "foo", :version=>"1.0" do
407
- # puts version
408
- # end
409
- #
410
- # define "bar" do
411
- # puts name
412
- # end
413
- 3 # => "1.0"
414
- # "bar"
415
487
  #
416
- # Each project also has a #define method that operates the same way, but
417
- # defines a sub-project. A sub-project has a compound name using the parent
418
- # project's name, and also inherits some of its properties. You can only
419
- # define a sub-project as part of the parent project's definition.
420
- #
421
- # For example:
422
- # define "foo", :version=>"1.0" do
423
- # define "bar"
424
- # puts name
425
- # puts version
488
+ # define "bar" do
489
+ # compile.with "org.apache.axis2:axis2:jar:1.1"
426
490
  # end
427
491
  # end
428
- # => "foo:bar"
429
- # "1.0"
430
- def define(*args, &block)
431
- Project.define(*args, &block)
492
+ #
493
+ # puts project("foo").version
494
+ # => "1.0"
495
+ # puts project("foo:bar").compile.classpath.map(&:to_spec)
496
+ # => "org.apache.axis2:axis2:jar:1.1"
497
+ # % rake build
498
+ # => Compiling 14 source files in foo:bar
499
+ def define(name, properties = nil, &block) #:yields:project
500
+ Project.define(name, properties, &block)
432
501
  end
433
502
 
434
- # Returns the named project.
503
+ # :call-seq:
504
+ # project(name) => project
505
+ #
506
+ # Returns a project definition.
435
507
  #
436
- # For a sub-project, use the full name, for example "foo:bar" to find
437
- # the sub-project "bar" of the parent project "foo".
508
+ # You cannot reference a project before the project is defined. When working with
509
+ # sub-projects, the project definition is stored by calling #define, and evaluated
510
+ # before a call to the parent project's #define method returns.
438
511
  #
439
- # You cannot reference a project before the project is defined, with one
440
- # exception. When working with sub-projects, the project definitions are
441
- # stored but not executed until the parent project is defined. So within
442
- # a sub-project definition you can reference another sub-project definition.
443
- # The definitions are then performed (invoked) based on that dependency.
444
- # You cannot have circular references between project definitions.
512
+ # However, if you call #project with the name of another sub-project, its definition
513
+ # is evaluated immediately. So the returned project definition is always complete,
514
+ # and you can access its definition (e.g. to find files relative to the base directory,
515
+ # or packages created by that project).
445
516
  #
446
517
  # For example:
447
- # define "project1" do
518
+ # define "myapp" do
448
519
  # self.version = "1.1"
449
520
  #
450
- # define "module1" do
451
- # package :jar
521
+ # define "webapp" do
522
+ # # webapp is defined first, but beans is evaluated first
523
+ # compile.with project("myapp:beans")
524
+ # package :war
452
525
  # end
453
526
  #
454
- # define "module2" do
455
- # compile.with project("project1:module1")
527
+ # define "beans" do
456
528
  # package :jar
457
529
  # end
458
530
  # end
@@ -460,18 +532,22 @@ module Buildr
460
532
  Project.project(name)
461
533
  end
462
534
 
463
- # With no arguments, returns a list of all the projects defined so far.
535
+ # :call-seq:
536
+ # projects(*names) => projects
537
+ #
538
+ # With no arguments, returns a list of all projects defined so far. With arguments,
539
+ # returns a list of these projects, fails on undefined projects.
464
540
  #
465
- # With arguments, returns a list of these projects. Equivalent to calling #project
466
- # for each named project.
541
+ # Like #project, this method evaluates the definition of each project before returning it.
542
+ # Be advised of circular dependencies.
467
543
  #
468
544
  # For example:
469
545
  # files = projects.map { |prj| FileList[prj.path_to("src/**/*.java") }.flatten
470
546
  # puts "There are #{files.size} source files in #{projects.size} projects"
471
547
  #
472
- # projects("project1", "project2").map(&:base_dir)
473
- def projects(*args)
474
- Project.projects *args
548
+ # puts projects("project1", "project2").map(&:base_dir)
549
+ def projects(*names)
550
+ Project.projects *names
475
551
  end
476
552
 
477
553
  # Add project definition tests.