fastlane-plugin-create_dmg 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +48 -0
- data/README.md +52 -0
- data/lib/fastlane/plugin/create_dmg/actions/create_dmg_action.rb +226 -0
- data/lib/fastlane/plugin/create_dmg/actions/update_dmg_action.rb +118 -0
- data/lib/fastlane/plugin/create_dmg/assets/update-dmg.sh +206 -0
- data/lib/fastlane/plugin/create_dmg/helper/create_dmg_helper.rb +86 -0
- data/lib/fastlane/plugin/create_dmg/helper/update_dmg_helper.rb +43 -0
- data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/LICENSE +22 -0
- data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/Makefile +33 -0
- data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/README.md +115 -0
- data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/builder/create-dmg.builder +26 -0
- data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/create-dmg +484 -0
- data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/doc-project/Developer Notes.md +35 -0
- data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/doc-project/Release Checklist.md +10 -0
- data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/examples/01-main-example/installer_background.png +0 -0
- data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/examples/01-main-example/sample +25 -0
- data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/examples/01-main-example/source_folder/Application.app +0 -0
- data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/support/eula-resources-template.xml +105 -0
- data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/support/template.applescript +74 -0
- data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/tests/007-space-in-dir-name/my files/hello.txt +1 -0
- data/lib/fastlane/plugin/create_dmg/vendor/create-dmg/tests/007-space-in-dir-name/run-test +5 -0
- data/lib/fastlane/plugin/create_dmg/version.rb +5 -0
- data/lib/fastlane/plugin/create_dmg.rb +16 -0
- data/lib/fastlane.dmg +0 -0
- 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
|