fastlane-plugin-create_dmg 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (26) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +48 -0
  3. data/README.md +52 -0
  4. data/lib/fastlane/plugin/create_dmg/actions/create_dmg_action.rb +226 -0
  5. data/lib/fastlane/plugin/create_dmg/actions/update_dmg_action.rb +118 -0
  6. data/lib/fastlane/plugin/create_dmg/assets/update-dmg.sh +206 -0
  7. data/lib/fastlane/plugin/create_dmg/helper/create_dmg_helper.rb +86 -0
  8. data/lib/fastlane/plugin/create_dmg/helper/update_dmg_helper.rb +43 -0
  9. data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/LICENSE +22 -0
  10. data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/Makefile +33 -0
  11. data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/README.md +115 -0
  12. data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/builder/create-dmg.builder +26 -0
  13. data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/create-dmg +484 -0
  14. data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/doc-project/Developer Notes.md +35 -0
  15. data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/doc-project/Release Checklist.md +10 -0
  16. data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/examples/01-main-example/installer_background.png +0 -0
  17. data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/examples/01-main-example/sample +25 -0
  18. data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/examples/01-main-example/source_folder/Application.app +0 -0
  19. data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/support/eula-resources-template.xml +105 -0
  20. data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/support/template.applescript +74 -0
  21. data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/tests/007-space-in-dir-name/my files/hello.txt +1 -0
  22. data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/tests/007-space-in-dir-name/run-test +5 -0
  23. data/lib/fastlane/plugin/create_dmg/version.rb +5 -0
  24. data/lib/fastlane/plugin/create_dmg.rb +16 -0
  25. data/lib/fastlane.dmg +0 -0
  26. metadata +207 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fa86f88b5d47522d28ec391b30c0d38f5fecf28e8c931186a30d3b32bd03a559
