omnibus 1.3.0 → 2.0.0.rc1

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 (69) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -1
  3. data/.rubocop.yml +30 -0
  4. data/.travis.yml +14 -3
  5. data/CHANGELOG.md +72 -49
  6. data/Gemfile +8 -5
  7. data/NOTICE +2 -2
  8. data/README.md +65 -7
  9. data/Rakefile +12 -3
  10. data/bin/makeself-header.sh +1 -1
  11. data/bin/makeself.sh +2 -2
  12. data/bin/omnibus +2 -2
  13. data/functional/fixtures/mac_pkg/files/mac_pkg/Resources/background.png +0 -0
  14. data/functional/fixtures/mac_pkg/files/mac_pkg/Resources/license.html +1 -0
  15. data/functional/fixtures/mac_pkg/files/mac_pkg/Resources/welcome.html +1 -0
  16. data/functional/fixtures/mac_pkg/package-scripts/functional-test-project/postinstall +4 -0
  17. data/functional/packagers/mac_pkg_spec.rb +72 -0
  18. data/lib/omnibus/artifact.rb +11 -13
  19. data/lib/omnibus/build_version.rb +18 -21
  20. data/lib/omnibus/builder.rb +37 -48
  21. data/lib/omnibus/clean_tasks.rb +3 -5
  22. data/lib/omnibus/cli/application.rb +46 -53
  23. data/lib/omnibus/cli/base.rb +16 -19
  24. data/lib/omnibus/cli/build.rb +13 -13
  25. data/lib/omnibus/cli/cache.rb +13 -15
  26. data/lib/omnibus/cli/release.rb +4 -9
  27. data/lib/omnibus/cli.rb +2 -4
  28. data/lib/omnibus/config.rb +43 -23
  29. data/lib/omnibus/exceptions.rb +35 -1
  30. data/lib/omnibus/fetcher.rb +9 -13
  31. data/lib/omnibus/fetchers/git_fetcher.rb +15 -19
  32. data/lib/omnibus/fetchers/net_fetcher.rb +34 -38
  33. data/lib/omnibus/fetchers/path_fetcher.rb +7 -9
  34. data/lib/omnibus/fetchers/s3_cache_fetcher.rb +3 -4
  35. data/lib/omnibus/fetchers.rb +3 -3
  36. data/lib/omnibus/health_check.rb +126 -127
  37. data/lib/omnibus/library.rb +11 -12
  38. data/lib/omnibus/overrides.rb +6 -8
  39. data/lib/omnibus/package_release.rb +20 -22
  40. data/lib/omnibus/packagers/mac_pkg.rb +285 -0
  41. data/lib/omnibus/project.rb +215 -110
  42. data/lib/omnibus/reports.rb +16 -24
  43. data/lib/omnibus/s3_cacher.rb +15 -21
  44. data/lib/omnibus/software.rb +178 -88
  45. data/lib/omnibus/util.rb +25 -13
  46. data/lib/omnibus/version.rb +2 -2
  47. data/lib/omnibus.rb +11 -13
  48. data/omnibus.gemspec +20 -18
  49. data/spec/artifact_spec.rb +55 -52
  50. data/spec/build_version_spec.rb +121 -129
  51. data/spec/config_spec.rb +40 -0
  52. data/spec/data/projects/chefdk.rb +41 -0
  53. data/spec/data/projects/sample.rb +10 -0
  54. data/spec/data/software/erchef.rb +12 -12
  55. data/spec/data/software/zlib.rb +67 -0
  56. data/spec/fetchers/git_fetcher_spec.rb +55 -48
  57. data/spec/fetchers/net_fetcher_spec.rb +72 -78
  58. data/spec/omnibus_spec.rb +59 -0
  59. data/spec/overrides_spec.rb +64 -64
  60. data/spec/package_release_spec.rb +65 -64
  61. data/spec/packagers/mac_pkg_spec.rb +261 -0
  62. data/spec/project_spec.rb +138 -0
  63. data/spec/s3_cacher_spec.rb +9 -10
  64. data/spec/software_spec.rb +71 -50
  65. data/spec/spec_helper.rb +14 -7
  66. metadata +68 -60
  67. data/.rspec +0 -1
  68. data/.yardopts +0 -6
  69. data/spec/software_dirs_spec.rb +0 -34
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright:: Copyright (c) 2012 Opscode, Inc.
2
+ # Copyright:: Copyright (c) 2012-2014 Chef Software, Inc.
3
3
  # License:: Apache License, Version 2.0
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,6 @@ module Omnibus
19
19
  #
