omnibus 1.3.0 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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