realityforge-buildr 1.5.9

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 (85) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE +176 -0
  4. data/NOTICE +26 -0
  5. data/README.md +3 -0
  6. data/Rakefile +50 -0
  7. data/addon/buildr/checkstyle-report.xsl +104 -0
  8. data/addon/buildr/checkstyle.rb +254 -0
  9. data/addon/buildr/git_auto_version.rb +36 -0
  10. data/addon/buildr/gpg.rb +90 -0
  11. data/addon/buildr/gwt.rb +413 -0
  12. data/addon/buildr/jacoco.rb +161 -0
  13. data/addon/buildr/pmd.rb +185 -0
  14. data/addon/buildr/single_intermediate_layout.rb +71 -0
  15. data/addon/buildr/spotbugs.rb +265 -0
  16. data/addon/buildr/top_level_generate_dir.rb +37 -0
  17. data/addon/buildr/wsgen.rb +192 -0
  18. data/bin/buildr +20 -0
  19. data/buildr.gemspec +61 -0
  20. data/lib/buildr.rb +86 -0
  21. data/lib/buildr/core/application.rb +705 -0
  22. data/lib/buildr/core/assets.rb +96 -0
  23. data/lib/buildr/core/build.rb +587 -0
  24. data/lib/buildr/core/common.rb +167 -0
  25. data/lib/buildr/core/compile.rb +599 -0
  26. data/lib/buildr/core/console.rb +124 -0
  27. data/lib/buildr/core/doc.rb +275 -0
  28. data/lib/buildr/core/environment.rb +128 -0
  29. data/lib/buildr/core/filter.rb +405 -0
  30. data/lib/buildr/core/help.rb +114 -0
  31. data/lib/buildr/core/progressbar.rb +161 -0
  32. data/lib/buildr/core/project.rb +994 -0
  33. data/lib/buildr/core/test.rb +776 -0
  34. data/lib/buildr/core/transports.rb +456 -0
  35. data/lib/buildr/core/util.rb +77 -0
  36. data/lib/buildr/ide/idea.rb +1664 -0
  37. data/lib/buildr/java/commands.rb +230 -0
  38. data/lib/buildr/java/compiler.rb +85 -0
  39. data/lib/buildr/java/custom_pom.rb +300 -0
  40. data/lib/buildr/java/doc.rb +62 -0
  41. data/lib/buildr/java/packaging.rb +393 -0
  42. data/lib/buildr/java/pom.rb +191 -0
  43. data/lib/buildr/java/test_result.rb +54 -0
  44. data/lib/buildr/java/tests.rb +111 -0
  45. data/lib/buildr/packaging/archive.rb +586 -0
  46. data/lib/buildr/packaging/artifact.rb +1113 -0
  47. data/lib/buildr/packaging/artifact_namespace.rb +1010 -0
  48. data/lib/buildr/packaging/artifact_search.rb +138 -0
  49. data/lib/buildr/packaging/package.rb +237 -0
  50. data/lib/buildr/packaging/version_requirement.rb +189 -0
  51. data/lib/buildr/packaging/zip.rb +189 -0
  52. data/lib/buildr/packaging/ziptask.rb +387 -0
  53. data/lib/buildr/version.rb +18 -0
  54. data/rakelib/release.rake +99 -0
  55. data/spec/addon/checkstyle_spec.rb +58 -0
  56. data/spec/core/application_spec.rb +576 -0
  57. data/spec/core/build_spec.rb +922 -0
  58. data/spec/core/common_spec.rb +670 -0
  59. data/spec/core/compile_spec.rb +656 -0
  60. data/spec/core/console_spec.rb +65 -0
  61. data/spec/core/doc_spec.rb +194 -0
  62. data/spec/core/extension_spec.rb +200 -0
  63. data/spec/core/project_spec.rb +736 -0
  64. data/spec/core/test_spec.rb +1131 -0
  65. data/spec/core/transport_spec.rb +452 -0
  66. data/spec/core/util_spec.rb +154 -0
  67. data/spec/ide/idea_spec.rb +1952 -0
  68. data/spec/java/commands_spec.rb +79 -0
  69. data/spec/java/compiler_spec.rb +274 -0
  70. data/spec/java/custom_pom_spec.rb +165 -0
  71. data/spec/java/doc_spec.rb +55 -0
  72. data/spec/java/packaging_spec.rb +786 -0
  73. data/spec/java/pom_spec.rb +162 -0
  74. data/spec/java/test_coverage_helper.rb +257 -0
  75. data/spec/java/tests_spec.rb +224 -0
  76. data/spec/packaging/archive_spec.rb +686 -0
  77. data/spec/packaging/artifact_namespace_spec.rb +757 -0
  78. data/spec/packaging/artifact_spec.rb +1351 -0
  79. data/spec/packaging/packaging_helper.rb +63 -0
  80. data/spec/packaging/packaging_spec.rb +690 -0
  81. data/spec/sandbox.rb +166 -0
  82. data/spec/spec_helpers.rb +420 -0
  83. data/spec/version_requirement_spec.rb +145 -0
  84. data/spec/xpath_matchers.rb +123 -0
  85. metadata +295 -0
