motion-sparkle-sandbox 2.0.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +7 -0
  5. data/.rubocop_todo.yml +183 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +37 -0
  8. data/Gemfile +13 -3
  9. data/README.md +72 -72
  10. data/Rakefile +2 -7
  11. data/bin/bundle +114 -0
  12. data/bin/byebug +29 -0
  13. data/bin/coderay +29 -0
  14. data/bin/fuzzy_match +29 -0
  15. data/bin/htmldiff +29 -0
  16. data/bin/httpclient +29 -0
  17. data/bin/ldiff +29 -0
  18. data/bin/pod +29 -0
  19. data/bin/pry +29 -0
  20. data/bin/rake +29 -0
  21. data/bin/rspec +29 -0
  22. data/bin/rubocop +29 -0
  23. data/bin/ruby-parse +29 -0
  24. data/bin/ruby-rewrite +29 -0
  25. data/bin/sandbox-pod +29 -0
  26. data/bin/xcodeproj +29 -0
  27. data/lib/motion/project/appcast.rb +294 -111
  28. data/lib/motion/project/indent_string.rb +18 -0
  29. data/lib/motion/project/install.rb +22 -66
  30. data/lib/motion/project/package.rb +52 -36
  31. data/lib/motion/project/project.rb +42 -51
  32. data/lib/motion/project/rake_tasks.rb +38 -28
  33. data/lib/motion/project/setup.rb +67 -73
  34. data/lib/motion/project/sparkle.rb +317 -148
  35. data/lib/motion/project/templates.rb +24 -22
  36. data/lib/motion-sparkle-sandbox/version.rb +5 -0
  37. data/lib/motion-sparkle-sandbox.rb +19 -3
  38. data/motion-sparkle-sandbox.gemspec +26 -16
  39. data/sample-app/.gitignore +10 -0
  40. data/sample-app/Gemfile +8 -0
  41. data/sample-app/README.md +87 -0
  42. data/sample-app/Rakefile +47 -0
  43. data/sample-app/app/app_delegate.rb +15 -0
  44. data/sample-app/app/menu.rb +155 -0
  45. data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/1024x1024.png +0 -0
  46. data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
  47. data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_128x128.png +0 -0
  48. data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_128x128@2x.png +0 -0
  49. data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_16x16.png +0 -0
  50. data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_16x16@2x.png +0 -0
  51. data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_256x256.png +0 -0
  52. data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_256x256@2x.png +0 -0
  53. data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_32x32.png +0 -0
  54. data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_32x32@2x.png +0 -0
  55. data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_512x512.png +0 -0
  56. data/sample-app/resources/Assets.xcassets/AppIcon.appiconset/Icon_512x512@2x.png +0 -0
  57. data/sample-app/resources/Assets.xcassets/Contents.json +6 -0
  58. data/sample-app/resources/Credits.rtf +29 -0
  59. data/sample-app/spec/main_spec.rb +11 -0
  60. data/spec/appcast_spec.rb +60 -0
  61. data/spec/setup_spec.rb +42 -0
  62. data/spec/sparkle_spec.rb +94 -73
  63. data/spec/spec_helper.rb +100 -27
  64. data/spec/spec_utils.rb +68 -0
  65. data/vendor/.git_keep +0 -0
  66. metadata +80 -14
  67. data/vendor/README.md +0 -34
  68. data/vendor/Sparkle.zip +0 -0
  69. data/vendor/codesign_embedded_executable +0 -46
  70. data/vendor/generate_appcast +0 -0
