sparkle_appcast 0.1.0
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.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +100 -0
- data/bin/sparkle_appcast +7 -0
- data/lib/sparkle_appcast/appcast.rb +42 -0
- data/lib/sparkle_appcast/archive.rb +80 -0
- data/lib/sparkle_appcast/cli.rb +72 -0
- data/lib/sparkle_appcast/release_note.rb +21 -0
- data/lib/sparkle_appcast/rss.rb +88 -0
- data/lib/sparkle_appcast/signer.rb +26 -0
- data/lib/sparkle_appcast.rb +8 -0
- metadata +126 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1371a567e13d8c53f4625dc93c5a85a05121fcc8229f7d715abada093726da47
|
4
|
+
data.tar.gz: d6d952e901c2abe3fa1f1035b3ff900c68f963d0804475da26e3db6405889dd3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 67a6eaed29a811a75075f3b47b61667d6e0fcd484641524a4b10dfc471310b6fb6ccf9d614c1ca28202bd0d4b29584342c11f01997c6219d114a8822470fec43
|
7
|
+
data.tar.gz: fb6649d00d9bd4be1fe454a9471781fb11afc81b31e6bf98b85f02186e997cabae86ed258a29cae8438d79932dc35ebf336dd4fe5dca67ad111ca18da0525895
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2018 Yoshimasa Niwa
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
sparkle_appcast
|
2
|
+
===============
|
3
|
+
|
4
|
+
|
5
|
+
NAME
|
6
|
+
----
|
7
|
+
|
8
|
+
`sparkle_appcast` -- A simple Sparkle `appcast.xml` tool
|
9
|
+
|
10
|
+
|
11
|
+
SYNOPSIS
|
12
|
+
--------
|
13
|
+
|
14
|
+
sparkle_appcast COMMAND [OPTIONS...] [ARGS...]
|
15
|
+
|
16
|
+
|
17
|
+
DESCRIPTION
|
18
|
+
-----------
|
19
|
+
|
20
|
+
`sparkle_appcast` is a Ruby gem that provides a command line interface and a Ruby library
|
21
|
+
to create and update `appcast.xml` for [Sparkle](https://sparkle-project.org).
|
22
|
+
|
23
|
+
`sparkle_appcast` command line interface takes next commands.
|
24
|
+
|
25
|
+
### `appcast [OPTIONS...] FILE_PATH`
|
26
|
+
|
27
|
+
Create `appcast.xml` with an application archive at `FILE_PATH`.
|
28
|
+
The application archive file must contain exact one application bundle.
|
29
|
+
|
30
|
+
* `--key=KEY`
|
31
|
+
|
32
|
+
Path to DSA private key file. Required.
|
33
|
+
|
34
|
+
* `--url=URL`
|
35
|
+
|
36
|
+
URL to the application archive file published. Required.
|
37
|
+
|
38
|
+
* `--release-note=RELEASE_NOTE`
|
39
|
+
|
40
|
+
Path to a release note text file in Markdown format. Required.
|
41
|
+
|
42
|
+
* `--output=OUTPUT`
|
43
|
+
|
44
|
+
Path to an output `appcast.xml`. Optional.
|
45
|
+
Default to puts in the standard output.
|
46
|
+
|
47
|
+
* `--title=TITLE`
|
48
|
+
|
49
|
+
Title for the release note. Optional.
|
50
|
+
Default to `"{{Bundle Name}} {Bundle Short Version String}} ({{Bundle Version}})"`.
|
51
|
+
|
52
|
+
* `--publish-date=PUBLISH_DATE`
|
53
|
+
|
54
|
+
Publish date time in local timezone. Optional.
|
55
|
+
Default to the creation time of the application archive file.
|
56
|
+
|
57
|
+
* `--channel-title=CHANNEL_TITLE`
|
58
|
+
|
59
|
+
Title of the channel. Optional.
|
60
|
+
Default to `"Change log"`.
|
61
|
+
|
62
|
+
* `--channel-description=CHANNEL_DESCRIPTION`
|
63
|
+
|
64
|
+
Description of the channel. Optional.
|
65
|
+
Default to `"The most recent changes."`.
|
66
|
+
|
67
|
+
### `sign [OPTIONS...] [FILE_PATH]`
|
68
|
+
|
69
|
+
Sign data at `FILE_PATH` or reading from the standard input with `DSA_PRIVATE_KEY_PATH`
|
70
|
+
and print signature that can be used in `appcast.xml`.
|
71
|
+
Use this for testing private key.
|
72
|
+
|
73
|
+
* `--key=KEY`
|
74
|
+
|
75
|
+
Path to DSA private key file. Required.
|
76
|
+
|
77
|
+
### `markdown [FILE_PATH]`
|
78
|
+
|
79
|
+
Format Markdown text file at `FILE_PATH` or reading from the standard input in HTML.
|
80
|
+
Use this for writing the release note.
|
81
|
+
|
82
|
+
|
83
|
+
USAGE
|
84
|
+
-----
|
85
|
+
|
86
|
+
Use Ruby Gems to install `sparkle_appcast`.
|
87
|
+
|
88
|
+
gem install sparkle_appcast
|
89
|
+
|
90
|
+
Or use [bundler](http://bundler.io/), add next line to `Gemfile` in your project.
|
91
|
+
|
92
|
+
gem "sprkle_appcast"
|
93
|
+
|
94
|
+
|
95
|
+
SEE ALSO
|
96
|
+
--------
|
97
|
+
|
98
|
+
* [generate-key](https://github.com/sparkle-project/Sparkle/blob/master/bin/generate_keys)
|
99
|
+
* [sign-update](https://github.com/sparkle-project/Sparkle/blob/master/bin/sign_update)
|
100
|
+
* [generate-appcast](https://github.com/sparkle-project/Sparkle/tree/master/generate_appcast)
|
data/bin/sparkle_appcast
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module SparkleAppcast
|
2
|
+
class Appcast
|
3
|
+
attr_reader :signer, :archive, :release_note, :url, :params
|
4
|
+
|
5
|
+
def initialize(archive, signer, url, release_note, params = {})
|
6
|
+
@archive = archive
|
7
|
+
@signer = signer
|
8
|
+
@url = url
|
9
|
+
@release_note = release_note
|
10
|
+
@params = params
|
11
|
+
end
|
12
|
+
|
13
|
+
def rss
|
14
|
+
Rss.new(rss_params)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def rss_params
|
20
|
+
{
|
21
|
+
channel_link: archive.feed_url,
|
22
|
+
title: title,
|
23
|
+
description: release_note.html,
|
24
|
+
publish_date: archive.created_at,
|
25
|
+
url: url,
|
26
|
+
length: archive.size,
|
27
|
+
version: archive.bundle_version,
|
28
|
+
short_version_string: archive.bundle_short_version_string,
|
29
|
+
minimum_system_version: archive.minimum_system_version,
|
30
|
+
dsa_signature: dsa_signature
|
31
|
+
}.merge(params)
|
32
|
+
end
|
33
|
+
|
34
|
+
def title
|
35
|
+
"#{archive.bundle_name} #{archive.bundle_short_version_string} (#{archive.bundle_version})"
|
36
|
+
end
|
37
|
+
|
38
|
+
def dsa_signature
|
39
|
+
@dsa_signature ||= signer.sign(archive.data)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require "tmpdir"
|
2
|
+
require "plist"
|
3
|
+
|
4
|
+
module SparkleAppcast
|
5
|
+
class Archive
|
6
|
+
attr_reader :path
|
7
|
+
|
8
|
+
def initialize(path)
|
9
|
+
@path = File.expand_path(path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def bundle_name
|
13
|
+
info_plist["CFBundleDisplayName"] || info_plist["CFBundleName"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def bundle_version
|
17
|
+
info_plist["CFBundleVersion"]
|
18
|
+
end
|
19
|
+
|
20
|
+
def bundle_short_version_string
|
21
|
+
info_plist["CFBundleShortVersionString"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def minimum_system_version
|
25
|
+
info_plist["LSMinimumSystemVersion"]
|
26
|
+
end
|
27
|
+
|
28
|
+
def feed_url
|
29
|
+
info_plist["SUFeedURL"]
|
30
|
+
end
|
31
|
+
|
32
|
+
def created_at
|
33
|
+
File.birthtime(path)
|
34
|
+
end
|
35
|
+
|
36
|
+
def size
|
37
|
+
File.size(path)
|
38
|
+
end
|
39
|
+
|
40
|
+
def data
|
41
|
+
File.binread(path)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
# TODO: Support localizable string.
|
47
|
+
|
48
|
+
def info_plist
|
49
|
+
@info_plist ||= Dir.mktmpdir do |tmpdir_path|
|
50
|
+
case File.basename(path)
|
51
|
+
when /\.zip\z/i
|
52
|
+
Kernel.system("/usr/bin/ditto", "-x", "-k", path, tmpdir_path)
|
53
|
+
when /\.tar\z/i
|
54
|
+
Kernel.system("/usr/bin/tar", "-x", "-f", path, "-C", tmpdir_path)
|
55
|
+
when /\.tar\.gz\z/i, /\.tgz\z/i, /\.tar\.xz\z/i, /\.txz\z/i, /\.tar\.lzma\z/i
|
56
|
+
Kernel.system("/usr/bin/tar", "-x", "-z", "-f", path, "-C", tmpdir_path)
|
57
|
+
when /\.tar\.bz2\z/i, /\.tbz\z/i
|
58
|
+
Kernel.system("/usr/bin/tar", "-x", "-j", "-f", path, "-C", tmpdir_path)
|
59
|
+
else
|
60
|
+
raise NotImplementedError.new("Disk image support is not implemented yet.")
|
61
|
+
end
|
62
|
+
|
63
|
+
unless $?.success?
|
64
|
+
raise RuntimeError.new("Failed to expand archive: #{path}")
|
65
|
+
end
|
66
|
+
|
67
|
+
app_paths = Dir.glob(File.join(tmpdir_path, "*.app"), File::FNM_CASEFOLD)
|
68
|
+
if app_paths.size == 0
|
69
|
+
raise RuntimeError.new("No application bundle found: #{path}")
|
70
|
+
elsif app_paths.size > 1
|
71
|
+
raise RuntimeError.new("Found multiple application bundles: #{app_paths.map{|path| File.basename(path)}}")
|
72
|
+
else
|
73
|
+
app_path = app_paths.first
|
74
|
+
info_plist_path = File.join(app_path, "Contents", "Info.plist")
|
75
|
+
Plist.parse_xml(info_plist_path)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "thor"
|
3
|
+
require "kramdown"
|
4
|
+
require "time"
|
5
|
+
|
6
|
+
module SparkleAppcast
|
7
|
+
class Cli < Thor
|
8
|
+
def self.exit_on_failure?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "appcast FILE", "Create `appcast.xml` with an application archive file."
|
13
|
+
long_desc <<-END_OF_DESCRIPTION
|
14
|
+
Create `appcast.xml` with an application archive file.
|
15
|
+
The application archive file must contain exact one application bundle.
|
16
|
+
END_OF_DESCRIPTION
|
17
|
+
option :key, type: :string, required: true, desc: "Path to a DSA private key."
|
18
|
+
option :url, type: :string, required: true, desc: "URL to the application archive file published."
|
19
|
+
option :release_note, type: :string, required: true, desc: "Path to a release note text file in Markdown format."
|
20
|
+
option :output, type: :string, desc: "Path to an output `appcast.xml`."
|
21
|
+
option :title, type: :string, desc: "Title for the release note."
|
22
|
+
option :publish_date, type: :string, desc: "Publish date time in local timezone."
|
23
|
+
option :channel_title, type: :string, default: "Change log", desc: "Title of the channel."
|
24
|
+
option :channel_description, type: :string, default: "The most recent changes.", desc: "Description of the channel."
|
25
|
+
def appcast(file)
|
26
|
+
params = {
|
27
|
+
channel_title: options[:channel_title],
|
28
|
+
channel_description: options[:channel_description]
|
29
|
+
}
|
30
|
+
params[:title] = options[:title] if options[:title]
|
31
|
+
params[:publish_date] = Time.parse(options[:publish_date]) if options[:publish_date]
|
32
|
+
|
33
|
+
appcast = Appcast.new(
|
34
|
+
Archive.new(file),
|
35
|
+
Signer.new(options[:key]),
|
36
|
+
options[:url],
|
37
|
+
ReleaseNote.new(options[:release_note]),
|
38
|
+
params
|
39
|
+
)
|
40
|
+
|
41
|
+
rss = appcast.rss.to_s
|
42
|
+
if options[:output]
|
43
|
+
File.open(options[:output], "w") do |output|
|
44
|
+
output.puts(rss)
|
45
|
+
end
|
46
|
+
else
|
47
|
+
STDOUT.puts(rss)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "sign [FILE]", "Sign a file with a DSA private key."
|
52
|
+
option :key, type: :string, required: true, desc: "Path to a DSA private key."
|
53
|
+
def sign(file = nil)
|
54
|
+
source = if file
|
55
|
+
File.binread(file)
|
56
|
+
else
|
57
|
+
STDIN.read
|
58
|
+
end
|
59
|
+
puts Signer.new(options[:key]).sign(source)
|
60
|
+
end
|
61
|
+
|
62
|
+
desc "markdown [FILE]", "Format Markdown text file in HTML."
|
63
|
+
def markdown(file = nil)
|
64
|
+
text = if file
|
65
|
+
File.read(file)
|
66
|
+
else
|
67
|
+
STDIN.read
|
68
|
+
end
|
69
|
+
puts ReleaseNote.markdown(text)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SparkleAppcast
|
2
|
+
class ReleaseNote
|
3
|
+
def self.markdown(text)
|
4
|
+
Kramdown::Document.new(text, auto_ids: false).to_html
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_reader :path
|
8
|
+
|
9
|
+
def initialize(path)
|
10
|
+
@path = path
|
11
|
+
end
|
12
|
+
|
13
|
+
def html
|
14
|
+
@html ||= self.class.markdown(text)
|
15
|
+
end
|
16
|
+
|
17
|
+
def text
|
18
|
+
@text ||= File.read(path)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require "rexml/document"
|
2
|
+
require "time"
|
3
|
+
|
4
|
+
module SparkleAppcast
|
5
|
+
class Rss
|
6
|
+
REQUIRED_FILEDS = [
|
7
|
+
:url,
|
8
|
+
:length,
|
9
|
+
:version,
|
10
|
+
:dsa_signature
|
11
|
+
]
|
12
|
+
|
13
|
+
attr_reader :params
|
14
|
+
|
15
|
+
def initialize(params)
|
16
|
+
REQUIRED_FILEDS.each do |field|
|
17
|
+
unless params[field]
|
18
|
+
raise ArgumentError.new("Missing #{field} param")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
@params = params
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
StringIO.new.tap do |output|
|
26
|
+
output << %(<?xml version="1.0" encoding="UTF-8"?>\n)
|
27
|
+
formatter = REXML::Formatters::Pretty.new(2)
|
28
|
+
formatter.compact = true
|
29
|
+
formatter.write(document, output)
|
30
|
+
end.string
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def document
|
36
|
+
@document ||= REXML::Document.new.tap do |document|
|
37
|
+
document.context = {
|
38
|
+
# Use double quote for attributes escape.
|
39
|
+
attribute_quote: :quote
|
40
|
+
}
|
41
|
+
|
42
|
+
# <rss ... > ... </rss>
|
43
|
+
document.add_element("rss").tap do |rss|
|
44
|
+
rss.add_namespace("xmlns:sparkle", "http://www.andymatuschak.org/xml-namespaces/sparkle")
|
45
|
+
rss.add_namespace("xmlns:dc", "http://purl.org/dc/elements/1.1/")
|
46
|
+
rss.add_attribute("version", "2.0")
|
47
|
+
|
48
|
+
# <channel> ... </channel>
|
49
|
+
rss.add_element("channel").tap do |channel|
|
50
|
+
channel.add_element("title").add_text(params[:channel_title]) if params[:channel_title]
|
51
|
+
channel.add_element("description").add_text(params[:channel_description]) if params[:channel_description]
|
52
|
+
channel.add_element("link").add_text(params[:channel_link]) if params[:channel_link]
|
53
|
+
channel.add_element("language").add_text(params[:language]) if params[:language]
|
54
|
+
|
55
|
+
# <item> ... </item>
|
56
|
+
channel.add_element("item").tap do |item|
|
57
|
+
item.add_element("title").add_text(params[:title]) if params[:title]
|
58
|
+
item.add_element("description").add(REXML::CData.new(params[:description])) if params[:description]
|
59
|
+
item.add_element("pubDate").add_text(publish_date) if publish_date
|
60
|
+
|
61
|
+
# <enclosure ... />
|
62
|
+
item.add_element("enclosure").tap do |enclosure|
|
63
|
+
enclosure.add_attribute("url", params[:url])
|
64
|
+
enclosure.add_attribute("type", "application/octet-stream")
|
65
|
+
enclosure.add_attribute("length", params[:length])
|
66
|
+
enclosure.add_attribute("sparkle:version", params[:version])
|
67
|
+
enclosure.add_attribute("sparkle:shortVersionString", params[:short_version_string]) if params[:short_version_string]
|
68
|
+
enclosure.add_attribute("sparkle:dsaSignature", params[:dsa_signature])
|
69
|
+
enclosure.add_attribute("sparkle:minimumSystemVersion", params[:minimum_system_version]) if params[:minimum_system_version]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def publish_date
|
78
|
+
case params[:publish_date]
|
79
|
+
when nil
|
80
|
+
nil
|
81
|
+
when Time
|
82
|
+
params[:publish_date].utc.rfc2822
|
83
|
+
else
|
84
|
+
params[:publish_date]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "openssl"
|
2
|
+
require "base64"
|
3
|
+
|
4
|
+
module SparkleAppcast
|
5
|
+
class Signer
|
6
|
+
attr_reader :private_key_path
|
7
|
+
|
8
|
+
def initialize(private_key_path)
|
9
|
+
@private_key_path = private_key_path
|
10
|
+
end
|
11
|
+
|
12
|
+
def sign(data)
|
13
|
+
# Sparkle is signing SHA1 digest with DSA private key and encoding it in Base64.
|
14
|
+
# See <https://github.com/sparkle-project/Sparkle/blob/master/bin/sign_update>.
|
15
|
+
digest = OpenSSL::Digest::SHA1.digest(data)
|
16
|
+
signature = private_key.sign(OpenSSL::Digest::SHA1.new, digest)
|
17
|
+
Base64.strict_encode64(signature)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def private_key
|
23
|
+
@private_key ||= OpenSSL::PKey::DSA.new(File.binread(private_key_path))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
module SparkleAppcast
|
2
|
+
autoload :Appcast, "sparkle_appcast/appcast"
|
3
|
+
autoload :Archive, "sparkle_appcast/archive"
|
4
|
+
autoload :Cli, "sparkle_appcast/cli"
|
5
|
+
autoload :ReleaseNote, "sparkle_appcast/release_note"
|
6
|
+
autoload :Rss, "sparkle_appcast/rss"
|
7
|
+
autoload :Signer, "sparkle_appcast/signer"
|
8
|
+
end
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sparkle_appcast
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yoshimasa Niwa
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-02-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: kramdown
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: plist
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Generate Sparkle appcast.xml
|
84
|
+
email:
|
85
|
+
- niw@niw.at
|
86
|
+
executables:
|
87
|
+
- sparkle_appcast
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files:
|
90
|
+
- LICENSE
|
91
|
+
- README.md
|
92
|
+
files:
|
93
|
+
- LICENSE
|
94
|
+
- README.md
|
95
|
+
- bin/sparkle_appcast
|
96
|
+
- lib/sparkle_appcast.rb
|
97
|
+
- lib/sparkle_appcast/appcast.rb
|
98
|
+
- lib/sparkle_appcast/archive.rb
|
99
|
+
- lib/sparkle_appcast/cli.rb
|
100
|
+
- lib/sparkle_appcast/release_note.rb
|
101
|
+
- lib/sparkle_appcast/rss.rb
|
102
|
+
- lib/sparkle_appcast/signer.rb
|
103
|
+
homepage:
|
104
|
+
licenses: []
|
105
|
+
metadata: {}
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
requirements: []
|
121
|
+
rubyforge_project:
|
122
|
+
rubygems_version: 2.7.3
|
123
|
+
signing_key:
|
124
|
+
specification_version: 4
|
125
|
+
summary: Generate Sparkle appcast.xml
|
126
|
+
test_files: []
|