assaf-buildr 1.3.3

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 (163) hide show
  1. data/CHANGELOG +887 -0
  2. data/DISCLAIMER +7 -0
  3. data/LICENSE +176 -0
  4. data/NOTICE +26 -0
  5. data/README.rdoc +146 -0
  6. data/Rakefile +62 -0
  7. data/_buildr +38 -0
  8. data/addon/buildr/antlr.rb +65 -0
  9. data/addon/buildr/cobertura.rb +236 -0
  10. data/addon/buildr/emma.rb +238 -0
  11. data/addon/buildr/hibernate.rb +142 -0
  12. data/addon/buildr/javacc.rb +85 -0
  13. data/addon/buildr/jdepend.rb +60 -0
  14. data/addon/buildr/jetty.rb +248 -0
  15. data/addon/buildr/jibx.rb +86 -0
  16. data/addon/buildr/nailgun.rb +817 -0
  17. data/addon/buildr/openjpa.rb +90 -0
  18. data/addon/buildr/org/apache/buildr/BuildrNail$Main.class +0 -0
  19. data/addon/buildr/org/apache/buildr/BuildrNail.class +0 -0
  20. data/addon/buildr/org/apache/buildr/BuildrNail.java +41 -0
  21. data/addon/buildr/org/apache/buildr/JettyWrapper$1.class +0 -0
  22. data/addon/buildr/org/apache/buildr/JettyWrapper$BuildrHandler.class +0 -0
  23. data/addon/buildr/org/apache/buildr/JettyWrapper.class +0 -0
  24. data/addon/buildr/org/apache/buildr/JettyWrapper.java +144 -0
  25. data/addon/buildr/xmlbeans.rb +93 -0
  26. data/bin/buildr +28 -0
  27. data/buildr.buildfile +53 -0
  28. data/buildr.gemspec +58 -0
  29. data/doc/css/default.css +228 -0
  30. data/doc/css/print.css +100 -0
  31. data/doc/css/syntax.css +52 -0
  32. data/doc/images/apache-incubator-logo.png +0 -0
  33. data/doc/images/buildr-hires.png +0 -0
  34. data/doc/images/buildr.png +0 -0
  35. data/doc/images/favicon.png +0 -0
  36. data/doc/images/growl-icon.tiff +0 -0
  37. data/doc/images/note.png +0 -0
  38. data/doc/images/project-structure.png +0 -0
  39. data/doc/images/tip.png +0 -0
  40. data/doc/images/zbuildr.tif +0 -0
  41. data/doc/pages/artifacts.textile +207 -0
  42. data/doc/pages/building.textile +240 -0
  43. data/doc/pages/contributing.textile +208 -0
  44. data/doc/pages/download.textile +62 -0
  45. data/doc/pages/extending.textile +175 -0
  46. data/doc/pages/getting_started.textile +273 -0
  47. data/doc/pages/index.textile +42 -0
  48. data/doc/pages/languages.textile +407 -0
  49. data/doc/pages/mailing_lists.textile +17 -0
  50. data/doc/pages/more_stuff.textile +286 -0
  51. data/doc/pages/packaging.textile +427 -0
  52. data/doc/pages/projects.textile +274 -0
  53. data/doc/pages/recipes.textile +103 -0
  54. data/doc/pages/settings_profiles.textile +274 -0
  55. data/doc/pages/testing.textile +212 -0
  56. data/doc/pages/troubleshooting.textile +103 -0
  57. data/doc/pages/whats_new.textile +323 -0
  58. data/doc/print.haml +51 -0
  59. data/doc/print.toc.yaml +29 -0
  60. data/doc/scripts/buildr-git.rb +412 -0
  61. data/doc/scripts/install-jruby.sh +44 -0
  62. data/doc/scripts/install-linux.sh +64 -0
  63. data/doc/scripts/install-osx.sh +52 -0
  64. data/doc/site.haml +56 -0
  65. data/doc/site.toc.yaml +47 -0
  66. data/etc/KEYS +151 -0
  67. data/etc/git-svn-authors +16 -0
  68. data/lib/buildr.rb +35 -0
  69. data/lib/buildr/core.rb +27 -0
  70. data/lib/buildr/core/application.rb +489 -0
  71. data/lib/buildr/core/application_cli.rb +139 -0
  72. data/lib/buildr/core/build.rb +311 -0
  73. data/lib/buildr/core/checks.rb +382 -0
  74. data/lib/buildr/core/common.rb +154 -0
  75. data/lib/buildr/core/compile.rb +596 -0
  76. data/lib/buildr/core/environment.rb +120 -0
  77. data/lib/buildr/core/filter.rb +362 -0
  78. data/lib/buildr/core/generate.rb +195 -0
  79. data/lib/buildr/core/help.rb +118 -0
  80. data/lib/buildr/core/progressbar.rb +156 -0
  81. data/lib/buildr/core/project.rb +892 -0
  82. data/lib/buildr/core/test.rb +715 -0
  83. data/lib/buildr/core/transports.rb +558 -0
  84. data/lib/buildr/core/util.rb +289 -0
  85. data/lib/buildr/groovy.rb +18 -0
  86. data/lib/buildr/groovy/bdd.rb +105 -0
  87. data/lib/buildr/groovy/compiler.rb +138 -0
  88. data/lib/buildr/ide.rb +19 -0
  89. data/lib/buildr/ide/eclipse.rb +212 -0
  90. data/lib/buildr/ide/idea.ipr.template +300 -0
  91. data/lib/buildr/ide/idea.rb +189 -0
  92. data/lib/buildr/ide/idea7x.ipr.template +290 -0
  93. data/lib/buildr/ide/idea7x.rb +210 -0
  94. data/lib/buildr/java.rb +23 -0
  95. data/lib/buildr/java/ant.rb +92 -0
  96. data/lib/buildr/java/bdd.rb +449 -0
  97. data/lib/buildr/java/commands.rb +211 -0
  98. data/lib/buildr/java/compiler.rb +348 -0
  99. data/lib/buildr/java/deprecated.rb +141 -0
  100. data/lib/buildr/java/jruby.rb +117 -0
  101. data/lib/buildr/java/jtestr_runner.rb.erb +116 -0
  102. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.class +0 -0
  103. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.java +119 -0
  104. data/lib/buildr/java/packaging.rb +713 -0
  105. data/lib/buildr/java/pom.rb +178 -0
  106. data/lib/buildr/java/rjb.rb +155 -0
  107. data/lib/buildr/java/test_result.rb +308 -0
  108. data/lib/buildr/java/tests.rb +324 -0
  109. data/lib/buildr/java/version_requirement.rb +172 -0
  110. data/lib/buildr/packaging.rb +21 -0
  111. data/lib/buildr/packaging/artifact.rb +730 -0
  112. data/lib/buildr/packaging/artifact_namespace.rb +972 -0
  113. data/lib/buildr/packaging/artifact_search.rb +140 -0
  114. data/lib/buildr/packaging/gems.rb +102 -0
  115. data/lib/buildr/packaging/package.rb +233 -0
  116. data/lib/buildr/packaging/tar.rb +104 -0
  117. data/lib/buildr/packaging/zip.rb +722 -0
  118. data/lib/buildr/resources/buildr.icns +0 -0
  119. data/lib/buildr/scala.rb +19 -0
  120. data/lib/buildr/scala/compiler.rb +109 -0
  121. data/lib/buildr/scala/tests.rb +203 -0
  122. data/rakelib/apache.rake +191 -0
  123. data/rakelib/changelog.rake +57 -0
  124. data/rakelib/doc.rake +103 -0
  125. data/rakelib/package.rake +73 -0
  126. data/rakelib/release.rake +65 -0
  127. data/rakelib/rspec.rake +83 -0
  128. data/rakelib/rubyforge.rake +53 -0
  129. data/rakelib/scm.rake +49 -0
  130. data/rakelib/setup.rake +86 -0
  131. data/rakelib/stage.rake +48 -0
  132. data/spec/addon/cobertura_spec.rb +77 -0
  133. data/spec/addon/emma_spec.rb +120 -0
  134. data/spec/addon/test_coverage_spec.rb +255 -0
  135. data/spec/core/application_spec.rb +412 -0
  136. data/spec/core/artifact_namespace_spec.rb +646 -0
  137. data/spec/core/build_spec.rb +415 -0
  138. data/spec/core/checks_spec.rb +537 -0
  139. data/spec/core/common_spec.rb +664 -0
  140. data/spec/core/compile_spec.rb +566 -0
  141. data/spec/core/generate_spec.rb +33 -0
  142. data/spec/core/project_spec.rb +754 -0
  143. data/spec/core/test_spec.rb +1091 -0
  144. data/spec/core/transport_spec.rb +500 -0
  145. data/spec/groovy/bdd_spec.rb +80 -0
  146. data/spec/groovy/compiler_spec.rb +239 -0
  147. data/spec/ide/eclipse_spec.rb +243 -0
  148. data/spec/java/ant.rb +28 -0
  149. data/spec/java/bdd_spec.rb +358 -0
  150. data/spec/java/compiler_spec.rb +446 -0
  151. data/spec/java/java_spec.rb +88 -0
  152. data/spec/java/packaging_spec.rb +1103 -0
  153. data/spec/java/tests_spec.rb +466 -0
  154. data/spec/packaging/archive_spec.rb +503 -0
  155. data/spec/packaging/artifact_spec.rb +754 -0
  156. data/spec/packaging/packaging_helper.rb +63 -0
  157. data/spec/packaging/packaging_spec.rb +589 -0
  158. data/spec/sandbox.rb +137 -0
  159. data/spec/scala/compiler_spec.rb +228 -0
  160. data/spec/scala/tests_spec.rb +215 -0
  161. data/spec/spec_helpers.rb +304 -0
  162. data/spec/version_requirement_spec.rb +123 -0
  163. metadata +369 -0