@@ -1,127 +1,310 @@
1
- module Motion::Project
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
- def create_appcast
17
- create_release_folder
18
- appcast_file = File.open("#{sparkle_release_path}/#{appcast.feed_filename}", 'w') do |f|
19
- xml_string = ''
20
- doc = REXML::Formatters::Pretty.new
21
- doc.write(appcast_xml, xml_string)
22
- f << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
23
- f << xml_string
24
- f << "\n"
25
- end
26
- if appcast_file
27
- App.info "Create", "./#{sparkle_release_path}/#{appcast.feed_filename}"
28
- else
29
- App.info "Fail", "./#{sparkle_release_path}/#{appcast.feed_filename} not created"
30
- end
31
- end
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
- def appcast_xml
34
- rss = REXML::Element.new 'rss'
35
- rss.attributes['xmlns:atom'] = "http://www.w3.org/2005/Atom"
36
- rss.attributes['xmlns:sparkle'] = "http://www.andymatuschak.org/xml-namespaces/sparkle"
37
- rss.attributes['xmlns:version'] = "2.0"
38
- rss.attributes['xmlns:dc'] = "http://purl.org/dc/elements/1.1/"
39
- channel = rss.add_element 'channel'
40
- channel.add_element('title').text = @config.name
41
- channel.add_element('description').text = "#{@config.name} updates"
42
- channel.add_element('link').text = @config.info_plist["SUFeedURL"]
43
- channel.add_element('language').text = 'en'
44
- channel.add_element('pubDate').text = Time.now.strftime("%a, %d %b %Y %H:%M:%S %z")
45
- atom_link = channel.add_element('atom:link')
46
- atom_link.attributes['href'] = @config.info_plist["SUFeedURL"]
47
- atom_link.attributes['rel'] = 'self'
48
- atom_link.attributes['type'] = "application/rss+xml"
49
- item = channel.add_element 'item'
50
- item.add_element('title').text = "#{@config.name} #{@config.short_version}"
51
- item.add_element('pubDate').text = Time.now.strftime("%a, %d %b %Y %H:%M:%S %z")
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
- def release_notes_template_path
67
- sparkle_config_path + "release_notes.template.erb"
68
- end
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
- def release_notes_content_path
71
- sparkle_config_path + "release_notes.content.html"
72
- end
51
+ def initialize(sparkle_object)
52
+ @sparkle = sparkle_object
53
+ @cli_options = {
54
+ account: 'ed25519' # Sparkle's default account
55
+ }
73
56
 
74
- def release_notes_path
75
- sparkle_release_path + appcast.notes_filename.to_s
76
- end
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
- def release_notes_content
79
- if File.exist?(release_notes_content_path)
80
- File.read(release_notes_content_path)
81
- else
82
- App.fail "Missing #{release_notes_content_path}"
83
- end
84
- end
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
- def release_notes_html
87
- release_notes_content
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
- class Appcast
92
- attr_accessor :base_url,
93
- :feed_base_url,
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
- def feed_url
113
- "#{feed_base_url || base_url}/#{feed_filename}"
114
- end
88
+ def package_base_url
89
+ @package_base_url || base_url
90
+ end
115
91
 
116
- def notes_url
117
- "#{notes_base_url || base_url}/#{notes_filename}"
118
- end
92
+ def prepare_args
93
+ args = []
119
94
 
120
- def package_url
121
- "#{package_base_url || base_url}/#{package_filename}"
122
- end
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
- end
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
- module Motion::Project
2
- class Sparkle
1
+ # frozen_string_literal: true
3
2
 
4
- SPARKLE_ZIP_FILE = 'Sparkle.zip'
5
-
6
- def sparkle_distrib
7
- file_path = Pathname.new File.dirname(__FILE__)
8
- distrib_path = "vendor/#{SPARKLE_ZIP_FILE}"
9
- (file_path.parent.parent.parent + distrib_path).to_s
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
- def install
48
- FileUtils.rm_rf(sparkle_path) if File.directory?(sparkle_path) # force clean install
49
- copy_zipball
50
- unzip
51
- end
10
+ def vendored_sparkle_framework_path
11
+ vendored_sparkle_path.join('Sparkle.framework')
12
+ end
52
13
 
53
- def embed
54
- @config.embedded_frameworks << sparkle_framework_path
55
- end
14
+ def vendored_sparkle_xpc_path
15
+ vendored_sparkle_path.join('XPCServices')
16
+ end
56
17
 
57
- def install_and_embed
58
- install unless installed?
59
- embed
60
- end
18
+ def installed?
19
+ File.directory?(vendored_sparkle_framework_path)
20
+ end
61
21
 
62
- def verify_installation
63
- if installed?
64
- App.info "Sparkle", "Framework installed in #{sparkle_framework_path.to_s}"
65
- else
66
- App.fail "Sparkle framework not correctly copied to #{sparkle_framework_path.to_s}
67
- Run `rake sparkle:install` manually or, if the problem persists,
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
- module Motion::Project
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
- def create_zip_file
20
- unless File.exist?(app_bundle_path)
21
- App.fail "You need to build your app with the Release target to use Sparkle"
22
- end
23
- if File.exist?("#{sparkle_release_path}/#{zip_file}")
24
- App.fail "Release already exists at ./#{sparkle_release_path}/#{zip_file} (remove it manually with `rake sparkle:clean`)"
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
- FileUtils.cd(app_release_path) do
27
- `zip -r --symlinks "#{zip_file}" "#{app_file}"`
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
- def sign_package
36
- package = "./#{sparkle_release_path}/#{zip_file}"
37
- @package_signature = `#{openssl} dgst -sha1 -binary < "#{package}" | #{openssl} dgst -dss1 -sign "#{private_key_path}" | #{openssl} enc -base64`
38
- @package_signature = @package_signature.strip
39
- App.info "Signature", "\"#{@package_signature}\""
40
- end
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