20
20
  # Used to generate the manifest of all software components with versions
21
21
  class Library
22
-
23
22
  attr_reader :components
24
23
 
25
24
  def initialize(project)
@@ -32,31 +31,31 @@ module Omnibus
32
31
  end
33
32
 
34
33
  def version_map
35
- @components.inject({}) {|map, component|
36
- map[component.name] = if component.given_version
37
- {:version => component.version,
38
- :given_version => component.given_version,
39
- :overridden => component.overridden?,
40
- :version_guid => component.version_guid}
34
+ @components.reduce({}) do |map, component|
35
+ map[component.name] = if component.default_version
36
+ {
37
+ version: component.version,
38
+ default_version: component.default_version,
39
+ overridden: component.overridden?,
40
+ version_guid: component.version_guid,
41
+ }
41
42
  else
42
43
  ## Components without a version are
43
44
  ## pieces of the omnibus project
44
45
  ## itself, and so don't really fit
45
46
  ## with the concept of overrides
46
- v = {:version => @project.build_version}
47
+ v = { version: @project.build_version }
47
48
  if @project.build_version.respond_to?(:git_sha)
48
49
  v[:version_guid] = "git:#{@project.build_version.git_sha}"
49
50
  end
50
51
  v
51
52
  end
52
53
  map
53
- }
54
+ end
54
55
  end
55
56
 
56
57
  def select(*args, &block)
57
58
  @components.select(*args, &block)
58
59
  end
59
60
  end
60
-
61
61
  end
62
-
@@ -2,8 +2,7 @@ require 'pp'
2
2
 
3
3
  module Omnibus
4
4
  module Overrides
5
-
6
- DEFAULT_OVERRIDE_FILE_NAME = "omnibus.overrides"
5
+ DEFAULT_OVERRIDE_FILE_NAME = 'omnibus.overrides'
7
6
 
8
7
  # Parses a file of override information into a Hash.
9
8
  #
@@ -18,17 +17,17 @@ module Omnibus
18
17
  # @return [Hash, nil]
19
18
  def self.parse_file(file)
20
19
  if file
21
- File.readlines(file).inject({}) do |acc, line|
20
+ File.readlines(file).reduce({}) do |acc, line|
22
21
  info = line.split
23
22
 
24
23
  unless info.count == 2
25
- raise ArgumentError, "Invalid overrides line: '#{line.chomp}'"
24
+ fail ArgumentError, "Invalid overrides line: '#{line.chomp}'"
26
25
  end
27
26
 
28
27
  package, version = info
29
28
 
30
29
  if acc[package]
31
- raise ArgumentError, "Multiple overrides present for '#{package}' in overrides file #{file}!"
30
+ fail ArgumentError, "Multiple overrides present for '#{package}' in overrides file #{file}!"
32
31
  end
33
32
 
34
33
  acc[package] = version
@@ -56,14 +55,13 @@ module Omnibus
56
55
  overrides = parse_file(file)
57
56
 
58
57
  if overrides
59
- puts "********************************************************************************"
58
+ puts '********************************************************************************'
60
59
  puts "Using Overrides from #{Omnibus::Overrides.resolve_override_file}"
61
60
  pp overrides
62
- puts "********************************************************************************"
61
+ puts '********************************************************************************'
63
62
  end
64
63
 
65
64
  overrides || {}
66
65
  end
67
-
68
66
  end
69
67
  end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright:: Copyright (c) 2012 Opscode, Inc.
2
+ # Copyright:: Copyright (c) 2012-2014 Chef Software, Inc.
3
3
  # License:: Apache License, Version 2.0
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,7 +26,6 @@ require 'uber-s3'
26
26
 
27
27
  module Omnibus
28
28
  class PackageRelease
29
-
30
29
  attr_reader :package_path
31
30
  attr_reader :access_policy
32
31
 
@@ -36,16 +35,16 @@ module Omnibus
36
35
  # @yield callback triggered by successful upload. Allows users of this
37
36
  # class to add UI feedback.
38
37
  # @yieldparam s3_object_key [String] the S3 key of the uploaded object.
39
- def initialize(package_path, opts={:access=>:private}, &block)
38
+ def initialize(package_path, opts = { access: :private }, &block)
40
39
  @package_path = package_path
