buildr 1.2.10 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. data/CHANGELOG +566 -268
  2. data/DISCLAIMER +7 -1
  3. data/KEYS +151 -0
  4. data/NOTICE +23 -8
  5. data/README +122 -22
  6. data/Rakefile +49 -229
  7. data/{lib → addon}/buildr/antlr.rb +23 -10
  8. data/addon/buildr/cobertura.rb +232 -0
  9. data/{lib → addon}/buildr/hibernate.rb +20 -4
  10. data/{lib → addon}/buildr/javacc.rb +27 -12
  11. data/addon/buildr/jdepend.rb +60 -0
  12. data/{lib → addon}/buildr/jetty.rb +34 -18
  13. data/addon/buildr/nailgun.rb +892 -0
  14. data/{lib → addon}/buildr/openjpa.rb +23 -6
  15. data/addon/buildr/org/apache/buildr/JettyWrapper$1.class +0 -0
  16. data/addon/buildr/org/apache/buildr/JettyWrapper$BuildrHandler.class +0 -0
  17. data/addon/buildr/org/apache/buildr/JettyWrapper.class +0 -0
  18. data/{lib/buildr/jetty → addon/buildr/org/apache/buildr}/JettyWrapper.java +19 -0
  19. data/{lib → addon}/buildr/xmlbeans.rb +39 -14
  20. data/bin/buildr +21 -7
  21. data/buildr.gemspec +50 -0
  22. data/doc/css/default.css +225 -0
  23. data/doc/css/print.css +95 -0
  24. data/doc/css/syntax.css +43 -0
  25. data/doc/images/apache-incubator-logo.png +0 -0
  26. data/doc/images/buildr-hires.png +0 -0
  27. data/doc/images/buildr.png +0 -0
  28. data/doc/images/note.png +0 -0
  29. data/doc/images/tip.png +0 -0
  30. data/doc/images/zbuildr.tif +0 -0
  31. data/doc/pages/artifacts.textile +317 -0
  32. data/doc/pages/building.textile +501 -0
  33. data/doc/pages/contributing.textile +178 -0
  34. data/doc/pages/download.textile +25 -0
  35. data/doc/pages/extending.textile +229 -0
  36. data/doc/pages/getting_started.textile +337 -0
  37. data/doc/pages/index.textile +63 -0
  38. data/doc/pages/mailing_lists.textile +17 -0
  39. data/doc/pages/more_stuff.textile +367 -0
  40. data/doc/pages/packaging.textile +592 -0
  41. data/doc/pages/projects.textile +449 -0
  42. data/doc/pages/recipes.textile +127 -0
  43. data/doc/pages/settings_profiles.textile +339 -0
  44. data/doc/pages/testing.textile +475 -0
  45. data/doc/pages/troubleshooting.textile +121 -0
  46. data/doc/pages/whats_new.textile +389 -0
  47. data/doc/print.haml +52 -0
  48. data/doc/print.toc.yaml +28 -0
  49. data/doc/scripts/buildr-git.rb +411 -0
  50. data/doc/scripts/install-jruby.sh +44 -0
  51. data/doc/scripts/install-linux.sh +64 -0
  52. data/doc/scripts/install-osx.sh +52 -0
  53. data/doc/site.haml +55 -0
  54. data/doc/site.toc.yaml +44 -0
  55. data/lib/buildr.rb +28 -45
  56. data/lib/buildr/core.rb +27 -0
  57. data/lib/buildr/core/application.rb +373 -0
  58. data/lib/buildr/core/application_cli.rb +134 -0
  59. data/lib/{core → buildr/core}/build.rb +91 -77
  60. data/lib/{core → buildr/core}/checks.rb +116 -95
  61. data/lib/buildr/core/common.rb +155 -0
  62. data/lib/buildr/core/compile.rb +594 -0
  63. data/lib/buildr/core/environment.rb +120 -0
  64. data/lib/buildr/core/filter.rb +258 -0
  65. data/lib/{core → buildr/core}/generate.rb +22 -5
  66. data/lib/buildr/core/help.rb +118 -0
  67. data/lib/buildr/core/progressbar.rb +156 -0
  68. data/lib/{core → buildr/core}/project.rb +468 -213
  69. data/lib/buildr/core/test.rb +690 -0
  70. data/lib/{core → buildr/core}/transports.rb +107 -127
  71. data/lib/buildr/core/util.rb +235 -0
  72. data/lib/buildr/ide.rb +19 -0
  73. data/lib/{java → buildr/ide}/eclipse.rb +86 -60
  74. data/lib/{java → buildr/ide}/idea.ipr.template +16 -0
  75. data/lib/buildr/ide/idea.rb +194 -0
  76. data/lib/buildr/ide/idea7x.ipr.template +290 -0
  77. data/lib/buildr/ide/idea7x.rb +210 -0
  78. data/lib/buildr/java.rb +26 -0
  79. data/lib/buildr/java/ant.rb +71 -0
  80. data/lib/buildr/java/bdd_frameworks.rb +267 -0
  81. data/lib/buildr/java/commands.rb +210 -0
  82. data/lib/buildr/java/compilers.rb +432 -0
  83. data/lib/buildr/java/deprecated.rb +141 -0
  84. data/lib/buildr/java/groovyc.rb +137 -0
  85. data/lib/buildr/java/jruby.rb +99 -0
  86. data/lib/buildr/java/org/apache/buildr/BuildrNail$Main.class +0 -0
  87. data/lib/buildr/java/org/apache/buildr/BuildrNail.class +0 -0
  88. data/lib/buildr/java/org/apache/buildr/BuildrNail.java +41 -0
  89. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.class +0 -0
  90. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.java +116 -0
  91. data/lib/buildr/java/packaging.rb +706 -0
  92. data/lib/{java → buildr/java}/pom.rb +20 -4
  93. data/lib/buildr/java/rjb.rb +142 -0
  94. data/lib/buildr/java/test_frameworks.rb +290 -0
  95. data/lib/buildr/java/version_requirement.rb +172 -0
  96. data/lib/buildr/packaging.rb +21 -0
  97. data/lib/{java → buildr/packaging}/artifact.rb +170 -179
  98. data/lib/buildr/packaging/artifact_namespace.rb +957 -0
  99. data/lib/buildr/packaging/artifact_search.rb +140 -0
  100. data/lib/buildr/packaging/gems.rb +102 -0
  101. data/lib/buildr/packaging/package.rb +233 -0
  102. data/lib/{tasks → buildr/packaging}/tar.rb +18 -1
  103. data/lib/{tasks → buildr/packaging}/zip.rb +153 -105
  104. data/rakelib/apache.rake +126 -0
  105. data/rakelib/changelog.rake +56 -0
  106. data/rakelib/doc.rake +103 -0
  107. data/rakelib/package.rake +44 -0
  108. data/rakelib/release.rake +53 -0
  109. data/rakelib/rspec.rake +81 -0
  110. data/rakelib/rubyforge.rake +45 -0
  111. data/rakelib/scm.rake +49 -0
  112. data/rakelib/setup.rake +59 -0
  113. data/rakelib/stage.rake +45 -0
  114. data/spec/application_spec.rb +316 -0
  115. data/spec/archive_spec.rb +494 -0
  116. data/spec/artifact_namespace_spec.rb +635 -0
  117. data/spec/artifact_spec.rb +738 -0
  118. data/spec/build_spec.rb +193 -0
  119. data/spec/checks_spec.rb +537 -0
  120. data/spec/common_spec.rb +579 -0
  121. data/spec/compile_spec.rb +561 -0
  122. data/spec/groovy_compilers_spec.rb +239 -0
  123. data/spec/java_bdd_frameworks_spec.rb +238 -0
  124. data/spec/java_compilers_spec.rb +446 -0
  125. data/spec/java_packaging_spec.rb +1042 -0
  126. data/spec/java_test_frameworks_spec.rb +414 -0
  127. data/spec/packaging_helper.rb +63 -0
  128. data/spec/packaging_spec.rb +589 -0
  129. data/spec/project_spec.rb +739 -0
  130. data/spec/sandbox.rb +116 -0
  131. data/spec/scala_compilers_spec.rb +239 -0
  132. data/spec/spec.opts +6 -0
  133. data/spec/spec_helpers.rb +283 -0
  134. data/spec/test_spec.rb +871 -0
  135. data/spec/transport_spec.rb +300 -0
  136. data/spec/version_requirement_spec.rb +115 -0
  137. metadata +188 -77
  138. data/lib/buildr/cobertura.rb +0 -89
  139. data/lib/buildr/jdepend.rb +0 -40
  140. data/lib/buildr/jetty/JettyWrapper$1.class +0 -0
  141. data/lib/buildr/jetty/JettyWrapper$BuildrHandler.class +0 -0
  142. data/lib/buildr/jetty/JettyWrapper.class +0 -0
  143. data/lib/buildr/scala.rb +0 -368
  144. data/lib/core/application.rb +0 -188
  145. data/lib/core/common.rb +0 -562
  146. data/lib/core/help.rb +0 -72
  147. data/lib/core/rake_ext.rb +0 -81
  148. data/lib/java/ant.rb +0 -71
  149. data/lib/java/compile.rb +0 -589
  150. data/lib/java/idea.rb +0 -159
  151. data/lib/java/java.rb +0 -432
  152. data/lib/java/packaging.rb +0 -581
  153. data/lib/java/test.rb +0 -795
  154. data/lib/tasks/concat.rb +0 -35
