buildr 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.