omnibus 2.0.2 → 3.0.0

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 (71) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +2 -0
  3. data/.travis.yml +0 -2
  4. data/CHANGELOG.md +26 -6
  5. data/Gemfile +7 -0
  6. data/Guardfile +10 -0
  7. data/README.md +103 -160
  8. data/Rakefile +6 -1
  9. data/docs/Building on OSX.md +66 -0
  10. data/docs/omnibus-build-cache.md +75 -0
  11. data/lib/omnibus.rb +9 -13
  12. data/lib/omnibus/artifact.rb +1 -13
  13. data/lib/omnibus/assets/README-logo.png +0 -0
  14. data/lib/omnibus/assets/logo.psd +0 -0
  15. data/lib/omnibus/builder.rb +1 -0
  16. data/lib/omnibus/cli/application.rb +17 -4
  17. data/lib/omnibus/cli/build.rb +6 -4
  18. data/lib/omnibus/config.rb +33 -0
  19. data/lib/omnibus/exceptions.rb +20 -14
  20. data/lib/omnibus/health_check.rb +2 -0
  21. data/lib/omnibus/install_path_cache.rb +106 -0
  22. data/lib/omnibus/library.rb +18 -1
  23. data/lib/omnibus/packagers/base.rb +228 -0
  24. data/lib/omnibus/packagers/mac_dmg.rb +215 -0
  25. data/lib/omnibus/packagers/mac_pkg.rb +129 -253
  26. data/lib/omnibus/project.rb +89 -95
  27. data/lib/omnibus/s3_cacher.rb +4 -7
  28. data/lib/omnibus/software.rb +47 -83
  29. data/lib/omnibus/sugar.rb +49 -0
  30. data/lib/omnibus/templates/.kitchen.yml.erb +3 -0
  31. data/lib/omnibus/templates/Berksfile.erb +4 -0
  32. data/lib/omnibus/templates/Gemfile.erb +1 -1
  33. data/lib/omnibus/templates/mac_dmg/background.png +0 -0
  34. data/lib/omnibus/templates/mac_dmg/icon.png +0 -0
  35. data/lib/omnibus/templates/mac_pkg/background.png +0 -0
  36. data/lib/omnibus/templates/mac_pkg/license.html.erb +1 -0
  37. data/lib/omnibus/templates/mac_pkg/welcome.html.erb +9 -0
  38. data/lib/omnibus/templates/omnibus.rb.example.erb +31 -4
  39. data/lib/omnibus/version.rb +1 -1
  40. data/omnibus.gemspec +5 -4
  41. data/spec/fixtures/sample/files/mac_dmg/Resources/background.png +0 -0
  42. data/spec/fixtures/sample/files/mac_dmg/Resources/icon.png +0 -0
  43. data/spec/fixtures/sample/files/mac_pkg/Resources/background.png +0 -0
  44. data/spec/fixtures/sample/files/mac_pkg/Resources/license.html +1 -0
  45. data/spec/fixtures/sample/files/mac_pkg/Resources/welcome.html +9 -0
  46. data/{functional/fixtures/mac_pkg/package-scripts/functional-test-project → spec/fixtures/sample/package-scripts/sample}/postinstall +0 -0
  47. data/spec/functional/packagers/mac_spec.rb +74 -0
  48. data/spec/spec_helper.rb +14 -3
  49. data/spec/sugar_spec.rb +20 -0
  50. data/spec/{artifact_spec.rb → unit/artifact_spec.rb} +2 -3
  51. data/spec/{build_version_spec.rb → unit/build_version_spec.rb} +0 -0
  52. data/spec/{config_spec.rb → unit/config_spec.rb} +4 -0
  53. data/spec/{fetchers → unit/fetchers}/git_fetcher_spec.rb +0 -0
  54. data/spec/{fetchers → unit/fetchers}/net_fetcher_spec.rb +0 -0
  55. data/spec/unit/install_path_cache_spec.rb +175 -0
  56. data/spec/unit/library_spec.rb +67 -0
  57. data/spec/{omnibus_spec.rb → unit/omnibus_spec.rb} +0 -0
  58. data/spec/{overrides_spec.rb → unit/overrides_spec.rb} +0 -0
  59. data/spec/{package_release_spec.rb → unit/package_release_spec.rb} +0 -0
  60. data/spec/unit/packagers/base_spec.rb +221 -0
  61. data/spec/unit/packagers/mac_pkg_spec.rb +163 -0
  62. data/spec/{project_spec.rb → unit/project_spec.rb} +0 -14
  63. data/spec/{s3_cacher_spec.rb → unit/s3_cacher_spec.rb} +0 -0
  64. data/spec/{software_spec.rb → unit/software_spec.rb} +0 -1
  65. metadata +122 -103
  66. data/functional/fixtures/mac_pkg/files/mac_pkg/Resources/background.png +0 -0
  67. data/functional/fixtures/mac_pkg/files/mac_pkg/Resources/license.html +0 -1
  68. data/functional/fixtures/mac_pkg/files/mac_pkg/Resources/welcome.html +0 -1
  69. data/functional/packagers/mac_pkg_spec.rb +0 -72
  70. data/lib/omnibus/clean_tasks.rb +0 -28
  71. data/spec/packagers/mac_pkg_spec.rb +0 -262
