omnibus 3.2.0.rc.1 → 3.2.0.rc.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -2
- data/Rakefile +2 -2
- data/lib/omnibus.rb +13 -4
- data/lib/omnibus/builder.rb +596 -248
- data/lib/omnibus/cleanroom.rb +7 -7
- data/lib/omnibus/cli/deprecated.rb +1 -1
- data/lib/omnibus/exceptions.rb +36 -5
- data/lib/omnibus/fetchers/net_fetcher.rb +4 -0
- data/lib/omnibus/git_cache.rb +3 -3
- data/lib/omnibus/instrumentation.rb +29 -0
- data/lib/omnibus/package.rb +98 -5
- data/lib/omnibus/packagers/base.rb +1 -0
- data/lib/omnibus/project.rb +5 -64
- data/lib/omnibus/publishers/artifactory_publisher.rb +4 -1
- data/lib/omnibus/software.rb +52 -29
- data/lib/omnibus/util.rb +11 -1
- data/lib/omnibus/version.rb +1 -1
- data/omnibus.gemspec +2 -3
- data/spec/data/complicated/config/software/libyaml-windows.rb +1 -1
- data/spec/functional/builder_spec.rb +305 -0
- data/spec/{functional → integration}/packagers/mac_spec.rb +0 -0
- data/spec/{functional → integration}/packagers/windows_spec.rb +0 -0
- data/spec/spec_helper.rb +8 -7
- data/spec/unit/build_version_dsl_spec.rb +77 -75
- data/spec/unit/build_version_spec.rb +4 -4
- data/spec/unit/builder_spec.rb +49 -0
- data/spec/unit/config_spec.rb +1 -1
- data/spec/unit/fetchers/git_fetcher_spec.rb +11 -11
- data/spec/unit/fetchers/net_fetcher_spec.rb +3 -5
- data/spec/unit/git_cache_spec.rb +2 -2
- data/spec/unit/package_spec.rb +118 -11
- data/spec/unit/packagers/base_spec.rb +17 -17
- data/spec/unit/packagers/mac_pkg_spec.rb +1 -1
- data/spec/unit/project_spec.rb +27 -101
- data/spec/unit/publisher_spec.rb +2 -2
- data/spec/unit/publishers/artifactory_publisher_spec.rb +8 -7
- data/spec/unit/publishers/s3_publisher_spec.rb +3 -3
- data/spec/unit/s3_cacher_spec.rb +2 -2
- data/spec/unit/software_spec.rb +26 -18
- metadata +27 -22
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 713b0a1bd3b7ac7ea05f5d7b40eb80824c24477e
|
|
4
|
+
data.tar.gz: b0d7e0927ed88cd196966be1891268e62a0ce5f7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8289bda18635035acc08431683e4444c24bf2759bdcbe15aa3c69537458c4c1d0718562e45faa789832b0710a5b96e75eb55be4910b4f17ecb3108287ed9ce9c
|
|
7
|
+
data.tar.gz: f524d6d38c6f328a408b2531c6eabd9853462c3b020a5e10de9b84bf3c5e3bb8d50318c04763bfcf8e69056e66ff768e7882a06c3896439f17e4dbd7560fdeff
|
data/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Omnibus Ruby CHANGELOG
|
|
2
2
|
======================
|
|
3
3
|
|
|
4
|
-
v3.2.0.rc.
|
|
5
|
-
|
|
4
|
+
v3.2.0.rc.2 (July 17, 2014)
|
|
5
|
+
---------------------------
|
|
6
6
|
- Make build commands output during `log.info` instead of `log.debug`
|
|
7
7
|
- Refactor Chef Sugar into an includable module, permitting DSL methods in both Software and Project definitions
|
|
8
8
|
- Refactor `omnibus release` into a non-S3-specific backend "publisher"
|
|
@@ -21,6 +21,8 @@ v3.2.0.rc.1 (July 14, 2014)
|
|
|
21
21
|
- Add publish APIs for dirtying the git cache
|
|
22
22
|
- Add test coverage for the "public" API
|
|
23
23
|
- Add validation to `source` in software DSL
|
|
24
|
+
- Add logging to the Packager class
|
|
25
|
+
- Add functional tests for builders
|
|
24
26
|
- Update generator templates to use the new APIs
|
|
25
27
|
- Upgrade to Ohai 7.2
|
|
26
28
|
- Improve YARDoc
|
|
@@ -40,11 +42,13 @@ v3.2.0.rc.1 (July 14, 2014)
|
|
|
40
42
|
- Deprecate `Project#install_path` in favor of `Project.install_dir`
|
|
41
43
|
- Deprecate [DSL] `install_path` in favor of `install_dir`
|
|
42
44
|
- Rename `Config.install_path_cache_dir` to `git_cache_dir`
|
|
45
|
+
- Fix a bug in the deprecations where a hardcoded output was used instead of a dynamic variable
|
|
43
46
|
|
|
44
47
|
### DSL Changes
|
|
45
48
|
- Add `with_embedded_path` to software
|
|
46
49
|
- Add `with_standard_compiler_flags` to software
|
|
47
50
|
- Add `package_scripts_path` to project
|
|
51
|
+
- Add builder DSL methods for `mkdir`, `touch`, `delete`, `copy`, `move`, and `link`
|
|
48
52
|
|
|
49
53
|
### Bug fixes
|
|
50
54
|
- Fix a small typo in the project generator (come -> some)
|
|
@@ -63,6 +67,9 @@ v3.2.0.rc.1 (July 14, 2014)
|
|
|
63
67
|
- Intelligently parse the project's homepage because Ruby's native URI implementation is buggy
|
|
64
68
|
- Fetch all software at the start of the build - this fixes a bug where a build would fail halfway through because of a tiny typo of GitHub outage. Now, all required software is downloaded **before** the build starts, lowering the feedback time for a failure due to networking issues
|
|
65
69
|
- Use the fetcher's `version_for_cache` method directly, falling back to `0.0.0` (and a warining) if no version is given
|
|
70
|
+
- Require `net/http`, `net/https`, and `net/ftp` in the base fetcher module
|
|
71
|
+
- Use -R, not -W1 on FreeBSD's compile flags
|
|
72
|
+
- Expand all paths relative to the project_root
|
|
66
73
|
|
|
67
74
|
### Potentially breaking changes
|
|
68
75
|
- Merged `Package` and `Artifact` into the same class and updated API - this was considered an **internal** API so it is not a violation of semver
|
|
@@ -70,6 +77,8 @@ v3.2.0.rc.1 (July 14, 2014)
|
|
|
70
77
|
- Use a cleanroom object when evaluating the DSL - prior to this release, Omnibus did not declare a public API. Project and software definitions had unrestricted access to the entire project.rb and software.rb methods respectively. This poses two problems - first, it makes it impossible to guarantee a public DSL API over a public (code) API. Second, it permits a developer to change the behavior of project.rb or software.rb accidentially, simply by defining a new method. The introducing of a cleanroom fixes both these bugs, however, it was impossible to know what was formerly considered a public API. Thus, it is possible that a previously-relied-on method is now unavaiable using the cleanroom. Please open an issue if you encounter such a case.
|
|
71
78
|
- Remove mixlib-config - if you were relying on mixlib-config as a transitive dependency, it is no longer available
|
|
72
79
|
- Remove the ability to use an overrides file - this was for internal use only and was never exposed as a public API. However, if you dug into the code and found it, it has now been removed. For BC purposes, the value still exists in the configuration object, but is essentially a no-op
|
|
80
|
+
- Move project loading from INFO to DEBUG
|
|
81
|
+
- Truncate platforms to short versions
|
|
73
82
|
|
|
74
83
|
|
|
75
84
|
v3.1.1 (May 20, 2014)
|
data/Rakefile
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require 'bundler/gem_tasks'
|
|
2
2
|
|
|
3
3
|
require 'rspec/core/rake_task'
|
|
4
|
-
[:unit, :functional].each do |type|
|
|
4
|
+
[:unit, :functional, :integration].each do |type|
|
|
5
5
|
RSpec::Core::RakeTask.new(type) do |t|
|
|
6
6
|
t.pattern = "spec/#{type}/**/*_spec.rb"
|
|
7
7
|
t.rspec_opts = [].tap do |a|
|
|
@@ -22,7 +22,7 @@ end
|
|
|
22
22
|
|
|
23
23
|
namespace :travis do
|
|
24
24
|
desc 'Run tests on Travis'
|
|
25
|
-
task ci: %w(unit acceptance)
|
|
25
|
+
task ci: %w(unit functional acceptance)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
task default: %w(travis:ci)
|
data/lib/omnibus.rb
CHANGED
|
@@ -40,6 +40,7 @@ module Omnibus
|
|
|
40
40
|
autoload :Generator, 'omnibus/generator'
|
|
41
41
|
autoload :GitCache, 'omnibus/git_cache'
|
|
42
42
|
autoload :HealthCheck, 'omnibus/health_check'
|
|
43
|
+
autoload :Instrumentation, 'omnibus/instrumentation'
|
|
43
44
|
autoload :Library, 'omnibus/library'
|
|
44
45
|
autoload :Logger, 'omnibus/logger'
|
|
45
46
|
autoload :Logging, 'omnibus/logging'
|
|
@@ -249,13 +250,15 @@ module Omnibus
|
|
|
249
250
|
# @return [Array<String>]
|
|
250
251
|
#
|
|
251
252
|
def software_dirs
|
|
253
|
+
return @software_dirs if @software_dirs
|
|
254
|
+
|
|
252
255
|
directories = [
|
|
253
256
|
paths_from_project_root,
|
|
254
257
|
paths_from_local_software_dirs,
|
|
255
258
|
paths_from_software_gems,
|
|
256
259
|
].flatten
|
|
257
260
|
|
|
258
|
-
directories.inject([]) do |array, directory|
|
|
261
|
+
@software_dirs = directories.inject([]) do |array, directory|
|
|
259
262
|
softwares_path = File.join(directory, Config.software_dir)
|
|
260
263
|
|
|
261
264
|
if File.directory?(softwares_path)
|
|
@@ -269,6 +272,8 @@ module Omnibus
|
|
|
269
272
|
|
|
270
273
|
array
|
|
271
274
|
end
|
|
275
|
+
|
|
276
|
+
@software_dirs
|
|
272
277
|
end
|
|
273
278
|
|
|
274
279
|
#
|
|
@@ -283,12 +288,14 @@ module Omnibus
|
|
|
283
288
|
# @return [Hash<String, String>]
|
|
284
289
|
#
|
|
285
290
|
def software_map
|
|
286
|
-
|
|
291
|
+
return @software_map if @software_map
|
|
292
|
+
|
|
293
|
+
@software_map = software_dirs.inject({}) do |hash, directory|
|
|
287
294
|
Dir.glob("#{directory}/*.rb").each do |path|
|
|
288
295
|
name = File.basename(path, '.rb')
|
|
289
296
|
|
|
290
297
|
if hash[name].nil?
|
|
291
|
-
Omnibus.logger.
|
|
298
|
+
Omnibus.logger.debug('Omnibus#software_map') do
|
|
292
299
|
"Using software `#{name}' from `#{path}'."
|
|
293
300
|
end
|
|
294
301
|
|
|
@@ -303,6 +310,8 @@ module Omnibus
|
|
|
303
310
|
|
|
304
311
|
hash
|
|
305
312
|
end
|
|
313
|
+
|
|
314
|
+
@software_map
|
|
306
315
|
end
|
|
307
316
|
|
|
308
317
|
private
|
|
@@ -323,7 +332,7 @@ module Omnibus
|
|
|
323
332
|
name = File.basename(path, '.rb')
|
|
324
333
|
|
|
325
334
|
if hash[name].nil?
|
|
326
|
-
Omnibus.logger.
|
|
335
|
+
Omnibus.logger.debug('Omnibus#projects') do
|
|
327
336
|
"Using project `#{name}' from `#{path}'."
|
|
328
337
|
end
|
|
329
338
|
|
data/lib/omnibus/builder.rb
CHANGED
|
@@ -14,178 +14,453 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
#
|
|
16
16
|
|
|
17
|
-
require '
|
|
17
|
+
require 'bundler'
|
|
18
|
+
require 'fileutils'
|
|
18
19
|
require 'ostruct'
|
|
20
|
+
require 'mixlib/shellout'
|
|
19
21
|
|
|
20
22
|
module Omnibus
|
|
21
23
|
class Builder
|
|
24
|
+
include Cleanroom
|
|
25
|
+
include Digestable
|
|
26
|
+
include Instrumentation
|
|
22
27
|
include Logging
|
|
28
|
+
include Util
|
|
23
29
|
|
|
24
|
-
#
|
|
25
|
-
# builder
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def_delegator :@builder, :command
|
|
34
|
-
def_delegator :@builder, :ruby
|
|
35
|
-
def_delegator :@builder, :gem
|
|
36
|
-
def_delegator :@builder, :bundle
|
|
37
|
-
def_delegator :@builder, :rake
|
|
38
|
-
def_delegator :@builder, :block
|
|
39
|
-
def_delegator :@builder, :name
|
|
40
|
-
def_delegator :@builder, :max_build_jobs
|
|
41
|
-
|
|
42
|
-
def initialize(builder, software)
|
|
43
|
-
@builder, @software = builder, software
|
|
30
|
+
#
|
|
31
|
+
# Since builder is also a proxy object to software, we dynamically re-define
|
|
32
|
+
# all the methods that exist on {Software} as proxy methhods here. This
|
|
33
|
+
# permits developers to use {Software} methods as if they were directly
|
|
34
|
+
# part of this DSL.
|
|
35
|
+
#
|
|
36
|
+
Software.exposed_methods.each do |name, _|
|
|
37
|
+
define_method(name) do |*args, &block|
|
|
38
|
+
software.send(name, *args, &block)
|
|
44
39
|
end
|
|
40
|
+
expose(name)
|
|
41
|
+
end
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
#
|
|
44
|
+
# @return [Software]
|
|
45
|
+
# the software definition that created this builder
|
|
46
|
+
#
|
|
47
|
+
attr_reader :software
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
#
|
|
50
|
+
# Create a new builder object for evaluation.
|
|
51
|
+
#
|
|
52
|
+
# @param [Software] software
|
|
53
|
+
# the software definition that created this builder
|
|
54
|
+
#
|
|
55
|
+
def initialize(software)
|
|
56
|
+
@software = software
|
|
57
|
+
end
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
#
|
|
60
|
+
# @!group System DSL methods
|
|
61
|
+
#
|
|
62
|
+
# The following DSL methods are available from within build blocks.
|
|
63
|
+
# --------------------------------------------------
|
|
57
64
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
#
|
|
66
|
+
# Execute the given command string or command arguments.
|
|
67
|
+
#
|
|
68
|
+
# @example
|
|
69
|
+
# command 'make install', env: { 'PATH' => '/my/custom/path' }
|
|
70
|
+
#
|
|
71
|
+
# @param [String] command
|
|
72
|
+
# the command to execute
|
|
73
|
+
# @param [Hash] options
|
|
74
|
+
# a list of options to pass to the +Mixlib::ShellOut+ instance when it is
|
|
75
|
+
# executed
|
|
76
|
+
#
|
|
77
|
+
# @return [void]
|
|
78
|
+
#
|
|
79
|
+
def command(command, options = {})
|
|
80
|
+
build_commands << BuildCommand.new("Execute: `#{command}'") do
|
|
81
|
+
_shellout!(command, options)
|
|
64
82
|
end
|
|
65
83
|
end
|
|
84
|
+
expose :command
|
|
66
85
|
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
86
|
+
#
|
|
87
|
+
# Apply the patch by the given name. This method will search all possible
|
|
88
|
+
# locations for a patch (such as {Config#software_gems}).
|
|
89
|
+
#
|
|
90
|
+
# @example
|
|
91
|
+
# patch source: 'ncurses-clang.patch'
|
|
92
|
+
#
|
|
93
|
+
# @example
|
|
94
|
+
# patch source: 'patch-ad', plevel: 0
|
|
95
|
+
#
|
|
96
|
+
# @param [Hash] options
|
|
97
|
+
# the list of options
|
|
98
|
+
#
|
|
99
|
+
# @option options [String] :source
|
|
100
|
+
# the name of the patch to apply
|
|
101
|
+
# @option options [Fixnum] :plevel
|
|
102
|
+
# the level to apply the patch
|
|
103
|
+
# @option options [String] :target
|
|
104
|
+
# the destination to apply the patch
|
|
105
|
+
#
|
|
106
|
+
# @return (see #command)
|
|
107
|
+
#
|
|
108
|
+
def patch(options = {})
|
|
109
|
+
source = options.delete(:source)
|
|
110
|
+
plevel = options.delete(:plevel) || 1
|
|
111
|
+
target = options.delete(:target)
|
|
74
112
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
113
|
+
locations, patch_path = find_file('config/patches', source)
|
|
114
|
+
|
|
115
|
+
unless patch_path
|
|
116
|
+
raise MissingPatch.new(source, locations)
|
|
78
117
|
end
|
|
79
118
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
119
|
+
# Apply patches nicely on Windows
|
|
120
|
+
patch_path = windows_safe_path(patch_path)
|
|
121
|
+
|
|
122
|
+
if target
|
|
123
|
+
command = "cat #{patch_path} | patch -p#{plevel} #{target}"
|
|
124
|
+
else
|
|
125
|
+
command = "patch -d #{software.project_dir} -p#{plevel} -i #{patch_path}"
|
|
87
126
|
end
|
|
88
127
|
|
|
89
|
-
|
|
128
|
+
patches << patch_path
|
|
90
129
|
|
|
91
|
-
|
|
92
|
-
|
|
130
|
+
build_commands << BuildCommand.new("Apply patch `#{source}'") do
|
|
131
|
+
_shellout!(command, options)
|
|
93
132
|
end
|
|
94
133
|
end
|
|
134
|
+
expose :patch
|
|
95
135
|
|
|
96
|
-
#
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
136
|
+
#
|
|
137
|
+
# The maximum number of build jobs, as computed from Ohai data. If the Ohai
|
|
138
|
+
# data is unavailable, +3+ is used.
|
|
139
|
+
#
|
|
140
|
+
# @todo Should this be moved to {Software}?
|
|
141
|
+
#
|
|
142
|
+
# @example
|
|
143
|
+
# command "make install -j#{max_build_jobs}"
|
|
144
|
+
#
|
|
145
|
+
# @return [Fixnum]
|
|
146
|
+
#
|
|
147
|
+
def max_build_jobs
|
|
148
|
+
if Ohai['cpu'] && Ohai['cpu']['total'] && Ohai['cpu']['total'].to_s =~ /^\d+$/
|
|
149
|
+
Ohai['cpu']['total'].to_i + 1
|
|
150
|
+
else
|
|
151
|
+
3
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
expose :max_build_jobs
|
|
104
155
|
|
|
105
|
-
|
|
156
|
+
#
|
|
157
|
+
# @!endgroup
|
|
158
|
+
# --------------------------------------------------
|
|
106
159
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
160
|
+
#
|
|
161
|
+
# @!group Ruby DSL methods
|
|
162
|
+
#
|
|
163
|
+
# The following DSL methods are available from within build blocks and
|
|
164
|
+
# expose Ruby DSL methods.
|
|
165
|
+
# --------------------------------------------------
|
|
113
166
|
|
|
114
|
-
|
|
115
|
-
|
|
167
|
+
#
|
|
168
|
+
# Execute the given Ruby command or script against the embedded Ruby.
|
|
169
|
+
#
|
|
170
|
+
# @example
|
|
171
|
+
# ruby 'setup.rb'
|
|
172
|
+
#
|
|
173
|
+
# @param (see #command)
|
|
174
|
+
# @return (see #command)
|
|
175
|
+
#
|
|
176
|
+
def ruby(command, options = {})
|
|
177
|
+
build_commands << BuildCommand.new("ruby `#{command}'") do
|
|
178
|
+
bin = windows_safe_path("#{install_dir}/embedded/bin/ruby")
|
|
179
|
+
_shellout!("#{bin} #{command}", options)
|
|
180
|
+
end
|
|
116
181
|
end
|
|
182
|
+
expose :ruby
|
|
117
183
|
|
|
118
|
-
|
|
119
|
-
|
|
184
|
+
#
|
|
185
|
+
# Execute the given Rubygem command against the embedded Rubygems.
|
|
186
|
+
#
|
|
187
|
+
# @example
|
|
188
|
+
# gem 'install chef'
|
|
189
|
+
#
|
|
190
|
+
# @param (see #command)
|
|
191
|
+
# @return (see #command)
|
|
192
|
+
#
|
|
193
|
+
def gem(command, options = {})
|
|
194
|
+
build_commands << BuildCommand.new("gem `#{command}'") do
|
|
195
|
+
bin = windows_safe_path("#{install_dir}/embedded/bin/gem")
|
|
196
|
+
_shellout!("#{bin} #{command}", options)
|
|
197
|
+
end
|
|
120
198
|
end
|
|
199
|
+
expose :gem
|
|
121
200
|
|
|
122
|
-
|
|
123
|
-
|
|
201
|
+
#
|
|
202
|
+
# Execute the given bundle command against the embedded Ruby's bundler. This
|
|
203
|
+
# command assumes the +bundler+ gem is installed and in the embedded Ruby.
|
|
204
|
+
# You should add a dependency on the +bundler+ software definition if you
|
|
205
|
+
# want to use this command.
|
|
206
|
+
#
|
|
207
|
+
# @example
|
|
208
|
+
# bundle 'install'
|
|
209
|
+
#
|
|
210
|
+
# @param (see #command)
|
|
211
|
+
# @return (see #command)
|
|
212
|
+
#
|
|
213
|
+
def bundle(command, options = {})
|
|
214
|
+
build_commands << BuildCommand.new("bundle `#{command}'") do
|
|
215
|
+
bin = windows_safe_path("#{install_dir}/embedded/bin/bundle")
|
|
216
|
+
_shellout!("#{bin} #{command}", options)
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
expose :bundle
|
|
124
220
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
221
|
+
#
|
|
222
|
+
# Execute the given Rake command against the embedded Ruby's rake. This
|
|
223
|
+
# command assumes the +rake+ gem has been installed.
|
|
224
|
+
#
|
|
225
|
+
# @example
|
|
226
|
+
# rake 'test'
|
|
227
|
+
#
|
|
228
|
+
# @param (see #command)
|
|
229
|
+
# @return (see #command)
|
|
230
|
+
#
|
|
231
|
+
def rake(command, options = {})
|
|
232
|
+
build_commands << BuildCommand.new("rake `#{command}'") do
|
|
233
|
+
bin = windows_safe_path("#{install_dir}/embedded/bin/rake")
|
|
234
|
+
_shellout!("#{bin} #{command}", options)
|
|
129
235
|
end
|
|
236
|
+
end
|
|
237
|
+
expose :rake
|
|
238
|
+
|
|
239
|
+
#
|
|
240
|
+
# Execute the given Ruby block at runtime. The block is captured as-is and
|
|
241
|
+
# no validation is performed. As a general rule, you should avoid this
|
|
242
|
+
# method unless you know what you are doing.
|
|
243
|
+
#
|
|
244
|
+
# TODO: the "name" does nothing right now
|
|
245
|
+
#
|
|
246
|
+
# @example
|
|
247
|
+
# block do
|
|
248
|
+
# # Some complex operation
|
|
249
|
+
# end
|
|
250
|
+
#
|
|
251
|
+
# @example
|
|
252
|
+
# block 'Named operation' do
|
|
253
|
+
# # The above name can be used in log output to identify the operation
|
|
254
|
+
# end
|
|
255
|
+
#
|
|
256
|
+
# @param (see #command)
|
|
257
|
+
# @return (see #command)
|
|
258
|
+
#
|
|
259
|
+
def block(name = '<Dynamic Ruby block>', &proc)
|
|
260
|
+
build_commands << BuildCommand.new(name, &proc)
|
|
261
|
+
end
|
|
262
|
+
expose :block
|
|
263
|
+
|
|
264
|
+
#
|
|
265
|
+
# Render the erb template by the given name. This method will search all
|
|
266
|
+
# possible locations for an erb template (such as {Config#software_gems}).
|
|
267
|
+
#
|
|
268
|
+
# @example
|
|
269
|
+
# erb source: 'example.erb',
|
|
270
|
+
# dest: '/path/on/disk/to/render'
|
|
271
|
+
#
|
|
272
|
+
# @example
|
|
273
|
+
# erb source: 'example.erb',
|
|
274
|
+
# dest: '/path/on/disk/to/render',
|
|
275
|
+
# vars: { foo: 'bar' },
|
|
276
|
+
# mode: '0755'
|
|
277
|
+
#
|
|
278
|
+
# @param [Hash] options
|
|
279
|
+
# the list of options
|
|
280
|
+
#
|
|
281
|
+
# @option options [String] :source
|
|
282
|
+
# the name of the patch to apply
|
|
283
|
+
# @option options [String] :dest
|
|
284
|
+
# the path on disk where the erb should be rendered
|
|
285
|
+
# @option options [Hash] :vars
|
|
286
|
+
# the list of variables to pass to the ERB rendering
|
|
287
|
+
# @option options [String] :mode
|
|
288
|
+
# the file mode for the rendered template (default varies by system)
|
|
289
|
+
#
|
|
290
|
+
# @return (see #command)
|
|
291
|
+
#
|
|
292
|
+
def erb(options = {})
|
|
293
|
+
source = options.delete(:source)
|
|
294
|
+
dest = options.delete(:dest)
|
|
295
|
+
mode = options.delete(:mode) || 0644
|
|
296
|
+
vars = options.delete(:vars) || {}
|
|
297
|
+
|
|
298
|
+
raise "Missing required option `:source'!" unless source
|
|
299
|
+
raise "Missing required option `:dest'!" unless dest
|
|
130
300
|
|
|
131
|
-
|
|
301
|
+
locations, source_path = find_file('config/templates', source)
|
|
132
302
|
|
|
133
|
-
unless
|
|
134
|
-
raise
|
|
303
|
+
unless source_path
|
|
304
|
+
raise MissingTemplate.new(source, locations)
|
|
135
305
|
end
|
|
136
306
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
307
|
+
erbs << source_path
|
|
308
|
+
|
|
309
|
+
block "Render erb `#{source}'" do
|
|
310
|
+
template = ERB.new(File.read(source_path), nil, '%')
|
|
311
|
+
struct = OpenStruct.new(vars)
|
|
312
|
+
result = template.result(struct.instance_eval { binding })
|
|
313
|
+
|
|
314
|
+
File.open(dest, 'w') do |file|
|
|
315
|
+
file.write(result)
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
File.chmod(mode, dest)
|
|
145
319
|
end
|
|
146
320
|
end
|
|
321
|
+
expose :erb
|
|
147
322
|
|
|
148
|
-
|
|
149
|
-
|
|
323
|
+
#
|
|
324
|
+
# @!endgroup
|
|
325
|
+
# --------------------------------------------------
|
|
150
326
|
|
|
151
|
-
|
|
327
|
+
#
|
|
328
|
+
# @!group File system DSL methods
|
|
329
|
+
#
|
|
330
|
+
# The following DSL methods are available from within build blocks that
|
|
331
|
+
# mutate the file system.
|
|
332
|
+
#
|
|
333
|
+
# **These commands are run from inside {Software#install_dir}, so exercise
|
|
334
|
+
# good judgement when using relative paths!**
|
|
335
|
+
# --------------------------------------------------
|
|
152
336
|
|
|
153
|
-
|
|
154
|
-
|
|
337
|
+
#
|
|
338
|
+
# Make a directory at runtime. This method uses the equivalent of +mkdir -p+
|
|
339
|
+
# under the covers.
|
|
340
|
+
#
|
|
341
|
+
# @param [String] directory
|
|
342
|
+
# the name or path of the directory to create
|
|
343
|
+
# @param [Hash] options
|
|
344
|
+
# the list of options to pass to the underlying +FileUtils+ call
|
|
345
|
+
#
|
|
346
|
+
# @return (see #command)
|
|
347
|
+
#
|
|
348
|
+
def mkdir(directory, options = {})
|
|
349
|
+
build_commands << BuildCommand.new("mkdir `#{directory}'") do
|
|
350
|
+
Dir.chdir(software.install_dir) do
|
|
351
|
+
FileUtils.mkdir_p(directory, options)
|
|
352
|
+
end
|
|
155
353
|
end
|
|
354
|
+
end
|
|
355
|
+
expose :mkdir
|
|
156
356
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
357
|
+
#
|
|
358
|
+
# Touch the given filepath at runtime.
|
|
359
|
+
#
|
|
360
|
+
# @param [String] file
|
|
361
|
+
# the path of the file to touch
|
|
362
|
+
# @param (see #mkdir)
|
|
363
|
+
#
|
|
364
|
+
# @return (see #command)
|
|
365
|
+
#
|
|
366
|
+
def touch(file, options = {})
|
|
367
|
+
build_commands << BuildCommand.new("touch `#{file}'") do
|
|
368
|
+
Dir.chdir(software.install_dir) do
|
|
369
|
+
FileUtils.touch(file, options)
|
|
161
370
|
end
|
|
162
|
-
|
|
163
|
-
File.chmod(args[:mode], args[:dest])
|
|
164
371
|
end
|
|
165
372
|
end
|
|
373
|
+
expose :touch
|
|
166
374
|
|
|
167
|
-
#
|
|
168
|
-
#
|
|
169
|
-
#
|
|
170
|
-
|
|
171
|
-
|
|
375
|
+
#
|
|
376
|
+
# Delete the given file or directory on the system. This method uses the
|
|
377
|
+
# equivalent of +rm -rf+.
|
|
378
|
+
#
|
|
379
|
+
# @param [String] path
|
|
380
|
+
# the path of the file to delete
|
|
381
|
+
# @param (see #mkdir)
|
|
382
|
+
#
|
|
383
|
+
# @return (see #command)
|
|
384
|
+
#
|
|
385
|
+
def delete(path, options = {})
|
|
386
|
+
build_commands << BuildCommand.new("delete `#{path}'") do
|
|
387
|
+
Dir.chdir(software.install_dir) do
|
|
388
|
+
FileUtils.rm_rf(path, options)
|
|
389
|
+
end
|
|
390
|
+
end
|
|
172
391
|
end
|
|
392
|
+
expose :delete
|
|
173
393
|
|
|
174
|
-
|
|
175
|
-
|
|
394
|
+
#
|
|
395
|
+
# Copy the given source to the destination.
|
|
396
|
+
#
|
|
397
|
+
# @param [String] source
|
|
398
|
+
# the path on disk to copy from
|
|
399
|
+
# @param [String] destination
|
|
400
|
+
# the path on disk to copy to
|
|
401
|
+
# @param (see #mkdir)
|
|
402
|
+
#
|
|
403
|
+
# @return (see #command)
|
|
404
|
+
#
|
|
405
|
+
def copy(source, destination, options = {})
|
|
406
|
+
build_commands << BuildCommand.new("copy `#{source}' to `#{destination}'") do
|
|
407
|
+
Dir.chdir(software.install_dir) do
|
|
408
|
+
FileUtils.cp_r(source, destination, options)
|
|
409
|
+
end
|
|
410
|
+
end
|
|
176
411
|
end
|
|
412
|
+
expose :copy
|
|
177
413
|
|
|
178
|
-
|
|
179
|
-
|
|
414
|
+
#
|
|
415
|
+
# Copy the given source to the destination.
|
|
416
|
+
#
|
|
417
|
+
# @param [String] source
|
|
418
|
+
# the path on disk to move from
|
|
419
|
+
# @param [String] destination
|
|
420
|
+
# the path on disk to move to
|
|
421
|
+
# @param (see #mkdir)
|
|
422
|
+
#
|
|
423
|
+
# @return (see #command)
|
|
424
|
+
#
|
|
425
|
+
def move(source, destination, options = {})
|
|
426
|
+
build_commands << BuildCommand.new("move `#{source}' to `#{destination}'") do
|
|
427
|
+
Dir.chdir(software.install_dir) do
|
|
428
|
+
FileUtils.mv(source, destination, options)
|
|
429
|
+
end
|
|
430
|
+
end
|
|
180
431
|
end
|
|
432
|
+
expose :move
|
|
181
433
|
|
|
182
|
-
|
|
183
|
-
|
|
434
|
+
#
|
|
435
|
+
# Link the given source to the destination.
|
|
436
|
+
#
|
|
437
|
+
# @param [String] source
|
|
438
|
+
# the path on disk to link from
|
|
439
|
+
# @param [String] destination
|
|
440
|
+
# the path on disk to link to
|
|
441
|
+
# @param (see #mkdir)
|
|
442
|
+
#
|
|
443
|
+
# @return (see #command)
|
|
444
|
+
#
|
|
445
|
+
def link(source, destination, options = {})
|
|
446
|
+
build_commands << BuildCommand.new("link `#{source}' to `#{destination}'") do
|
|
447
|
+
Dir.chdir(software.install_dir) do
|
|
448
|
+
FileUtils.ln_s(source, destination, options)
|
|
449
|
+
end
|
|
450
|
+
end
|
|
184
451
|
end
|
|
452
|
+
expose :link
|
|
185
453
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
454
|
+
#
|
|
455
|
+
# @!endgroup
|
|
456
|
+
# --------------------------------------------------
|
|
457
|
+
|
|
458
|
+
#
|
|
459
|
+
# @!group Deprecated DSL methods
|
|
460
|
+
#
|
|
461
|
+
# The following DSL methods are available from within build blocks, but are
|
|
462
|
+
# deprecated and will be removed in the next major release.
|
|
463
|
+
# --------------------------------------------------
|
|
189
464
|
|
|
190
465
|
#
|
|
191
466
|
# @deprecated Use {Config.project_root} instead
|
|
@@ -197,177 +472,250 @@ module Omnibus
|
|
|
197
472
|
|
|
198
473
|
Config.project_root
|
|
199
474
|
end
|
|
475
|
+
expose :project_root
|
|
200
476
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
477
|
+
#
|
|
478
|
+
# @!endgroup
|
|
479
|
+
# --------------------------------------------------
|
|
204
480
|
|
|
205
481
|
#
|
|
206
|
-
#
|
|
482
|
+
# @!group Public API
|
|
207
483
|
#
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
install_dir
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
def install_dir
|
|
217
|
-
@software.install_dir
|
|
218
|
-
end
|
|
484
|
+
# The following methods are considered part of the public API for a
|
|
485
|
+
# builder. All DSL methods are also considered part of the public API.
|
|
486
|
+
# --------------------------------------------------
|
|
219
487
|
|
|
488
|
+
#
|
|
489
|
+
# Execute all the {BuildCommand} instances, in order, for this builder.
|
|
490
|
+
#
|
|
491
|
+
# @return [void]
|
|
492
|
+
#
|
|
220
493
|
def build
|
|
221
|
-
log.info(log_key) { 'Starting
|
|
494
|
+
log.info(log_key) { 'Starting build' }
|
|
222
495
|
|
|
223
|
-
if
|
|
496
|
+
if software.overridden?
|
|
224
497
|
log.info(log_key) do
|
|
225
|
-
"Version overridden from #{
|
|
226
|
-
"#{
|
|
498
|
+
"Version overridden from #{software.default_version} to "\
|
|
499
|
+
"#{software.version}"
|
|
227
500
|
end
|
|
228
501
|
end
|
|
229
502
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
execute(
|
|
503
|
+
measure("Build #{software.name}") do
|
|
504
|
+
build_commands.each do |command|
|
|
505
|
+
execute(command)
|
|
233
506
|
end
|
|
234
507
|
end
|
|
235
|
-
end
|
|
236
508
|
|
|
237
|
-
|
|
238
|
-
case cmd
|
|
239
|
-
when Proc
|
|
240
|
-
execute_proc(cmd)
|
|
241
|
-
else
|
|
242
|
-
execute_sh(cmd)
|
|
243
|
-
end
|
|
509
|
+
log.info(log_key) { 'Finished build' }
|
|
244
510
|
end
|
|
245
511
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
512
|
+
#
|
|
513
|
+
# The shasum for this builder object. The shasum is calculated using the
|
|
514
|
+
# following:
|
|
515
|
+
#
|
|
516
|
+
# - The descriptions of all {BuildCommand} objects
|
|
517
|
+
# - The digest of all patch files on disk
|
|
518
|
+
# - The digest of all erb files on disk
|
|
519
|
+
#
|
|
520
|
+
# @return [String]
|
|
521
|
+
#
|
|
522
|
+
def shasum
|
|
523
|
+
@shasum ||= begin
|
|
524
|
+
digest = Digest::SHA256.new
|
|
525
|
+
|
|
526
|
+
build_commands.each do |build_command|
|
|
527
|
+
update_with_string(digest, build_command.description)
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
patches.each do |patch_path|
|
|
531
|
+
update_with_file_contents(digest, patch_path)
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
erbs.each do |erb_path|
|
|
535
|
+
update_with_file_contents(digest, erb_path)
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
digest.hexdigest
|
|
251
539
|
end
|
|
252
540
|
end
|
|
253
541
|
|
|
542
|
+
#
|
|
543
|
+
# @!endgroup
|
|
544
|
+
# --------------------------------------------------
|
|
545
|
+
|
|
254
546
|
private
|
|
255
547
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
548
|
+
#
|
|
549
|
+
# The **in-order** list of {BuildCommand} for this builder.
|
|
550
|
+
#
|
|
551
|
+
# @return [Array<BuildCommand>]
|
|
552
|
+
#
|
|
553
|
+
def build_commands
|
|
554
|
+
@build_commands ||= []
|
|
263
555
|
end
|
|
264
556
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if cmd_args.last.is_a? Hash
|
|
275
|
-
cmd_options = cmd_args.last
|
|
276
|
-
cmd_args[cmd_args.size - 1] = options.merge(cmd_options)
|
|
277
|
-
else
|
|
278
|
-
cmd_args << options
|
|
279
|
-
end
|
|
557
|
+
#
|
|
558
|
+
# The list of paths to patch files on disk. This is used in the calculation
|
|
559
|
+
# of the shasum.
|
|
560
|
+
#
|
|
561
|
+
# @return [Array<String>]
|
|
562
|
+
#
|
|
563
|
+
def patches
|
|
564
|
+
@patches ||= []
|
|
565
|
+
end
|
|
280
566
|
|
|
281
|
-
|
|
282
|
-
|
|
567
|
+
#
|
|
568
|
+
# The list of paths to erb files on disk. This is used in the calculation
|
|
569
|
+
# of the shasum.
|
|
570
|
+
#
|
|
571
|
+
# @return [Array<String>]
|
|
572
|
+
#
|
|
573
|
+
def erbs
|
|
574
|
+
@erbs ||= []
|
|
575
|
+
end
|
|
283
576
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
577
|
+
#
|
|
578
|
+
# This is a helper method that wraps {Util#shellout!} for the purposes of
|
|
579
|
+
# setting the +:cwd+ value.
|
|
580
|
+
#
|
|
581
|
+
# @see (Util#shellout!)
|
|
582
|
+
#
|
|
583
|
+
def _shellout!(command_string, options = {})
|
|
584
|
+
# Make sure the PWD is set to the correct directory
|
|
585
|
+
options = { cwd: software.project_dir }.merge(options)
|
|
287
586
|
|
|
288
|
-
|
|
289
|
-
|
|
587
|
+
# Use Util's shellout
|
|
588
|
+
shellout!(command_string, options)
|
|
589
|
+
end
|
|
290
590
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
"Failed to execute cmd `#{cmd}` #{retries} time(s). " \
|
|
309
|
-
"Retrying in #{time_to_sleep}s."
|
|
591
|
+
#
|
|
592
|
+
# Execute the given command object. This method also wraps the following
|
|
593
|
+
# operations:
|
|
594
|
+
#
|
|
595
|
+
# - Reset bundler's environment using +Bundler.with_clean_env+
|
|
596
|
+
# - Instrument (time/measure) the individual command's execution
|
|
597
|
+
# - Retry failed commands in accordance with {Config#build_retries}
|
|
598
|
+
#
|
|
599
|
+
# @param [BuildCommand] command
|
|
600
|
+
# the command object to build
|
|
601
|
+
#
|
|
602
|
+
def execute(command)
|
|
603
|
+
Bundler.with_clean_env do
|
|
604
|
+
measure(command.description) do
|
|
605
|
+
with_retries do
|
|
606
|
+
command.run(self)
|
|
607
|
+
end
|
|
310
608
|
end
|
|
311
|
-
sleep(time_to_sleep)
|
|
312
|
-
retry
|
|
313
609
|
end
|
|
314
610
|
end
|
|
315
611
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
612
|
+
#
|
|
613
|
+
# Execute the given block with (n) reties defined by {Config#build_retries}.
|
|
614
|
+
# This method will only retry for the following exceptions:
|
|
615
|
+
#
|
|
616
|
+
# - +Mixlib::ShellOut::ShellCommandFailed+
|
|
617
|
+
# - +Mixlib::ShellOut::CommandTimeout+
|
|
618
|
+
#
|
|
619
|
+
# @param [Proc] block
|
|
620
|
+
# the block to execute
|
|
621
|
+
#
|
|
622
|
+
def with_retries(&block)
|
|
623
|
+
tries = Config.build_retries
|
|
624
|
+
delay = 5
|
|
625
|
+
exceptions = [
|
|
626
|
+
Mixlib::ShellOut::ShellCommandFailed,
|
|
627
|
+
Mixlib::ShellOut::CommandTimeout,
|
|
628
|
+
]
|
|
629
|
+
|
|
630
|
+
begin
|
|
631
|
+
block.call
|
|
632
|
+
rescue *exceptions => e
|
|
633
|
+
if tries <= 0
|
|
634
|
+
raise e
|
|
635
|
+
else
|
|
636
|
+
delay = delay * 2
|
|
637
|
+
|
|
638
|
+
log.warn(log_key) do
|
|
639
|
+
label = "#{(Config.build_retries - tries) + 1}/#{Config.build_retries}"
|
|
640
|
+
"[#{label}] Failed to execute command. Retrying in #{delay} seconds..."
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
sleep(delay)
|
|
644
|
+
tries -= 1
|
|
645
|
+
retry
|
|
646
|
+
end
|
|
328
647
|
end
|
|
329
648
|
end
|
|
330
649
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
650
|
+
#
|
|
651
|
+
# Find a file amonst all local files, "remote" local files, and
|
|
652
|
+
# {Config#software_gems}.
|
|
653
|
+
#
|
|
654
|
+
# @param [String] path
|
|
655
|
+
# the path to find the file
|
|
656
|
+
# @param [String] source
|
|
657
|
+
# the source name of the file to find
|
|
658
|
+
#
|
|
659
|
+
# @return [Array<Array<String>, String, nil>]
|
|
660
|
+
# an array where the first entry is the list of candidate paths searched,
|
|
661
|
+
# and the second entry is the first occurence of the matched file (or
|
|
662
|
+
# +nil+) if one does not exist.
|
|
663
|
+
#
|
|
664
|
+
def find_file(path, source)
|
|
665
|
+
# Search for patches just like we search for software
|
|
666
|
+
candidate_paths = Omnibus.software_dirs.map do |directory|
|
|
667
|
+
full_path = directory.sub(Config.software_dir, path)
|
|
668
|
+
"#{full_path}/#{software.name}/#{source}"
|
|
339
669
|
end
|
|
340
|
-
end
|
|
341
670
|
|
|
342
|
-
|
|
343
|
-
start = Time.now
|
|
344
|
-
yield
|
|
345
|
-
rescue Exception
|
|
346
|
-
elapsed = Time.now - start
|
|
347
|
-
log.warn(log_key) { "#{what} failed! (#{elapsed.to_f}s)" }
|
|
348
|
-
raise
|
|
349
|
-
else
|
|
350
|
-
elapsed = Time.now - start
|
|
351
|
-
log.info(log_key) { "#{what} succeeded! (#{elapsed.to_f}s)" }
|
|
352
|
-
end
|
|
671
|
+
file = candidate_paths.find { |path| File.exist?(path) }
|
|
353
672
|
|
|
354
|
-
|
|
355
|
-
# whatever input is given but is designed to make the options to ShellOut
|
|
356
|
-
# look nice.
|
|
357
|
-
def to_kv_str(hash, join_str = ',')
|
|
358
|
-
hash.reduce([]) do |kv_pair_strs, (k, v)|
|
|
359
|
-
val_str = case v
|
|
360
|
-
when Hash
|
|
361
|
-
%Q("#{to_kv_str(v, " ") }")
|
|
362
|
-
else
|
|
363
|
-
v.to_s
|
|
364
|
-
end
|
|
365
|
-
kv_pair_strs << "#{k}=#{val_str}"
|
|
366
|
-
end.join(join_str)
|
|
673
|
+
[candidate_paths, file]
|
|
367
674
|
end
|
|
368
675
|
|
|
676
|
+
#
|
|
677
|
+
# The log key for this class, overriden to incorporate the software name.
|
|
678
|
+
#
|
|
679
|
+
# @return [String]
|
|
680
|
+
#
|
|
369
681
|
def log_key
|
|
370
|
-
@log_key ||= "#{super}: #{name}"
|
|
682
|
+
@log_key ||= "#{super}: #{software.name}"
|
|
683
|
+
end
|
|
684
|
+
|
|
685
|
+
#
|
|
686
|
+
# This is an internal wrapper around a command executed on the system. The
|
|
687
|
+
# block could contain a Ruby command (such as +FileUtils.rm_rf('/')+), or it
|
|
688
|
+
# could contain a call to shell out to the system.
|
|
689
|
+
#
|
|
690
|
+
class BuildCommand
|
|
691
|
+
attr_reader :description
|
|
692
|
+
|
|
693
|
+
#
|
|
694
|
+
# Create a new BuildCommand object.
|
|
695
|
+
#
|
|
696
|
+
# @param [String] description
|
|
697
|
+
# a unique identifier for this build command - it will be used for
|
|
698
|
+
# logging and timing labels
|
|
699
|
+
# @param [Proc] block
|
|
700
|
+
# the block to capture
|
|
701
|
+
#
|
|
702
|
+
def initialize(description, &block)
|
|
703
|
+
@description, @block = description, block
|
|
704
|
+
end
|
|
705
|
+
|
|
706
|
+
#
|
|
707
|
+
# Execute the build command against the given object. Because BuildCommand
|
|
708
|
+
# objects could reference internal DSL methods, this method requires you
|
|
709
|
+
# pass in an object against which to +instance_eval+ the block. Otherwise,
|
|
710
|
+
# you would be severly restricted in the commands avaiable to you via the
|
|
711
|
+
# DSL.
|
|
712
|
+
#
|
|
713
|
+
# @param [Builder] builder
|
|
714
|
+
# the builder to +instance_eval+ against
|
|
715
|
+
#
|
|
716
|
+
def run(builder)
|
|
717
|
+
builder.instance_eval(&@block)
|
|
718
|
+
end
|
|
371
719
|
end
|
|
372
720
|
end
|
|
373
721
|
end
|