41
40
  @metadata = nil
42
41
  @s3_client = nil
43
42
 
44
43
  @after_upload = if block_given?
45
- block
46
- else
47
- lambda { |item_key| nil }
48
- end
44
+ block
45
+ else
46
+ ->(item_key) { nil }
47
+ end
49
48
 
50
49
  # sets @access_policy
51
50
  handle_opts(opts)
@@ -62,9 +61,9 @@ module Omnibus
62
61
  def release
63
62
  validate_config!
64
63
  validate_package!
65
- s3_client.store(metadata_key, metadata_json, :access => access_policy)
64
+ s3_client.store(metadata_key, metadata_json, access: access_policy)
66
65
  uploaded(metadata_key)
67
- s3_client.store(package_key, package_content, :access => access_policy, :content_md5 => md5)
66
+ s3_client.store(package_key, package_content, access: access_policy, content_md5: md5)
68
67
  uploaded(package_key)
69
68
  end
70
69
 
@@ -81,11 +80,11 @@ module Omnibus
81
80
  end
82
81
 
83
82
  def platform_path
84
- File.join(metadata["platform"], metadata["platform_version"], metadata["arch"])
83
+ File.join(metadata['platform'], metadata['platform_version'], metadata['arch'])
85
84
  end
86
85
 
87
86
  def md5
88
- metadata["md5"]
87
+ metadata['md5']
89
88
  end
90
89
 
91
90
  def metadata
@@ -106,9 +105,9 @@ module Omnibus
106
105
 
107
106
  def validate_package!
108
107
  if !File.exist?(package_path)
109
- raise NoPackageFile.new(package_path)
108
+ fail NoPackageFile.new(package_path)
110
109
  elsif !File.exist?(package_metadata_path)
111
- raise NoPackageMetadataFile.new(package_metadata_path)
110
+ fail NoPackageMetadataFile.new(package_metadata_path)
112
111
  else
113
112
  true
114
113
  end
@@ -119,16 +118,16 @@ module Omnibus
119
118
  true
120
119
  else
121
120
  err = InvalidS3ReleaseConfiguration.new(s3_bucket, s3_access_key, s3_secret_key)
122
- raise err
121
+ fail err
123
122
  end
124
123
  end
125
124
 
126
125
  def s3_client
127
126
  @s3_client ||= UberS3.new(
128
- :access_key => s3_access_key,
129
- :secret_access_key => s3_secret_key,
130
- :bucket => s3_bucket,
131
- :adaper => :net_http
127
+ access_key: s3_access_key,
128
+ secret_access_key: s3_secret_key,
129
+ bucket: s3_bucket,
130
+ adaper: :net_http,
132
131
  )
133
132
  end
134
133
 
@@ -151,13 +150,12 @@ module Omnibus
151
150
  def handle_opts(opts)
152
151
  access_policy = opts[:access]
153
152
  if access_policy.nil?
154
- raise ArgumentError, "options to #{self.class} must specify `:access' (given: #{opts.inspect})"
155
- elsif not [:private, :public_read].include?(access_policy)
156
- raise ArgumentError, "option `:access' must be one of `[:private, :public_read]' (given: #{access_policy.inspect})"
153
+ fail ArgumentError, "options to #{self.class} must specify `:access' (given: #{opts.inspect})"
154
+ elsif ![:private, :public_read].include?(access_policy)
155
+ fail ArgumentError, "option `:access' must be one of `[:private, :public_read]' (given: #{access_policy.inspect})"
157
156
  else
158
157
  @access_policy = access_policy
159
158
  end
160
159
  end
161
-
162
160
  end
163
161
  end