@@ -0,0 +1,156 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with this
3
+ # work for additional information regarding copyright ownership. The ASF
4
+ # licenses this file to you under the Apache License, Version 2.0 (the
5
+ # "License"); you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations under
14
+ # the License.
15
+
16
+
17
+ class ProgressBar
18
+
19
+ class << self
20
+
21
+ def start(args, &block)
22
+ new(args).start &block
23
+ end
24
+
25
+ def width
26
+ @width ||= $terminal.output_cols || 80
27
+ end
28
+
29
+ end
30
+
31
+ def initialize(args = {})
32
+ @title = args[:title] || ''
33
+ @total = args[:total] || 0
34
+ @mark = args[:mark] || '.'
35
+ @format = args[:format] || default_format
36
+ @output = args[:output] || $stderr unless args[:hidden] || !$stdout.isatty
37
+ clear
38
+ end
39
+
40
+ def start
41
+ @start = @last_time = Time.now
42
+ @count = 0
43
+ @finished = false
44
+ render
45
+ if block_given?
46
+ result = yield(self) if block_given?
47
+ finish
48
+ result
49
+ else
50
+ self
51
+ end
52
+ end
53
+
54
+ def inc(count)
55
+ set @count + count
56
+ end
57
+
58
+ def <<(bytes)
59
+ inc bytes.size
60
+ end
61
+
62
+ def set(count)
63
+ @count = [count, 0].max
64
+ @count = [count, @total].min unless @total == 0
65
+ render if changed?
66
+ end
67
+
68
+ def title
69
+ @title.size > ProgressBar.width / 5 ? (@title[0, ProgressBar.width / 5 - 2] + '..') : @title
70
+ end
71
+
72
+ def count
73
+ human(@count)
74
+ end
75
+
76
+ def total
77
+ human(@total)
78
+ end
79
+
80
+ def percentage
81
+ '%3d%%' % (@total == 0 ? 100 : (@count * 100 / @total))
82
+ end
83
+
84
+ def time
85
+ @finished ? elapsed : eta
86
+ end
87
+
88
+ def eta
89
+ return 'ETA: --:--:--' if @count == 0
90
+ elapsed = Time.now - @start
91
+ eta = elapsed * @total / @count - elapsed
92
+ 'ETA: %s' % duration(eta.ceil)
93
+ end
94
+
95
+ def elapsed
96
+ 'Time: %s' % duration(Time.now - @start)
97
+ end
98
+
99
+ def rate
100
+ '%s/s' % human(@count / (Time.now - @start))
101
+ end
102
+
103
+ def progress(width)
104
+ width -= 2
105
+ marks = @total == 0 ? width : (@count * width / @total)
106
+ "|%-#{width}s|" % (@mark * marks)
107
+ end
108
+
109
+ def human(bytes)
110
+ magnitude = (0..3).find { |i| bytes < (1024 << i * 10) } || 3
111
+ return '%dB' % bytes if magnitude == 0
112
+ return '%.1f%s' % [ bytes.to_f / (1 << magnitude * 10), [nil, 'KB', 'MB', 'GB'][magnitude] ]
113
+ end
114
+
115
+ def duration(seconds)
116
+ '%02d:%02d:%02d' % [seconds / 3600, (seconds / 60) % 60, seconds % 60]
117
+ end
118
+
119
+ def finish
120
+ unless @finished
121
+ @finished = true
122
+ render
123
+ end
124
+ end
125
+
126
+ protected
127
+
128
+ def clear
129
+ return unless @output
130
+ @output.print "\r", " " * (ProgressBar.width - 1), "\r"
131
+ @output.flush
132
+ end
133
+
134
+ def render
135
+ return unless @output
136
+ format, *args = @format
137
+ line = format % args.map { |arg| send(arg) }
138
+ @output.print line.sub('|--|') { progress(ProgressBar.width - line.size + 3) }
139
+ @output.print @finished ? "\n" : "\r"
140
+ @output.flush
141
+ @previous = @count
142
+ @last_time = Time.now
143
+ end
144
+
145
+ def changed?
146
+ return false unless @output
147
+ return human(@count) != human(@previous) if @total == 0
148
+ return true if (@count - @previous) >= @total / 100
149
+ return Time.now - @last_time > 1
150
+ end
151
+
152
+ def default_format
153
+ @total == 0 ? ['%s %8s %s', :title, :count, :elapsed] : ['%s: %s |--| %8s/%s %s', :title, :percentage, :count, :total, :time]
154
+ end
155
+
156
+ end
@@ -1,46 +1,107 @@
1
- require "core/rake_ext"
2
- require "core/common"
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with this
3
+ # work for additional information regarding copyright ownership. The ASF
4
+ # licenses this file to you under the Apache License, Version 2.0 (the
5
+ # "License"); you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations under
14
+ # the License.
15
+
16
+
17
+ require 'buildr/core/util'
18
+
3
19
 
