motion-sparkle-sandbox 2.0.0 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/.rubocop.yml +7 -0
- data/.rubocop_todo.yml +183 -0
- data/.ruby-version +1 -0
- data/.travis.yml +37 -0
- data/Gemfile +13 -3
- data/README.md +72 -72
- data/Rakefile +2 -7
- data/bin/bundle +114 -0
- data/bin/byebug +29 -0
- data/bin/coderay +29 -0
- data/bin/fuzzy_match +29 -0
- data/bin/htmldiff +29 -0
- data/bin/httpclient +29 -0
- data/bin/ldiff +29 -0
- data/bin/pod +29 -0
- data/bin/pry +29 -0
- data/bin/rake +29 -0
- data/bin/rspec +29 -0
- data/bin/rubocop +29 -0
- data/bin/ruby-parse +29 -0
- data/bin/ruby-rewrite +29 -0
- data/bin/sandbox-pod +29 -0
- data/bin/xcodeproj +29 -0
- data/lib/motion/project/appcast.rb +294 -111
- data/lib/motion/project/indent_string.rb +18 -0
- data/lib/motion/project/install.rb +22 -66
- data/lib/motion/project/package.rb +52 -36
- data/lib/motion/project/project.rb +42 -51
- data/lib/motion/project/rake_tasks.rb +38 -28
- data/lib/motion/project/setup.rb +67 -73
- data/lib/motion/project/sparkle.rb +317 -148
- data/lib/motion/project/templates.rb +24 -22
- data/lib/motion-sparkle-sandbox/version.rb +5 -0
- data/lib/motion-sparkle-sandbox.rb +19 -3
- data/motion-sparkle-sandbox.gemspec +26 -16
- data/sample-app/.gitignore +10 -0
- data/sample-app/Gemfile +8 -0
- data/sample-app/README.md +87 -0
- data/sample-app/Rakefile +47 -0
- data/sample-app/app/app_delegate.rb +15 -0
- data/sample-app/app/menu.rb +155 -0
- data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/1024x1024.png +0 -0
- data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
- data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_128x128.png +0 -0
- data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_128x128@2x.png +0 -0
- data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_16x16.png +0 -0
- data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_16x16@2x.png +0 -0
- data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_256x256.png +0 -0
- data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_256x256@2x.png +0 -0
- data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_32x32.png +0 -0
- data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_32x32@2x.png +0 -0
- data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_512x512.png +0 -0
- data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_512x512@2x.png +0 -0
- data/sample-app/resources/Assets.xcassets/Contents.json +6 -0
- data/sample-app/resources/Credits.rtf +29 -0
- data/sample-app/spec/main_spec.rb +11 -0
- data/spec/appcast_spec.rb +60 -0
- data/spec/setup_spec.rb +42 -0
- data/spec/sparkle_spec.rb +94 -73
- data/spec/spec_helper.rb +100 -27
- data/spec/spec_utils.rb +68 -0
- data/vendor/.git_keep +0 -0
- metadata +80 -14
- data/vendor/README.md +0 -34
- data/vendor/Sparkle.zip +0 -0
- data/vendor/codesign_embedded_executable +0 -46
- data/vendor/generate_appcast +0 -0
@@ -1,127 +1,310 @@
|
|
1
|
-
|
2
|
-
class Sparkle
|
3
|
-
|
4
|
-
def create_release_notes
|
5
|
-
if File.exist?(release_notes_template_path)
|
6
|
-
File.open("#{release_notes_path}", "w") do |f|
|
7
|
-
template = File.read(release_notes_template_path)
|
8
|
-
f << ERB.new(template).result(binding)
|
9
|
-
end
|
10
|
-
App.info 'Create', "./#{release_notes_path}"
|
11
|
-
else
|
12
|
-
App.fail "Release notes template not found as expected at ./#{release_notes_template_path}"
|
13
|
-
end
|
14
|
-
end
|
1
|
+
# frozen_string_literal: true
|
15
2
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
3
|
+
# rubocop:disable Metrics/ClassLength
|
4
|
+
module Motion
|
5
|
+
module Project
|
6
|
+
class Sparkle
|
7
|
+
class Appcast
|
8
|
+
PARAMS = %i[
|
9
|
+
package_base_url
|
10
|
+
package_filename
|
11
|
+
notes_base_url
|
12
|
+
notes_filename
|
13
|
+
use_exported_private_key
|
14
|
+
base_url
|
15
|
+
releases_folder
|
16
|
+
feed_base_url
|
17
|
+
feed_filename
|
18
|
+
].freeze
|
32
19
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
guid = item.add_element('guid')
|
53
|
-
guid.text = "#{@config.name}-#{@config.short_version}"
|
54
|
-
guid.attributes['isPermaLink'] = false
|
55
|
-
item.add_element('sparkle:releaseNotesLink').text = "#{appcast.notes_url}"
|
56
|
-
enclosure = item.add_element('enclosure')
|
57
|
-
enclosure.attributes['url'] = "#{appcast.package_url}"
|
58
|
-
enclosure.attributes['length'] = "#{@package_size}"
|
59
|
-
enclosure.attributes['type'] = "application/octet-stream"
|
60
|
-
enclosure.attributes['sparkle:version'] = @config.version
|
61
|
-
enclosure.attributes['sparkle:shortVersionString'] = @config.short_version
|
62
|
-
enclosure.attributes['sparkle:dsaSignature'] = @package_signature
|
63
|
-
rss
|
64
|
-
end
|
20
|
+
CLI_OPTIONS = {
|
21
|
+
account: '--account',
|
22
|
+
private_eddsa_key: '-s',
|
23
|
+
download_url_prefix: '--download-url-prefix',
|
24
|
+
release_notes_url_prefix: '--release-notes-url-prefix',
|
25
|
+
full_release_notes_url: '--full-release-notes-url',
|
26
|
+
link: '--link',
|
27
|
+
versions: '--versions',
|
28
|
+
maximum_deltas: '--maximum-deltas',
|
29
|
+
delta_compression: '--delta-compression',
|
30
|
+
delta_compression_level: '--delta-compression-level',
|
31
|
+
channel: '--channel',
|
32
|
+
major_version: '--major-version',
|
33
|
+
ignore_skipped_upgrades_below_version: '--ignore-skipped-upgrades-below-version',
|
34
|
+
phased_rollout_interval: '--phased-rollout-interval',
|
35
|
+
critical_update_version: '--critical-update-version',
|
36
|
+
informational_update_versions: '--informational-update-versions',
|
37
|
+
output_path: '-o'
|
38
|
+
}.freeze
|
65
39
|
|
66
|
-
|
67
|
-
|
68
|
-
|
40
|
+
attr_accessor :base_url,
|
41
|
+
:feed_base_url,
|
42
|
+
:feed_filename,
|
43
|
+
:notes_filename,
|
44
|
+
:package_filename,
|
45
|
+
:releases_folder,
|
46
|
+
:use_exported_private_key,
|
47
|
+
:cli_options
|
48
|
+
attr_writer :notes_base_url,
|
49
|
+
:package_base_url
|
69
50
|
|
70
|
-
|
71
|
-
|
72
|
-
|
51
|
+
def initialize(sparkle_object)
|
52
|
+
@sparkle = sparkle_object
|
53
|
+
@cli_options = {
|
54
|
+
account: 'ed25519' # Sparkle's default account
|
55
|
+
}
|
73
56
|
|
74
|
-
|
75
|
-
|
76
|
-
|
57
|
+
@feed_base_url = nil
|
58
|
+
@feed_filename = 'releases.xml'
|
59
|
+
@notes_base_url = nil
|
60
|
+
@notes_filename = nil
|
61
|
+
@package_base_url = nil
|
62
|
+
@package_filename = nil
|
63
|
+
@base_url = nil
|
64
|
+
@releases_folder = nil
|
65
|
+
@use_exported_private_key = false
|
66
|
+
end
|
77
67
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
68
|
+
def process_option(key, value)
|
69
|
+
if CLI_OPTIONS.keys.include?(key)
|
70
|
+
cli_options[key] = value
|
71
|
+
elsif PARAMS.include?(key)
|
72
|
+
send("#{key}=", value)
|
73
|
+
else
|
74
|
+
return false
|
75
|
+
end
|
85
76
|
|
86
|
-
|
87
|
-
|
88
|
-
end
|
77
|
+
true
|
78
|
+
end
|
89
79
|
|
80
|
+
def feed_url
|
81
|
+
"#{feed_base_url || base_url}#{feed_filename}"
|
82
|
+
end
|
90
83
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
:feed_filename,
|
95
|
-
:notes_base_url,
|
96
|
-
:notes_filename,
|
97
|
-
:package_base_url,
|
98
|
-
:package_filename,
|
99
|
-
:archive_folder
|
100
|
-
|
101
|
-
def initialize
|
102
|
-
@feed_base_url = nil
|
103
|
-
@feed_filename = 'releases.xml'
|
104
|
-
@notes_base_url = nil
|
105
|
-
@notes_filename = 'release_notes.html'
|
106
|
-
@package_base_url = nil
|
107
|
-
@package_filename = nil
|
108
|
-
@base_url = nil
|
109
|
-
@archive_folder = nil
|
110
|
-
end
|
84
|
+
def notes_base_url
|
85
|
+
@notes_base_url || base_url
|
86
|
+
end
|
111
87
|
|
112
|
-
|
113
|
-
|
114
|
-
|
88
|
+
def package_base_url
|
89
|
+
@package_base_url || base_url
|
90
|
+
end
|
115
91
|
|
116
|
-
|
117
|
-
|
118
|
-
end
|
92
|
+
def prepare_args
|
93
|
+
args = []
|
119
94
|
|
120
|
-
|
121
|
-
|
122
|
-
|
95
|
+
account(args)
|
96
|
+
private_eddsa_key(args)
|
97
|
+
download_url_prefix(args)
|
98
|
+
release_notes_url_prefix(args)
|
99
|
+
full_release_notes_url(args)
|
100
|
+
link(args)
|
101
|
+
versions(args)
|
102
|
+
maximum_deltas(args)
|
103
|
+
delta_compression(args)
|
104
|
+
delta_compression_level(args)
|
105
|
+
channel(args)
|
106
|
+
major_version(args)
|
107
|
+
ignore_skipped_upgrades_below_version(args)
|
108
|
+
phased_rollout_interval(args)
|
109
|
+
critical_update_version(args)
|
110
|
+
informational_update_versions(args)
|
111
|
+
output_path(args)
|
123
112
|
|
124
|
-
|
113
|
+
args
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
# --account <account> The account name in your keychain associated with
|
119
|
+
# your private EdDSA (ed25519) key to use for signing
|
120
|
+
# new updates. (default: ed25519)
|
121
|
+
def account(args)
|
122
|
+
return unless cli_options[:account].present?
|
123
|
+
|
124
|
+
args << "--account=#{cli_options[:account]}"
|
125
|
+
end
|
126
|
+
|
127
|
+
# -s <private-EdDSA-key> The private EdDSA string (128 characters). If not
|
128
|
+
# specified, the private EdDSA key will be read from
|
129
|
+
# the Keychain instead.
|
130
|
+
def private_eddsa_key(args)
|
131
|
+
if cli_options[:private_eddsa_key].present?
|
132
|
+
args << "-s=#{cli_options[:private_eddsa_key]}"
|
133
|
+
elsif use_exported_private_key && File.exist?(private_key_path)
|
134
|
+
private_key = File.read(private_key_path)
|
135
|
+
args << "-s=#{private_key}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# --download-url-prefix <url> A URL that will be used as prefix for the URL from
|
140
|
+
# where updates will be downloaded.
|
141
|
+
def download_url_prefix(args)
|
142
|
+
if cli_options[:download_url_prefix].present?
|
143
|
+
args << "--download-url-prefix=#{cli_options[:download_url_prefix]}"
|
144
|
+
elsif package_base_url.present?
|
145
|
+
args << "--download-url-prefix=#{package_base_url}"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# --release-notes-url-prefix <url> A URL that will be used as prefix for constructing
|
150
|
+
# URLs for release notes.
|
151
|
+
def release_notes_url_prefix(args)
|
152
|
+
if cli_options[:release_notes_url_prefix].present?
|
153
|
+
args << "--release-notes-url-prefix=#{cli_options[:release_notes_url_prefix]}"
|
154
|
+
elsif notes_base_url.present?
|
155
|
+
args << "--release-notes-url-prefix=#{notes_base_url}"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# --full-release-notes-url <url>
|
160
|
+
# A URL that will be used for the full release notes.
|
161
|
+
def full_release_notes_url(args)
|
162
|
+
return unless cli_options[:full_release_notes_url].present?
|
163
|
+
|
164
|
+
args << "--full-release-notes-url=#{cli_options[:full_release_notes_url]}"
|
165
|
+
end
|
166
|
+
|
167
|
+
# --link <link> A URL to the application's website which Sparkle may
|
168
|
+
# use for directing users to if they cannot download a
|
169
|
+
# new update from within the application. This will be
|
170
|
+
# used for new generated update items. By default, no
|
171
|
+
# product link is used.
|
172
|
+
def link(args)
|
173
|
+
return unless cli_options[:link].present?
|
125
174
|
|
175
|
+
args << "--link=#{cli_options[:link]}"
|
176
|
+
end
|
177
|
+
|
178
|
+
# --versions <versions> An optional comma delimited list of application
|
179
|
+
# versions (specified by CFBundleVersion) to generate
|
180
|
+
# new update items for. By default, new update items
|
181
|
+
# are inferred from the available archives and are only
|
182
|
+
# generated if they are in the latest 5 updates in the
|
183
|
+
# appcast.
|
184
|
+
def versions(args)
|
185
|
+
return unless cli_options[:versions].present?
|
186
|
+
|
187
|
+
args << "--versions=#{cli_options[:versions]}"
|
188
|
+
end
|
189
|
+
|
190
|
+
# --maximum-deltas <maximum-deltas>
|
191
|
+
# The maximum number of delta items to create for the
|
192
|
+
# latest update for each minimum required operating
|
193
|
+
# system. (default: 5)
|
194
|
+
def maximum_deltas(args)
|
195
|
+
return unless cli_options[:maximum_deltas].present?
|
196
|
+
|
197
|
+
args << "--maximum-deltas=#{cli_options[:maximum_deltas]}"
|
198
|
+
end
|
199
|
+
|
200
|
+
# --delta-compression <delta-compression>
|
201
|
+
# The compression method to use for generating delta
|
202
|
+
# updates. Supported methods for version 3 delta files
|
203
|
+
# are 'lzma', 'bzip2', 'zlib', 'lzfse', 'lz4', 'none',
|
204
|
+
# and 'default'. Note that version 2 delta files only
|
205
|
+
# support 'bzip2', 'none', and 'default' so other
|
206
|
+
# methods will be ignored if version 2 files are being
|
207
|
+
# generated. The 'default' compression for version 3
|
208
|
+
# delta files is currently lzma. (default: default)
|
209
|
+
def delta_compression(args)
|
210
|
+
return unless cli_options[:delta_compression].present?
|
211
|
+
|
212
|
+
args << "--delta-compression=#{cli_options[:delta_compression]}"
|
213
|
+
end
|
214
|
+
|
215
|
+
# --delta-compression-level <delta-compression-level>
|
216
|
+
# The compression level to use for generating delta
|
217
|
+
# updates. This only applies if the compression method
|
218
|
+
# used is bzip2 which accepts values from 1 - 9. A
|
219
|
+
# special value of 0 will use the default compression
|
220
|
+
# level. (default: 0)
|
221
|
+
def delta_compression_level(args)
|
222
|
+
return unless cli_options[:delta_compression_level].present?
|
223
|
+
|
224
|
+
args << "--delta-compression-level=#{cli_options[:delta_compression_level]}"
|
225
|
+
end
|
226
|
+
|
227
|
+
# --channel <channel-name>
|
228
|
+
# The Sparkle channel name that will be used for
|
229
|
+
# generating new updates. By default, no channel is
|
230
|
+
# used. Old applications need to be using Sparkle 2 to
|
231
|
+
# use this feature.
|
232
|
+
def channel(args)
|
233
|
+
return unless cli_options[:channel].present?
|
234
|
+
|
235
|
+
args << "--channel=#{cli_options[:channel]}"
|
236
|
+
end
|
237
|
+
|
238
|
+
# --major-version <major-version>
|
239
|
+
# The last major or minimum autoupdate sparkle:version
|
240
|
+
# that will be used for generating new updates. By
|
241
|
+
# default, no last major version is used.
|
242
|
+
def major_version(args)
|
243
|
+
return unless cli_options[:major_version].present?
|
244
|
+
|
245
|
+
args << "--major-version=#{cli_options[:major_version]}"
|
246
|
+
end
|
247
|
+
|
248
|
+
# --ignore-skipped-upgrades-below-version <below-version>
|
249
|
+
# Ignore skipped major upgrades below this specified
|
250
|
+
# version. Only applicable for major upgrades.
|
251
|
+
def ignore_skipped_upgrades_below_version(args)
|
252
|
+
return unless cli_options[:ignore_skipped_upgrades_below_version].present?
|
253
|
+
|
254
|
+
args << "--ignore-skipped-upgrades-below-version=#{cli_options[:ignore_skipped_upgrades_below_version]}"
|
255
|
+
end
|
256
|
+
|
257
|
+
# --phased-rollout-interval <phased-rollout-interval>
|
258
|
+
# The phased rollout interval in seconds that will be
|
259
|
+
# used for generating new updates. By default, no
|
260
|
+
# phased rollout interval is used.
|
261
|
+
def phased_rollout_interval(args)
|
262
|
+
return unless cli_options[:phased_rollout_interval].present?
|
263
|
+
|
264
|
+
args << "--phased-rollout-interval=#{cli_options[:phased_rollout_interval]}"
|
265
|
+
end
|
266
|
+
|
267
|
+
# --critical-update-version <critical-update-version>
|
268
|
+
# The last critical update sparkle:version that will be
|
269
|
+
# used for generating new updates. An empty string
|
270
|
+
# argument will treat this update as critical coming
|
271
|
+
# from any application version. By default, no last
|
272
|
+
# critical update version is used. Old applications
|
273
|
+
# need to be using Sparkle 2 to use this feature.
|
274
|
+
def critical_update_version(args)
|
275
|
+
return unless cli_options[:critical_update_version].present?
|
276
|
+
|
277
|
+
args << "--critical-update-version=#{cli_options[:critical_update_version]}"
|
278
|
+
end
|
279
|
+
|
280
|
+
# --informational-update-versions <informational-update-versions>
|
281
|
+
# A comma delimited list of application
|
282
|
+
# sparkle:version's that will see newly generated
|
283
|
+
# updates as being informational only. An empty string
|
284
|
+
# argument will treat this update as informational
|
285
|
+
# coming from any application version. Prefix a version
|
286
|
+
# string with '<' to indicate (eg "<2.5") to indicate
|
287
|
+
# older versions than the one specified should treat
|
288
|
+
# the update as informational only. By default, updates
|
289
|
+
# are not informational only. --link must also be
|
290
|
+
# provided. Old applications need to be using Sparkle 2
|
291
|
+
# to use this feature, and 2.1 or later to use the '<'
|
292
|
+
# upper bound feature.
|
293
|
+
def informational_update_versions(args)
|
294
|
+
return unless cli_options[:informational_update_versions].present?
|
295
|
+
|
296
|
+
args << "--informational-update-versions=#{cli_options[:informational_update_versions]}"
|
297
|
+
end
|
298
|
+
|
299
|
+
# -o <output-path> Path to filename for the generated appcast (allowed
|
300
|
+
# when only one will be created).
|
301
|
+
def output_path(args)
|
302
|
+
return unless cli_options[:output_path].present?
|
303
|
+
|
304
|
+
args << "-o=#{cli_options[:output_path]}"
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
126
308
|
end
|
127
309
|
end
|
310
|
+
# rubocop:enable Metrics/ClassLength
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# https://makandracards.com/makandra/6087-ruby-indent-a-string
|
4
|
+
String.class_eval do
|
5
|
+
def indent(count, char = ' ', skip_first_line: false)
|
6
|
+
gsub(/([^\n]*)(\n|$)/) do |_match|
|
7
|
+
last_iteration = (Regexp.last_match(1) == '' && Regexp.last_match(2) == '')
|
8
|
+
line = String.new
|
9
|
+
line << (char * count) unless last_iteration || skip_first_line
|
10
|
+
line << Regexp.last_match(1)
|
11
|
+
line << Regexp.last_match(2)
|
12
|
+
|
13
|
+
skip_first_line = false
|
14
|
+
|
15
|
+
line
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,75 +1,31 @@
|
|
1
|
-
|
2
|
-
class Sparkle
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
Pathname.new(sparkle_vendor_path + SPARKLE_ZIP_FILE)
|
11
|
-
end
|
12
|
-
|
13
|
-
def sparkle_vendor_path
|
14
|
-
file_path = Pathname.new File.dirname(__FILE__)
|
15
|
-
(file_path.parent.parent.parent + 'vendor/').to_s
|
16
|
-
end
|
17
|
-
|
18
|
-
def sparkle_path
|
19
|
-
Pathname.new(vendor_path + 'Sparkle')
|
20
|
-
end
|
21
|
-
|
22
|
-
def sparkle_framework_path
|
23
|
-
Pathname.new(vendor_path + 'Sparkle/Sparkle.framework')
|
24
|
-
end
|
25
|
-
|
26
|
-
def sparkle_xpc_path
|
27
|
-
Pathname.new(vendor_path + 'Sparkle/XPCServices')
|
28
|
-
end
|
29
|
-
|
30
|
-
def sparkle_zipball
|
31
|
-
Pathname.new(vendor_path + SPARKLE_ZIP_FILE)
|
32
|
-
end
|
33
|
-
|
34
|
-
def copy_zipball
|
35
|
-
`cp #{sparkle_distrib} #{sparkle_zipball}`
|
36
|
-
end
|
37
|
-
|
38
|
-
def unzip
|
39
|
-
`unzip #{sparkle_zipball.to_s} -d #{vendor_path.to_s}`
|
40
|
-
`rm #{sparkle_zipball}`
|
41
|
-
end
|
42
|
-
|
43
|
-
def installed?
|
44
|
-
File.directory?(sparkle_framework_path)
|
45
|
-
end
|
3
|
+
module Motion
|
4
|
+
module Project
|
5
|
+
class Sparkle
|
6
|
+
def vendored_sparkle_path
|
7
|
+
vendor_path.join('Pods/Sparkle')
|
8
|
+
end
|
46
9
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
unzip
|
51
|
-
end
|
10
|
+
def vendored_sparkle_framework_path
|
11
|
+
vendored_sparkle_path.join('Sparkle.framework')
|
12
|
+
end
|
52
13
|
|
53
|
-
|
54
|
-
|
55
|
-
|
14
|
+
def vendored_sparkle_xpc_path
|
15
|
+
vendored_sparkle_path.join('XPCServices')
|
16
|
+
end
|
56
17
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
18
|
+
def installed?
|
19
|
+
File.directory?(vendored_sparkle_framework_path)
|
20
|
+
end
|
61
21
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
please explain your setup and problem as an issue on GitHub at:
|
69
|
-
https://github.com/digitalmoksha/motion-sparkle-sandbox/issues
|
70
|
-
"
|
22
|
+
def verify_installation
|
23
|
+
if installed?
|
24
|
+
App.info 'Sparkle', "Framework installed in #{vendored_sparkle_framework_path}"
|
25
|
+
else
|
26
|
+
App.fail "Sparkle Cocoapod not correctly installed to #{vendored_sparkle_path}. Run `rake pod:install`."
|
27
|
+
end
|
71
28
|
end
|
72
29
|
end
|
73
|
-
|
74
30
|
end
|
75
31
|
end
|
@@ -1,44 +1,60 @@
|
|
1
|
-
|
2
|
-
class Sparkle
|
3
|
-
|
4
|
-
def package
|
5
|
-
return unless setup_ok?
|
6
|
-
create_release_folder
|
7
|
-
@config.build_mode = :release
|
8
|
-
return unless create_zip_file
|
9
|
-
App.info "Release", version_string
|
10
|
-
App.info "Version", @config.short_version
|
11
|
-
App.info "Build", @config.version || 'unspecified in Rakefile'
|
12
|
-
App.info "Size", @package_size.to_s
|
13
|
-
sign_package
|
14
|
-
create_appcast
|
15
|
-
create_release_notes
|
16
|
-
`open #{sparkle_release_path}`
|
17
|
-
end
|
1
|
+
# frozen_string_literal: true
|
18
2
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
3
|
+
module Motion
|
4
|
+
module Project
|
5
|
+
class Sparkle
|
6
|
+
def package
|
7
|
+
return unless setup_ok?
|
8
|
+
|
9
|
+
create_release_folder
|
10
|
+
@config.build_mode = :release
|
11
|
+
return unless create_zip_file
|
12
|
+
|
13
|
+
App.info 'Release', version_string
|
14
|
+
App.info 'Version', @config.short_version
|
15
|
+
App.info 'Build', @config.version || 'unspecified in Rakefile'
|
16
|
+
App.info 'Size', @package_size.to_s
|
17
|
+
|
18
|
+
sign_package
|
19
|
+
create_release_notes
|
20
|
+
|
21
|
+
`open #{sparkle_release_path}`
|
25
22
|
end
|
26
|
-
|
27
|
-
|
23
|
+
|
24
|
+
def create_zip_file
|
25
|
+
App.fail 'You need to build your app with the Release target to use Sparkle' unless File.exist?(app_bundle_path)
|
26
|
+
|
27
|
+
App.info 'Create', "./#{sparkle_release_path}/#{zip_file}"
|
28
|
+
|
29
|
+
if File.exist?("#{sparkle_release_path}/#{zip_file}")
|
30
|
+
App.fail "Release already exists at ./#{sparkle_release_path}/#{zip_file} (remove it manually with `rake sparkle:clean`)"
|
31
|
+
end
|
32
|
+
|
33
|
+
FileUtils.cd(app_release_path) do
|
34
|
+
`zip -r --symlinks "#{zip_file}" "#{app_file}"`
|
35
|
+
end
|
36
|
+
|
37
|
+
FileUtils.mv "#{app_release_path}/#{zip_file}", "./#{sparkle_release_path}/"
|
38
|
+
|
39
|
+
@package_file = zip_file
|
40
|
+
@package_size = File.size "./#{sparkle_release_path}/#{zip_file}"
|
28
41
|
end
|
29
|
-
FileUtils.mv "#{app_release_path}/#{zip_file}", "./#{sparkle_release_path}/"
|
30
|
-
App.info "Create", "./#{sparkle_release_path}/#{zip_file}"
|
31
|
-
@package_file = zip_file
|
32
|
-
@package_size = File.size "./#{sparkle_release_path}/#{zip_file}"
|
33
|
-
end
|
34
42
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
43
|
+
def sign_package
|
44
|
+
package = "./#{sparkle_release_path}/#{zip_file}"
|
45
|
+
sign_update_app = "#{vendored_sparkle_path}/bin/sign_update"
|
46
|
+
args = []
|
47
|
+
|
48
|
+
if appcast.use_exported_private_key && File.exist?(private_key_path)
|
49
|
+
# -s <private-key> The private EdDSA (ed25519) key
|
50
|
+
private_key = File.read(private_key_path)
|
51
|
+
args << "-s=#{private_key}"
|
52
|
+
end
|
41
53
|
|
54
|
+
results, _status = Open3.capture2e(sign_update_app, *args, package)
|
42
55
|
|
56
|
+
App.info 'Signature', results
|
57
|
+
end
|
58
|
+
end
|
43
59
|
end
|
44
60
|
end
|