buildr 1.2.10 → 1.3.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.
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