@@ -0,0 +1,139 @@
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
+ # Portion of this file derived from Rake.
17
+ # Copyright (c) 2003, 2004 Jim Weirich
18
+ #
19
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
20
+ # of this software and associated documentation files (the "Software"), to deal
21
+ # in the Software without restriction, including without limitation the rights
22
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23
+ # copies of the Software, and to permit persons to whom the Software is
24
+ # furnished to do so, subject to the following conditions:
25
+ #
26
+ # The above copyright notice and this permission notice shall be included in
27
+ # all copies or substantial portions of the Software.
28
+ #
29
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35
+ # SOFTWARE.
36
+
37
+
38
+ require 'getoptlong'
39
+
40
+
41
+ module Buildr
42
+ module CommandLineInterface
43
+
44
+ OPTIONS = [ # :nodoc:
45
+ ['--help', '-h', GetoptLong::NO_ARGUMENT,
46
+ 'Display this help message.'],
47
+ ['--nosearch', '-n', GetoptLong::NO_ARGUMENT,
48
+ 'Do not search parent directories for the buildfile.'],
49
+ ['--quiet', '-q', GetoptLong::NO_ARGUMENT,
50
+ 'Do not log messages to standard output.'],
51
+ ['--buildfile', '-f', GetoptLong::REQUIRED_ARGUMENT,
52
+ 'Use FILE as the buildfile.'],
53
+ ['--require', '-r', GetoptLong::REQUIRED_ARGUMENT,
54
+ 'Require MODULE before executing buildfile.'],
55
+ ['--trace', '-t', GetoptLong::NO_ARGUMENT,
56
+ 'Turn on invoke/execute tracing, enable full backtrace.'],
57
+ ['--prereqs', '-P', GetoptLong::OPTIONAL_ARGUMENT,
58
+ 'Display tasks and dependencies, then exit.'],
59
+ ['--version', '-v', GetoptLong::NO_ARGUMENT,
60
+ 'Display the program version.'],
61
+ ['--environment', '-e', GetoptLong::REQUIRED_ARGUMENT,
62
+ 'Environment name (e.g. development, test, production).']
63
+ ]
64
+
65
+ def collect_tasks
66
+ top_level_tasks.clear
67
+ ARGV.each do |arg|
68
+ if arg =~ /^(\w+)=(.*)$/
69
+ ENV[$1.upcase] = $2
70
+ else
71
+ top_level_tasks << arg
72
+ end
73
+ end
74
+ top_level_tasks.push("default") if top_level_tasks.size == 0
75
+ end
76
+
77
+ def parse_options
78
+ opts = GetoptLong.new(*command_line_options)
79
+ opts.each { |opt, value| do_option(opt, value) }
80
+ end
81
+
82
+ def do_option(opt, value)
83
+ case opt
84
+ when '--help'
85
+ help
86
+ exit
87
+ when '--buildfile'
88
+ rakefiles.clear
89
+ rakefiles << value
90
+ when '--version'
91
+ puts version
92
+ exit
93
+ when '--environment'
94
+ ENV['BUILDR_ENV'] = value
95
+ when '--require'
96
+ requires << value
97
+ when '--prereqs'
98
+ options.show_prereqs = true
99
+ options.show_task_pattern = Regexp.new(value || '.')
100
+ when '--nosearch', '--quiet', '--trace'
101
+ super
102
+ end
103
+ end
104
+
105
+ def command_line_options
106
+ OPTIONS.collect { |lst| lst[0..-2] }
107
+ end
108
+
109
+ def version
110
+ "Buildr #{Buildr::VERSION} #{RUBY_PLATFORM[/java/] && '(JRuby '+JRUBY_VERSION+')'}"
111
+ end
112
+
113
+ def usage
114
+ puts version
115
+ puts
116
+ puts 'Usage:'
117
+ puts ' buildr [options] [tasks] [name=value]'
118
+ end
119
+
120
+ def help
121
+ usage
122
+ puts
123
+ puts 'Options:'
124
+ OPTIONS.sort.each do |long, short, mode, desc|
125
+ if mode == GetoptLong::REQUIRED_ARGUMENT
126
+ if desc =~ /\b([A-Z]{2,})\b/
127
+ long = long + "=#{$1}"
128
+ end
129
+ end
130
+ printf " %-20s (%s)\n", long, short
131
+ printf " %s\n", desc
132
+ end
133
+ puts
134
+ puts 'For help with your buildfile:'
135
+ puts ' buildr help'
136
+ end
137
+
138
+ end
139
+ end
@@ -0,0 +1,311 @@
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/project'
18
+ require 'buildr/core/common'
19
+ require 'buildr/core/checks'
20
+ require 'buildr/core/environment'
21
+
22
+
23
+ module Buildr
24
+
25
+ class Options
26
+
27
+ # Runs the build in parallel when true (defaults to false). You can force a parallel build by
28
+ # setting this option directly, or by running the parallel task ahead of the build task.
29
+ #
30
+ # This option only affects recursive tasks. For example:
31
+ # buildr parallel package
32
+ # will run all package tasks (from the sub-projects) in parallel, but each sub-project's package
33
+ # task runs its child tasks (prepare, compile, resources, etc) in sequence.
34
+ attr_accessor :parallel
35
+
36
+ end
37
+
38
+ task('parallel') { Buildr.options.parallel = true }
39
+
40
+
41
+ module Build
42
+
43
+ include Extension
44
+
45
+ first_time do
46
+ desc 'Build the project'
47
+ Project.local_task('build') { |name| "Building #{name}" }
48
+ desc 'Clean files generated during a build'
49
+ Project.local_task('clean') { |name| "Cleaning #{name}" }
50
+
51
+ desc 'The default task is build'
52
+ task 'default'=>'build'
53
+ end
54
+
55
+ before_define do |project|
56
+ project.recursive_task 'build'
57
+ project.recursive_task 'clean'
58
+ project.clean do
59
+ verbose(true) do
60
+ rm_rf project.path_to(:target)
61
+ rm_rf project.path_to(:reports)
62
+ end
63
+ end
64
+ end
65
+
66
+
67
+ # *Deprecated:* Use +path_to(:target)+ instead.
68
+ def target
69
+ Buildr.application.deprecated 'Use path_to(:target) instead'
70
+ layout.expand(:target)
71
+ end
72
+
73
+ # *Deprecated:* Use Layout instead.
74
+ def target=(dir)
75
+ Buildr.application.deprecated 'Use Layout instead'
76
+ layout[:target] = _(dir)
77
+ end
78
+
79
+ # *Deprecated:* Use +path_to(:reports)+ instead.
80
+ def reports()
81
+ Buildr.application.deprecated 'Use path_to(:reports) instead'
82
+ layout.expand(:reports)
83
+ end
84
+
85
+ # *Deprecated:* Use Layout instead.
86
+ def reports=(dir)
87
+ Buildr.application.deprecated 'Use Layout instead'
88
+ layout[:reports] = _(dir)
89
+ end
90
+
91
+ # :call-seq:
92
+ # build(*prereqs) => task
93
+ # build { |task| .. } => task
94
+ #
95
+ # Returns the project's build task. With arguments or block, also enhances that task.
96
+ def build(*prereqs, &block)
97
+ task('build').enhance prereqs, &block
98
+ end
99
+
100
+ # :call-seq:
101
+ # clean(*prereqs) => task
102
+ # clean { |task| .. } => task
103
+ #
104
+ # Returns the project's clean task. With arguments or block, also enhances that task.
105
+ def clean(*prereqs, &block)
106
+ task('clean').enhance prereqs, &block
107
+ end
108
+
109
+ end
110
+
111
+
112
+ class Svn
113
+
114
+ class << self
115
+ def commit(file, message)
116
+ svn 'commit', '-m', message, file
117
+ end
118
+
119
+ def copy(dir, url, message)
120
+ svn 'copy', dir, url, '-m', message
121
+ end
122
+
123
+ # Return the current SVN URL
124
+ def repo_url
125
+ svn('info').scan(/URL: (.*)/)[0][0]
126
+ end
127
+
128
+ def remove(url, message)
129
+ svn 'remove', url, '-m', message
130
+ end
131
+
132
+ # Status check reveals modified files, but also SVN externals which we can safely ignore.
133
+ def uncommitted_files
134
+ svn('status', '--ignore-externals').reject { |line| line =~ /^X\s/ }
135
+ end
136
+
137
+ # :call-seq:
138
+ # svn(*args)
139
+ #
140
+ # Executes SVN command and returns the output.
141
+ def svn(*args)
142
+ cmd = 'svn ' + args.map { |arg| arg[' '] ? %Q{"#{arg}"} : arg }.join(' ')
143
+ trace cmd
144
+ `#{cmd}`.tap { fail 'SVN command failed' unless $?.exitstatus == 0 }
145
+ end
146
+ end
147
+ end
148
+
149
+
150
+ class Release
151
+
152
+ THIS_VERSION_PATTERN = /(THIS_VERSION|VERSION_NUMBER)\s*=\s*(["'])(.*)\2/
153
+
154
+ class << self
155
+
156
+ # Use this to specify a different tag name for tagging the release in source control.
157
+ # You can set the tag name or a proc that will be called with the version number,
158
+ # for example:
159
+ # Release.tag_name = lambda { |ver| "foo-#{ver}" }
160
+ attr_accessor :tag_name
161
+
162
+ # :call-seq:
163
+ # make()
164
+ #
165
+ # Make a release.
166
+ def make
167
+ check
168
+ with_release_candidate_version do |release_candidate_buildfile|
169
+ options = ['--buildfile', release_candidate_buildfile, 'DEBUG=no']
170
+ options << '--environment' << Buildr.environment unless Buildr.environment.to_s.empty?
171
+ buildr %w{clean upload}, options
172
+ end
173
+ tag_release
174
+ commit_new_snapshot
175
+ end
176
+
177
+ # :call-seq:
178
+ # extract_version() => this_version
179
+ #
180
+ # Extract the current version number from the buildfile.
181
+ # Raise an error if not found.
182
+ def extract_version
183
+ buildfile = File.read(Buildr.application.buildfile.to_s)
184
+ buildfile.scan(THIS_VERSION_PATTERN)[0][2]
185
+ rescue
186
+ fail 'Looking for THIS_VERSION = "..." in your Buildfile, none found'
187
+ end
188
+
189
+ # :call-seq:
190
+ # tag_url(svn_url, version) => tag_url
191
+ #
192
+ # Returns the SVN url for the tag.
193
+ # Can tag from the trunk or from branches.
194
+ # Can handle the two standard repository layouts.
195
+ # - http://my.repo/foo/trunk => http://my.repo/foo/tags/1.0.0
196
+ # - http://my.repo/trunk/foo => http://my.repo/tags/foo/1.0.0
197
+ def tag_url(svn_url, version)
198
+ trunk_or_branches = Regexp.union(%r{^(.*)/trunk(.*)$}, %r{^(.*)/branches(.*)/([^/]*)$})
199
+ match = trunk_or_branches.match(svn_url)
200
+ prefix = match[1] || match[3]
201
+ suffix = match[2] || match[4]
202
+ tag = tag_name || version
203
+ tag = tag.call(version) if Proc === tag
204
+ prefix + '/tags' + suffix + '/' + tag
205
+ end
206
+
207
+ # :call-seq:
208
+ # check()
209
+ #
210
+ # Check that we don't have any local changes in the working copy. Fails if it finds anything
211
+ # in the working copy that is not checked into source control.
212
+ def check
213
+ fail "SVN URL must contain 'trunk' or 'branches/...'" unless Svn.repo_url =~ /(trunk)|(branches.*)$/
214
+ fail "Uncommitted SVN files violate the First Principle Of Release!\n#{Svn.uncommitted_files}" unless Svn.uncommitted_files.empty?
215
+ end
216
+
217
+ protected
218
+
219
+ # :call-seq:
220
+ # buildr(tasks, options)
221
+ #
222
+ # Calls another instance of buildr.
223
+ def buildr(tasks, options)
224
+ sh "#{command} _#{Buildr::VERSION}_ #{tasks.join(' ')} #{options.join(' ')}"
225
+ end
226
+
227
+ def command #:nodoc:
228
+ Config::CONFIG['arch'] =~ /dos|win32/i ? $PROGRAM_NAME.ext('cmd') : $PROGRAM_NAME
229
+ end
230
+
231
+ # :call-seq:
232
+ # with_release_candidate_version() { |filename| ... }
233
+ #
234
+ # Yields to block with release candidate buildfile, before committing to use it.
235
+ #
236
+ # We need a Buildfile with upgraded version numbers to run the build, but we don't want the
237
+ # Buildfile modified unless the build succeeds. So this method updates the version number in
238
+ # a separate (Buildfile.next) file, yields to the block with that filename, and if successful
239
+ # copies the new file over the existing one.
240
+ #
241
+ # The release version is the current version without '-SNAPSHOT'. So:
242
+ # THIS_VERSION = 1.1.0-SNAPSHOT
243
+ # becomes:
244
+ # THIS_VERSION = 1.1.0
245
+ # for the release buildfile.
246
+ def with_release_candidate_version
247
+ release_candidate_buildfile = Buildr.application.buildfile.to_s + '.next'
248
+ release_candidate_buildfile_contents = change_version { |version| version[-1] = version[-1].to_i }
249
+ File.open(release_candidate_buildfile, 'w') { |file| file.write release_candidate_buildfile_contents }
250
+ begin
251
+ yield release_candidate_buildfile
252
+ mv release_candidate_buildfile, Buildr.application.buildfile.to_s
253
+ ensure
254
+ rm release_candidate_buildfile rescue nil
255
+ end
256
+ end
257
+
258
+ # :call-seq:
259
+ # change_version() { |this_version| ... } => buildfile
260
+ #
261
+ # Change version number in the current Buildfile, but without writing a new file (yet).
262
+ # Returns the contents of the Buildfile with the modified version number.
263
+ #
264
+ # This method yields to the block with the current (this) version number as an array and expects
265
+ # the block to update it.
266
+ def change_version
267
+ this_version = extract_version
268
+ new_version = this_version.split('.')
269
+ yield(new_version)
270
+ new_version = new_version.join('.')
271
+ buildfile = File.read(Buildr.application.buildfile.to_s)
272
+ buildfile.gsub(THIS_VERSION_PATTERN) { |ver| ver.sub(/(["']).*\1/, %Q{"#{new_version}"}) }
273
+ end
274
+
275
+ # :call-seq:
276
+ # tag_release()
277
+ #
278
+ # Tags the current working copy with the release version number.
279
+ def tag_release
280
+ version = extract_version
281
+ info "Tagging release #{version}"
282
+ url = tag_url Svn.repo_url, version
283
+ Svn.remove url, 'Removing old copy' rescue nil
284
+ Svn.copy Dir.pwd, url, "Release #{version}"
285
+ end
286
+
287
+ # :call-seq:
288
+ # commit_new_snapshot()
289
+ #
290
+ # Last, we commit what we currently have in the working copy with an upgraded version number.
291
+ def commit_new_snapshot
292
+ buildfile = change_version { |version| version[-1] = (version[-1].to_i + 1).to_s + '-SNAPSHOT' }
293
+ File.open(Buildr.application.buildfile.to_s, 'w') { |file| file.write buildfile }
294
+ Svn.commit Buildr.application.buildfile.to_s, "Changed version number to #{extract_version}"
295
+ info "Current version is now #{extract_version}"
296
+ end
297
+ end
298
+ end
299
+
300
+
301
+ desc 'Make a release'
302
+ task 'release' do |task|
303
+ Release.make
304
+ end
305
+
306
+ end
307
+
308
+
309
+ class Buildr::Project
310
+ include Buildr::Build
311
+ end
@@ -0,0 +1,382 @@
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/project'
18
+ require 'buildr/packaging/zip'
19
+ #require 'test/unit'
20
+ require 'spec/matchers'
21
+ require 'spec/expectations'
22
+
23
+
24
+ module Buildr
25
+ # Methods added to Project to allow checking the build.
26
+ module Checks
27
+
28
+ module Matchers #:nodoc:
29
+
30
+ class << self
31
+
32
+ # Define matchers that operate by calling a method on the tested object.
33
+ # For example:
34
+ # foo.should contain(bar)
35
+ # calls:
36
+ # foo.contain(bar)
37
+ def match_using(*names)
38
+ names.each do |name|
39
+ matcher = Class.new do
40
+ # Initialize with expected arguments (i.e. contain(bar) initializes with bar).
41
+ define_method(:initialize) { |*args| @expects = args }
42
+ # Matches against actual value (i.e. foo.should exist called with foo).
43
+ define_method(:matches?) do |actual|
44
+ @actual = actual
45
+ return actual.send("#{name}?", *@expects) if actual.respond_to?("#{name}?")
46
+ return actual.send(name, *@expects) if actual.respond_to?(name)
47
+ raise "You can't check #{actual}, it doesn't respond to #{name}."
48
+ end
49
+ # Some matchers have arguments, others don't, treat appropriately.
50
+ define_method :failure_message do
51
+ args = " " + @expects.map{ |arg| "'#{arg}'" }.join(", ") unless @expects.empty?
52
+ "Expected #{@actual} to #{name}#{args}"
53
+ end
54
+ define_method :negative_failure_message do
55
+ args = " " + @expects.map{ |arg| "'#{arg}'" }.join(", ") unless @expects.empty?
56
+ "Expected #{@actual} to not #{name}#{args}"
57
+ end
58
+ end
59
+ # Define method to create matcher.
60
+ define_method(name) { |*args| matcher.new(*args) }
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ # Define delegate matchers for exist and contain methods.
67
+ match_using :exist, :contain
68
+
69
+ end
70
+
71
+
72
+ # An expectation has subject, description and block. The expectation is validated by running the block,
73
+ # and can access the subject from the method #it. The description is used for reporting.
74
+ #
75
+ # The expectation is run by calling #run_against. You can share expectations by running them against
76
+ # different projects (or any other context for that matter).
77
+ #
78
+ # If the subject is missing, it is set to the argument of #run_against, typically the project itself.
79
+ # If the description is missing, it is set from the project. If the block is missing, the default behavior
80
+ # prints "Pending" followed by the description. You can use this to write place holders and fill them later.
81
+ class Expectation
82
+
83
+ attr_reader :description, :subject, :block
84
+
85
+ # :call-seq:
86
+ # initialize(subject, description?) { .... }
87
+ # initialize(description?) { .... }
88
+ #
89
+ # First argument is subject (returned from it method), second argument is description. If you omit the
90
+ # description, it will be set from the subject. If you omit the subject, it will be set from the object
91
+ # passed to run_against.
92
+ def initialize(*args, &block)
93
+ @description = args.pop if String === args.last
94
+ @subject = args.shift
95
+ raise ArgumentError, "Expecting subject followed by description, and either one is optional. Not quite sure what to do with this list of arguments." unless args.empty?
96
+ @block = block || lambda { puts "Pending: #{description}" if verbose }
97
+ end
98
+
99
+ # :call-seq:
100
+ # run_against(context)
101
+ #
102
+ # Runs this expectation against the context object. The context object is different from the subject,
103
+ # but used as the subject if no subject specified (i.e. returned from the it method).
104
+ #
105
+ # This method creates a new context object modeled after the context argument, but a separate object
106
+ # used strictly for running this expectation, and used only once. The context object will pass methods
107
+ # to the context argument, so you can call any method, e.g. package(:jar).
108
+ #
109
+ # It also adds all matchers defined in Buildr and RSpec, and two additional methods:
110
+ # * it() -- Returns the subject.
111
+ # * description() -- Returns the description.
112
+ def run_against(context)
113
+ subject = @subject || context
114
+ description = @description ? "#{subject} #{@description}" : subject.to_s
115
+ # Define anonymous class and load it with:
116
+ # - All instance methods defined in context, so we can pass method calls to the context.
117
+ # - it() method to return subject, description() method to return description.
118
+ # - All matchers defined by Buildr and RSpec.
119
+ klass = Class.new
120
+ klass.instance_eval do
121
+ context.class.instance_methods(false).each do |method|
122
+ define_method(method) { |*args| context.send(method, *args) }
123
+ end
124
+ define_method(:it) { subject }
125
+ define_method(:description) { description }
126
+ include Spec::Matchers
127
+ include Matchers
128
+ end
129
+
130
+ # Run the expectation. We only print the expectation name when tracing (to know they all ran),
131
+ # or when we get a failure.
132
+ begin
133
+ trace description
134
+ klass.new.instance_eval &@block
135
+ rescue Exception=>error
136
+ raise error.exception("#{description}\n#{error}").tap { |wrapped| wrapped.set_backtrace(error.backtrace) }
137
+ end
138
+ end
139
+
140
+ end
141
+
142
+
143
+ include Extension
144
+
145
+ before_define do |project|
146
+ # The check task can do any sort of interesting things, but the most important is running expectations.
147
+ project.task("check") do |task|
148
+ project.expectations.inject(true) do |passed, expect|
149
+ begin
150
+ expect.run_against project
151
+ passed
152
+ rescue Exception=>ex
153
+ if verbose
154
+ error ex.backtrace.select { |line| line =~ /#{Buildr.application.buildfile}/ }.join("\n")
155
+ error ex
156
+ end
157
+ false
158
+ end
159
+ end or fail "Checks failed for project #{project.name} (see errors above)."
160
+ end
161
+ project.task("package").enhance do |task|
162
+ # Run all actions before checks.
163
+ task.enhance { project.task("check").invoke }
164
+ end
165
+ end
166
+
167
+
168
+ # :call-seq:
169
+ # check(description) { ... }
170
+ # check(subject, description) { ... }
171
+ #
172
+ # Adds an expectation. The expectation is run against the project by the check task, executed after packaging.
173
+ # You can access any package created by the project.
174
+ #
175
+ # An expectation is written using a subject, description and block to validate the expectation. For example:
176
+ #
177
+ # For example:
178
+ # check package(:jar), "should exist" do
179
+ # it.should exist
180
+ # end
181
+ # check package(:jar), "should contain a manifest" do
182
+ # it.should contain("META-INF/MANIFEST.MF")
183
+ # end
184
+ # check package(:jar).path("com/acme"), "should contain classes" do
185
+ # it.should_not be_empty
186
+ # end
187
+ # check package(:jar).entry("META-INF/MANIFEST"), "should be a recent license" do
188
+ # it.should contain(/Copyright (C) 2007/)
189
+ # end
190
+ #
191
+ # If you omit the subject, the project is used as the subject. If you omit the description, the subject is
192
+ # used as description.
193
+ #
194
+ # During development you can write placeholder expectations by omitting the block. This will simply report
195
+ # the expectation as pending.
196
+ def check(*args, &block)
197
+ expectations << Checks::Expectation.new(*args, &block)
198
+ end
199
+
200
+ # :call-seq:
201
+ # expectations() => Expectation*
202
+ #
203
+ # Returns a list of expectations (see #check).
204
+ def expectations()
205
+ @expectations ||= []
206
+ end
207
+
208
+ end
209
+
210
+ end
211
+
212
+
213
+ module Rake #:nodoc:
214
+ class FileTask
215
+
216
+ # :call-seq:
217
+ # exist?() => boolean
218
+ #
219
+ # Returns true if this file exists.
220
+ def exist?()
221
+ File.exist?(name)
222
+ end
223
+
224
+ # :call-seq:
225
+ # empty?() => boolean
226
+ #
227
+ # Returns true if file/directory is empty.
228
+ def empty?()
229
+ File.directory?(name) ? Dir.glob("#{name}/*").empty? : File.read(name).empty?
230
+ end
231
+
232
+ # :call-seq:
233
+ # contain?(pattern*) => boolean
234
+ # contain?(file*) => boolean
235
+ #
236
+ # For a file, returns true if the file content matches against all the arguments. An argument may be
237
+ # a string or regular expression.
238
+ #
239
+ # For a directory, return true if the directory contains the specified files. You can use relative
240
+ # file names and glob patterns (using *, **, etc).
241
+ def contain?(*patterns)
242
+ if File.directory?(name)
243
+ patterns.map { |pattern| "#{name}/#{pattern}" }.all? { |pattern| !Dir[pattern].empty? }
244
+ else
245
+ contents = File.read(name)
246
+ patterns.map { |pattern| Regexp === pattern ? pattern : Regexp.new(Regexp.escape(pattern.to_s)) }.
247
+ all? { |pattern| contents =~ pattern }
248
+ end
249
+ end
250
+
251
+ end
252
+ end
253
+
254
+
255
+ module Zip #:nodoc:
256
+ class ZipEntry
257
+
258
+ # :call-seq:
259
+ # exist() => boolean
260
+ #
261
+ # Returns true if this entry exists.
262
+ def exist?()
263
+ Zip::ZipFile.open(zipfile) { |zip| zip.file.exist?(@name) }
264
+ end
265
+
266
+ # :call-seq:
267
+ # empty?() => boolean
268
+ #
269
+ # Returns true if this entry is empty.
270
+ def empty?()
271
+ Zip::ZipFile.open(zipfile) { |zip| zip.file.read(@name) }.empty?
272
+ end
273
+
274
+ # :call-seq:
275
+ # contain(patterns*) => boolean
276
+ #
277
+ # Returns true if this ZIP file entry matches against all the arguments. An argument may be
278
+ # a string or regular expression.
279
+ def contain?(*patterns)
280
+ content = Zip::ZipFile.open(zipfile) { |zip| zip.file.read(@name) }
281
+ patterns.map { |pattern| Regexp === pattern ? pattern : Regexp.new(Regexp.escape(pattern.to_s)) }.
282
+ all? { |pattern| content =~ pattern }
283
+ end
284
+
285
+ end
286
+ end
287
+
288
+
289
+ class Buildr::ArchiveTask
290
+
291
+ class Path #:nodoc:
292
+
293
+ # :call-seq:
294
+ # exist() => boolean
295
+ #
296
+ # Returns true if this path exists. This only works if the path has any entries in it,
297
+ # so exist on path happens to be the opposite of empty.
298
+ def exist?()
299
+ !entries.empty?
300
+ end
301
+
302
+ # :call-seq:
303
+ # empty?() => boolean
304
+ #
305
+ # Returns true if this path is empty (has no other entries inside).
306
+ def empty?()
307
+ entries.all? { |entry| entry.empty? }
308
+ end
309
+
310
+ # :call-seq:
311
+ # contain(file*) => boolean
312
+ #
313
+ # Returns true if this ZIP file path contains all the specified files. You can use relative
314
+ # file names and glob patterns (using *, **, etc).
315
+ def contain?(*files)
316
+ files.all? { |file| entries.detect { |entry| File.fnmatch(file, entry.to_s, File::FNM_PATHNAME) } }
317
+ end
318
+
319
+ # :call-seq:
320
+ # entry(name) => ZipEntry
321
+ #
322
+ # Returns a ZIP file entry. You can use this to check if the entry exists and its contents,
323
+ # for example:
324
+ # package(:jar).path("META-INF").entry("LICENSE").should contain(/Apache Software License/)
325
+ def entry(name)
326
+ root.entry("#{@path}#{name}")
327
+ end
328
+
329
+ protected
330
+
331
+ def entries() #:nodoc:
332
+ return root.entries unless @path
333
+ @entries ||= root.entries.inject([]) { |selected, entry|
334
+ selected << entry.name.sub(@path, "") if entry.name.index(@path) == 0
335
+ selected
336
+ }
337
+ end
338
+
339
+ end
340
+
341
+ # :call-seq:
342
+ # empty?() => boolean
343
+ #
344
+ # Returns true if this ZIP file is empty (has no other entries inside).
345
+ def empty?()
346
+ path("").empty
347
+ end
348
+
349
+ # :call-seq:
350
+ # contain(file*) => boolean
351
+ #
352
+ # Returns true if this ZIP file contains all the specified files. You can use absolute
353
+ # file names and glob patterns (using *, **, etc).
354
+ def contain?(*files)
355
+ path("").contain?(*files)
356
+ end
357
+
358
+ end
359
+
360
+
361
+ class Buildr::ZipTask #:nodoc:
362
+
363
+ # :call-seq:
364
+ # entry(name) => Entry
365
+ #
366
+ # Returns a ZIP file entry. You can use this to check if the entry exists and its contents,
367
+ # for example:
368
+ # package(:jar).entry("META-INF/LICENSE").should contain(/Apache Software License/)
369
+ def entry(entry_name)
370
+ ::Zip::ZipEntry.new(name, entry_name)
371
+ end
372
+
373
+ def entries() #:nodoc:
374
+ @entries ||= Zip::ZipFile.open(name) { |zip| zip.entries }
375
+ end
376
+
377
+ end
378
+
379
+
380
+ class Buildr::Project
381
+ include Buildr::Checks
382
+ end