@@ -0,0 +1,37 @@
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
+ module Buildr
17
+
18
+ # A simple extension that modifies the project layout to place generated files at the top level.
19
+ # Generated files are typically created below layout[:target, :generated], placing them at the top
20
+ # level makes it easy for IDEs to inspect source in the generated directory while ignoring the dir
21
+ # containing the intermediate artifacts.
22
+ #
23
+ module TopLevelGenerateDir
24
+ module ProjectExtension
25
+ include Extension
26
+
27
+ before_define do |project|
28
+ project.layout[:target, :generated] = "generated"
29
+ project.clean { rm_rf project._(:target, :generated) }
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ class Buildr::Project
36
+ include Buildr::TopLevelGenerateDir::ProjectExtension
37
+ end
@@ -0,0 +1,192 @@
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
+ module Buildr
17
+ module Wsgen
18
+ class << self
19
+
20
+ # :call-seq:
21
+ # java2wsdl(project, classnames, options) => String
22
+ #
23
+ # Uses wsgen to generate wsdl files form annotated, compiled classes. The parameters are
24
+ # * :project -- The project in which the classes are compiled.
25
+ # * :classnames -- Either an array of classnames to convert to wsdl or a map keyed on classnames and service
26
+ # specific customizations provided.
27
+ #
28
+ # Service options include:
29
+ # * :service_name -- The name of the service.
30
+ # * :namespace_url -- The namespace of the service.
31
+ #
32
+ # Method options include:
33
+ # * :output_dir -- The target directory.
34
+ # * :namespace_url -- The default namespace for the services.
35
+ #
36
+ # For example:
37
+ # Buildr::Wsgen.java2wsdl(project, %w(com.example.MyService))
38
+ # Buildr::Wsgen.java2wsdl(project, %w(com.example.MyService com.example.MyOtherService))
39
+ # Buildr::Wsgen.java2wsdl(project, %w(com.example.MyService com.example.MyOtherService), :namespace_url => "http://example.com/services")
40
+ # Buildr::Wsgen.java2wsdl(project, {"com.example.MyService" => {:service_name => 'MiaService', :namespace_url => "http://example.com/it/services"}))
41
+ def java2wsdl(project, classnames, options = {})
42
+ desc 'Generate wsdl from java'
43
+ project.task('java2wsdl').enhance([project.compile.target])
44
+
45
+ base_wsdl_dir = File.expand_path(options[:output_dir] || project._(:target, :generated, :wsgen, :main, :wsdl))
46
+ project.iml.main_generated_source_directories << base_wsdl_dir if project.iml?
47
+ project.file(base_wsdl_dir)
48
+ project.task('java2wsdl').enhance([base_wsdl_dir])
49
+
50
+ services = classnames.is_a?(Array) ? classnames.inject({}) {|result, element| result[element] = {}; result} : classnames
51
+
52
+ services.each_pair do |classname, config|
53
+
54
+ name_parts = classname.split('.')
55
+ service_name = config[:service_name] || name_parts.last
56
+ namespace_url = config[:namespace_url] || options[:namespace_url] || "http://#{name_parts[0...-1].reverse.join('.')}"
57
+ wsdl_file = File.expand_path("#{base_wsdl_dir}/META-INF/wsdl/#{service_name}.wsdl")
58
+
59
+ project.file(wsdl_file) do
60
+ mkdir_p File.dirname(wsdl_file)
61
+ cp = Buildr.artifacts(project.compile.dependencies + [project.compile.target]).map(&:to_s).join(File::PATH_SEPARATOR)
62
+
63
+ java_dir = project._(:target, :ignored, :wsgen, :main, :java)
64
+ intermediate_dir = project._(:target, :ignored, :wsgen, :main, :java)
65
+
66
+ rm_rf java_dir
67
+ rm_rf intermediate_dir
68
+ mkdir_p java_dir
69
+ mkdir_p intermediate_dir
70
+
71
+ args = []
72
+ args << '-keep'
73
+ args << '-inlineSchemas' if (options[:inlineSchemas] && ENV_JAVA['java.version'] >= '1.7')
74
+ args << '-wsdl'
75
+ args << '-servicename'
76
+ args << "{#{namespace_url}}#{service_name}"
77
+ args << '-portname'
78
+ args << "{#{namespace_url}}#{service_name}Port"
79
+ args << '-d'
80
+ args << intermediate_dir
81
+ args << '-r'
82
+ args << "#{base_wsdl_dir}/META-INF/wsdl"
83
+ args << '-s'
84
+ args << java_dir
85
+ args << '-cp'
86
+ args << cp
87
+ args << classname
88
+
89
+ command = "wsgen #{args.join(' ')}"
90
+ trace command
91
+ sh command
92
+ if $? != 0
93
+ raise 'Problem building wsdl'
94
+ end
95
+
96
+ content = IO.read(wsdl_file).gsub('REPLACE_WITH_ACTUAL_URL', "http://example.com/#{service_name}")
97
+ File.open(wsdl_file, 'wb') { |f| f.write content }
98
+ end
99
+
100
+ project.file(base_wsdl_dir).enhance([wsdl_file])
101
+ project.task('java2wsdl').enhance([wsdl_file])
102
+ end
103
+
104
+ base_wsdl_dir
105
+ end
106
+
107
+ # :call-seq:
108
+ # wsdl2java(project, wsdls, options) => String
109
+ #
110
+ # Uses wsgen to generate java files form wsdls. The parameters are
111
+ # * :project -- The project in which the classes are compiled.
112
+ # * :wsdls -- A hash of wsdl filenames to service configuration.
113
+ #
114
+ # Service options include:
115
+ # * :service_name -- The name of the service.
116
+ # * :package -- The package in which to generate the code.
117
+ # * :extension -- Should we allow non-portable extensions.
118
+ #
119
+ # Method options include:
120
+ # * :output_dir -- The target directory.
121
+ # * :target -- The target version for generated source..
122
+ # * :package -- The default package in which to generate the code.
123
+ #
124
+ # For example:
125
+ # Buildr::Wsgen.wsdl2java(project, {_('src/main/wsdl/MyService.wsdl') => {}})
126
+ # Buildr::Wsgen.wsdl2java(project, {_('src/main/wsdl/MyService.wsdl') => {:package => 'com.example'}})
127
+ # Buildr::Wsgen.wsdl2java(project, {_('src/main/wsdl/MyService.wsdl') => {:output_dir => _(:target, :wsdl, :java)}})
128
+ # Buildr::Wsgen.wsdl2java(project, {_('src/main/wsdl/MyService.wsdl') => {}}, :package => 'com.example' )
129
+ # Buildr::Wsgen.wsdl2java(project, {_('src/main/wsdl/MyService.wsdl') => {}}, :wsdl_location => 'file:META-INF/wsdl/SpecificTaskService.wsdl' )
130
+ def wsdl2java(project, wsdls, options = {})
131
+ desc 'Generate java from wsdl'
132
+ project.task('wsdl2java')
133
+
134
+ ws_dir = File.expand_path(options[:output_dir] || project._(:target, :generated, 'ws/main/java'))
135
+ project.file(ws_dir)
136
+ project.task('wsdl2java').enhance([ws_dir])
137
+
138
+ target = options[:target] || '2.1'
139
+
140
+ wsdls.each_pair do |wsdl_file, config|
141
+ pkg = config[:package] || options[:package]
142
+ service = config[:service] || File.basename(wsdl_file, '.wsdl')
143
+ wsdl_location = config[:wsdl_location]
144
+ java_file = "#{ws_dir}/#{pkg.gsub('.', '/')}/#{service}.java"
145
+ project.file(java_file => [project.file(wsdl_file)]) do
146
+ mkdir_p ws_dir
147
+ command = []
148
+ command << 'wsimport'
149
+ command << '-keep'
150
+ command << '-Xnocompile'
151
+ command << '-target'
152
+ command << target
153
+ command << '-s'
154
+ command << ws_dir
155
+ command << '-p'
156
+ command << pkg
157
+ if config[:extension]
158
+ command << '-extension'
159
+ end
160
+ if wsdl_location
161
+ command << '-wsdllocation'
162
+ command << wsdl_location
163
+ end
164
+ command << wsdl_file
165
+
166
+ trace command.join(' ')
167
+ output = `#{command.join(' ')}`
168
+ if $? != 0
169
+ rm_rf java_file
170
+ puts output
171
+ raise 'Problem building webservices'
172
+ end
173
+ unless File.exist?(java_file)
174
+ puts output
175
+ raise 'Problem building webservices'
176
+ end
177
+ if output =~ /\[WARNING\]/
178
+ puts output
179
+ end
180
+ end
181
+ project.file(ws_dir).enhance([java_file])
182
+ end
183
+
184
+ project.compile.from ws_dir
185
+ project.iml.main_generated_source_directories << ws_dir if project.iml?
186
+ project.compile.enhance(['wsdl2java'])
187
+
188
+ ws_dir
189
+ end
190
+ end
191
+ end
192
+ end
data/bin/buildr ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ # Licensed to the Apache Software Foundation (ASF) under one or more
3
+ # contributor license agreements. See the NOTICE file distributed with this
4
+ # work for additional information regarding copyright ownership. The ASF
5
+ # licenses this file to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations under
15
+ # the License.
16
+
17
+ require 'rubygems'
18
+ require 'bundler/setup'
19
+ require 'buildr'
20
+ Buildr.application.run
data/buildr.gemspec ADDED
@@ -0,0 +1,61 @@
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
+ unless defined?(Buildr::VERSION)
17
+ require File.join(File.dirname(__FILE__), 'lib', 'buildr', 'version.rb')
18
+ $LOADED_FEATURES << 'buildr/version.rb'
19
+ end
20
+
21
+ Gem::Specification.new do |spec|
22
+ spec.name = 'realityforge-buildr'
23
+ spec.version = Buildr::VERSION.dup
24
+ spec.platform = Gem::Platform::RUBY
25
+ spec.author = 'Apache Buildr'
26
+ spec.email = 'users@buildr.apache.org'
27
+ spec.homepage = 'http://buildr.apache.org/'
28
+ spec.summary = 'Build like you code'
29
+ spec.licenses = %w(Apache-2.0)
30
+ spec.description = <<-TEXT
31
+ Apache Buildr is a build system for Java-based applications. We wanted
32
+ something that's simple and intuitive to use, so we only need to tell it what
33
+ to do, and it takes care of the rest. But also something we can easily extend
34
+ for those one-off tasks, with a language that's a joy to use.
35
+ TEXT
36
+
37
+ spec.files = Dir['{addon,bin,lib,rakelib,spec}/**/*', '*.{gemspec}'] +
38
+ %w(LICENSE NOTICE CHANGELOG.md README.md Rakefile)
39
+ spec.require_paths = 'lib', 'addon'
40
+ spec.bindir = 'bin'
41
+ spec.executable = 'buildr'
42
+
43
+ spec.extra_rdoc_files = 'README.md', 'CHANGELOG.md', 'LICENSE', 'NOTICE'
44
+ spec.rdoc_options = '--title', 'Buildr', '--main', 'README.md',
45
+ '--webcvs', 'https://github.com/realityforge/buildr'
46
+ spec.post_install_message = 'To get started run buildr --help'
47
+
48
+ # Tested against these dependencies.
49
+ spec.add_dependency 'rake', '0.9.2.2'
50
+ spec.add_dependency 'builder', '3.2.4'
51
+ spec.add_dependency 'rubyzip', '2.3.0'
52
+ spec.add_dependency 'json_pure', '2.5.1'
53
+ spec.add_dependency 'xml-simple', '1.1.8'
54
+ spec.add_dependency 'bundler'
55
+
56
+ spec.add_development_dependency 'rspec-expectations', '2.14.3'
57
+ spec.add_development_dependency 'rspec-mocks', '2.14.3'
58
+ spec.add_development_dependency 'rspec-core', '2.14.5'
59
+ spec.add_development_dependency 'rspec', '2.14.1'
60
+ spec.add_development_dependency 'rspec-retry', '0.2.1'
61
+ end
data/lib/buildr.rb ADDED
@@ -0,0 +1,86 @@
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
+ unless defined?(Buildr::VERSION)
17
+ require 'buildr/version'
18
+ end
19
+
20
+ require 'rake'
21
+ include Rake::DSL
22
+ Rake::TaskManager.record_task_metadata = true
23
+
24
+ require 'rbconfig'
25
+ require 'pathname'
26
+ autoload :Tempfile, 'tempfile'
27
+ autoload :YAML, 'yaml'
28
+ autoload :REXML, 'rexml/document'
29
+ autoload :XmlSimple, 'xmlsimple'
30
+ autoload :Builder, 'builder' # A different kind of buildr, one we use to create XML.
31
+ require 'erb'
32
+ require 'find'
33
+ require 'uri'
34
+ require 'stringio'
35
+ require 'fileutils'
36
+ require 'securerandom'
37
+
38
+ require 'buildr/core/util'
39
+ require 'buildr/core/console'
40
+ require 'buildr/core/common'
41
+ require 'buildr/core/application'
42
+ require 'buildr/core/project'
43
+ require 'buildr/core/assets'
44
+ require 'buildr/core/environment'
45
+ require 'buildr/core/help'
46
+ require 'buildr/core/build'
47
+ require 'buildr/core/filter'
48
+ require 'buildr/core/compile'
49
+ require 'buildr/core/test'
50
+ require 'buildr/java/commands'
51
+ require 'buildr/core/transports'
52
+ require 'buildr/java/pom'
53
+ require 'buildr/core/doc'
54
+ require 'buildr/packaging/version_requirement'
55
+ require 'buildr/packaging/artifact_namespace'
56
+ require 'buildr/packaging/artifact'
57
+ require 'buildr/packaging/package'
58
+ require 'buildr/packaging/archive'
59
+ require 'buildr/packaging/ziptask'
60
+ require 'buildr/packaging/zip'
61
+ require 'buildr/java/compiler'
62
+ require 'buildr/java/tests'
63
+ require 'buildr/java/test_result'
64
+ require 'buildr/java/packaging'
65
+ require 'buildr/java/commands'
66
+ require 'buildr/java/doc'
67
+ require 'buildr/java/custom_pom'
68
+ require 'buildr/ide/idea'
69
+
70
+ # Methods defined in Buildr are both instance methods (e.g. when included in Project)
71
+ # and class methods when invoked like Buildr.artifacts().
72
+ module Buildr ; extend self ; end
73
+
74
+ # The Buildfile object (self) has access to all the Buildr methods and constants.
75
+ class << self ; include Buildr ; end
76
+
77
+ # All modules defined under Buildr::* can be referenced without Buildr:: prefix
78
+ # unless a conflict exists (e.g. Buildr::RSpec vs ::RSpec)
79
+ class Object #:nodoc:
80
+ Buildr.constants.each do |name|
81
+ const = Buildr.const_get(name)
82
+ if const.is_a?(Module)
83
+ const_set name, const unless const_defined?(name)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,705 @@
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
+ # Portion of this file derived from Rake.
18
+ # Copyright (c) 2003, 2004 Jim Weirich
19
+ #
20
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
21
+ # of this software and associated documentation files (the "Software"), to deal
22
+ # in the Software without restriction, including without limitation the rights
23
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24
+ # copies of the Software, and to permit persons to whom the Software is
25
+ # furnished to do so, subject to the following conditions:
26
+ #
27
+ # The above copyright notice and this permission notice shall be included in
28
+ # all copies or substantial portions of the Software.
29
+ #
30
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36
+ # SOFTWARE.
37
+
38
+
39
+ # Gem::user_home is nice, but ENV['HOME'] lets you override from the environment.
40
+ ENV['HOME'] ||= File.expand_path(Gem::user_home)
41
+ ENV['BUILDR_ENV'] ||= 'development'
42
+
43
+ module Buildr
44
+
45
+ # Provide settings that come from three sources.
46
+ #
47
+ # User settings are placed in the .buildr/settings.yaml file located in the user's home directory.
48
+ # They should only be used for settings that are specific to the user and applied the same way
49
+ # across all builds. Example for user settings are preferred repositories, path to local repository,
50
+ # user/name password for uploading to remote repository.
51
+ #
52
+ # Build settings are placed in the build.yaml file located in the build directory. They help keep
53
+ # the buildfile and build.yaml file simple and readable, working to the advantages of each one.
54
+ # Example for build settings are gems, repositories and artifacts used by that build.
55
+ #
56
+ # Profile settings are placed in the profiles.yaml file located in the build directory. They provide
57
+ # settings that differ in each environment the build runs in. For example, URLs and database
58
+ # connections will be different when used in development, test and production environments.
59
+ # The settings for the current environment are obtained by calling #profile.
60
+ class Settings
61
+
62
+ def initialize(application) #:nodoc:
63
+ @application = application
64
+ end
65
+
66
+ # User settings loaded from setting.yaml file in user's home directory.
67
+ def user
68
+ @user ||= load_from('settings', @application.home_dir)
69
+ end
70
+
71
+ # Build settings loaded from build.yaml file in build directory.
72
+ def build
73
+ @build ||= load_from('build')
74
+ end
75
+
76
+ # Profiles loaded from profiles.yaml file in build directory.
77
+ def profiles
78
+ @profiles ||= load_from('profiles')
79
+ end
80
+
81
+ # :call-seq:
82
+ # profile => hash
83
+ #
84
+ # Returns the profile for the current environment.
85
+ def profile
86
+ profiles[@application.environment] ||= {}
87
+ end
88
+
89
+ private
90
+
91
+ def load_from(name, path = nil)
92
+ unless path
93
+ fail "Internal error: attempting to access local setting before buildfile located" unless @application.rakefile
94
+ path = File.expand_path(File.dirname(@application.rakefile))
95
+ end
96
+ file_name = %w[yaml yml].map { |ext| File.join(path, "#{name}.#{ext}") }.find { |fn| File.exist?(fn) }
97
+ return {} unless file_name
98
+ yaml = YAML.load(File.read(file_name)) || {}
99
+ fail "Expecting #{file_name} to be a map (name: value)!" unless Hash === yaml
100
+ @application.buildfile.enhance [file_name]
101
+ yaml
102
+ end
103
+
104
+ end
105
+
106
+
107
+ class Application < Rake::Application #:nodoc:
108
+
109
+ DEFAULT_BUILDFILES = %w[buildfile Buildfile buildfile.rb Buildfile.rb]
110
+
111
+ attr_reader :rakefiles, :requires
112
+ private :rakefiles, :requires
113
+
114
+ def initialize
115
+ super
116
+ @rakefiles = DEFAULT_BUILDFILES.dup
117
+ @top_level_tasks = []
118
+ @home_dir = File.expand_path('.buildr', ENV['HOME'])
119
+ mkpath @home_dir if !File.exist?(@home_dir) && File.writable?(ENV['HOME'])
120
+ @settings = Settings.new(self)
121
+ @on_completion = []
122
+ @on_failure = []
123
+ end
124
+
125
+ def run
126
+ @start = Time.now
127
+ standard_exception_handling do
128
+ init 'Buildr'
129
+ load_buildfile
130
+ top_level
131
+ end
132
+ end
133
+
134
+ # Not for external consumption.
135
+ def switch_to_namespace(names) #:nodoc:
136
+ current, @scope = @scope, names
137
+ begin
138
+ yield
139
+ ensure
140
+ @scope = current
141
+ end
142
+ end
143
+
144
+ # Returns list of Gems associated with this buildfile, as listed in build.yaml.
145
+ # Each entry is of type Gem::Specification.
146
+ attr_reader :gems
147
+
148
+ # Buildr home directory, .buildr under user's home directory.
149
+ attr_reader :home_dir
150
+
151
+ # Copied from BUILD_ENV.
152
+ def environment
153
+ ENV['BUILDR_ENV']
154
+ end
155
+
156
+ # Returns the Settings associated with this build.
157
+ attr_reader :settings
158
+
159
+ # :call-seq:
160
+ # buildfile
161
+ # Returns the buildfile as a task that you can use as a dependency.
162
+ def buildfile
163
+ @buildfile_task ||= BuildfileTask.define_task(File.expand_path(rakefile))
164
+ end
165
+
166
+ # Files that complement the buildfile itself
167
+ def build_files #:nodoc:
168
+ deprecated 'Please call buildfile.prerequisites instead'
169
+ buildfile.prerequisites
170
+ end
171
+
172
+ # Yields to block on successful completion. Primarily used for notifications.
173
+ def on_completion(&block)
174
+ @on_completion << block
175
+ end
176
+
177
+ # Yields to block on failure with exception. Primarily used for notifications.
178
+ def on_failure(&block)
179
+ @on_failure << block
180
+ end
181
+
182
+ # Call on_completion hooks with the given title and message
183
+ def build_completed(title, message)
184
+ @on_completion.each do |block|
185
+ block.call(title, message) rescue nil
186
+ end
187
+ end
188
+
189
+ # Call on_failure hooks with the given title, message and exception
190
+ def build_failed(title, message, ex = nil)
191
+ @on_failure.each do |block|
192
+ block.call(title, message, ex) rescue nil
193
+ end
194
+ end
195
+
196
+ # :call-seq:
197
+ # deprecated(message)
198
+ #
199
+ # Use with deprecated methods and classes. This method automatically adds the file name and line number,
200
+ # and the text 'Deprecated' before the message, and eliminated duplicate warnings. It only warns when
201
+ # running in verbose mode.
202
+ #
203
+ # For example:
204
+ # deprecated 'Please use new_foo instead of foo.'
205
+ def deprecated(message) #:nodoc:
206
+ return unless verbose
207
+ "#{caller[1]}: Deprecated: #{message}".tap do |message|
208
+ @deprecated ||= {}
209
+ unless @deprecated[message]
210
+ @deprecated[message] = true
211
+ warn message
212
+ end
213
+ end
214
+ end
215
+
216
+ protected
217
+
218
+ def load_buildfile # replaces load_rakefile
219
+ standard_exception_handling do
220
+ find_buildfile
221
+ load_gems
222
+ load_artifact_ns
223
+ load_tasks
224
+ raw_load_buildfile
225
+ end
226
+ end
227
+
228
+ def top_level # adds on_completion hook
229
+ standard_exception_handling do
230
+ if options.show_tasks
231
+ display_tasks_and_comments
232
+ elsif options.show_prereqs
233
+ display_prerequisites
234
+ elsif options.execute
235
+ eval options.execute
236
+ else
237
+ top_level_tasks.each { |task_name| invoke_task(task_name) }
238
+ if verbose
239
+ elapsed = Time.now - @start
240
+ real = []
241
+ real << ('%ih' % (elapsed / 3600)) if elapsed >= 3600
242
+ real << ('%im' % ((elapsed / 60) % 60)) if elapsed >= 60
243
+ real << ('%.3fs' % (elapsed % 60))
244
+ puts Buildr::Console.color("Completed in #{real.join}", :green)
245
+ end
246
+ # On OS X this will load Cocoa and Growl which takes half a second we
247
+ # don't want to measure, so put this after the console message.
248
+ title, message = "Your build has completed", "#{Dir.pwd}\nbuildr #{@top_level_tasks.join(' ')}"
249
+ build_completed(title, message)
250
+ end
251
+ end
252
+ end
253
+
254
+ def handle_options
255
+ options.rakelib = ['tasks']
256
+
257
+ OptionParser.new do |opts|
258
+ opts.banner = "buildr [-f rakefile] {options} targets..."
259
+ opts.separator ""
260
+ opts.separator "Options are ..."
261
+
262
+ opts.on_tail("-h", "--help", "-H", "Display this help message.") do
263
+ puts opts
264
+ exit 0
265
+ end
266
+ standard_buildr_options.each { |args| opts.on(*args) }
267
+ end.parse!
268
+ end
269
+
270
+ def standard_buildr_options # replaces standard_rake_options
271
+ [
272
+ ['--describe', '-D [PATTERN]', "Describe the tasks (matching optional PATTERN), then exit.",
273
+ lambda { |value|
274
+ options.show_tasks = true
275
+ options.full_description = true
276
+ options.show_task_pattern = Regexp.new(value || '')
277
+ }
278
+ ],
279
+ ['--execute', '-E CODE',
280
+ "Execute some Ruby code after loading the buildfile",
281
+ lambda { |value| options.execute = value }
282
+ ],
283
+ ['--environment', '-e ENV',
284
+ "Environment name (e.g. development, test, production).",
285
+ lambda { |value| ENV['BUILDR_ENV'] = value }
286
+ ],
287
+ ['--generate [PATH]',
288
+ "Generate buildfile from either pom.xml file or directory path.",
289
+ lambda { |value|
290
+ value ||= File.exist?('pom.xml') ? 'pom.xml' : Dir.pwd
291
+ raw_generate_buildfile value
292
+ exit 0
293
+ }
294
+ ],
295
+ ['--libdir', '-I LIBDIR', "Include LIBDIR in the search path for required modules.",
296
+ lambda { |value| $:.push(value) }
297
+ ],
298
+ ['--prereqs', '-P [PATTERN]', "Display the tasks and dependencies (matching optional PATTERN), then exit.",
299
+ lambda { |value|
300
+ options.show_prereqs = true
301
+ options.show_task_pattern = Regexp.new(value || '')
302
+ }
303
+ ],
304
+ ['--quiet', '-q', "Do not log messages to standard output.",
305
+ lambda { |value| verbose(false) }
306
+ ],
307
+ ['--buildfile', '-f FILE', "Use FILE as the buildfile.",
308
+ lambda { |value|
309
+ @rakefiles.clear
310
+ @rakefiles << value
311
+ }
312
+ ],
313
+ ['--rakelibdir', '--rakelib', '-R PATH',
314
+ "Auto-import any .rake files in PATH. (default is 'tasks')",
315
+ lambda { |value| options.rakelib = value.split(':') }
316
+ ],
317
+ ['--require', '-r MODULE', "Require MODULE before executing rakefile.",
318
+ lambda { |value|
319
+ begin
320
+ require value
321
+ rescue LoadError => ex
322
+ begin
323
+ rake_require value
324
+ rescue LoadError => ex2
325
+ raise ex
326
+ end
327
+ end
328
+ }
329
+ ],
330
+ ['--rules', "Trace the rules resolution.",
331
+ lambda { |value| options.trace_rules = true }
332
+ ],
333
+ ['--no-search', '--nosearch', '-N', "Do not search parent directories for the Buildfile.",
334
+ lambda { |value| options.nosearch = true }
335
+ ],
336
+ ['--silent', '-s', "Like --quiet, but also suppresses the 'in directory' announcement.",
337
+ lambda { |value|
338
+ verbose(false)
339
+ options.silent = true
340
+ }
341
+ ],
342
+ ['--tasks', '-T [PATTERN]', "Display the tasks (matching optional PATTERN) with descriptions, then exit.",
343
+ lambda { |value|
344
+ options.show_tasks = true
345
+ options.show_task_pattern = Regexp.new(value || '')
346
+ options.full_description = false
347
+ }
348
+ ],
349
+ ['--trace', '-t [CATEGORIES]', "Turn on invoke/execute tracing, enable full backtrace.",
350
+ lambda { |value|
351
+ options.trace = true
352
+ options.trace_categories = value ? value.split(',').map { |v| v.downcase.to_sym } : []
353
+ options.trace_all = options.trace_categories.include? :all
354
+ verbose(true)
355
+ }
356
+ ],
357
+ ['--verbose', '-v', "Log message to standard output (default).",
358
+ lambda { |value| verbose(true) }
359
+ ],
360
+ ['--version', '-V', "Display the program version.",
361
+ lambda { |value|
362
+ puts "Buildr #{Buildr::VERSION}"
363
+ exit 0
364
+ }
365
+ ],
366
+ ['--offline', '-o', "Do not try to download anything",
367
+ lambda { |value|
368
+ trace 'Working in offline mode; snapshot will not be updated.'
369
+ options.work_offline = true
370
+ }
371
+ ],
372
+ ['--update-snapshots', '-u', "Force updating all dependencies whose version contains SNAPSHOT",
373
+ lambda { |value|
374
+ trace 'Force update of SNAPSHOT artifacts.'
375
+ options.update_snapshots = true
376
+ }
377
+ ]
378
+ ]
379
+ end
380
+
381
+ def find_buildfile
382
+ buildfile, location = find_rakefile_location || (tty_output? && ask_generate_buildfile)
383
+ fail "No Buildfile found (looking for: #{@rakefiles.join(', ')})" if buildfile.nil?
384
+ @rakefile = buildfile
385
+ Dir.chdir(location)
386
+ end
387
+
388
+ def ask_generate_buildfile
389
+ header = "To use Buildr you need a buildfile. Do you want me to create one?"
390
+ options = {}
391
+ options["From Maven2 POM file"] = ['pom.xml', false] if File.exist?('pom.xml')
392
+ options["From directory structure"] = [Dir.pwd, false]
393
+ options["Cancel"]= nil
394
+ source, from_eclipse = Buildr::Console.present_menu(header, options)
395
+ if source
396
+ buildfile = raw_generate_buildfile(source, from_eclipse)
397
+ [buildfile, File.dirname(buildfile)]
398
+ end
399
+ end
400
+
401
+ def raw_generate_buildfile(source, from_eclipse=Generate.has_eclipse_project?)
402
+ # We need rakefile to be known, for settings.build to be accessible.
403
+ @rakefile = File.expand_path(DEFAULT_BUILDFILES.first)
404
+ fail "Buildfile already exists" if File.exist?(@rakefile) && !(tty_output? && Buildr::Console.agree?('Buildfile exists, overwrite?'))
405
+ script = nil
406
+ if from_eclipse
407
+ script = Generate.from_eclipse(source)
408
+ elsif File.directory?(source)
409
+ script = Generate.from_directory(source)
410
+ else
411
+ script = Generate.from_maven2_pom(source)
412
+ end
413
+ File.open @rakefile, 'w' do |file|
414
+ file.puts script
415
+ end
416
+ puts "Created #{@rakefile}" if verbose
417
+ @rakefile
418
+ end
419
+
420
+ def raw_load_buildfile # replaces raw_load_rakefile
421
+ puts "(in #{Dir.pwd}, #{environment})" unless options.silent
422
+ load File.expand_path(@rakefile) if @rakefile && @rakefile != ''
423
+ load_imports
424
+ Buildr.projects
425
+ end
426
+
427
+ # Load/install all Gems specified in build.yaml file.
428
+ def load_gems #:nodoc:
429
+ installed, missing_deps = listed_gems
430
+ unless missing_deps.empty?
431
+ fail Gem::LoadError, "Build requires the gems #{missing_deps.join(', ')}, which cannot be found in the local repository. Please install the gems before attempting to build project."
432
+ end
433
+ installed.each { |spec| spec.activate }
434
+ @gems = installed
435
+ end
436
+
437
+ # Returns two lists. The first contains a Gem::Specification for every listed and installed
438
+ # Gem, the second contains a Gem::Dependency for every listed and uninstalled Gem.
439
+ def listed_gems #:nodoc:
440
+ found = []
441
+ missing = []
442
+ Array(settings.build['gems']).each do |dep|
443
+ name, versions = parse_gem_dependency(dep)
444
+ begin
445
+ found << Gem::Specification.find_by_name(name, versions)
446
+ rescue Exception
447
+ missing << Gem::Dependency.new(name, versions)
448
+ end
449
+ end
450
+ return [found, missing]
451
+ end
452
+
453
+ def parse_gem_dependency(dep) #:nodoc:
454
+ name, trail = dep.scan(/^\s*(\S*)\s*(.*)\s*$/).first
455
+ versions = trail.scan(/[=><~!]{0,2}\s*[\d\.]+/)
456
+ versions = ['>= 0'] if versions.empty?
457
+ return name, versions
458
+ end
459
+
460
+ # Load artifact specs from the build.yaml file, making them available
461
+ # by name ( ruby symbols ).
462
+ def load_artifact_ns #:nodoc:
463
+ hash = settings.build['artifacts']
464
+ return unless hash
465
+ raise "Expected 'artifacts' element to be a hash" unless Hash === hash
466
+ # Currently we only use one artifact namespace to rule them all. (the root NS)
467
+ Buildr::ArtifactNamespace.load(:root => hash)
468
+ end
469
+
470
+ # Loads buildr.rb files from home/.buildr directory and project directory.
471
+ # Loads custom tasks from .rake files in tasks directory.
472
+ def load_tasks #:nodoc:
473
+ # TODO: this might need to be split up, look for deprecated features, better method name.
474
+ old = File.expand_path('buildr.rb', ENV['HOME'])
475
+ new = File.expand_path('buildr.rb', home_dir)
476
+ if File.exist?(old) && !File.exist?(new)
477
+ warn "Deprecated: Please move buildr.rb from your home directory to the .buildr directory in your home directory"
478
+ end
479
+
480
+ # Load home/.buildr/buildr.rb in preference
481
+ files = [ File.exist?(new) ? new : old, 'buildr.rb' ].select { |file| File.exist?(file) }
482
+ files += [ File.expand_path('buildr.rake', ENV['HOME']), File.expand_path('buildr.rake') ].
483
+ select { |file| File.exist?(file) }.each { |file| warn "Please use '#{file.ext('rb')}' instead of '#{file}'" }
484
+ files += (options.rakelib || []).collect { |rlib| Dir["#{File.expand_path(rlib)}/*.rake"] }.flatten
485
+
486
+ # Load .buildr/_buildr.rb same directory as buildfile
487
+ %w{.buildr.rb _buildr.rb}.each do |f|
488
+ local_buildr = File.expand_path("#{File.dirname(Buildr.application.buildfile.to_s)}/#{f}")
489
+ files << local_buildr if File.exist?( local_buildr )
490
+ end
491
+
492
+ files.each do |file|
493
+ file = File.expand_path(file)
494
+ unless $LOADED_FEATURES.include?(file)
495
+ load file
496
+ $LOADED_FEATURES << file
497
+ end
498
+ end
499
+ buildfile.enhance files
500
+ true
501
+ end
502
+
503
+ def display_tasks_and_comments
504
+ displayable_tasks = tasks.select { |t| t.comment && t.name =~ options.show_task_pattern }
505
+ if options.full_description
506
+ displayable_tasks.each do |t|
507
+ puts "buildr #{t.name_with_args}"
508
+ t.full_comment.split("\n").each do |line|
509
+ puts " #{line}"
510
+ end
511
+ puts
512
+ end
513
+ else
514
+ width = displayable_tasks.collect { |t| t.name_with_args.length }.max || 10
515
+ max_column = truncate_output? ? terminal_width - name.size - width - 7 : nil
516
+ displayable_tasks.each do |t|
517
+ printf "buildr %-#{width}s # %s\n",
518
+ t.name_with_args, max_column ? truncate(t.comment, max_column) : t.comment
519
+ end
520
+ end
521
+ end
522
+
523
+ def display_prerequisites
524
+ displayable_tasks = tasks.select { |t| t.name =~ options.show_task_pattern }
525
+ displayable_tasks.each do |t|
526
+ puts "buildr #{t.name}"
527
+ t.prerequisites.each { |pre| puts " #{pre}" }
528
+ end
529
+ end
530
+
531
+ def standard_exception_handling # adds on_failure hook
532
+ begin
533
+ yield
534
+ rescue SystemExit => ex
535
+ # Exit silently with current status
536
+ exit(ex.status)
537
+ rescue OptionParser::ParseError => ex
538
+ $stderr.puts Buildr::Console.color(ex.message, :red)
539
+ exit(1)
540
+ rescue Exception => ex
541
+ ex_msg = ex.class.name == "Exception" ? ex.message : "#{ex.class.name} : #{ex.message}"
542
+ title, message = "Your build failed with an error", "#{Dir.pwd}:\n#{ex_msg}"
543
+ build_failed(title, message, ex)
544
+ # Exit with error message
545
+ $stderr.puts "Buildr aborted!"
546
+ $stderr.puts Buildr::Console.color(ex_msg, :red)
547
+ if options.trace
548
+ $stderr.puts ex.backtrace.join("\n")
549
+ else
550
+ $stderr.puts ex.backtrace.select { |str| str =~ /#{rakefile}/ }.map { |line| Buildr::Console.color(line, :red) }.join("\n") if rakefile
551
+ $stderr.puts "(See full trace by running task with --trace)"
552
+ end
553
+ exit(1)
554
+ end
555
+ end
556
+
557
+ end
558
+
559
+
560
+ # This task stands for the buildfile and all its associated helper files (e.g., buildr.rb, build.yaml).
561
+ # By using this task as a prerequisite for other tasks, you can ensure these tasks will be needed
562
+ # whenever the buildfile changes.
563
+ class BuildfileTask < Rake::FileTask #:nodoc:
564
+
565
+ def timestamp
566
+ ([name] + prerequisites).map { |f| File.stat(f).mtime }.max rescue Time.now
567
+ end
568
+ end
569
+
570
+
571
+ class << self
572
+
573
+ # Returns the Buildr::Application object.
574
+ def application
575
+ Rake.application
576
+ end
577
+
578
+ def application=(app) #:nodoc:
579
+ Rake.application = app
580
+ end
581
+
582
+ # Returns the Settings associated with this build.
583
+ def settings
584
+ Buildr.application.settings
585
+ end
586
+
587
+ # Copied from BUILD_ENV.
588
+ def environment
589
+ Buildr.application.environment
590
+ end
591
+
592
+ end
593
+
594
+ Buildr.application = Buildr::Application.new
595
+
596
+ end
597
+
598
+ alias :warn_without_color :warn
599
+
600
+ # Show warning message.
601
+ def warn(*message, uplevel: nil)
602
+ warn_without_color(Buildr::Console.color(message.join(' '), :blue), :uplevel => uplevel) if verbose
603
+ end
604
+
605
+ # Show error message. Use this when you need to show an error message and not throwing
606
+ # an exception that will stop the build.
607
+ def error(message)
608
+ puts Buildr::Console.color(message.to_s, :red)
609
+ end
610
+
611
+ # Show optional information. The message is printed only when running in verbose
612
+ # mode (the default).
613
+ def info(message)
614
+ puts message if verbose
615
+ end
616
+
617
+ # Show message. The message is printed out only when running in trace mode.
618
+ def trace(message)
619
+ puts message if Buildr.application.options.trace
620
+ end
621
+
622
+ def trace?(*category)
623
+ options = Buildr.application.options
624
+ return options.trace if category.empty?
625
+ return true if options.trace_all
626
+ return false unless options.trace_categories
627
+ options.trace_categories.include?(category.first)
628
+ end
629
+
630
+ module Rake #:nodoc
631
+ # Rake's circular dependency checks (InvocationChain) only applies to task prerequisites,
632
+ # all other cases result in the non too-descriptive thread sleeping error. This change can
633
+ # deal with circular dependencies that occur from direct task invocation, e.g:
634
+ # task 'foo'=>'bar'
635
+ # task 'bar' do
636
+ # task('foo').invoke
637
+ # end
638
+ class Task #:nodoc:
639
+ def invoke(*args)
640
+ task_args = TaskArguments.new(arg_names, args)
641
+ invoke_with_call_chain(task_args, Thread.current[:rake_chain] || InvocationChain::EMPTY)
642
+ end
643
+
644
+ def invoke_with_call_chain(task_args, invocation_chain)
645
+ new_chain = InvocationChain.append(self, invocation_chain)
646
+ @lock.synchronize do
647
+ if application.options.trace
648
+ puts "** Invoke #{name} #{format_trace_flags}"
649
+ end
650
+ return if @already_invoked
651
+ @already_invoked = true
652
+ begin
653
+ invoke_prerequisites(task_args, new_chain)
654
+ rescue
655
+ trace "Exception while invoking prerequisites of task #{self.inspect}"
656
+ raise
657
+ end
658
+ begin
659
+ old_chain, Thread.current[:rake_chain] = Thread.current[:rake_chain], new_chain
660
+ execute(task_args) if needed?
661
+ ensure
662
+ Thread.current[:rake_chain] = old_chain
663
+ end
664
+ end
665
+ end
666
+ end
667
+ end
668
+
669
+ module FileUtils
670
+ def fu_output_message(msg) #:nodoc:
671
+ if Rake::FileUtilsExt::DEFAULT == RakeFileUtils.verbose_flag
672
+ # Swallow the default output
673
+ elsif RakeFileUtils.verbose_flag
674
+ @fileutils_output ||= $stderr
675
+ @fileutils_label ||= ''
676
+ @fileutils_output.puts @fileutils_label + msg
677
+ end
678
+ end
679
+ module_function :fu_output_message
680
+ private_class_method :fu_output_message
681
+ end
682
+
683
+ module ::Rake
684
+ class FileList
685
+ # Add matching glob patterns.
686
+ def add_matching(pattern)
687
+ # Patch to use File::FNM_DOTMATCH where appropriate
688
+ flags = 0
689
+ args = [pattern]
690
+ flags |= File::FNM_DOTMATCH if pattern =~ /\.\*/
691
+ flags |= File::FNM_EXTGLOB if pattern =~ /[^\\]\{.*\}/
692
+ args << flags unless 0 == flags
693
+ FileList.glob(*args).each do |fn|
694
+ self << fn unless exclude?(fn)
695
+ end
696
+ end
697
+ private :add_matching
698
+
699
+ class << self
700
+ def glob(pattern, *args)
701
+ Dir.glob(pattern, *args).sort
702
+ end
703
+ end
704
+ end
705
+ end if RUBY_VERSION >= "2.0.0"