@@ -0,0 +1,285 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2014 Chef Software, 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 'fileutils'
20
+ require 'omnibus/util'
21
+
22
+ module Omnibus
23
+ module Packagers
24
+ # Builds a Mac OS X "product" package (.pkg extension)
25
+ #
26
+ # Mac OS X packages are built in two stages. First, files are packaged up
27
+ # into one or more "component" .pkg files (MacPkg only supports making a
28
+ # single component). This is done with `pkgbuild`. Next the component(s)
29
+ # are combined into a single "product" package, using `productbuild`. It is
30
+ # this container package that can have custom branding (background image)
31
+ # and a license. It can also allow for user customization of which
32
+ # component packages to install, but MacPkg does not expose this feature.
33
+ class MacPkg
34
+ include Util
35
+
36
+ extend Forwardable
37
+
38
+ # The Omnibus::Project instance that we're packaging.
39
+ attr_reader :project
40
+
41
+ # !@method name
42
+ # @return (see Project#name)
43
+ def_delegator :@project, :name
44
+
45
+ # !@method version
46
+ # @return (see Project#build_version)
47
+ def_delegator :@project, :build_version, :version
48
+
49
+ # !@method identifier
50
+ # @return (see Project#mac_pkg_identifier)
51
+ def_delegator :@project, :mac_pkg_identifier, :identifier
52
+
53
+ # !@method pkg_root
54
+ # @return (see Project#install_path)
55
+ def_delegator :@project, :install_path, :pkg_root
56
+
57
+ # !@method install_location
58
+ # @return (see Project#install_path)
59
+ def_delegator :@project, :install_path, :install_location
60
+
61
+ # !@method scripts
62
+ # @return (see Project#package_scripts_path)
63
+ def_delegator :@project, :package_scripts_path, :scripts
64
+
65
+ # !@method files_path
66
+ # @return (see Project#files_path)
67
+ def_delegator :@project, :files_path
68
+
69
+ # !@method package_dir
70
+ # @return (see Project#package_dir)
71
+ def_delegator :@project, :package_dir
72
+
73
+ # @param project [Project] the omnibus project to package.
74
+ def initialize(project)
75
+ @project = project
76
+ end
77
+
78
+ # Build the package.
79
+ def build
80
+ # Ensure the omnibus project repo contains the stuff we need.
81
+ validate_omnibus_project!
82
+
83
+ # create the staging dir for intermediate build products, if needed.
84
+ setup_staging_dir!
85
+
86
+ # build the component package
87
+ build_component_pkg
88
+
89
+ # build the product package
90
+ build_product_pkg
91
+ end
92
+
93
+ # Verifies that the #required_files are present in the
94
+ # omnibus project repo.
95
+ # @return [true] if required files are present.
96
+ # @raise [MissingMacPkgResource] if anything is missing.
97
+ def validate_omnibus_project!
98
+ missing_files = required_files.select { |f| !File.exist?(f) }
99
+ if missing_files.empty?
100
+ true # all good
101
+ else
102
+ fail MissingMacPkgResource.new(missing_files)
103
+ end
104
+ end
105
+
106
+ # Nukes and re-creates the staging_dir
107
+ # @return [void]
108
+ def setup_staging_dir!
109
+ FileUtils.rm_rf(staging_dir)
110
+ FileUtils.mkdir_p(staging_dir)
111
+ end
112
+
113
+ def build_component_pkg
114
+ shellout!(*pkgbuild_command, shellout_opts)
115
+ end
116
+
117
+ def build_product_pkg
118
+ generate_distribution
119
+ shellout!(*productbuild_command, shellout_opts)
120
+ end
121
+
122
+ # The argv for a pkgbuild command that will build the component package.
123
+ # The resulting package is only an intermediate build product. It can be
124
+ # installed with the mac installer, but doesn't contain the data needed
125
+ # to customize the installer UI.
126
+ # @return [Array<String>] argv for the pkgbuild command.
127
+ def pkgbuild_command
128
+ %W[
129
+ pkgbuild
130
+ --identifier #{identifier}
131
+ --version #{version}
132
+ --scripts #{scripts}
133
+ --root #{pkg_root}
134
+ --install-location #{install_location}
135
+ #{component_pkg_name}
136
+ ]
137
+ end
138
+
139
+ # The argv for a productbuild command that will build the product package.
140
+ # The generated package is the final build product that you ship to end
141
+ # users.
142
+ # @return [Array<String>] argv for the productbuild command
143
+ def productbuild_command
144
+ %W[
145
+ productbuild
146
+ --distribution #{distribution_staging_path}
147
+ --resources #{mac_pkg_files_path}
148
+ #{product_pkg_path}
149
+ ]
150
+ end
151
+
152
+ # Writes the Distribution file to the staging area.
153
+ # @return [void]
154
+ def generate_distribution
155
+ File.open(distribution_staging_path, File::RDWR | File::CREAT | File::EXCL, 0600) do |file|
156
+ file.print(distribution)
157
+ end
158
+ end
159
+
160
+ # The name of the (only) component package.
161
+ # @return [String] the filename of the component .pkg file to create.
162
+ def component_pkg_name
163
+ "#{name}-core.pkg"
164
+ end
165
+
166
+ # The basename of the end-result package (that will be distributed to
167
+ # users).
168
+ #
169
+ # Project uses this to generate metadata about the package after its
170
+ # built.
171
+ #
172
+ # @return [String] the basename of the package file
173
+ def package_name
174
+ "#{name}.pkg"
175
+ end
176
+
177
+ def identifier
178
+ project.mac_pkg_identifier ||
179
+ "test.#{sanitized_maintainer}.pkg.#{sanitized_name}"
180
+ end
181
+
182
+ # Internally in this class we want to call this the "product package" so
183
+ # we can be unambiguous and consistent.
184
+ alias_method :product_pkg_name, :package_name
185
+
186
+ # The full path where the product package was/will be written.
187
+ #
188
+ # @return [String] Path to the packge file.
189
+ def product_pkg_path
190
+ File.join(package_dir, product_pkg_name)
191
+ end
192
+
193
+ # @return [String] Filesystem path where the Distribution file is written.
194
+ def distribution_staging_path
195
+ File.join(staging_dir, 'Distribution')
196
+ end
197
+
198
+ # Generates the content of the Distribution file, which is used by
199
+ # productbuild to select the component packages to include in the product
200
+ # package. Also includes information used to customize the UI of the Mac
201
+ # OS X installer.
202
+ # @return [String] Distribution file content (XML)
203
+ def distribution
204
+ <<-END_DISTRIBTION
205
+ <?xml version="1.0" standalone="no"?>
206
+ <installer-gui-script minSpecVersion="1">
207
+ <title>#{name.capitalize}</title>
208
+ <background file="background.png" alignment="bottomleft" mime-type="image/png"/>
209
+ <welcome file="welcome.html" mime-type="text/html"/>
210
+ <license file="license.html" mime-type="text/html"/>
211
+
212
+ <!-- Generated by productbuild - - synthesize -->
213
+ <pkg-ref id="#{identifier}"/>
214
+ <options customize="never" require-scripts="false"/>
215
+ <choices-outline>
216
+ <line choice="default">
217
+ <line choice="#{identifier}"/>
218
+ </line>
219
+ </choices-outline>
220
+ <choice id="default"/>
221
+ <choice id="#{identifier}" visible="false">
222
+ <pkg-ref id="#{identifier}"/>
223
+ </choice>
224
+ <pkg-ref id="#{identifier}" version="#{version}" onConclusion="none">#{component_pkg_name}</pkg-ref>
225
+ </installer-gui-script>
226
+ END_DISTRIBTION
227
+ end
228
+
229
+ # A directory where intermediate build products are stored.
230
+ # @return [String] Path to the directory
231
+ def staging_dir
232
+ File.join(project.package_tmp, 'mac-pkg')
233
+ end
234
+
235
+ # A list of the files that will be used to customize the "product" package.P
236
+ # @return [Array<String>] paths to the required files.
237
+ def required_files
238
+ [
239
+ background_png_path,
240
+ license_file_path,
241
+ welcome_file_path,
242
+ ]
243
+ end
244
+
245
+ def sanitized_name
246
+ name.gsub(/[^[:alnum:]]/, '').downcase
247
+ end
248
+
249
+ def sanitized_maintainer
250
+ project.maintainer.gsub(/[^[:alnum:]]/, '').downcase
251
+ end
252
+
253
+ # The path to the directory inside the omnibus project's repo where the
254
+ # pkg resource files are.
255
+ # @return [String] path to the Resources directory
256
+ def mac_pkg_files_path
257
+ File.join(files_path, 'mac_pkg', 'Resources')
258
+ end
259
+
260
+ # @return [String] path to the license file
261
+ def license_file_path
262
+ File.join(mac_pkg_files_path, 'license.html')
263
+ end
264
+
265
+ # @return [String] path to the background image for the product package.
266
+ def background_png_path
267
+ File.join(mac_pkg_files_path, 'background.png')
268
+ end
269
+
270
+ # Path to the welcome file. This is the content that's displayed on the
271
+ # first screen of the installer.
272
+ # @return [String] path to the welcome file
273
+ def welcome_file_path
274
+ File.join(mac_pkg_files_path, 'welcome.html')
275
+ end
276
+
277
+ def shellout_opts
278
+ {
279
+ timeout: 3600,
280
+ cwd: staging_dir,
281
+ }
282
+ end
283
+ end
284
+ end
285
+ end