4
20
  module Buildr
5
21
 
6
- # An inherited attribute gets its value an accessor with the same name.
7
- # But if the value is not set, it will obtain a value from the parent,
8
- # so setting the value in the parent make it accessible to all the children
9
- # that did not override it.
10
- module InheritedAttributes
22
+ # Symbolic mapping for directory layout. Used for both the default and custom layouts.
23
+ #
24
+ # For example, the default layout maps [:source, :main, :java] to 'src/main/java', and
25
+ # [:target, :main, :classes] to 'target/classes'. You can use this to change the layout
26
+ # of your projects.
27
+ #
28
+ # To map [:source, :main] into the 'sources' directory:
29
+ # my_layout = Layout.new
30
+ # my_layout[:source, :main] = 'sources'
31
+ #
32
+ # define 'foo', :layout=>my_layout do
33
+ # ...
34
+ # end
35
+ #
36
+ # To map [:source, :main, :java] to 'java/main':
37
+ # class MainLast < Layout
38
+ # def expand(*args)
39
+ # if args[0..1] == [:source, :main]
40
+ # super args[2], :main, *args[3,]
41
+ # else
42
+ # super
43
+ # end
44
+ # end
45
+ # end
46
+ #
47
+ # define 'foo', :layout=>MainLast do
48
+ # ...
49
+ # end
50
+ class Layout
11
51
 
12
52
  class << self
13
- private
14
- def included(mod)
15
- mod.extend(self)
16
- end
53
+
54
+ # Default layout used by new projects.
55
+ attr_accessor :default
56
+
17
57
  end
18
58
 
19
- # :call-seq:
20
- # inherited_attr(symbol, default?)
21
- # inherited_attr(symbol) { |obj| ... }
22
- #
23
- # Defines an inherited attribute. The first form can provide a default value
24
- # for the top-level object, used if the attribute was not set. The second form
25
- # provides a default value by calling the block.
26
- #
27
- # For example:
28
- # inherited_attr :version
29
- # inherited_attr :src_dir, "src"
30
- # inherited_attr(:created_on) { Time.now }
31
- def inherited_attr(symbol, default = nil, &block)
32
- block ||= proc { default }
33
- attr_accessor symbol
34
- define_method "#{symbol}_with_inheritence" do
35
- value = send("#{symbol}_without_inheritence")
36
- if value.nil?
37
- value = parent ? parent.send(symbol) : self.instance_eval(&block)
38
- send "#{symbol}=", value
39
- end
40
- value
59
+ def initialize #:nodoc:
60
+ @mapping = {}
61
+ end
62
+
63
+ # Expands list of symbols and path names into a full path, for example:
64
+ # puts default.expand(:source, :main, :java)
65
+ # => "src/main/java"
66
+ def expand(*args)
67
+ return '' if args.empty?
68
+ @mapping[args] ||= File.join(*[expand(*args[0..-2]), args.last.to_s].reject(&:empty?)) if args.size > 1
69
+ return @mapping[args] || args.first.to_s
70
+ end
71
+
72
+ # Resolves a list of symbols into a path.
73
+ def [](*args)
74
+ @mapping[args.map(&:to_sym)]
75
+ end
76
+
77
+ # Specifies the path resolved from a list of symbols.
78
+ def []=(*args)
79
+ @mapping[args[0...-1].map(&:to_sym)] = args.last
80
+ end
81
+
82
+ def initialize_copy(copy)
83
+ copy.instance_variable_set :@mapping, @mapping.clone
84
+ end
85
+
86
+ # Default layout has the following properties:
87
+ # * :source maps to the 'src' directory.
88
+ # * Anything under :source maps verbatim (e.g. :source, :main becomes 'src/main')
89
+ # * :target maps to the 'target' directory.
90
+ # * :target, :main maps to the 'target' directory as well.
91
+ # * Anything under :target, :main maps verbatim (e.g. :target, :main, :classes becomes 'target/classes')
92
+ # * Anything else under :target also maps verbatim (e.g. :target, :test becomes 'target/test')
93
+ class Default < Layout
94
+
95
+ def initialize
96
+ super
97
+ self[:source] = 'src'
98
+ self[:target, :main] = 'target'
41
99
  end
42
- alias_method_chain symbol, :inheritence
100
+
43
101
  end
102
+
103
+ self.default = Default.new
104
+
44
105
  end
45
106
 
46
107
 
@@ -89,34 +150,39 @@ module Buildr
89
150
  # | |__resources <-- Resources to copy (tests)
90
151
  # |__target <-- Packages created here
91
152
  # | |__classes <-- Generated when compiling
92
- # | |__test-classes <-- Generated when compiling tests
153
+ # | |__resources <-- Copied (and filtered) from resources
154
+ # | |__test/classes <-- Generated when compiling tests
155
+ # | |__test/resources <-- Copied (and filtered) from resources
156
+ # |__reports <-- Test, coverage and other reports
157
+ #
158
+ # You can change the project layout by passing a new Layout to the project definition.
93
159
  #
94
160
  # You can only define a project once using #define. Afterwards, you can obtain the project
95
161
  # definition using #project. The order in which you define projects is not important,
96
162
  # project definitions are evaluated when you ask for them. Circular dependencies will not
97
163
  # work. Rake tasks are only created after the project is evaluated, so if you need to access
98
- # a task (e.g. compile) use <code>project("foo").compile</code> instead of <code>task("foo:compile")</code>.
164
+ # a task (e.g. compile) use <code>project('foo').compile</code> instead of <code>task('foo:compile')</code>.
99
165
  #
100
166
  # For example:
101
- # define "myapp", :version=>"1.1" do
167
+ # define 'myapp', :version=>'1.1' do
102
168
  #
103
- # define "wepapp" do
104
- # compile.with project("myapp:beans")
169
+ # define 'wepapp' do
170
+ # compile.with project('myapp:beans')
105
171
  # package :war
