omnibus 2.0.2 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +0 -2
- data/CHANGELOG.md +26 -6
- data/Gemfile +7 -0
- data/Guardfile +10 -0
- data/README.md +103 -160
- data/Rakefile +6 -1
- data/docs/Building on OSX.md +66 -0
- data/docs/omnibus-build-cache.md +75 -0
- data/lib/omnibus.rb +9 -13
- data/lib/omnibus/artifact.rb +1 -13
- data/lib/omnibus/assets/README-logo.png +0 -0
- data/lib/omnibus/assets/logo.psd +0 -0
- data/lib/omnibus/builder.rb +1 -0
- data/lib/omnibus/cli/application.rb +17 -4
- data/lib/omnibus/cli/build.rb +6 -4
- data/lib/omnibus/config.rb +33 -0
- data/lib/omnibus/exceptions.rb +20 -14
- data/lib/omnibus/health_check.rb +2 -0
- data/lib/omnibus/install_path_cache.rb +106 -0
- data/lib/omnibus/library.rb +18 -1
- data/lib/omnibus/packagers/base.rb +228 -0
- data/lib/omnibus/packagers/mac_dmg.rb +215 -0
- data/lib/omnibus/packagers/mac_pkg.rb +129 -253
- data/lib/omnibus/project.rb +89 -95
- data/lib/omnibus/s3_cacher.rb +4 -7
- data/lib/omnibus/software.rb +47 -83
- data/lib/omnibus/sugar.rb +49 -0
- data/lib/omnibus/templates/.kitchen.yml.erb +3 -0
- data/lib/omnibus/templates/Berksfile.erb +4 -0
- data/lib/omnibus/templates/Gemfile.erb +1 -1
- data/lib/omnibus/templates/mac_dmg/background.png +0 -0
- data/lib/omnibus/templates/mac_dmg/icon.png +0 -0
- data/lib/omnibus/templates/mac_pkg/background.png +0 -0
- data/lib/omnibus/templates/mac_pkg/license.html.erb +1 -0
- data/lib/omnibus/templates/mac_pkg/welcome.html.erb +9 -0
- data/lib/omnibus/templates/omnibus.rb.example.erb +31 -4
- data/lib/omnibus/version.rb +1 -1
- data/omnibus.gemspec +5 -4
- data/spec/fixtures/sample/files/mac_dmg/Resources/background.png +0 -0
- data/spec/fixtures/sample/files/mac_dmg/Resources/icon.png +0 -0
- data/spec/fixtures/sample/files/mac_pkg/Resources/background.png +0 -0
- data/spec/fixtures/sample/files/mac_pkg/Resources/license.html +1 -0
- data/spec/fixtures/sample/files/mac_pkg/Resources/welcome.html +9 -0
- data/{functional/fixtures/mac_pkg/package-scripts/functional-test-project → spec/fixtures/sample/package-scripts/sample}/postinstall +0 -0
- data/spec/functional/packagers/mac_spec.rb +74 -0
- data/spec/spec_helper.rb +14 -3
- data/spec/sugar_spec.rb +20 -0
- data/spec/{artifact_spec.rb → unit/artifact_spec.rb} +2 -3
- data/spec/{build_version_spec.rb → unit/build_version_spec.rb} +0 -0
- data/spec/{config_spec.rb → unit/config_spec.rb} +4 -0
- data/spec/{fetchers → unit/fetchers}/git_fetcher_spec.rb +0 -0
- data/spec/{fetchers → unit/fetchers}/net_fetcher_spec.rb +0 -0
- data/spec/unit/install_path_cache_spec.rb +175 -0
- data/spec/unit/library_spec.rb +67 -0
- data/spec/{omnibus_spec.rb → unit/omnibus_spec.rb} +0 -0
- data/spec/{overrides_spec.rb → unit/overrides_spec.rb} +0 -0
- data/spec/{package_release_spec.rb → unit/package_release_spec.rb} +0 -0
- data/spec/unit/packagers/base_spec.rb +221 -0
- data/spec/unit/packagers/mac_pkg_spec.rb +163 -0
- data/spec/{project_spec.rb → unit/project_spec.rb} +0 -14
- data/spec/{s3_cacher_spec.rb → unit/s3_cacher_spec.rb} +0 -0
- data/spec/{software_spec.rb → unit/software_spec.rb} +0 -1
- metadata +122 -103
- data/functional/fixtures/mac_pkg/files/mac_pkg/Resources/background.png +0 -0
- data/functional/fixtures/mac_pkg/files/mac_pkg/Resources/license.html +0 -1
- data/functional/fixtures/mac_pkg/files/mac_pkg/Resources/welcome.html +0 -1
- data/functional/packagers/mac_pkg_spec.rb +0 -72
- data/lib/omnibus/clean_tasks.rb +0 -28
- data/spec/packagers/mac_pkg_spec.rb +0 -262
data/lib/omnibus/library.rb
CHANGED
@@ -27,7 +27,24 @@ module Omnibus
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def component_added(component)
|
30
|
-
@components
|
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
|