omnibus-sonian 1.2.0.1
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 +15 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.travis.yml +5 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +96 -0
- data/Gemfile +9 -0
- data/LICENSE +201 -0
- data/NOTICE +9 -0
- data/README.md +195 -0
- data/Rakefile +7 -0
- data/bin/makeself-header.sh +401 -0
- data/bin/makeself.sh +407 -0
- data/bin/omnibus +11 -0
- data/lib/omnibus.rb +304 -0
- data/lib/omnibus/artifact.rb +151 -0
- data/lib/omnibus/build_version.rb +285 -0
- data/lib/omnibus/builder.rb +328 -0
- data/lib/omnibus/clean_tasks.rb +30 -0
- data/lib/omnibus/cli.rb +35 -0
- data/lib/omnibus/cli/application.rb +140 -0
- data/lib/omnibus/cli/base.rb +118 -0
- data/lib/omnibus/cli/build.rb +62 -0
- data/lib/omnibus/cli/cache.rb +60 -0
- data/lib/omnibus/cli/release.rb +49 -0
- data/lib/omnibus/config.rb +224 -0
- data/lib/omnibus/exceptions.rb +143 -0
- data/lib/omnibus/fetcher.rb +184 -0
- data/lib/omnibus/fetchers.rb +22 -0
- data/lib/omnibus/fetchers/git_fetcher.rb +212 -0
- data/lib/omnibus/fetchers/net_fetcher.rb +193 -0
- data/lib/omnibus/fetchers/path_fetcher.rb +65 -0
- data/lib/omnibus/fetchers/s3_cache_fetcher.rb +42 -0
- data/lib/omnibus/health_check.rb +356 -0
- data/lib/omnibus/library.rb +62 -0
- data/lib/omnibus/overrides.rb +69 -0
- data/lib/omnibus/package_release.rb +163 -0
- data/lib/omnibus/project.rb +715 -0
- data/lib/omnibus/reports.rb +99 -0
- data/lib/omnibus/s3_cacher.rb +138 -0
- data/lib/omnibus/software.rb +441 -0
- data/lib/omnibus/templates/Berksfile.erb +3 -0
- data/lib/omnibus/templates/Gemfile.erb +4 -0
- data/lib/omnibus/templates/README.md.erb +102 -0
- data/lib/omnibus/templates/Vagrantfile.erb +95 -0
- data/lib/omnibus/templates/gitignore.erb +8 -0
- data/lib/omnibus/templates/omnibus.rb.example.erb +5 -0
- data/lib/omnibus/templates/package_scripts/makeselfinst.erb +27 -0
- data/lib/omnibus/templates/package_scripts/postinst.erb +17 -0
- data/lib/omnibus/templates/package_scripts/postrm.erb +9 -0
- data/lib/omnibus/templates/project.rb.erb +21 -0
- data/lib/omnibus/templates/software/c-example.rb.erb +42 -0
- data/lib/omnibus/templates/software/erlang-example.rb.erb +38 -0
- data/lib/omnibus/templates/software/ruby-example.rb.erb +24 -0
- data/lib/omnibus/util.rb +61 -0
- data/lib/omnibus/version.rb +20 -0
- data/omnibus.gemspec +34 -0
- data/spec/artifact_spec.rb +106 -0
- data/spec/build_version_spec.rb +266 -0
- data/spec/data/overrides/bad_line.overrides +3 -0
- data/spec/data/overrides/good.overrides +5 -0
- data/spec/data/overrides/with_dupes.overrides +4 -0
- data/spec/data/software/erchef.rb +40 -0
- data/spec/fetchers/net_fetcher_spec.rb +16 -0
- data/spec/overrides_spec.rb +114 -0
- data/spec/package_release_spec.rb +197 -0
- data/spec/s3_cacher_spec.rb +47 -0
- data/spec/software_spec.rb +85 -0
- data/spec/spec_helper.rb +28 -0
- metadata +252 -0
@@ -0,0 +1,285 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright (c) 2012 Opscode, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# 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,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require 'time'
|
19
|
+
require 'omnibus/util'
|
20
|
+
|
21
|
+
module Omnibus
|
22
|
+
|
23
|
+
# Provides methods for generating Omnibus project build version
|
24
|
+
# strings automatically from Git repository information.
|
25
|
+
#
|
26
|
+
# @see Omnibus::Project#build_version
|
27
|
+
#
|
28
|
+
# @note Requires a Git repository
|
29
|
+
# @todo Add class method shortcuts for semver and git_describe
|
30
|
+
# versions e.g., Omnibus::BuildVersion.semver.
|
31
|
+
# @todo Rename this class to reflect its absolute dependence on running in a
|
32
|
+
# Git repository.
|
33
|
+
class BuildVersion
|
34
|
+
include Omnibus::Util
|
35
|
+
|
36
|
+
# Formatting string for the timestamp component of our SemVer build specifier.
|
37
|
+
#
|
38
|
+
# @see Omnibus::BuildVersion#semver
|
39
|
+
# @see Time#strftime
|
40
|
+
TIMESTAMP_FORMAT = "%Y%m%d%H%M%S"
|
41
|
+
|
42
|
+
# @deprecated Use {#semver} or {#git_describe} instead
|
43
|
+
def self.full
|
44
|
+
puts "#{self.name}.full is deprecated. Use #{self.name}.new.semver or #{self.name}.new.git_describe."
|
45
|
+
Omnibus::BuildVersion.new.git_describe
|
46
|
+
end
|
47
|
+
|
48
|
+
# Create a new BuildVersion
|
49
|
+
#
|
50
|
+
# @param [String] path Path from which to read git version information
|
51
|
+
def initialize(path=Omnibus.root)
|
52
|
+
@path = path
|
53
|
+
end
|
54
|
+
|
55
|
+
# @!group Version Generator Methods
|
56
|
+
|
57
|
+
# Generate a {http://semver.org/ SemVer 2.0.0-rc.1 compliant}
|
58
|
+
# version string for an Omnibus project.
|
59
|
+
#
|
60
|
+
# This relies on the Omnibus project being a Git repository, as
|
61
|
+
# well as having tags named according to SemVer conventions
|
62
|
+
# (specifically, the `MAJOR.MINOR.PATCH-PRERELEASE` aspects)
|
63
|
+
#
|
64
|
+
# The specific format of the version string is:
|
65
|
+
#
|
66
|
+
# MAJOR.MINOR.PATCH-PRERELEASE+TIMESTAMP.git.COMMITS_SINCE.GIT_SHA
|
67
|
+
#
|
68
|
+
# By default, a timestamp is incorporated into the build component
|
69
|
+
# of version string (see
|
70
|
+
# {Omnibus::BuildVersion::TIMESTAMP_FORMAT}). This can be
|
71
|
+
# disabled by setting the environment variable
|
72
|
+
# `OMNIBUS_APPEND_TIMESTAMP` to a "falsey" value (e.g. "false",
|
73
|
+
# "f", "no", "n", "0")
|
74
|
+
#
|
75
|
+
# @example 11.0.0-alpha.1+20121218164140.git.207.694b062
|
76
|
+
# @return [String]
|
77
|
+
# @see #git_describe
|
78
|
+
# @todo Issue a warning or throw an exception if the tags of the
|
79
|
+
# repository are not themselves SemVer-compliant?
|
80
|
+
# @todo Consider making the {#build_start_time} method public, as
|
81
|
+
# its function influences how build timestamps are generated,
|
82
|
+
# and can be influenced by users.
|
83
|
+
def semver
|
84
|
+
build_tag = version_tag
|
85
|
+
|
86
|
+
# PRERELEASE VERSION
|
87
|
+
if prerelease_version?
|
88
|
+
# ensure all dashes are dots per precedence rules (#12) in Semver
|
89
|
+
# 2.0.0-rc.1
|
90
|
+
prerelease = prerelease_tag.gsub("-", ".")
|
91
|
+
build_tag << "-" << prerelease
|
92
|
+
end
|
93
|
+
|
94
|
+
# BUILD VERSION
|
95
|
+
# Follows SemVer conventions and the build version begins with a '+'.
|
96
|
+
build_version_items = []
|
97
|
+
|
98
|
+
# By default we will append a timestamp to every build. This behavior can
|
99
|
+
# be overriden by setting the OMNIBUS_APPEND_TIMESTAMP environment
|
100
|
+
# variable to a 'falsey' value (ie false, f, no, n or 0).
|
101
|
+
#
|
102
|
+
# format: YYYYMMDDHHMMSS example: 20130131123345
|
103
|
+
build_version_items << build_start_time.strftime(TIMESTAMP_FORMAT) if append_timestamp?
|
104
|
+
|
105
|
+
# We'll append the git describe information unless we are sitting right
|
106
|
+
# on an annotated tag.
|
107
|
+
#
|
108
|
+
# format: git.COMMITS_SINCE_TAG.GIT_SHA example: git.207.694b062
|
109
|
+
unless commits_since_tag == 0
|
110
|
+
build_version_items << ["git", commits_since_tag, git_sha_tag].join(".")
|
111
|
+
end
|
112
|
+
|
113
|
+
unless build_version_items.empty?
|
114
|
+
build_tag << "+" << build_version_items.join(".")
|
115
|
+
end
|
116
|
+
|
117
|
+
build_tag
|
118
|
+
end
|
119
|
+
|
120
|
+
# Generates a version string by running
|
121
|
+
# {https://www.kernel.org/pub/software/scm/git/docs/git-describe.html
|
122
|
+
# git describe} in the root of the Omnibus project.
|
123
|
+
#
|
124
|
+
# Produces a version string of the format
|
125
|
+
#
|
126
|
+
# MOST_RECENT_TAG-COMMITS_SINCE-gGIT_SHA
|
127
|
+
#
|
128
|
+
# @example
|
129
|
+
# 11.0.0-alpha.1-207-g694b062
|
130
|
+
# @return [String]
|
131
|
+
def git_describe
|
132
|
+
@git_describe ||= begin
|
133
|
+
git_cmd = "git describe"
|
134
|
+
cmd = shellout(git_cmd,
|
135
|
+
:live_stream => nil,
|
136
|
+
:cwd => @path)
|
137
|
+
if cmd.exitstatus == 0
|
138
|
+
cmd.stdout.chomp
|
139
|
+
else
|
140
|
+
msg = "Could not extract version information from `git describe`. "
|
141
|
+
msg << "Setting version to 0.0.0"
|
142
|
+
puts msg
|
143
|
+
"0.0.0"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# @!endgroup
|
149
|
+
|
150
|
+
# Note: The remaining methods could just as well be private
|
151
|
+
|
152
|
+
# Return a `MAJOR.MINOR.PATCH` version string, as extracted from
|
153
|
+
# {#git_describe}.
|
154
|
+
#
|
155
|
+
# Here are some illustrative examples:
|
156
|
+
#
|
157
|
+
# 1.2.7-208-ge908a52 -> 1.2.7
|
158
|
+
# 11.0.0-alpha-59-gf55b180 -> 11.0.0
|
159
|
+
# 11.0.0-alpha2 -> 11.0.0
|
160
|
+
# 10.16.2.rc.1 -> 10.16.2
|
161
|
+
#
|
162
|
+
# @return [String]
|
163
|
+
def version_tag
|
164
|
+
version_composition.join(".")
|
165
|
+
end
|
166
|
+
|
167
|
+
# Return a prerelease tag string (if it exists), as extracted from {#git_describe}.
|
168
|
+
#
|
169
|
+
# Here are some illustrative examples:
|
170
|
+
#
|
171
|
+
# 1.2.7-208-ge908a52 -> nil
|
172
|
+
# 11.0.0-alpha-59-gf55b180 -> alpha
|
173
|
+
# 11.0.0-alpha2 -> alpha2
|
174
|
+
# 10.16.2.rc.1 -> rc.1
|
175
|
+
#
|
176
|
+
# @return [String] if a pre-release tag was found
|
177
|
+
# @return [nil] if no pre-release tag was found
|
178
|
+
def prerelease_tag
|
179
|
+
prerelease_regex = if commits_since_tag > 0
|
180
|
+
/^\d+\.\d+\.\d+(?:-|\.)([0-9A-Za-z.-]+)-\d+-g[0-9a-f]+$/
|
181
|
+
else
|
182
|
+
/^\d+\.\d+\.\d+(?:-|\.)([0-9A-Za-z.-]+)$/
|
183
|
+
end
|
184
|
+
match = prerelease_regex.match(git_describe)
|
185
|
+
match ? match[1] : nil
|
186
|
+
end
|
187
|
+
|
188
|
+
# Extracts the 7-character truncated Git SHA1 from the output of {#git_describe}.
|
189
|
+
#
|
190
|
+
# Here are some illustrative examples:
|
191
|
+
#
|
192
|
+
# 1.2.7-208-ge908a52 -> e908a52
|
193
|
+
# 11.0.0-alpha-59-gf55b180 -> f55b180
|
194
|
+
# 11.0.0-alpha2 -> nil
|
195
|
+
# 10.16.2.rc.1 -> nil
|
196
|
+
#
|
197
|
+
# @return [String] the truncated SHA1
|
198
|
+
# @return [nil] if no SHA1 is present in the output of #{git_describe}
|
199
|
+
def git_sha_tag
|
200
|
+
sha_regexp = /g([0-9a-f]+)$/
|
201
|
+
match = sha_regexp.match(git_describe)
|
202
|
+
match ? match[1] : nil
|
203
|
+
end
|
204
|
+
|
205
|
+
# Extracts the number of commits since the most recent Git tag, as
|
206
|
+
# determined by {#git_describe}.
|
207
|
+
#
|
208
|
+
# Here are some illustrative examples:
|
209
|
+
#
|
210
|
+
# 1.2.7-208-ge908a52 -> 208
|
211
|
+
# 11.0.0-alpha-59-gf55b180 -> 59
|
212
|
+
# 11.0.0-alpha2 -> 0
|
213
|
+
# 10.16.2.rc.1 -> 0
|
214
|
+
#
|
215
|
+
# @return [Fixnum]
|
216
|
+
def commits_since_tag
|
217
|
+
commits_regexp = /^.*-(\d+)\-g[0-9a-f]+$/
|
218
|
+
match = commits_regexp.match(git_describe)
|
219
|
+
match ? match[1].to_i : 0
|
220
|
+
end
|
221
|
+
|
222
|
+
# @todo This method is never called in Omnibus. Is this even used
|
223
|
+
# (e.g., in the DSL files)?
|
224
|
+
def development_version?
|
225
|
+
patch = version_composition.last
|
226
|
+
patch.to_i.odd?
|
227
|
+
end
|
228
|
+
|
229
|
+
# Indicates whether the version represents a pre-release or not, as
|
230
|
+
# signalled by the presence of a pre-release tag in the version
|
231
|
+
# string.
|
232
|
+
#
|
233
|
+
# @return [Boolean]
|
234
|
+
# @see #prerelease_tag
|
235
|
+
def prerelease_version?
|
236
|
+
!!(prerelease_tag)
|
237
|
+
end
|
238
|
+
|
239
|
+
private
|
240
|
+
|
241
|
+
# We'll attempt to retrive the timestamp from the Jenkin's set BUILD_ID
|
242
|
+
# environment variable. This will ensure platform specfic packages for the
|
243
|
+
# same build will share the same timestamp.
|
244
|
+
def build_start_time
|
245
|
+
@build_start_time ||= begin
|
246
|
+
if !ENV['BUILD_ID'].nil?
|
247
|
+
begin
|
248
|
+
Time.strptime(ENV['BUILD_ID'], "%Y-%m-%d_%H-%M-%S")
|
249
|
+
rescue ArgumentError
|
250
|
+
error_message = "BUILD_ID environment variable "
|
251
|
+
error_message << "should be in YYYY-MM-DD_hh-mm-ss "
|
252
|
+
error_message << "format."
|
253
|
+
raise ArgumentError, error_message
|
254
|
+
end
|
255
|
+
else
|
256
|
+
Time.now.utc
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
# Pulls out the major, minor, and patch components from the output
|
262
|
+
# of {#git_describe}.
|
263
|
+
#
|
264
|
+
# Relies on the most recent Git tag being SemVer compliant (i.e.,
|
265
|
+
# starting with a `MAJOR.MINOR.PATCH` string)
|
266
|
+
#
|
267
|
+
# @return [Array<(String, String, String)>]
|
268
|
+
#
|
269
|
+
# @todo Compute this once and store the result in an instance variable
|
270
|
+
def version_composition
|
271
|
+
version_regexp = /^(\d+)\.(\d+)\.(\d+)/
|
272
|
+
version_regexp.match(git_describe)[1..3]
|
273
|
+
end
|
274
|
+
|
275
|
+
def append_timestamp?
|
276
|
+
if ENV['OMNIBUS_APPEND_TIMESTAMP'] && (ENV['OMNIBUS_APPEND_TIMESTAMP'] =~ (/^(false|f|no|n|0)$/i))
|
277
|
+
false
|
278
|
+
elsif ENV['OMNIBUS_APPEND_TIMESTAMP'] && (ENV['OMNIBUS_APPEND_TIMESTAMP'] =~ (/^(true|t|yes|y|1)$/i))
|
279
|
+
true
|
280
|
+
else
|
281
|
+
Omnibus::Config.append_timestamp
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
@@ -0,0 +1,328 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright (c) 2012 Opscode, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# 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,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require 'forwardable'
|
19
|
+
require 'omnibus/exceptions'
|
20
|
+
|
21
|
+
module Omnibus
|
22
|
+
class Builder
|
23
|
+
|
24
|
+
# Proxies method calls to either a Builder object or the Software that the
|
25
|
+
# builder belongs to. Provides compatibility with our DSL where we never
|
26
|
+
# yield objects to blocks and hopefully hides some of the confusion that
|
27
|
+
# can arise from instance_eval.
|
28
|
+
class DSLProxy
|
29
|
+
extend Forwardable
|
30
|
+
|
31
|
+
# @todo def_delegators :@builder, :patch, :command, :ruby, ...
|
32
|
+
|
33
|
+
def_delegator :@builder, :patch
|
34
|
+
def_delegator :@builder, :command
|
35
|
+
def_delegator :@builder, :ruby
|
36
|
+
def_delegator :@builder, :gem
|
37
|
+
def_delegator :@builder, :bundle
|
38
|
+
def_delegator :@builder, :rake
|
39
|
+
def_delegator :@builder, :block
|
40
|
+
def_delegator :@builder, :name
|
41
|
+
|
42
|
+
def initialize(builder, software)
|
43
|
+
@builder, @software = builder, software
|
44
|
+
end
|
45
|
+
|
46
|
+
def eval_block(&block)
|
47
|
+
instance_eval(&block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def respond_to?(method)
|
51
|
+
super || @software.respond_to?(method)
|
52
|
+
end
|
53
|
+
|
54
|
+
def methods
|
55
|
+
super | @software.methods
|
56
|
+
end
|
57
|
+
|
58
|
+
def method_missing(method_name, *args, &block)
|
59
|
+
if @software.respond_to?(method_name)
|
60
|
+
@software.send(method_name, *args, &block)
|
61
|
+
else
|
62
|
+
super
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# @todo code duplication with {Fetcher::ErrorReporter}
|
70
|
+
class ErrorReporter
|
71
|
+
|
72
|
+
# @todo fetcher isn't even used
|
73
|
+
def initialize(error, fetcher)
|
74
|
+
@error, @fetcher = error, fetcher
|
75
|
+
end
|
76
|
+
|
77
|
+
# @todo this isn't necessary
|
78
|
+
def e
|
79
|
+
@error
|
80
|
+
end
|
81
|
+
|
82
|
+
def explain(why)
|
83
|
+
$stderr.puts "* " * 40
|
84
|
+
$stderr.puts why
|
85
|
+
$stderr.puts "Exception:"
|
86
|
+
$stderr.puts indent("#{e.class}: #{e.message.strip}", 2)
|
87
|
+
Array(e.backtrace).each {|l| $stderr.puts indent(l, 4) }
|
88
|
+
$stderr.puts "* " * 40
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def indent(string, n)
|
94
|
+
string.split("\n").map {|l| " ".rjust(n) << l }.join("\n")
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
# @todo Look at using Bundler.with_clean_env{ ... } instead
|
100
|
+
BUNDLER_BUSTER = { "RUBYOPT" => nil,
|
101
|
+
"BUNDLE_BIN_PATH" => nil,
|
102
|
+
"BUNDLE_GEMFILE" => nil,
|
103
|
+
"GEM_PATH" => nil,
|
104
|
+
"GEM_HOME" => nil }
|
105
|
+
|
106
|
+
attr_reader :build_commands
|
107
|
+
|
108
|
+
def initialize(software, &block)
|
109
|
+
@software = software
|
110
|
+
@build_commands = []
|
111
|
+
@dsl_proxy = DSLProxy.new(self, software)
|
112
|
+
@dsl_proxy.eval_block(&block) if block_given?
|
113
|
+
end
|
114
|
+
|
115
|
+
def name
|
116
|
+
@software.name
|
117
|
+
end
|
118
|
+
|
119
|
+
def command(*args)
|
120
|
+
@build_commands << args
|
121
|
+
end
|
122
|
+
|
123
|
+
def patch(*args)
|
124
|
+
args = args.dup.pop
|
125
|
+
|
126
|
+
# we'll search for a patch file in the project root AND
|
127
|
+
# the omnibus-software gem
|
128
|
+
candidate_roots = [Omnibus.project_root]
|
129
|
+
candidate_roots << Omnibus.omnibus_software_root if Omnibus.omnibus_software_root
|
130
|
+
|
131
|
+
candidate_paths = candidate_roots.map do |root|
|
132
|
+
File.expand_path("#{root}/config/patches/#{name}/#{args[:source]}")
|
133
|
+
end
|
134
|
+
|
135
|
+
source = candidate_paths.find{|path| File.exists?(path) }
|
136
|
+
|
137
|
+
unless source
|
138
|
+
raise MissingPatch.new(args[:source], candidate_paths)
|
139
|
+
end
|
140
|
+
|
141
|
+
plevel = args[:plevel] || 1
|
142
|
+
if args[:target]
|
143
|
+
target = File.expand_path("#{project_dir}/#{args[:target]}")
|
144
|
+
@build_commands <<
|
145
|
+
"cat #{source} | patch -p#{plevel} #{target}"
|
146
|
+
else
|
147
|
+
@build_commands <<
|
148
|
+
"patch -d #{project_dir} -p#{plevel} -i #{source}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# @todo all these ruby commands (ruby, gem, bundle, rake) could
|
153
|
+
# all be collapsed into a single underlying implementation, since
|
154
|
+
# they all just differ on the executable being called
|
155
|
+
def ruby(*args)
|
156
|
+
@build_commands << bundle_bust(*prepend_cmd("#{install_dir}/embedded/bin/ruby", *args))
|
157
|
+
end
|
158
|
+
|
159
|
+
def gem(*args)
|
160
|
+
@build_commands << bundle_bust(*prepend_cmd("#{install_dir}/embedded/bin/gem", *args))
|
161
|
+
end
|
162
|
+
|
163
|
+
def bundle(*args)
|
164
|
+
@build_commands << bundle_bust(*prepend_cmd("#{install_dir}/embedded/bin/bundle", *args))
|
165
|
+
end
|
166
|
+
|
167
|
+
def rake(*args)
|
168
|
+
@build_commands << bundle_bust(*prepend_cmd("#{install_dir}/embedded/bin/rake", *args))
|
169
|
+
end
|
170
|
+
|
171
|
+
def block(&rb_block)
|
172
|
+
@build_commands << rb_block
|
173
|
+
end
|
174
|
+
|
175
|
+
def project_dir
|
176
|
+
@software.project_dir
|
177
|
+
end
|
178
|
+
|
179
|
+
def install_dir
|
180
|
+
@software.install_dir
|
181
|
+
end
|
182
|
+
|
183
|
+
def log(message)
|
184
|
+
puts "[builder:#{name}] #{message}"
|
185
|
+
end
|
186
|
+
|
187
|
+
def build
|
188
|
+
log "building #{name}"
|
189
|
+
time_it("#{name} build") do
|
190
|
+
@build_commands.each do |cmd|
|
191
|
+
execute(cmd)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def execute(cmd)
|
197
|
+
case cmd
|
198
|
+
when Proc
|
199
|
+
execute_proc(cmd)
|
200
|
+
else
|
201
|
+
execute_sh(cmd)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
private
|
206
|
+
|
207
|
+
def execute_proc(cmd)
|
208
|
+
cmd.call
|
209
|
+
rescue Exception => e
|
210
|
+
# In Ruby 1.9, Procs have a #source_location method with file/line info.
|
211
|
+
# Too bad we can't use it :(
|
212
|
+
ErrorReporter.new(e, self).explain("Failed to build #{name} while running ruby block build step")
|
213
|
+
raise
|
214
|
+
end
|
215
|
+
|
216
|
+
def execute_sh(cmd)
|
217
|
+
retries ||= 0
|
218
|
+
shell = nil
|
219
|
+
cmd_args = Array(cmd)
|
220
|
+
options = {
|
221
|
+
:cwd => project_dir,
|
222
|
+
:timeout => 5400
|
223
|
+
}
|
224
|
+
options[:live_stream] = STDOUT if ENV['DEBUG']
|
225
|
+
if cmd_args.last.is_a? Hash
|
226
|
+
cmd_options = cmd_args.last
|
227
|
+
cmd_args[cmd_args.size - 1] = options.merge(cmd_options)
|
228
|
+
else
|
229
|
+
cmd_args << options
|
230
|
+
end
|
231
|
+
|
232
|
+
cmd_string = cmd_args[0..-2].join(' ')
|
233
|
+
cmd_opts_for_display = to_kv_str(cmd_args.last)
|
234
|
+
|
235
|
+
log "Executing: `#{cmd_string}` with #{cmd_opts_for_display}"
|
236
|
+
|
237
|
+
shell = Mixlib::ShellOut.new(*cmd)
|
238
|
+
shell.environment["HOME"] = "/tmp" unless ENV["HOME"]
|
239
|
+
|
240
|
+
cmd_name = cmd_string.split(/\s+/).first
|
241
|
+
time_it("#{cmd_name} command") do
|
242
|
+
shell.run_command
|
243
|
+
shell.error!
|
244
|
+
end
|
245
|
+
rescue Exception => e
|
246
|
+
# Getting lots of errors from github, particularly with erlang/rebar
|
247
|
+
# projects fetching tons of deps via git all the time. This isn't a
|
248
|
+
# particularly elegant way to solve that problem. But it should work.
|
249
|
+
if retries >= 3
|
250
|
+
ErrorReporter.new(e, self).explain("Failed to build #{name} while running `#{cmd_string}` with #{cmd_opts_for_display}")
|
251
|
+
raise
|
252
|
+
else
|
253
|
+
time_to_sleep = 5 * (2 ** retries)
|
254
|
+
retries +=1
|
255
|
+
log "Failed to execute cmd #{cmd} #{retries} time(s). Retrying in #{time_to_sleep}s."
|
256
|
+
sleep(time_to_sleep)
|
257
|
+
retry
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def prepend_cmd(str, *cmd_args)
|
262
|
+
if cmd_args.size == 1
|
263
|
+
# command as a string, no opts
|
264
|
+
"#{str} #{cmd_args.first}"
|
265
|
+
elsif cmd_args.size == 2 && cmd_args.last.is_a?(Hash)
|
266
|
+
# command as a string w/ opts
|
267
|
+
["#{str} #{cmd_args.first}", cmd_args.last]
|
268
|
+
elsif cmd_args.size == 0
|
269
|
+
raise ArgumentError, "I don't even"
|
270
|
+
else
|
271
|
+
# cmd given as argv array
|
272
|
+
cmd_args.dup.unshift(str)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def bundle_bust(*cmd_args)
|
277
|
+
if cmd_args.last.is_a?(Hash)
|
278
|
+
cmd_args = cmd_args.dup
|
279
|
+
cmd_opts = cmd_args.pop.dup
|
280
|
+
cmd_opts[:env] = cmd_opts[:env] ? BUNDLER_BUSTER.merge(cmd_opts[:env]) : BUNDLER_BUSTER
|
281
|
+
cmd_args << cmd_opts
|
282
|
+
else
|
283
|
+
cmd_args << {:env => BUNDLER_BUSTER}
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
|
288
|
+
def time_it(what)
|
289
|
+
start = Time.now
|
290
|
+
yield
|
291
|
+
rescue Exception
|
292
|
+
elapsed = Time.now - start
|
293
|
+
log "#{what} failed, #{elapsed.to_f}s"
|
294
|
+
raise
|
295
|
+
else
|
296
|
+
elapsed = Time.now - start
|
297
|
+
log "#{what} succeeded, #{elapsed.to_f}s"
|
298
|
+
end
|
299
|
+
|
300
|
+
# Convert a hash to a string in the form `key=value`. It should work with
|
301
|
+
# whatever input is given but is designed to make the options to ShellOut
|
302
|
+
# look nice.
|
303
|
+
def to_kv_str(hash, join_str=",")
|
304
|
+
hash.inject([]) do |kv_pair_strs, (k,v)|
|
305
|
+
val_str = case v
|
306
|
+
when Hash
|
307
|
+
%Q["#{to_kv_str(v, " ")}"]
|
308
|
+
else
|
309
|
+
v.to_s
|
310
|
+
end
|
311
|
+
kv_pair_strs << "#{k}=#{val_str}"
|
312
|
+
end.join(join_str)
|
313
|
+
end
|
314
|
+
|
315
|
+
end
|
316
|
+
|
317
|
+
# @todo What's the point of this class? Can we not just detect that
|
318
|
+
# there are no commands in {Omnibus::Builder#build} and output the
|
319
|
+
# appropriate message? Seems like a lot of extra ceremony.
|
320
|
+
class NullBuilder < Builder
|
321
|
+
|
322
|
+
def build
|
323
|
+
log "Nothing to build for #{name}"
|
324
|
+
end
|
325
|
+
|
326
|
+
end
|
327
|
+
|
328
|
+
end
|