106
172
  # end
107
173
  #
108
- # define "beans" do
174
+ # define 'beans' do
109
175
  # compile.with DEPENDS
110
176
  # package :jar
111
177
  # end
112
178
  # end
113
179
  #
114
180
  # puts projects.map(&:name)
115
- # => [ "myapp", "myapp:beans", "myapp:webapp" ]
116
- # puts project("myapp:webapp").parent.name
117
- # => "myapp"
118
- # puts project("myapp:webapp").compile.classpath.map(&:to_spec)
119
- # => "myapp:myapp-beans:jar:1.1"
181
+ # => [ 'myapp', 'myapp:beans', 'myapp:webapp' ]
182
+ # puts project('myapp:webapp').parent.name
183
+ # => 'myapp'
184
+ # puts project('myapp:webapp').compile.classpath.map(&:to_spec)
185
+ # => 'myapp:myapp-beans:jar:1.1'
120
186
  class Project < Rake::Task
121
187
 
122
188
  class << self
@@ -129,16 +195,28 @@ module Buildr
129
195
  # Make sure a sub-project is only defined within the parent project,
130
196
  # to prevent silly mistakes that lead to inconsistencies (e.g.
131
197
  # namespaces will be all out of whack).
132
- Rake.application.current_scope == name.split(":")[0...-1] or
198
+ Buildr.application.current_scope == name.split(':')[0...-1] or
133
199
  raise "You can only define a sub project (#{name}) within the definition of its parent project"
134
200
 
135
201
  @projects ||= {}
136
202
  raise "You cannot define the same project (#{name}) more than once" if @projects[name]
203
+ # Projects with names like: compile, test, build are invalid, so we have
204
+ # to make sure the project has not the name of an already defined task
205
+ raise "Invalid project name: #{name.inspect} is already used for a task" if Buildr.application.lookup(name)
206
+
137
207
  Project.define_task(name).tap do |project|
138
208
  # Define the project to prevent duplicate definition.
139
209
  @projects[name] = project
140
210
  # Set the project properties first, actions may use them.
141
211
  properties.each { |name, value| project.send "#{name}=", value } if properties
212
+ # Instantiate callbacks for this project, and setup to call before/after define.
213
+ # Don't cache list of callbacks, since project may add new callbacks.
214
+ project.enhance do |project|
215
+ project.send :call_callbacks, :before_define
216
+ project.enhance do |project|
217
+ project.send :call_callbacks, :after_define
218
+ end
219
+ end
142
220
  project.enhance do |project|
143
221
  @on_define.each { |callback| callback[project] }
144
222
  end if @on_define
@@ -146,7 +224,7 @@ module Buildr
146
224
  project.enhance { project.instance_eval &block } if block
147
225
 
148
226
  # Top-level project? Invoke the project definition. Sub-project? We don't invoke
149
- # the project definiton yet (allow project() calls to establish order of evaluation),
227
+ # the project definiton yet (allow project calls to establish order of evaluation),
150
228
  # but must do so before the parent project's definition is done.
151
229
  project.parent.enhance { project.invoke } if project.parent
152
230
  end
@@ -159,18 +237,18 @@ module Buildr
159
237
  def project(*args) #:nodoc:
160
238
  options = args.pop if Hash === args.last
161
239
  rake_check_options options, :scope if options
162
- raise ArgumentError, "Only one project name at a time" unless args.size == 1
240
+ raise ArgumentError, 'Only one project name at a time' unless args.size == 1
163
241
  @projects ||= {}
164
242
  name = args.first
165
243
  if options && options[:scope]
166
244
  # We assume parent project is evaluated.
167
- project = options[:scope].split(":").inject([[]]) { |scopes, scope| scopes << (scopes.last + [scope]) }.
168
- map { |scope| @projects[(scope + [name]).join(":")] }.
245
+ project = options[:scope].split(':').inject([[]]) { |scopes, scope| scopes << (scopes.last + [scope]) }.
246
+ map { |scope| @projects[(scope + [name]).join(':')] }.
169
247
  select { |project| project }.last
170
248
  end
171
249
  unless project
172
250
  # Parent project not evaluated.
173
- name.split(":").tap { |parts| @projects[parts.first].invoke if parts.size > 1 }
251
+ name.split(':').tap { |parts| @projects[parts.first].invoke if parts.size > 1 }
174
252
  project = @projects[name]
175
253
  end
176
254
  raise "No such project #{name}" unless project
@@ -202,16 +280,16 @@ module Buildr
202
280
  @projects.keys.map { |name| project(name) or raise "No such project #{name}" }.sort_by(&:name)
203
281
  else
204
282
  # Parent project(s) not evaluated, for the sub-projects we may need to find.
205
- names.map { |name| name.split(":") }.select { |name| name.size > 1 }.map(&:first).uniq.each { |name| project(name) }
283
+ names.map { |name| name.split(':') }.select { |name| name.size > 1 }.map(&:first).uniq.each { |name| project(name) }
206
284
  names.uniq.map { |name| project(name) or raise "No such project #{name}" }.sort_by(&:name)
207
285
  end
208
286
  end
209
287
 
210
288
  # :call-seq:
211
- # clear()
289
+ # clear
212
290
  #
213
291
  # Discard all project definitions.
214
- def clear()
292
+ def clear
215
293
  @projects.clear if @projects
216
294
  end
217
295
 
@@ -246,21 +324,9 @@ module Buildr
246
324
  end
247
325
  end
248
326
 
249
- # :call-seq:
250
- # on_define() { |project| ... }
251
- #
252
- # The Project class defines minimal behavior, only what is documented here.
253
- # To extend its definition, other modules use Project#on_define to incorporate
254
- # code called during a new project's definition.
255
- #
256
- # For example:
257
- # # Set the default version of each project to "1.0".
258
- # Project.on_define { |project| project.version ||= "1.0" }
259
- #
260
- # Since each project definition is essentially a task, if you need to do work
261
- # at the end of the project definition (after the block is executed), you can
262
- # enhance it from within #on_define.
327
+ # *Deprecated* Check the Extension module to see how extensions are handled.
263
328
  def on_define(&block)
329
+ Buildr.application.deprecated 'This method is deprecated, see Extension'
264
330
  (@on_define ||= []) << block if block
265
331
  end
266
332
 
@@ -269,13 +335,13 @@ module Buildr
269
335
  end
270
336
 
271
337
  def local_projects(dir = nil, &block) #:nodoc:
272
- dir = File.expand_path(dir || Rake.application.original_dir)
338
+ dir = File.expand_path(dir || Buildr.application.original_dir)
273
339
  projects = Project.projects.select { |project| project.base_dir == dir }