4
+ data.tar.gz: 8f4a2c0ca49521ad6cc683021bdfa2def9ca92367797bf2e8fc86b1050d7c5a1
5
+ SHA512:
6
+ metadata.gz: b3fc003bce6f69371fa7f499f77f10beae88829e12bfa7d5f39faba76733416208b775a986bed18e2bc0c1b760c60d5f08b4dfc624ba984574d46cdbd5cca206
7
+ data.tar.gz: 2fc8393a200f57a9703fa87ef96a04b32fa038a5a6e0b0d4d432e4b51efeb3f5e9eda1f6fe2bd19702d3d9c8968d190aefcd6deee0b4b895ea63cedae83d79a2
data/LICENSE ADDED
@@ -0,0 +1,48 @@
1
+ create-dmg fastlane plugin
2
+
3
+ The MIT License (MIT)
4
+
5
+ Copyright (c) 2021 Vitalii Budnik <inekrich@me.com>
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
24
+
25
+ create-dmg
26
+
27
+ The MIT License (MIT)
28
+
29
+ Copyright (c) 2008-2014 Andrey Tarantsov
30
+ Copyright (c) 2020 Andrew Janke
31
+
32
+ Permission is hereby granted, free of charge, to any person obtaining a copy
33
+ of this software and associated documentation files (the "Software"), to deal
34
+ in the Software without restriction, including without limitation the rights
35
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36
+ copies of the Software, and to permit persons to whom the Software is
37
+ furnished to do so, subject to the following conditions:
38
+
39
+ The above copyright notice and this permission notice shall be included in all
40
+ copies or substantial portions of the Software.
41
+
42
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
45
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
47
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
48
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # create_dmg plugin
2
+
3
+ [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-create_dmg)
4
+
5
+ ## Getting Started
6
+
7
+ This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-create_dmg`, add it to your project by running:
8
+
9
+ ```bash
10
+ fastlane add_plugin create_dmg
11
+ ```
12
+
13
+ ## About create_dmg
14
+
15
+ A Ruby wrapper over create-dmg - A shell script to build fancy DMGs.
16
+
17
+ **Note to author:** Add a more detailed description about this plugin here. If your plugin contains multiple actions, make sure to mention them here.
18
+
19
+ ## Example
20
+
21
+ Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin. Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`.
22
+
23
+ **Note to author:** Please set up a sample project to make it easy for users to explore what your plugin does. Provide everything that is necessary to try out the plugin in this project (including a sample Xcode/Android project if necessary)
24
+
25
+ ## Run tests for this plugin
26
+
27
+ To run both the tests, and code style validation, run
28
+
29
+ ```
30
+ rake
31
+ ```
32
+
33
+ To automatically fix many of the styling issues, use
34
+ ```
35
+ rubocop -a
36
+ ```
37
+
38
+ ## Issues and Feedback
39
+
40
+ For any other issues and feedback about this plugin, please submit it to this repository.
41
+
42
+ ## Troubleshooting
43
+
44
+ If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
45
+
46
+ ## Using _fastlane_ Plugins
47
+
48
+ For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
49
+
50
+ ## About _fastlane_
51
+
52
+ _fastlane_ is the easiest way to automate beta deployments and releases for your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools).
@@ -0,0 +1,226 @@
1
+ require 'fastlane/action'
2
+ require 'fastlane/boolean'
3
+ require 'fastlane_core/configuration/config_item'
4
+
5
+ require_relative '../helper/create_dmg_helper'
6
+
7
+ module Fastlane
8
+ module Actions
9
+ module SharedValues
10
+ CREATE_DMG_OUTPUT_PATH = :CREATE_DMG_OUTPUT_PATH
11
+ end
12
+
13
+ UI = FastlaneCore::UI
14
+
15
+ class CreateDmgAction < Action
16
+ def self.run(params)
17
+ helper = Fastlane::Helper::CreateDmgHelper.new(params: params)
18
+
19
+ if File.exist?(helper.output_filename)
20
+ UI.message("Remove #{helper.output_filename}") if helper.verbose
21
+ File.delete(helper.output_filename)
22
+ end
23
+
24
+ temp_source_folder = Dir.mktmpdir('create-dmg')
25
+
26
+ create_dmg_parameters = helper.create_dmg_parameters
27
+
28
+ create_dmg_script_path = File.expand_path("#{__dir__}/../vendor/create-dmg/create-dmg")
29
+
30
+ create_dmg_parameters.insert(0, create_dmg_script_path)
31
+ create_dmg_parameters << temp_source_folder
32
+
33
+ begin
34
+ UI.message("Copy source '#{helper.source}' to temp folder '#{temp_source_folder}'") if helper.verbose
35
+ Actions.sh(
36
+ 'ditto', '--rsrc', '--extattr', helper.source, "#{temp_source_folder}/#{helper.source_basename}",
37
+ log: helper.verbose
38
+ )
39
+ UI.message("Create DMG at #{helper.output_filename}") if helper.verbose
40
+ Actions.sh(
41
+ create_dmg_parameters,
42
+ log: true
43
+ )
44
+ ensure
45
+ UI.message("Delete temp folder #{temp_source_folder}") if helper.verbose
46
+ FileUtils.rm_rf(temp_source_folder)
47
+ end
48
+
49
+ UI.success("Successfully created DMG")
50
+ UI.message(helper.output_filename)
51
+
52
+ Actions.lane_context[SharedValues::CREATE_DMG_OUTPUT_PATH] = helper.output_filename
53
+ ENV[SharedValues::CREATE_DMG_OUTPUT_PATH.to_s] = helper.output_filename
54
+
55
+ return helper.output_filename
56
+ end
57
+
58
+ def self.description
59
+ "A Ruby wrapper over create-dmg."
60
+ end
61
+
62
+ def self.authors
63
+ ["Vitalii Budnik"]
64
+ end
65
+
66
+ def self.output
67
+ [
68
+ ['CREATE_DMG_OUTPUT_PATH', 'The path to the created DMG']
69
+ ]
70
+ end
71
+
72
+ def self.return_value
73
+ 'The path to the created DMG'
74
+ end
75
+
76
+ def self.return_type
77
+ :string
78
+ end
79
+
80
+ def self.details
81
+ # Optional:
82
+ "A Ruby wrapper over create-dmg - A shell script to build fancy DMGs."
83
+ end
84
+
85
+ def self.available_options
86
+ [
87
+ FastlaneCore::ConfigItem.new(key: :source,
88
+ env_name: "CREATE_DMG_SOURCE",
89
+ description: "Path to the folder or file to be archived to dmg",
90
+ optional: false,
91
+ type: String,
92
+ verify_block: proc do |value|
93
+ UI.user_error!("Could not find folder at #{value}") unless File.exist?(value)
94
+ end),
95
+ FastlaneCore::ConfigItem.new(key: :output_filename,
96
+ env_name: "CREATE_DMG_OUTPUT_FILENAME",
97
+ description: "Path to the folder to be archived to dmg",
98
+ optional: true,
99
+ type: String),
100
+
101
+ # Volume options
102
+ FastlaneCore::ConfigItem.new(key: :volume_name,
103
+ env_name: "CREATE_DMG_VOLUME_NAME",
104
+ description: "Volume name displayed in the Finder sidebar and window title",
105
+ optional: true,
106
+ type: String),
107
+ FastlaneCore::ConfigItem.new(key: :volume_icon,
108
+ env_name: "CREATE_DMG_VOLUME_ICON",
109
+ description: "Volume icon (*.incs)",
110
+ optional: true,
111
+ type: String),
112
+ FastlaneCore::ConfigItem.new(key: :volume_format,
113
+ env_name: "CREATE_DMG_VOLUME_FORMAT",
114
+ description: "The final image format. 'UDZO' or 'UDBZ'",
115
+ optional: true,
116
+ type: String,
117
+ default_value: 'UDZO',
118
+ verify_block: proc do |value|
119
+ UI.user_error!("Could not find folder at '#{value}'") unless ['UDZO', 'UDBZ'].include?(value)
120
+ end),
121
+ FastlaneCore::ConfigItem.new(key: :volume_size,
122
+ env_name: "CREATE_DMG_VOLUME_SIZE",
123
+ description: "Disk image size (in MB)",
124
+ optional: true,
125
+ type: Integer),
126
+
127
+ # Window options
128
+ FastlaneCore::ConfigItem.new(key: :window_position,
129
+ env_name: "CREATE_DMG_WINDOW_POSITION",
130
+ description: "Position of the disk image window on the screen X Y coordinates. E.g. '420 150'",
131
+ optional: true,
132
+ type: String),
133
+ FastlaneCore::ConfigItem.new(key: :window_size,
134
+ env_name: "CREATE_DMG_WINDOW_SIZE",
135
+ description: "Size of the disk image window on the screen WIDTH HEIGHT. E.g. '480 320'",
136
+ optional: true,
137
+ type: String),
138
+
139
+ # Disk image folder options
140
+ FastlaneCore::ConfigItem.new(key: :background,
141
+ env_name: "CREATE_DMG_BACKGROUND",
142
+ description: "Disk Image folder background image (png, gif, jpg)",
143
+ optional: true,
144
+ type: String),
145
+ FastlaneCore::ConfigItem.new(key: :icon_size,
146
+ env_name: "CREATE_DMG_ICON_SIZE",
147
+ description: "Icon size inside the DMG folder. Up to 128",
148
+ optional: true,
149
+ type: Integer),
150
+ FastlaneCore::ConfigItem.new(key: :text_size,
151
+ env_name: "CREATE_DMG_TEXT_SIZE",
152
+ description: "Text size inside the DMG folder (10-16)",
153
+ optional: true,
154
+ type: Integer),
155
+ FastlaneCore::ConfigItem.new(key: :source_icon_position,
156
+ env_name: "CREATE_DMG_SOURCE_ICON_POSITION",
157
+ description: "Position of the file's icon 'X Y'. E.g. '10 10'",
158
+ optional: true,
159
+ type: String),
160
+ FastlaneCore::ConfigItem.new(key: :hide_source_extension,
161
+ env_name: "CREATE_DMG_HIDE_SOURCE_EXTENSION",
162
+ description: "Hide the source extension",
163
+ optional: true,
164
+ type: Boolean),
165
+
166
+ # Link positions
167
+ FastlaneCore::ConfigItem.new(key: :applications_folder_position,
168
+ env_name: "CREATE_DMG_APPLICATIONS_FOLDER_ICON_POSITION",
169
+ description: "Position of the /Applications folder icon 'X Y'. E.g. '150 10'",
170
+ optional: true,
171
+ type: String),
172
+ FastlaneCore::ConfigItem.new(key: :quick_look_folder_position,
173
+ env_name: "CREATE_DMG_SOURCE_ICON_POSITION",
174
+ description: "Position of the QuickLook install folder icon 'X Y'. E.g. '150 150'",
175
+ optional: true,
176
+ type: String),
177
+
178
+ # EULA
179
+ FastlaneCore::ConfigItem.new(key: :eula_filename,
180
+ env_name: "CREATE_DMG_EULA_FILENAME",
181
+ description: "A path to the end-user license agreement file",
182
+ optional: true,
183
+ type: String),
184
+
185
+ # Additional files
186
+ FastlaneCore::ConfigItem.new(key: :addiional_files,
187
+ env_name: "CREATE_DMG_ADDITIONAL_FILES",
188
+ description: "A list of files to add '<target_name> <file>|<folder> <x> <y>'. E.g. 'Another.app Second.app 200 200'",
189
+ optional: true,
190
+ type: Array),
191
+
192
+ # hdiutil
193
+ FastlaneCore::ConfigItem.new(key: :hdiutil_verbose,
194
+ env_name: "CREATE_DMG_HDUTIL_VERBOSE",
195
+ description: "Execute hdiutil in verbose mode",
196
+ conflicting_options: [:hdiutil_quiet],
197
+ optional: true,
198
+ type: Boolean),
199
+ FastlaneCore::ConfigItem.new(key: :hdiutil_quiet,
200
+ env_name: "CREATE_DMG_HDUTIL_QUIET",
201
+ description: "Execute hdiutil in quiet mode",
202
+ conflicting_options: [:hdiutil_verbose],
203
+ optional: true,
204
+ type: Boolean),
205
+ FastlaneCore::ConfigItem.new(key: :hdiutil_sandbox_safe,
206
+ env_name: "CREATE_DMG_HDUTIL_SANDBOX_SAFE",
207
+ description: "Execute hdiutil with sandbox compatibility and do not bless. Some options are unavailable if this options is set to true",
208
+ optional: true,
209
+ type: Boolean,
210
+ default_value: false),
211
+
212
+ # Plugin options
213
+ FastlaneCore::ConfigItem.new(key: :verbose,
214
+ env_name: "CREATE_DMG_VERBOSE",
215
+ description: "Whether to log create-dmg output",
216
+ optional: true,
217
+ type: Boolean)
218
+ ]
219
+ end
220
+
221
+ def self.is_supported?(platform)
222
+ [:mac].include?(platform)
223
+ end
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,118 @@
1
+ require 'fastlane/action'
2
+ require 'fastlane/boolean'
3
+ require 'fastlane_core/configuration/config_item'
4
+
5
+ require_relative '../helper/update_dmg_helper'
6
+
7
+ module Fastlane
8
+ module Actions
9
+ module SharedValues
10
+ UPDATE_DMG_OUTPUT_PATH = :UPDATE_DMG_OUTPUT_PATH
11
+ end
12
+
13
+ UI = FastlaneCore::UI
14
+
15
+ class UpdateDmgAction < Action
16
+ def self.run(params)
17
+ helper = Fastlane::Helper::UpdateDmgHelper.new(params: params)
18
+
19
+ update_dmg_parameters = helper.update_dmg_parameters
20
+
21
+ update_dmg_script_path = File.expand_path("#{__dir__}/../assets/update-dmg.sh")
22
+
23
+ update_dmg_parameters.insert(0, update_dmg_script_path)
24
+ UI.message("Create DMG at #{params[:output_filename]}") if helper.verbose
25
+ Actions.sh(
26
+ update_dmg_parameters,
27
+ log: helper.verbose
28
+ )
29
+
30
+ UI.success("Successfully created DMG")
31
+ UI.message(helper.output_filename)
32
+
33
+ Actions.lane_context[SharedValues::UPDATE_DMG_OUTPUT_PATH] = helper.output_filename
34
+ ENV[SharedValues::UPDATE_DMG_OUTPUT_PATH.to_s] = helper.output_filename
35
+
36
+ return helper.output_filename
37
+ end
38
+
39
+ def self.description
40
+ "Update files in template DMG"
41
+ end
42
+
43
+ def self.authors
44
+ ["Vitalii Budnik"]
45
+ end
46
+
47
+ def self.output
48
+ [
49
+ ['UPDATE_DMG_OUTPUT_PATH', 'The path to the updated DMG']
50
+ ]
51
+ end
52
+
53
+ def self.return_value
54
+ 'The path to the updated DMG'
55
+ end
56
+
57
+ def self.return_type
58
+ :string
59
+ end
60
+
61
+ def self.details
62
+ # Optional:
63
+ "Update files in template DMG."
64
+ end
65
+
66
+ def self.available_options
67
+ [
68
+ FastlaneCore::ConfigItem.new(key: :source,
69
+ env_name: "UPDATE_DMG_SOURCE",
70
+ description: "Path to the folder or file to be updated in the original dmg",
71
+ optional: false,
72
+ type: String,
73
+ verify_block: proc do |value|
74
+ UI.user_error!("Could not find folder at '#{value}'") unless File.exist?(value)
75
+ end),
76
+ FastlaneCore::ConfigItem.new(key: :output_filename,
77
+ env_name: "UPDATE_DMG_OUTPUT_FILENAME",
78
+ description: "Path to the resulting dmg file",
79
+ optional: true,
80
+ type: String),
81
+ FastlaneCore::ConfigItem.new(key: :template,
82
+ env_name: "UPDATE_DMG_OUTPUT_FILENAME",
83
+ description: "Path to the template DMG where to update file",
84
+ optional: true,
85
+ type: String,
86
+ verify_block: proc do |value|
87
+ UI.user_error!("Could not find template DMG at '#{value}'") unless File.exist?(value)
88
+ end),
89
+
90
+ # hdiutil
91
+ FastlaneCore::ConfigItem.new(key: :hdiutil_verbose,
92
+ env_name: "UPDATE_DMG_HDUTIL_VERBOSE",
93
+ description: "Execute hdiutil in verbose mode",
94
+ conflicting_options: [:hdiutil_quiet],
95
+ optional: true,
96
+ type: Boolean),
97
+ FastlaneCore::ConfigItem.new(key: :hdiutil_quiet,
98
+ env_name: "UPDATE_DMG_HDUTIL_QUIET",
99
+ description: "Execute hdiutil in quiet mode",
100
+ conflicting_options: [:hdiutil_verbose],
101
+ optional: true,
102
+ type: Boolean),
103
+
104
+ # Plugin options
105
+ FastlaneCore::ConfigItem.new(key: :verbose,
106
+ env_name: "UPDATE_DMG_VERBOSE",
107
+ description: "Whether to log update-dmg output",
108
+ optional: true,
109
+ type: Boolean)
110
+ ]
111
+ end
112
+
113
+ def self.is_supported?(platform)
114
+ [:mac].include?(platform)
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,206 @@
1
+ #!/bin/sh
2
+
3
+ set -Eeo pipefail
4
+
5
+ # A path to the template DMG file
6
+ TEMPLATE_DMG=
7
+ # Source file to add to DMG
8
+ SOURCE_FILE=
9
+ # A path Output DMG
10
+ OUTPUT_DMG=
11
+ # Codesign identity if passed
12
+ CODE_SIGN_IDENTITY=
13
+ # hdiutil verbosity level
14
+ HDIUTIL_VERBOSITY=
15
+
16
+ # Mount point - random UUID to avoid conflicts
17
+ DMG_MOUNT_POINT=$(uuidgen)
18
+ # A path to a temporary (writable) DMG file
19
+ DMG_TEMP="$(mktemp).dmg"
20
+
21
+ # Maximum attempts to perform before trying force DMG detachment.
22
+ MAXIMUM_UNMOUNTING_ATTEMPTS=3
23
+
24
+ # Outputs script usage
25
+ function usage() {
26
+ cat <<EOHELP
27
+
28
+ Updates file or folder in template DMG file.
29
+
30
+ Usage: $(basename $0) [options] --source <source_folder> --template_dmg <template.dmg> --output_dmg <output_name.dmg>
31
+
32
+ The <source_folder> will be copied into the disk image.
33
+
34
+ Options:
35
+ --source
36
+ Source file or folder to add into the new DMG.
37
+ --template-dmg
38
+ Path to the template disk image file.
39
+ --output-dmg
40
+ Path to the resulting disk image file.
41
+ --code-sign-identity
42
+ Code sign idenity to sign the resulting DMG.
43
+ --hdiutil-verbose
44
+ Execute hdiutil in verbose mode.
45
+ --hdiutil-quiet
46
+ Execute hdiutil in quiet mode.
47
+ -h, --help
48
+ display this help screen
49
+
50
+ EOHELP
51
+ exit 0
52
+ }
53
+
54
+ # Detaches mounted DMG
55
+ function unmount() {
56
+ DEV_NAME=$1
57
+ DMG_MOUNT_POINT=$2
58
+
59
+ if [[ ! -z "${DMG_MOUNT_POINT}" && ! -d "${DMG_MOUNT_POINT}" ]]; then
60
+ # DMG is not mounted
61
+ break
62
+ fi
63
+
64
+ # Unmount
65
+ unmounting_attempts=0
66
+ until
67
+ echo "โ๏ธ Unmount '${DEV_NAME}'"
68
+ (( unmounting_attempts++ ))
69
+ hdiutil detach "${DEV_NAME}"
70
+ exit_code=$?
71
+ (( exit_code == 0 )) && break # nothing goes wrong
72
+ (( exit_code != 16 )) && exit $exit_code # exit with the original exit code
73
+ # The above statement returns 1 if test failed (exit_code == 16).
74
+ # It can make the code in the {do... done} block to be executed
75
+ do
76
+ (( unmounting_attempts == MAXIMUM_UNMOUNTING_ATTEMPTS )) && exit 16 # patience exhausted, exit with code EBUSY
77
+ echo "๐Ÿšฆ Wait a moment..."
78
+ sleep $(( 1 * (2 ** unmounting_attempts) ))
79
+ done
80
+ unset unmounting_attempts
81
+
82
+ if [[ ! -z "${DMG_MOUNT_POINT}" && -d "${DMG_MOUNT_POINT}" ]]; then
83
+ echo " โ๏ธ Unmount '${DEV_NAME}' at '${DMG_MOUNT_POINT}' with force"
84
+ hdiutil detach "${DEV_NAME}" -force
85
+ fi
86
+ }
87
+
88
+ # Check if min parameters count is set.
89
+ if [[ -z "$6" ]]; then
90
+ echo "๐Ÿ™… Not enough arguments. Run '$(basename $0) --help' for help."
91
+ exit 1
92
+ fi
93
+
94
+ # Argument parsing.
95
+ while [[ "${1:0:1}" = "-" ]]; do
96
+ case $1 in
97
+ --template-dmg)
98
+ TEMPLATE_DMG="$2"
99
+ shift; shift;;
100
+ --source)
101
+ SOURCE_FILE="$2"
102
+ shift; shift;;
103
+ --output-dmg)
104
+ OUTPUT_DMG="$2"
105
+ shift; shift;;
106
+ --code-sign-identity)
107
+ CODE_SIGN_IDENTITY="$2"
108
+ shift; shift;;
109
+ --hdiutil-verbose)
110
+ HDIUTIL_VERBOSITY='-verbose'
111
+ shift;;
112
+ --hdiutil-quiet)
113
+ HDIUTIL_VERBOSITY='-quiet'
114
+ shift;;
115
+ --help)
116
+ usage;;
117
+ -*)
118
+ echo "๐Ÿคจ Unknown option: $1. Run 'create-dmg --help' for help."
119
+ exit 1;;
120
+ esac
121
+ done
122
+
123
+ # Check codesing.
124
+ CODE_SIGN_FINGERPRINT_ID=
125
+ if [[ ! -z "${CODE_SIGN_IDENTITY}" ]]; then
126
+ CODE_SIGN_FINGERPRINT_ID=$(security find-identity -v -p codesigning | grep -E "${CODE_SIGN_IDENTITY}" | awk '{ print $2; exit }')
127
+ if [[ -z "${CODE_SIGN_FINGERPRINT_ID}" ]]; then
128
+ echo "โŒ Codesign identity '${CODE_SIGN_IDENTITY}' was not found in the Keychain. Import the codesign certificate '${CODE_SIGN_IDENTITY}' with private key into your Keychain and try again."
129
+ exit 1
130
+ fi
131
+ fi
132
+
133
+ # Returns dev/ name from mounting point.
134
+ function get_device_name {
135
+ DMG_MOUNT_POINT=$1
136
+ DEV_NAME=$(hdiutil info | egrep '^/dev/' | grep "$DMG_MOUNT_POINT" | sed 1q | awk '{ print $1 }' || echo '')
137
+ echo "${DEV_NAME}"
138
+ }
139
+
140
+ # Remove temp DMG if any.
141
+ if [[ -f "${DMG_TEMP}" ]]; then
142
+ echo "๐Ÿงน Clean-up"
143
+ rm -Rf "${DMG_TEMP}"
144
+ fi
145
+
146
+ # Convert DMG template to RW format.
147
+ echo "๐Ÿ”„ Convert template '${TEMPLATE_DMG}' to writable disk image at '${DMG_TEMP}'"
148
+ hdiutil convert "${TEMPLATE_DMG}" -format UDRW -o "${DMG_TEMP}" ${HDIUTIL_VERBOSITY}
149
+
150
+ # Calculate max resulting image size.
151
+ SOURCE_SIZE=$(du -sm "${SOURCE_FILE}" | awk '{ print $1 }')
152
+ TEMPLATE_SIZE=$(du -sm "${TEMPLATE_DMG}" | awk '{ print $1 }')
153
+ DISK_IMAGE_SIZE=$(expr $SOURCE_SIZE '+' $SOURCE_SIZE '*' 10 '/' 100 '+' 10 + $TEMPLATE_SIZE)
154
+ # Increase actual size by 10% and add extra 10MB on top.
155
+ echo "โ†”๏ธ Resize '${DMG_TEMP}' to ${DISK_IMAGE_SIZE}MB"
156
+ hdiutil resize "${DMG_TEMP}" -size ${DISK_IMAGE_SIZE}m ${HDIUTIL_VERBOSITY}
157
+
158
+ # Try unmount dmg if it was mounted previously.
159
+ DEV_NAME=$(get_device_name "${DMG_MOUNT_POINT}")
160
+ if [[ ! -z "${DEV_NAME}" ]]; then
161
+ unmount "${DEV_NAME}" "${DMG_MOUNT_POINT}"
162
+ fi
163
+
164
+ # Mount writable disk image.
165
+ echo "๐Ÿง— Mount '${DMG_TEMP}' at ${DMG_MOUNT_POINT}"
166
+ hdiutil attach -readwrite -noverify -noautoopen -nobrowse "${DMG_TEMP}" -mountpoint "${DMG_MOUNT_POINT}" ${HDIUTIL_VERBOSITY}
167
+ DEV_NAME=$(get_device_name "${DMG_MOUNT_POINT}")
168
+ echo "๐Ÿ’พ Device name: ${DEV_NAME}"
169
+
170
+ # Copy source to DMG.
171
+ echo "โ™Š๏ธ Copy '${SOURCE_FILE}' to '${DMG_MOUNT_POINT}'"
172
+ DESTINATION_FILE="${DMG_MOUNT_POINT}"/$(basename -- "${SOURCE_FILE}")
173
+ if [[ -f "${DESTINATION_FILE}" || -d "${DESTINATION_FILE}" ]]; then
174
+ echo "๐Ÿงน Remove existing ${DESTINATION_FILE}"
175
+ rm -rf "${DESTINATION_FILE}"
176
+ fi
177
+ ditto --rsrc --extattr "${SOURCE_FILE}" "${DMG_MOUNT_POINT}"/$(basename -- "${SOURCE_FILE}")
178
+
179
+ # Flush disk cache to prevent "Resource busy" failures.
180
+ sync
181
+
182
+ # Unmount updated disk image.
183
+ unmount "${DEV_NAME}" "${DMG_MOUNT_POINT}"
184
+
185
+ # Convert DMG to compressed RO format.
186
+ if [[ -f "${OUTPUT_DMG}" ]]; then
187
+ echo "๐Ÿงน Remove existing ${OUTPUT_DMG}"
188
+ rm -Rf "${OUTPUT_DMG}"
189
+ fi
190
+ hdiutil convert "${DMG_TEMP}" -format UDZO -imagekey zlib-level=9 -o "${OUTPUT_DMG}" ${HDIUTIL_VERBOSITY}
191
+
192
+ # Sign DMG if needed.
193
+ if [[ ! -z "${CODE_SIGN_IDENTITY}" ]]; then
194
+ echo "โœ๏ธ Codesign '${OUTPUT_DMG}'"
195
+ codesign -fv -s "${CODE_SIGN_FINGERPRINT_ID}" "${OUTPUT_DMG}"
196
+ fi
197
+
198
+ # Verify DMG.
199
+ echo "๐Ÿง Verify '${OUTPUT_DMG}'"
200
+ hdiutil verify "${OUTPUT_DMG}" ${HDIUTIL_VERBOSITY}
201
+
202
+ # Remove temp DMG.
203
+ if [[ -f "${DMG_TEMP}" ]]; then
204
+ echo "๐Ÿงน Clean-up"
205
+ rm -Rf "${DMG_TEMP}"
206
+ fi