@@ -27,7 +27,24 @@ module Omnibus
27
27
  end
28
28
 
29
29
  def component_added(component)
30
- @components << component unless @components.include?(component)
30
+ unless @components.find { |c| c.name == component.name }
31
+ @components << component
32
+ end
33
+ end
34
+
35
+ def build_order
36
+ head = []
37
+ tail = []
38
+ @components.each do |component|
39
+ if head.length == 0
40
+ head << component
41
+ elsif @project.dependencies.include?(component.name)
42
+ tail << component
43
+ else
44
+ head << component
45
+ end
46
+ end
47
+ [head, tail].flatten
31
48
  end
32
49
 
33
50
  def version_map
@@ -0,0 +1,228 @@
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 'fileutils'
19
+ require 'forwardable'
20
+ require 'omnibus/util'
21
+
22
+ module Omnibus
23
+ class Packager::Base
24
+ include Util
25
+
26
+ extend Forwardable
27
+
28
+ # The Omnibus::Project instance that we're packaging.
29
+ attr_reader :project
30
+
31
+ # !@method name
32
+ # @return (see Project#name)
33
+ def_delegator :@project, :name
34
+
35
+ # !@method version
36
+ # @return (see Project#build_version)
37
+ def_delegator :@project, :build_version, :version
38
+
39
+ # !@method iteration
40
+ # @return (see Project#iteration)
41
+ def_delegator :@project, :iteration, :iteration
42
+
43
+ # !@method identifier
44
+ # @return (see Project#mac_pkg_identifier)
45
+ def_delegator :@project, :mac_pkg_identifier, :identifier
46
+
47
+ # !@method install_path
48
+ # @return (see Project#install_path)
49
+ def_delegator :@project, :install_path, :install_path
50
+
51
+ # !@method scripts
52
+ # @return (see Project#package_scripts_path)
53
+ def_delegator :@project, :package_scripts_path, :scripts
54
+
55
+ # !@method files_path
56
+ # @return (see Project#files_path)
57
+ def_delegator :@project, :files_path
58
+
59
+ # !@method package_dir
60
+ # @return (see Project#package_dir)
61
+ def_delegator :@project, :package_dir
62
+
63
+ # The commands/steps to setup the file system.
64
+ def self.setup(&block)
65
+ if block_given?
66
+ @setup = block
67
+ else
68
+ @setup
69
+ end
70
+ end
71
+
72
+ # The commands/steps to validate any arguments.
73
+ def self.validate(&block)
74
+ if block_given?
75
+ @validate = block
76
+ else
77
+ @validate
78
+ end
79
+ end
80
+
81
+ # The commands/steps to build the package.
82
+ def self.build(&block)
83
+ if block_given?
84
+ @build = block
85
+ else
86
+ @build || fail(AbstractMethod.new("#{self.class.name}.build"))
87
+ end
88
+ end
89
+
90
+ # The commands/steps to cleanup any temporary files/directories.
91
+ def self.clean(&block)
92
+ if block_given?
93
+ @clean = block
94
+ else
95
+ @clean
96
+ end
97
+ end
98
+
99
+ # Create a new packager object.
100
+ #
101
+ # @param [Project] project
102
+ def initialize(project)
103
+ @project = project
104
+ end
105
+
106
+ #
107
+ # Generation methods
108
+ # ------------------------------
109
+
110
+ # Create a directory at the given +path+.
111
+ #
112
+ # @param [String] path
113
+ def create_directory(path)
114
+ FileUtils.mkdir_p(path)
115
+ path
116
+ end
117
+
118
+ # Remove the directory at the given +path+.
119
+ #
120
+ # @param [String] path
121
+ def remove_directory(path)
122
+ FileUtils.rm_rf(path)
123
+ end
124
+
125
+ # Purge the directory of all contents.
126
+ #
127
+ # @param [String] path
128
+ def purge_directory(path)
129
+ remove_directory(path)
130
+ create_directory(path)
131
+ end
132
+
133
+ # Copy the +source+ file to the +destination+.
134
+ #
135
+ # @param [String] source
136
+ # @param [String] destination
137
+ def copy_file(source, destination)
138
+ FileUtils.cp(source, destination)
139
+ destination
140
+ end
141
+
142
+ # Remove the file at the given path.
143
+ #
144
+ # @param [String] pah
145
+ def remove_file(path)
146
+ FileUtils.rm_f(path)
147
+ end
148
+
149
+ # Execute the command using shellout!
150
+ #
151
+ # @param [String] command
152
+ def execute(command)
153
+ shellout!(command, timeout: 3600, cwd: staging_dir)
154
+ end
155
+
156
+ #
157
+ # Validations
158
+ # ------------------------------
159
+
160
+ # Validate the presence of a file.
161
+ #
162
+ # @param [String] path
163
+ def assert_presence!(path)
164
+ fail MissingAsset.new(path) unless File.exist?(path)
165
+ end
166
+
167
+ # Execute this packager by running the following phases in order:
168
+ #
169
+ # - setup
170
+ # - validate
171
+ # - build
172
+ # - clean
173
+ #
174
+ def run!
175
+ instance_eval(&self.class.validate) if self.class.validate
176
+ instance_eval(&self.class.setup) if self.class.setup
177
+ instance_eval(&self.class.build) if self.class.build
178
+ instance_eval(&self.class.clean) if self.class.clean
179
+ end
180
+
181
+ # The ending name of this package on disk. +Omnibus::Project+ uses this to
182
+ # generate metadata about the package after it is built.
183
+ #
184
+ # @return [String]
185
+ def package_name
186
+ fail AbstractMethod.new("#{self.class.name}#package_name")
187
+ end
188
+
189
+ private
190
+
191
+ # The path to the directory where we can throw staged files.
192
+ #
193
+ # @return [String]
194
+ def staging_dir
195
+ File.expand_path("#{project.package_tmp}/#{underscore_name}")
196
+ end
197
+
198
+ # The path to a local resource on disk.
199
+ #
200
+ # @param [String]
201
+ # the name or path of the resource
202
+ # @return [String]
203
+ def resource(path)
204
+ File.expand_path("#{resources_path}/#{path}")
205
+ end
206
+
207
+ # The path to all the resources on the local file system.
208
+ #
209
+ # @return [String]
210
+ def resources_path
211
+ File.expand_path("#{project.files_path}/#{underscore_name}/Resources")
212
+ end
213
+
214
+ # The underscored equivalent of this class. This is mostly used by file
215
+ # paths.
216
+ #
217
+ # @return [String]
218
+ def underscore_name
219
+ @underscore_name ||= self.class.name
220
+ .split('::')
221
+ .last
222
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
223
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
224
+ .tr('-', '_')
225
+ .downcase
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,215 @@
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
+ module Omnibus
19
+ class Packager::MacDmg < Packager::Base
20
+ attr_reader :packager
21
+
22
+ validate do
23
+ assert_presence!(resource('background.png'))
24
+ assert_presence!(resource('icon.png'))
25
+ end
26
+
27
+ setup do
28
+ create_directory(dmg_stage)
29
+ copy_assets_to_dmg
30
+ end
31
+
32
+ build do
33
+ copy_assets_to_dmg
34
+ create_writable_dmg
35
+ attach_dmg
36
+ set_volume_icon
37
+ prettify_dmg
38
+ compress_dmg
39
+ set_dmg_icon
40
+ end
41
+
42
+ clean do
43
+ remove_file("#{staging_dir}/tmp.icns")
44
+ remove_file("#{staging_dir}/tmp.rsrc")
45
+ end
46
+
47
+ #
48
+ # Create a new DMG packager.
49
+ #
50
+ # @param [Packager::MacPkg] mac_packager
51
+ #
52
+ def initialize(mac_packager)
53
+ @packager = mac_packager
54
+ super(mac_packager.project)
55
+ end
56
+
57
+ #
58
+ # Copy the assets in the local omnibus project into a staging folder that
59
+ # will soon become our writable dmg.
60
+ #
61
+ def copy_assets_to_dmg
62
+ # Copy the compiled pkg into the dmg
63
+ copy_file(packager.final_pkg, "#{dmg_stage}/#{project.name}.pkg")
64
+
65
+ # Copy support files
66
+ support = create_directory("#{dmg_stage}/.support")
67
+ copy_file(resource('background.png'), "#{support}/background.png")
68
+ end
69
+
70
+ #
71
+ # Create a writable dmg we can put assets on.
72
+ #
73
+ def create_writable_dmg
74
+ execute <<-EOH.gsub(/^ {8}/, '')
75
+ hdiutil create \\
76
+ -srcfolder "#{dmg_stage}" \\
77
+ -volname "#{project.name}" \\
78
+ -fs HFS+ \\
79
+ -fsargs "-c c=64,a=16,e=16" \\
80
+ -format UDRW \\
81
+ -size 512000k \\
82
+ "#{writable_dmg}"
83
+ EOH
84
+ end
85
+
86
+ #
87
+ # Attach the dmg, storing a reference to the device for later use.
88
+ #
89
+ def attach_dmg
90
+ @device = execute(<<-EOH.gsub(/^ {8}/, '')).stdout.strip
91
+ hdiutil attach \\
92
+ -readwrite \\
93
+ -noverify \\
94
+ -noautoopen \\
95
+ "#{writable_dmg}" | egrep '^/dev/' | sed 1q | awk '{print $1}'
96
+ EOH
97
+ end
98
+
99
+ #
100
+ # Create the icon for the volume using sips.
101
+ #
102
+ def set_volume_icon
103
+ execute <<-EOH.gsub(/^ {8}/, '')
104
+ # Generate the icns
105
+ mkdir tmp.iconset
106
+ sips -z 16 16 #{resource('icon.png')} --out tmp.iconset/icon_16x16.png
107
+ sips -z 32 32 #{resource('icon.png')} --out tmp.iconset/icon_16x16@2x.png
108
+ sips -z 32 32 #{resource('icon.png')} --out tmp.iconset/icon_32x32.png
109
+ sips -z 64 64 #{resource('icon.png')} --out tmp.iconset/icon_32x32@2x.png
110
+ sips -z 128 128 #{resource('icon.png')} --out tmp.iconset/icon_128x128.png
111
+ sips -z 256 256 #{resource('icon.png')} --out tmp.iconset/icon_128x128@2x.png
112
+ sips -z 256 256 #{resource('icon.png')} --out tmp.iconset/icon_256x256.png
113
+ sips -z 512 512 #{resource('icon.png')} --out tmp.iconset/icon_256x256@2x.png
114
+ sips -z 512 512 #{resource('icon.png')} --out tmp.iconset/icon_512x512.png
115
+ sips -z 1024 1024 #{resource('icon.png')} --out tmp.iconset/icon_512x512@2x.png
116
+ iconutil -c icns tmp.iconset
117
+
118
+ # Copy it over
119
+ cp tmp.icns "/Volumes/#{project.name}/.VolumeIcon.icns"
120
+
121
+ # Source the icon
122
+ SetFile -a C "/Volumes/#{project.name}"
123
+ EOH
124
+ end
125
+
126
+ #
127
+ # Use Applescript to setup the DMG with pretty logos and colors.
128
+ #
129
+ def prettify_dmg
130
+ execute <<-EOH.gsub(/ ^{8}/, '')
131
+ echo '
132
+ tell application "Finder"
133
+ tell disk "'#{project.name}'"
134
+ open
135
+ set current view of container window to icon view
136
+ set toolbar visible of container window to false
137
+ set statusbar visible of container window to false
138
+ set the bounds of container window to {#{project.config[:dmg_window_bounds]}}
139
+ set theViewOptions to the icon view options of container window
140
+ set arrangement of theViewOptions to not arranged
141
+ set icon size of theViewOptions to 72
142
+ set background picture of theViewOptions to file ".support:'background.png'"
143
+ delay 5
144
+ set position of item "'#{project.name}.pkg'" of container window to {#{project.config[:dmg_pkg_position]}}
145
+ update without registering applications
146
+ delay 5
147
+ end tell
148
+ end tell
149
+ ' | osascript
150
+ EOH
151
+ end
152
+
153
+ #
154
+ # Compress the dmg using hdiutil and zlib.
155
+ #
156
+ def compress_dmg
157
+ execute <<-EOH.gsub(/ ^{8}/, '')
158
+ chmod -Rf go-w /Volumes/#{project.name}
159
+ sync
160
+ hdiutil detach "#{@device}"
161
+ hdiutil convert \\
162
+ "#{writable_dmg}" \\
163
+ -format UDZO \\
164
+ -imagekey zlib-level=9 \\
165
+ -o "#{final_dmg}"
166
+ rm -rf "#{writable_dmg}"
167
+ EOH
168
+ end
169
+
170
+ #
171
+ # Set the dmg icon to our custom icon.
172
+ #
173
+ def set_dmg_icon
174
+ execute <<-EOH.gsub(/^ {8}/, '')
175
+ # Convert the png to an icon
176
+ sips -i "#{resource('icon.png')}"
177
+
178
+ # Extract the icon into its own resource
179
+ DeRez -only icns "#{resource('icon.png')}" > tmp.rsrc
180
+
181
+ # Append the icon reosurce to the DMG
182
+ Rez -append tmp.rsrc -o "#{final_dmg}"
183
+
184
+ # Source the icon
185
+ SetFile -a C "#{final_dmg}"
186
+ EOH
187
+ end
188
+
189
+ # @see Base#package_name
190
+ def package_name
191
+ "#{name}-#{version}-#{iteration}.dmg"
192
+ end
193
+
194
+ # The path to the folder that we should stage.
195
+ #
196
+ # @return [String]
197
+ def dmg_stage
198
+ File.expand_path("#{staging_dir}/dmg")
199
+ end
200
+
201
+ # The path to the writable dmg on disk.
202
+ #
203
+ # @return [String]
204
+ def writable_dmg
205
+ File.expand_path("#{staging_dir}/#{name}-writable.dmg")
206
+ end
207
+
208
+ # The path where the final dmg will be produced.
209
+ #
210
+ # @return [String]
211
+ def final_dmg
212
+ File.expand_path("#{project.package_dir}/#{name}-#{version}-#{iteration}.dmg")
213
+ end
214
+ end
215
+ end