274
340
  if projects.empty? && dir != Dir.pwd && File.dirname(dir) != dir
275
341
  local_projects(File.dirname(dir), &block)
276
342
  elsif block
277
343
  if projects.empty?
278
- warn "No projects defined for directory #{Rake.application.original_dir}" if verbose
344
+ warn "No projects defined for directory #{Buildr.application.original_dir}" if verbose
279
345
  else
280
346
  projects.each { |project| block[project] }
281
347
  end
@@ -285,23 +351,38 @@ module Buildr
285
351
  end
286
352
 
287
353
  # :call-seq:
288
- # task_in_parent_project(task_name) => task_name or nil
354
+ # parent_task(task_name) => task_name or nil
289
355
  #
290
- # Assuming the task name is prefixed with the current project, finds and returns a task with the
291
- # same name in a parent project. Call this with "foo:bar:test" will return "foo:test", but call
292
- # this with "foo:test" will return nil.
293
- def task_in_parent_project(task_name)
294
- namespace = task_name.split(":")
356
+ # Returns a parent task, basically a task in a higher namespace. For example, the parent
357
+ # of 'foo:test:compile' is 'foo:compile' and the parent of 'foo:compile' is 'compile'.
358
+ def parent_task(task_name) #:nodoc:
359
+ namespace = task_name.split(':')
295
360
  last_name = namespace.pop
296
361
  namespace.pop
297
- Rake.application.lookup((namespace + [last_name]).join(":"), []) unless namespace.empty?
362
+ Buildr.application.lookup((namespace + [last_name]).join(':'), []) unless namespace.empty?
363
+ end
364
+
365
+ # :call-seq:
366
+ # project_from_task(task) => project
367
+ #
368
+ # Figure out project associated to this task and return it.
369
+ def project_from_task(task) #:nodoc:
370
+ project = Buildr.application.lookup('rake:' + task.to_s.gsub(/:[^:]*$/, ''))
371
+ project if Project === project
372
+ end
373
+
374
+ # Callback classes.
375
+ def callbacks #:nodoc:
376
+ @callbacks ||= []
298
377
  end
299
378
 
300
379
  end
301
380
 
302
- include InheritedAttributes
303
381
 
304
- # The project name. For example, "foo" for the top-level project, and "foo:bar"
382
+ # Project has visibility to everything in the Buildr namespace.
383
+ include Buildr
384
+
385
+ # The project name. For example, 'foo' for the top-level project, and 'foo:bar'
305
386
  # for its sub-project.
306
387
  attr_reader :name
307
388
 
@@ -310,17 +391,22 @@ module Buildr
310
391
 
311
392
  def initialize(*args) #:nodoc:
312
393
  super
313
- split = name.split(":")
394
+ split = name.split(':')
314
395
  if split.size > 1
315
396
  # Get parent project, but do not invoke it's definition to prevent circular
316
- # dependencies (it's being invoked right now, so calling project() will fail).
317
- @parent = task(split[0...-1].join(":"))
318
- raise "No parent project #{split[0...-1].join(":")}" unless @parent && Project === parent
397
+ # dependencies (it's being invoked right now, so calling project will fail).
398
+ @parent = task(split[0...-1].join(':'))
399
+ raise "No parent project #{split[0...-1].join(':')}" unless @parent && Project === parent
400
+ end
401
+ callbacks = Project.callbacks.uniq.map(&:new)
402
+ @callbacks = [:before_define, :after_define].inject({}) do |hash, state|
403
+ methods = callbacks.select { |callback| callback.respond_to?(state) }.map { |callback| callback.method(state) }
404
+ hash.update(state=>methods)
319
405
  end
320
406
  end
321
407
 
322
408
  # :call-seq:
323
- # base_dir() => path
409
+ # base_dir => path
324
410
  #
325
411
  # Returns the project's base directory.
326
412
  #
@@ -329,15 +415,15 @@ module Buildr
329
415
  # a base directory that is one level down, with the same name as the sub-project.
330
416
  #
331
417
  # For example:
332
- # /home/foo/ <-- base_directory of project "foo"
333
- # /home/foo/Buildfile <-- builds "foo"
334
- # /home/foo/bar <-- sub-project "foo:bar"
335
- def base_dir()
418
+ # /home/foo/ <-- base_directory of project 'foo'
419
+ # /home/foo/Buildfile <-- builds 'foo'
420
+ # /home/foo/bar <-- sub-project 'foo:bar'
421
+ def base_dir
336
422
  if @base_dir.nil?
337
423
  if parent
338
424
  # For sub-project, a good default is a directory in the parent's base_dir,
339
425
  # using the same name as the project.
340
- @base_dir = File.join(parent.base_dir, name.split(":").last)
426
+ @base_dir = File.expand_path(name.split(':').last, parent.base_dir)
341
427
  else
342
428
  # For top-level project, a good default is the directory where we found the Buildfile.
343
429
  @base_dir = Dir.pwd
@@ -346,20 +432,9 @@ module Buildr
346
432
  @base_dir
347
433
  end
348
434
 
349
- # :call-seq:
350
- # base_dir = dir
351
- #
352
- # Sets the project's base directory. Allows you to specify a base directory by calling
353
- # this accessor, or with the :base_dir property when calling #define.
354
- #
355
- # You can only set the base directory once for a given project, and only before accessing
356
- # the base directory (for example, by calling #file or #path_to).
357
- # Set the base directory. Note: you can only do this once for a project,
358
- # and only before accessing the base directory. If you try reading the
359
- # value with #base_dir, the base directory cannot be set again.
360
- def base_dir=(dir)
361
- raise "Cannot set base directory twice, or after reading its value" if @base_dir
362
- @base_dir = File.expand_path(dir)
435
+ # Returns the layout associated with this project.
436
+ def layout
437
+ @layout ||= (parent ? parent.layout : Layout.default).clone
363
438
  end
364
439
 
365
440
  # :call-seq:
@@ -367,29 +442,102 @@ module Buildr
367
442
  #
368
443
  # Returns a path from a combination of name, relative to the project's base directory.
369
444
  # Essentially, joins all the supplied names and expands the path relative to #base_dir.
370
- # Symbol arguments are converted to paths by calling the attribute accessor on the project.
445
+ # Symbol arguments are converted to paths based on the layout, so whenever possible stick
446
+ # to these. For example:
447
+ # path_to(:source, :main, :java)
448
+ # => 'src/main/java'
371
449
  #
372
450
  # Keep in mind that all tasks are defined and executed relative to the Buildfile directory,
373
451
  # so you want to use #path_to to get the actual path within the project as a matter of practice.
374
452
  #
375
453
  # For example:
376
- # path_to("foo", "bar")
377
- # => /home/project1/foo/bar
378
- # path_to("/tmp")
454
+ # path_to('foo', 'bar')
455
+ # => foo/bar
456
+ # path_to('/tmp')
379
457
  # => /tmp
380
- # path_to(:base_dir, "foo") # same as path_to("foo")
458
+ # path_to(:base_dir, 'foo') # same as path_to('foo")
381
459
  # => /home/project1/foo
382
460
  def path_to(*names)
383
- File.expand_path(File.join(names.map { |name| Symbol === name ? send(name) : name.to_s }), base_dir)
461
+ File.expand_path(layout.expand(*names), base_dir)
384
462
  end
385
463
  alias :_ :path_to
386
464
 
387
465
  # :call-seq:
388
- # define(name, properties?) { |project| ... } => project
466
+ # file(path) => Task
467
+ # file(path=>prereqs) => Task
468
+ # file(path) { |task| ... } => Task
389
469
  #
390
- # Define a new sub-project within this project. See Buildr#define.
391
- def define(name, properties = nil, &block)
392
- Project.define "#{self.name}:#{name}", properties, &block
470
+ # Creates and returns a new file task in the project. Similar to calling Rake's
471
+ # file method, but the path is expanded relative to the project's base directory,
472
+ # and the task executes in the project's base directory.
473
+ #
474
+ # For example:
475
+ # define 'foo' do
476
+ # define 'bar' do
477
+ # file('src') { ... }
478
+ # end
479
+ # end
480
+ #
481
+ # puts project('foo:bar').file('src').to_s
482
+ # => '/home/foo/bar/src'
483
+ def file(*args, &block)
484
+ task_name, arg_names, deps = Buildr.application.resolve_args(args)
485
+ task = Rake::FileTask.define_task(path_to(task_name))
486
+ task.set_arg_names(arg_names) unless arg_names.empty?
487
+ task.enhance Array(deps), &block
488
+ end
489
+
490
+ # :call-seq:
491
+ # task(name) => Task
492
+ # task(name=>prereqs) => Task
493
+ # task(name) { |task| ... } => Task
494
+ #
495
+ # Creates and returns a new task in the project. Similar to calling Rake's task
496
+ # method, but prefixes the task name with the project name and executes the task
497
+ # in the project's base directory.
498
+ #
499
+ # For example:
500
+ # define 'foo' do
501
+ # task 'doda'
502
+ # end
503
+ #
504
+ # puts project('foo').task('doda').name
505
+ # => 'foo:doda'
506
+ #
507
+ # When called from within the project definition, creates a new task if the task
508
+ # does not already exist. If called from outside the project definition, returns
509
+ # the named task and raises an exception if the task is not defined.
510
+ #
511
+ # As with Rake's task method, calling this method enhances the task with the
512
+ # prerequisites and optional block.
513
+ def task(*args, &block)
514
+ task_name, arg_names, deps = Buildr.application.resolve_args(args)
515
+ if task_name =~ /^:/
516
+ Buildr.application.switch_to_namespace [] do
517
+ task = Rake::Task.define_task(task_name[1..-1])
518
+ end
519
+ elsif Buildr.application.current_scope == name.split(':')
520
+ task = Rake::Task.define_task(task_name)
521
+ else
522
+ unless task = Buildr.application.lookup(task_name, name.split(':'))
523
+ raise "You cannot define a project task outside the project definition, and no task #{name}:#{task_name} defined in the project"
524
+ end
525
+ end
526
+ task.set_arg_names(arg_names) unless arg_names.empty?
527
+ task.enhance Array(deps), &block
528
+ end
529
+
530
+ # :call-seq:
531
+ # recursive_task(name=>prereqs) { |task| ... }
532
+ #
533
+ # Define a recursive task. A recursive task executes itself and the same task
534
+ # in all the sub-projects.
535
+ def recursive_task(*args, &block)
536
+ task_name, arg_names, deps = Buildr.application.resolve_args(args)
537
+ task = Buildr.options.parallel ? multitask(task_name) : task(task_name)
538
+ parent.task(task_name).enhance [task] if parent
539
+ task.set_arg_names(arg_names) unless arg_names.empty?
540
+ task.enhance Array(deps), &block
393
541
  end
394
542
 
395
543
  # :call-seq:
@@ -401,8 +549,8 @@ module Buildr
401
549
  #
402
550
  # When called on a project without a name, returns the project itself. You can use that when
403
551
  # setting project properties, for example:
404
- # define "foo" do
405
- # project.version = "1.0"
552
+ # define 'foo' do
553
+ # project.version = '1.0'
406
554
  # end
407
555
  def project(*args)
408
556
  if Hash === args.last
@@ -431,101 +579,186 @@ module Buildr
431
579
  Project.projects *(args + [{ :scope=>self.name }.merge(options)])
432
580
  end
433
581
 
582
+ def inspect #:nodoc:
583
+ %Q{project(#{name.inspect})}
584
+ end
585
+
586
+ protected
587
+
434
588
  # :call-seq:
435
- # file(path) => Task
436
- # file(path=>prereqs) => Task
437
- # file(path) { |task| ... } => Task
438
- #
439
- # Creates and returns a new file task in the project. Similar to calling Rake's
440
- # file method, but the path is expanded relative to the project's base directory,
441
- # and the task executes in the project's base directory.
589
+ # base_dir = dir
442
590
  #
443
- # For example:
444
- # define "foo" do
445
- # define "bar" do
446
- # file("src") { ... }
447
- # end
448
- # end
591
+ # Sets the project's base directory. Allows you to specify a base directory by calling
592
+ # this accessor, or with the :base_dir property when calling #define.
449
593
  #
450
- # puts project("foo:bar").file("src").to_s
451
- # => "/home/foo/bar/src"
452
- def file(args, &block)
453
- task_name, deps = Rake.application.resolve_args(args)
454
- deps = [deps] unless deps.respond_to?(:to_ary)
455
- Rake::FileTask.define_task(path_to(task_name)=>deps, &block)
594
+ # You can only set the base directory once for a given project, and only before accessing
595
+ # the base directory (for example, by calling #file or #path_to).
596
+ # Set the base directory. Note: you can only do this once for a project,
597
+ # and only before accessing the base directory. If you try reading the
598
+ # value with #base_dir, the base directory cannot be set again.
599
+ def base_dir=(dir)
600
+ raise 'Cannot set base directory twice, or after reading its value' if @base_dir
601
+ @base_dir = File.expand_path(dir)
602
+ end
603
+
604
+ # Sets the project layout. Accepts Layout object or class (or for that matter, anything
605
+ # that can expand).
606
+ def layout=(layout)
607
+ raise 'Cannot set directory layout twice, or after reading its value' if @layout
608
+ @layout = layout.is_a?(Class) ? layout.new : layout
456
609
  end
457
610
 
458
611
  # :call-seq:
459
- # task(name) => Task
460
- # task(name=>prereqs) => Task
461
- # task(name) { |task| ... } => Task
462
- #
463
- # Creates and returns a new task in the project. Similar to calling Rake's task
464
- # method, but prefixes the task name with the project name and executes the task
465
- # in the project's base directory.
466
- #
467
- # For example:
468
- # define "foo" do
469
- # task "doda"
470
- # end
471
- #
472
- # puts project("foo").task("doda").name
473
- # => "foo:doda"
474
- #
475
- # When called from within the project definition, creates a new task if the task
476
- # does not already exist. If called from outside the project definition, returns
477
- # the named task and raises an exception if the task is not defined.
612
+ # define(name, properties?) { |project| ... } => project
478
613
  #
479
- # As with Rake's task method, calling this method enhances the task with the
480
- # prerequisites and optional block.
481
- def task(args, &block)
482
- task_name, deps = Rake.application.resolve_args(args)
483
- if task_name =~ /^:/
484
- Rake.application.instance_eval do
485
- scope, @scope = @scope, []
486
- begin
487
- Rake::Task.define_task(task_name[1..-1]=>deps, &block)
488
- ensure
489
- @scope = scope
490
- end
491
- end
492
- elsif Rake.application.current_scope == name.split(":")
493
- Rake::Task.define_task(task_name=>deps, &block)
494
- else
495
- if task = Rake.application.lookup(task_name, name.split(":"))
496
- deps = [deps] unless deps.respond_to?(:to_ary)
497
- task.enhance deps, &block
498
- else
499
- full_name = "#{name}:#{task_name}"
500
- raise "You cannot define a project task outside the project definition, and no task #{full_name} defined in the project"
501
- end
614
+ # Define a new sub-project within this project. See Buildr#define.
615
+ def define(name, properties = nil, &block)
616
+ Project.define "#{self.name}:#{name}", properties, &block
617
+ end
618
+
619
+ def execute(args) #:nodoc:
620
+ Buildr.application.switch_to_namespace name.split(':') do
621
+ super
502
622
  end
503
623
  end
504
624
 
505
- # :call-seq:
506
- # recursive_task(name=>prereqs) { |task| ... }
507
- #
508
- # Define a recursive task. A recursive task executes itself and the same task
509
- # in all the sub-projects.
510
- def recursive_task(args, &block)
511
- task_name, deps = Rake.application.resolve_args(args)
512
- deps = [deps] unless deps.respond_to?(:to_ary)
513
- task = Buildr.options.parallel ? multitask(task_name) : task(task_name)
514
- parent.task(task_name).enhance [task] if parent
515
- task.enhance deps, &block
625
+ # Call all callbacks for a particular state, e.g. :before_define, :after_define.
626
+ def call_callbacks(state) #:nodoc:
627
+ methods = @callbacks.delete(state) || []
628
+ methods.each { |method| method.call(project) }
516
629
  end
517
630
 
518
- def execute() #:nodoc:
519
- # Reset the namespace, so all tasks are automatically defined in the project's namespace.
520
- Rake.application.in_namespace(":#{name}") { super }
631
+ def add_callback(callback)
632
+ @callbacks[:after_define] << callback.method(:after_define) if callback.respond_to?(:after_define)
521
633
  end
522
634
 
523
- def inspect() #:nodoc:
524
- %Q{project(#{name.inspect})}
635
+ end
636
+
637
+
638
+ # The basic mechanism for extending projects in Buildr are Ruby modules. In fact,
639
+ # base features like compiling and testing are all developed in the form of modules,
640
+ # and then added to the core Project class.
641
+ #
642
+ # A module defines instance methods that are then mixed into the project and become
643
+ # instance methods of the project. There are two general ways for extending projects.
644
+ # You can extend all projects by including the module in Project:
645
+ # class Project
646
+ # include MyExtension
647
+ # end
648
+ # You can also extend a given project instance and only that instance by extending
649
+ # it with the module:
650
+ # define 'foo' do
651
+ # extend MyExtension
652
+ # end
653
+ #
654
+ # Some extensions require tighter integration with the project, specifically for
655
+ # setting up tasks and properties, or for configuring tasks based on the project
656
+ # definition. You can do that by adding callbacks to the process.
657
+ #
658
+ # The easiest way to add callbacks is by incorporating the Extension module in your
659
+ # own extension, and using the various class methods to define callback behavior:
660
+ # * first_time -- This block will be called once for any particular extension.
661
+ # You can use this to setup top-level and local tasks.
662
+ # * before_define -- This block is called once for the project with the project
663
+ # instance, right before running the project definition. You can use this
664
+ # to add tasks and set properties that will be used in the project definition.
665
+ # * after_define -- This block is called once for the project with the project
666
+ # instance, right after running the project definition. You can use this to
667
+ # do any post-processing that depends on the project definition.
668
+ #
669
+ # This example illustrates how to write a simple extension:
670
+ # module LinesOfCode
671
+ # include Extension
672
+ #
673
+ # first_time do
674
+ # # Define task not specific to any projet.
675
+ # desc 'Count lines of code in current project'
676
+ # Project.local_task('loc')
677
+ # end
678
+ #
679
+ # before_define do |project|
680
+ # # Define the loc task for this particular project.
681
+ # Rake::Task.define_task 'loc' do |task|
682
+ # lines = task.prerequisites.map { |path| Dir['#{path}/**/*'] }.flatten.uniq.
683
+ # inject(0) { |total, file| total + File.readlines(file).count }
684
+ # puts "Project #{project.name} has #{lines} lines of code"
685
+ # end
686
+ # end
687
+ #
688
+ # after_define do |project|
689
+ # # Now that we know all the source directories, add them.
690
+ # task('loc'=>compile.sources + compile.test.sources)
691
+ # end
692
+ #
693
+ # # To use this method in your project:
694
+ # # loc path_1, path_2
695
+ # def loc(*paths)
696
+ # task('loc'=>paths)
697
+ # end
698
+ #
699
+ # end
700
+ #
701
+ # class Buildr::Project
702
+ # include LinesOfCode
703
+ # end
704
+ module Extension
705
+
706
+ def self.included(base) #:nodoc:
707
+ base.extend ClassMethods
708
+ end
709
+
710
+ # Methods added to the extension module when including Extension.
711
+ module ClassMethods
712
+
713
+ def included(base) #:nodoc:
714
+ # When included in Project, add callback and call first_time.
715
+ if Project == base && !base.callbacks.include?(callbacks)
716
+ base.callbacks << callbacks
717
+ callbacks.first_time if callbacks.respond_to?(:first_time)
718
+ end
719
+ end
720
+
721
+ def extended(base) #:nodoc:
722
+ # When extending project, add instance and call before_define.
723
+ if Project === base
724
+ callbacks = self.send(:callbacks).new
725
+ callbacks.before_define(base) if callbacks.respond_to?(:before_define)
726
+ base.send :add_callback, callbacks
727
+ end
728
+ end
729
+
730
+ # This block will be called once for any particular extension.
731
+ # You can use this to setup top-level and local tasks.
732
+ def first_time(&block)
733
+ meta = class << callbacks ; self ; end
734
+ meta.send :define_method, :first_time, &block
735
+ end
736
+
737
+ # This block is called once for the project with the project instance,
738
+ # right before running the project definition. You can use this to add
739
+ # tasks and set properties that will be used in the project definition.
740
+ def before_define(&block)
741
+ callbacks.send :define_method, :before_define, &block
742
+ end
743
+
744
+ # This block is called once for the project with the project instance,
745
+ # right after running the project definition. You can use this to do
746
+ # any post-processing that depends on the project definition.
747
+ def after_define(&block)
748
+ callbacks.send :define_method, :after_define, &block
749
+ end
750
+
751
+ private
752
+
753
+ def callbacks
754
+ const_get('Callbacks') rescue const_set('Callbacks', Class.new)
755
+ end
756
+
525
757
  end
526
758
 
527
759
  end
528
760
 
761
+
529
762
  # :call-seq:
530
763
  # define(name, properties?) { |project| ... } => project
531
764
  #
@@ -547,17 +780,17 @@ module Buildr
547
780
  # related to the project.
548
781
  #
549
782
  # For example:
550
- # define "foo", :version=>"1.0" do
783
+ # define 'foo', :version=>'1.0' do
551
784
  #
552
- # define "bar" do
553
- # compile.with "org.apache.axis2:axis2:jar:1.1"
785
+ # define 'bar' do
786
+ # compile.with 'org.apache.axis2:axis2:jar:1.1'
554
787
  # end
555
788
  # end
556
789
  #
557
- # puts project("foo").version
558
- # => "1.0"
559
- # puts project("foo:bar").compile.classpath.map(&:to_spec)
560
- # => "org.apache.axis2:axis2:jar:1.1"
790
+ # puts project('foo').version
791
+ # => '1.0'
792
+ # puts project('foo:bar').compile.classpath.map(&:to_spec)
793
+ # => 'org.apache.axis2:axis2:jar:1.1'
561
794
  # % buildr build
562
795
  # => Compiling 14 source files in foo:bar
563
796
  def define(name, properties = nil, &block) #:yields:project
@@ -570,9 +803,9 @@ module Buildr
570
803
  # Returns a project definition.
571
804
  #
572
805
  # When called from outside a project definition, must reference the project by its
573
- # full name, e.g. "foo:bar" to access the sub-project "bar" in "foo". When called
574
- # from inside a project, relative names are sufficient, e.g. <code>project("foo").project("bar")</code>
575
- # will find the sub-project "bar" in "foo".
806
+ # full name, e.g. 'foo:bar' to access the sub-project 'bar' in 'foo'. When called
807
+ # from inside a project, relative names are sufficient, e.g. <code>project('foo').project('bar')</code>
808
+ # will find the sub-project 'bar' in 'foo'.
576
809
  #
577
810
  # You cannot reference a project before the project is defined. When working with
578
811
  # sub-projects, the project definition is stored by calling #define, and evaluated
@@ -584,21 +817,21 @@ module Buildr
584
817
  # or packages created by that project).
585
818
  #
586
819
  # For example:
587
- # define "myapp" do
588
- # self.version = "1.1"
820
+ # define 'myapp' do
821
+ # self.version = '1.1'
589
822
  #
590
- # define "webapp" do
823
+ # define 'webapp' do
591
824
  # # webapp is defined first, but beans is evaluated first
592
- # compile.with project("beans")
825
+ # compile.with project('beans')
593
826
  # package :war
594
827
  # end
595
828
  #
596
- # define "beans" do
829
+ # define 'beans' do
597
830
  # package :jar
598
831
  # end
599
832
  # end
600
833
  #
601
- # puts project("myapp:beans").version
834
+ # puts project('myapp:beans').version
602
835
  def project(*args)
603
836
  Project.project *args
604
837
  end
@@ -616,20 +849,42 @@ module Buildr
616
849
  # Be advised of circular dependencies.
617
850
  #
618
851
  # For example:
619
- # files = projects.map { |prj| FileList[prj.path_to("src/**/*.java") }.flatten
852
+ # files = projects.map { |prj| FileList[prj.path_to('src/**/*.java') }.flatten
620
853
  # puts "There are #{files.size} source files in #{projects.size} projects"
621
854
  #
622
- # puts projects("myapp:beans", "myapp:webapp").map(&:name)
855
+ # puts projects('myapp:beans', 'myapp:webapp').map(&:name)
623
856
  # Same as:
624
- # puts project("myapp").projects.map(&:name)
857
+ # puts project('myapp').projects.map(&:name)
625
858
  def projects(*args)
626
859
  Project.projects *args
627
860
  end
628
861
 
629
862
  # Forces all the projects to be evaluated before executing any other task.
630
863
  # If we don't do that, we don't get to have tasks available when running Rake.
631
- task "buildr:initialize" do
632
- projects
864
+ namespace 'buildr' do
865
+ task 'initialize' do
866
+ projects
867
+ end
868
+
869
+ desc "Freezes the Buildfile so it always uses Buildr version #{Buildr::VERSION}"
870
+ task 'freeze' do
871
+ puts "Freezing the Buildfile so it always uses Buildr version #{Buildr::VERSION}"
872
+ original = File.read(Buildr.application.buildfile)
873
+ if original =~ /gem\s*(["'])buildr\1/
874
+ modified = original.sub(/gem\s*(["'])buildr\1\s*,\s*(["']).*\2/, %{gem "buildr", "#{Buildr::VERSION}"})
875
+ else
876
+ modified = %{gem "buildr", "#{Buildr::VERSION}"\n} + original
877
+ end
878
+ File.open(Buildr.application.buildfile, "w") { |file| file.write modified }
879
+ end
880
+
881
+ desc 'Unfreezes the Buildfile to use the latest version of Buildr'
882
+ task 'unfreeze' do
883
+ puts 'Unfreezing the Buildfile to use the latest version of Buildr from your Gems repository.'
884
+ modified = File.read(Buildr.application.buildfile).sub(/^\s*gem\s*(["'])buildr\1.*\n/, "")
885
+ File.open(Buildr.application.buildfile, "w") { |file| file.write modified }
886
+ end
633
887
  end
634
888
 
889
+
635
890
  end