jekyll-fdroid 0.2.0 → 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.
- checksums.yaml +5 -5
- data/lib/fdroid/App.rb +45 -48
- data/lib/fdroid/IndexV1.rb +1 -2
- data/lib/fdroid/Package.rb +12 -8
- data/lib/fdroid/Permission.rb +3 -3
- data/lib/fdroid/Repo.rb +7 -4
- data/lib/jekyll/FDroidBrowsingPage.rb +10 -11
- data/lib/jekyll/FDroidFilters.rb +153 -152
- data/lib/jekyll/FDroidLastUpdatedPackagesTag.rb +9 -11
- data/lib/jekyll/FDroidLatestPackagesTag.rb +9 -11
- data/lib/jekyll/FDroidPackageDetailGenerator.rb +41 -42
- data/lib/jekyll/FDroidPackageDetailPage.rb +1 -3
- data/lib/jekyll/FDroidRepoInfoTag.rb +16 -14
- data/lib/jekyll/FDroidSearchAutocompleteTag.rb +72 -62
- data/lib/jekyll/ReadYamlPage.rb +17 -18
- data/lib/lunr/Javascript.rb +7 -7
- data/lib/lunr/LunrIndexer.rb +14 -14
- data/lib/lunr/SearchIndexFile.rb +9 -9
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f72286c732de382d651b8377c0083ed8faeb58cab5a865dd8e72978dd84e1a60
|
4
|
+
data.tar.gz: 57873902b7c8d5249f269293afc0b2d172db25c1371f37b70ec959f00192dfcc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 551e0cba8c4add0d485a7dec9e12d95107b6be1a38620a730e58fe9174b648a861aa054dac69e9e519058adb6dc010c89843958fed78f3ba581ce1ccad4991d6
|
7
|
+
data.tar.gz: '0098617770f3bd1f3bbeddfd0278a9dcdf2cf50f1cc2ed5c8c842051210f7ea36e2f8ad6d59112237b94724bf223b97036031cfb1d271bffd602261153545b87'
|
data/lib/fdroid/App.rb
CHANGED
@@ -39,21 +39,21 @@ module FDroid
|
|
39
39
|
localized = App.localized_graphic_path(@available_locales, @app['localized'], 'icon')
|
40
40
|
if localized
|
41
41
|
"#{package_name}/#{localized}"
|
42
|
-
|
42
|
+
elsif field('icon')
|
43
43
|
"icons-640/#{field('icon')}"
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
def name
|
48
|
-
App.localized(@available_locales, @app['localized'], 'name')
|
48
|
+
field('name') || App.localized(@available_locales, @app['localized'], 'name')
|
49
49
|
end
|
50
50
|
|
51
51
|
def summary
|
52
|
-
App.localized(@available_locales, @app['localized'], 'summary')
|
52
|
+
field('summary') || App.localized(@available_locales, @app['localized'], 'summary')
|
53
53
|
end
|
54
54
|
|
55
55
|
def description
|
56
|
-
desc = App.localized(@available_locales, @app['localized'], 'description')
|
56
|
+
desc = field('description') || App.localized(@available_locales, @app['localized'], 'description')
|
57
57
|
|
58
58
|
if desc != nil
|
59
59
|
desc = App.process_app_description(desc)
|
@@ -70,7 +70,6 @@ module FDroid
|
|
70
70
|
return code
|
71
71
|
end
|
72
72
|
|
73
|
-
|
74
73
|
# Generates a hash of dumb strings to be used in templates.
|
75
74
|
# If a specific value is not present, then it will have a nil value.
|
76
75
|
# If a value can be localized, then it will choose the most appropriate
|
@@ -79,39 +78,42 @@ module FDroid
|
|
79
78
|
# @return [Hash]
|
80
79
|
def to_data
|
81
80
|
{
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
81
|
+
# These fields are taken as is from the metadata. If not present, they are
|
82
|
+
'package_name' => package_name,
|
83
|
+
'author_email' => field('authorEmail'),
|
84
|
+
'author_name' => field('authorName'),
|
85
|
+
'author_website' => field('authorWebSite'),
|
86
|
+
'translation' => field('translation'),
|
87
|
+
'bitcoin' => field('bitcoin'),
|
88
|
+
'litecoin' => field('litecoin'),
|
89
|
+
'donate' => field('donate'),
|
90
|
+
'flattrID' => field('flattrID'),
|
91
|
+
'liberapayID' => field('liberapayID'),
|
92
|
+
'categories' => field('categories'),
|
93
|
+
'anti_features' => field('anti_features'),
|
94
|
+
'suggested_version_code' => suggested_version_code,
|
95
|
+
'suggested_version_name' => @packages.detect { |p| p.version_code == suggested_version_code }&.version_name,
|
96
|
+
'issue_tracker' => field('issueTracker'),
|
97
|
+
'changelog' => field('changelog'),
|
98
|
+
'license' => field('license'),
|
99
|
+
'source_code' => field('sourceCode'),
|
100
|
+
'website' => field('webSite'),
|
101
|
+
'added' => field('added'),
|
102
|
+
'last_updated' => field('lastUpdated'),
|
103
|
+
'whats_new' => App.process_app_description(App.localized(@available_locales, @app['localized'], 'whatsNew')),
|
104
|
+
|
105
|
+
'icon' => icon,
|
106
|
+
'title' => name,
|
107
|
+
'summary' => summary,
|
108
|
+
|
109
|
+
'description' => description,
|
110
|
+
'feature_graphic' => App.localized_graphic_path(@available_locales, @app['localized'], 'featureGraphic'),
|
111
|
+
'phone_screenshots' => App.localized_graphic_list_paths(@available_locales, @app['localized'], 'phoneScreenshots'),
|
112
|
+
'seven_inch_screenshots' => App.localized_graphic_list_paths(@available_locales, @app['localized'], 'sevenInchScreenshots'),
|
113
|
+
|
114
|
+
'packages' => @packages.sort.reverse.map { |p| p.to_data },
|
115
|
+
|
116
|
+
'beautiful_url' => "/packages/#{package_name}"
|
115
117
|
}
|
116
118
|
end
|
117
119
|
|
@@ -134,11 +136,10 @@ module FDroid
|
|
134
136
|
string.gsub /fdroid\.app:([\w._]*)/, '/packages/\1'
|
135
137
|
end
|
136
138
|
|
137
|
-
# Ensure
|
139
|
+
# Ensure newlines in descriptions are preserved (converted to "<br />" tags)
|
140
|
+
# Handles UNIX, Windows and MacOS newlines, with a one-to-one replacement
|
138
141
|
def self.format_description_to_html(string)
|
139
|
-
string
|
140
|
-
.gsub("\n\n", '<br />')
|
141
|
-
.gsub(/\r?\n/, ' ')
|
142
|
+
string.gsub(/(?:\n\r?|\r\n?)/, '<br />')
|
142
143
|
end
|
143
144
|
|
144
145
|
# @param [string] available_locales
|
@@ -156,34 +157,30 @@ module FDroid
|
|
156
157
|
|
157
158
|
return nil
|
158
159
|
end
|
159
|
-
|
160
|
+
|
160
161
|
# Prefixes the result with "chosen_locale/" before returning.
|
161
162
|
# @see localized
|
162
163
|
def self.localized_graphic_path(available_locales, localized, field)
|
163
164
|
return nil unless available_locales != nil
|
164
|
-
|
165
165
|
available_locales.each do |l|
|
166
166
|
if localized[l].key?(field)
|
167
167
|
return "#{l}/#{localized[l][field]}"
|
168
168
|
end
|
169
169
|
end
|
170
|
-
|
171
170
|
return nil
|
172
171
|
end
|
173
|
-
|
172
|
+
|
174
173
|
# Similar to localized_graphic_path, but prefixes each item in the resulting array
|
175
174
|
# with "chosen_locale/field/".
|
176
175
|
# @see localized
|
177
176
|
# @see localized_graphic_path
|
178
177
|
def self.localized_graphic_list_paths(available_locales, localized, field)
|
179
178
|
return nil unless available_locales != nil
|
180
|
-
|
181
179
|
available_locales.each do |l|
|
182
180
|
if localized[l].key?(field)
|
183
181
|
return localized[l][field].map { |val| "#{l}/#{field}/#{val}" }
|
184
182
|
end
|
185
183
|
end
|
186
|
-
|
187
184
|
return nil
|
188
185
|
end
|
189
186
|
|
data/lib/fdroid/IndexV1.rb
CHANGED
data/lib/fdroid/Package.rb
CHANGED
@@ -23,7 +23,7 @@ module FDroid
|
|
23
23
|
@package = package
|
24
24
|
end
|
25
25
|
|
26
|
-
def <=>
|
26
|
+
def <=>(other)
|
27
27
|
self.version_code <=> other.version_code
|
28
28
|
end
|
29
29
|
|
@@ -42,19 +42,23 @@ module FDroid
|
|
42
42
|
end
|
43
43
|
|
44
44
|
{
|
45
|
-
'version_name' => version_name,
|
46
|
-
'version_code' => version_code,
|
47
45
|
'added' => added,
|
46
|
+
'anti_features' => @package['antiFeatures'],
|
48
47
|
'apk_name' => @package['apkName'],
|
48
|
+
'file_extension' => File.extname(@package['apkName'].to_s).strip.upcase[1..-1],
|
49
49
|
'hash' => @package['hash'],
|
50
50
|
'hash_type' => @package['hashType'],
|
51
|
-
'min_sdk_version' => @package['minSdkVersion'],
|
52
51
|
'max_sdk_version' => @package['maxSdkVersion'],
|
53
|
-
'
|
54
|
-
'
|
52
|
+
'min_sdk_version' => @package['minSdkVersion'],
|
53
|
+
'nativecode' => @package['nativecode'],
|
54
|
+
'srcname' => @package['srcname'],
|
55
55
|
'sig' => @package['sig'],
|
56
|
+
'signer' => @package['signer'],
|
56
57
|
'size' => @package['size'],
|
58
|
+
'target_sdk_version' => @package['targetSdkVersion'],
|
57
59
|
'uses_permission' => permission,
|
60
|
+
'version_name' => version_name,
|
61
|
+
'version_code' => version_code,
|
58
62
|
}
|
59
63
|
end
|
60
64
|
|
@@ -62,7 +66,7 @@ module FDroid
|
|
62
66
|
if @package['uses-permission'] == nil then
|
63
67
|
[]
|
64
68
|
else
|
65
|
-
@package['uses-permission'].map {|perm| Permission.new(perm).to_data }
|
69
|
+
@package['uses-permission'].map { |perm| Permission.new(perm).to_data }
|
66
70
|
end
|
67
71
|
end
|
68
72
|
|
@@ -72,4 +76,4 @@ module FDroid
|
|
72
76
|
@app.key?(name) ? name : nil
|
73
77
|
end
|
74
78
|
end
|
75
|
-
end
|
79
|
+
end
|
data/lib/fdroid/Permission.rb
CHANGED
data/lib/fdroid/Repo.rb
CHANGED
@@ -24,7 +24,7 @@ module FDroid
|
|
24
24
|
def name
|
25
25
|
@repo['name']
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def address
|
29
29
|
@repo['address']
|
30
30
|
end
|
@@ -36,10 +36,13 @@ module FDroid
|
|
36
36
|
def description
|
37
37
|
@repo['description']
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
|
+
def timestamp
|
41
|
+
@repo['timestamp']
|
42
|
+
end
|
43
|
+
|
40
44
|
def date
|
41
45
|
added = Date.strptime("#{@repo['timestamp'] / 1000}", '%s')
|
42
46
|
end
|
43
|
-
|
44
47
|
end
|
45
|
-
end
|
48
|
+
end
|
@@ -16,16 +16,15 @@
|
|
16
16
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
|
18
18
|
module Jekyll
|
19
|
+
class FDroidBrowsingPage < ReadYamlPage
|
20
|
+
def initialize(site, base)
|
21
|
+
@site = site
|
22
|
+
@base = base
|
23
|
+
@dir = "packages"
|
24
|
+
@name = "index.html"
|
19
25
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
@dir = "packages"
|
25
|
-
@name = "index.html"
|
26
|
-
|
27
|
-
self.process(@name)
|
28
|
-
self.read_yaml((File.expand_path "../../_pages", File.dirname(__FILE__)), 'browse.html')
|
29
|
-
end
|
30
|
-
end
|
26
|
+
self.process(@name)
|
27
|
+
self.read_yaml((File.expand_path "../../_pages", File.dirname(__FILE__)), 'browse.html')
|
28
|
+
end
|
29
|
+
end
|
31
30
|
end
|
data/lib/jekyll/FDroidFilters.rb
CHANGED
@@ -16,164 +16,165 @@
|
|
16
16
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
|
18
18
|
module Jekyll
|
19
|
+
module Filters
|
20
|
+
# Convert an Android SDK level into an Android version.
|
21
|
+
#
|
22
|
+
# input - Android SDK Level.
|
23
|
+
#
|
24
|
+
# Returns the Android version.
|
25
|
+
def android_sdk_level_to_version(input)
|
26
|
+
sdkLevel = @@AndroidSdkLevelToVersionRelation[input]
|
27
|
+
if not sdkLevel.nil?
|
28
|
+
return sdkLevel
|
29
|
+
end
|
30
|
+
return '?'
|
31
|
+
end
|
19
32
|
|
20
|
-
|
33
|
+
# Hash with relation between Android SDK Level and Android version
|
34
|
+
# https://source.android.com/setup/build-numbers
|
35
|
+
@@AndroidSdkLevelToVersionRelation = {
|
36
|
+
'1' => '1.0',
|
37
|
+
'2' => '1.1',
|
38
|
+
'3' => '1.5',
|
39
|
+
'4' => '1.6',
|
40
|
+
'5' => '2.0',
|
41
|
+
'6' => '2.0.1',
|
42
|
+
'7' => '2.1',
|
43
|
+
'8' => '2.2',
|
44
|
+
'9' => '2.3',
|
45
|
+
'10' => '2.3.3',
|
46
|
+
'11' => '3.0',
|
47
|
+
'12' => '3.1',
|
48
|
+
'13' => '3.2',
|
49
|
+
'14' => '4.0',
|
50
|
+
'15' => '4.0.3',
|
51
|
+
'16' => '4.1',
|
52
|
+
'17' => '4.2',
|
53
|
+
'18' => '4.3',
|
54
|
+
'19' => '4.4',
|
55
|
+
'20' => '4.4W',
|
56
|
+
'21' => '5.0',
|
57
|
+
'22' => '5.1',
|
58
|
+
'23' => '6.0',
|
59
|
+
'24' => '7.0',
|
60
|
+
'25' => '7.1',
|
61
|
+
'26' => '8.0',
|
62
|
+
'27' => '8.1',
|
63
|
+
}
|
21
64
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
65
|
+
# Convert a file size to a human-readable String.
|
66
|
+
# Source: https://codereview.stackexchange.com/q/9107
|
67
|
+
#
|
68
|
+
# input - File size in Bytes.
|
69
|
+
#
|
70
|
+
# Returns human-readable String.
|
71
|
+
def file_size_human_readable(input)
|
72
|
+
input = input.to_f
|
73
|
+
i = PREFIX.length - 1
|
74
|
+
while input > 512 && i > 0
|
75
|
+
i -= 1
|
76
|
+
input /= 1024
|
77
|
+
end
|
78
|
+
return ((input > 9 || input.modulo(1) < 0.1 ? '%d' : '%.1f') % input) + ' ' + PREFIX[i]
|
79
|
+
end
|
80
|
+
PREFIX = %W(TiB GiB MiB KiB B).freeze
|
34
81
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
'20' => '4.4W',
|
57
|
-
'21' => '5.0',
|
58
|
-
'22' => '5.1',
|
59
|
-
'23' => '6.0',
|
60
|
-
'24' => '7.0',
|
61
|
-
'25' => '7.1'
|
62
|
-
}
|
82
|
+
# Convert a SPDX license identifier to its full name.
|
83
|
+
#
|
84
|
+
# input - SPDX license identifier.
|
85
|
+
#
|
86
|
+
# Returns full license name.
|
87
|
+
def get_license_name(input)
|
88
|
+
if input.nil? or input.empty?
|
89
|
+
return 'Unknown'
|
90
|
+
end
|
91
|
+
spdxLicense = @@SpdxLicenseNameToGnuUrlRelation[input]
|
92
|
+
if input.end_with? "+"
|
93
|
+
spdxLicense = @@SpdxLicenseNameToGnuUrlRelation[input.chomp('+')]
|
94
|
+
end
|
95
|
+
if not spdxLicense.nil?
|
96
|
+
if input.end_with? "+"
|
97
|
+
return spdxLicense['name'] + ' or later version'
|
98
|
+
end
|
99
|
+
return spdxLicense['name']
|
100
|
+
end
|
101
|
+
return input
|
102
|
+
end
|
63
103
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
104
|
+
# Convert a SPDX license identifier to its URL on GNU.org.
|
105
|
+
#
|
106
|
+
# input - SPDX license identifier.
|
107
|
+
#
|
108
|
+
# Returns URL on GNU.org.
|
109
|
+
def get_license_url(input)
|
110
|
+
if input.nil? or input.empty?
|
111
|
+
return ''
|
112
|
+
end
|
113
|
+
if input.end_with? "+"
|
114
|
+
input = input.chomp('+')
|
115
|
+
end
|
116
|
+
spdxLicense = @@SpdxLicenseNameToGnuUrlRelation[input]
|
117
|
+
if not spdxLicense.nil?
|
118
|
+
return spdxLicense['url']
|
119
|
+
end
|
120
|
+
return 'https://spdx.org/licenses/' + input + '.html'
|
121
|
+
end
|
80
122
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
'name' => 'BSD 2-clause "Simplified" License',
|
135
|
-
'url' => 'https://www.gnu.org/licenses/license-list.html#FreeBSD'
|
136
|
-
},
|
137
|
-
'BSD-3-Clause' => {
|
138
|
-
'name' => 'BSD 3-clause "New" or "Revised" License',
|
139
|
-
'url' => 'https://www.gnu.org/licenses/license-list.html#ModifiedBSD'
|
140
|
-
},
|
141
|
-
'GPL-2.0' => {
|
142
|
-
'name' => 'GNU General Public License v2.0',
|
143
|
-
'url' => 'https://www.gnu.org/licenses/license-list.html#GPLv2'
|
144
|
-
},
|
145
|
-
'GPL-3.0' => {
|
146
|
-
'name' => 'GNU General Public License v3.0',
|
147
|
-
'url' => 'https://www.gnu.org/licenses/license-list.html#GNUGPLv3'
|
148
|
-
},
|
149
|
-
'ISC' => {
|
150
|
-
'name' => 'ISC License',
|
151
|
-
'url' => 'https://www.gnu.org/licenses/license-list.en.html#ISC'
|
152
|
-
},
|
153
|
-
'LGPL-2.1' => {
|
154
|
-
'name' => 'GNU Lesser General Public License v2.1',
|
155
|
-
'url' => 'https://www.gnu.org/licenses/license-list.html#LGPLv2.1'
|
156
|
-
},
|
157
|
-
'LGPL-3.0' => {
|
158
|
-
'name' => 'GNU Lesser General Public License v3.0',
|
159
|
-
'url' => 'https://www.gnu.org/licenses/license-list.html#LGPLv3'
|
160
|
-
},
|
161
|
-
'MIT' => {
|
162
|
-
'name' => 'MIT License',
|
163
|
-
'url' => 'https://www.gnu.org/licenses/license-list.html#X11License'
|
164
|
-
},
|
165
|
-
'MPL-1.1' => {
|
166
|
-
'name' => 'Mozilla Public License 1.1',
|
167
|
-
'url' => 'https://www.gnu.org/licenses/license-list.html#MPL'
|
168
|
-
},
|
169
|
-
'MPL-2.0' => {
|
170
|
-
'name' => 'Mozilla Public License 2.0',
|
171
|
-
'url' => 'https://www.gnu.org/licenses/license-list.html#MPL-2.0'
|
172
|
-
}
|
173
|
-
}
|
174
|
-
end
|
123
|
+
# Hash with relation between SPDX license identifier and its full name and URL, mostly on GNU.org.
|
124
|
+
# For the beginning, I only used OSI approved and frequently used licenses.
|
125
|
+
@@SpdxLicenseNameToGnuUrlRelation = {
|
126
|
+
'AGPL-3.0' => {
|
127
|
+
'name' => 'GNU Affero General Public License v3.0',
|
128
|
+
'url' => 'https://www.gnu.org/licenses/license-list.html#AGPLv3.0'
|
129
|
+
},
|
130
|
+
'Apache-2.0' => {
|
131
|
+
'name' => 'Apache License 2.0',
|
132
|
+
'url' => 'https://www.gnu.org/licenses/license-list.html#apache2'
|
133
|
+
},
|
134
|
+
'BSD-2-Clause' => {
|
135
|
+
'name' => 'BSD 2-clause "Simplified" License',
|
136
|
+
'url' => 'https://www.gnu.org/licenses/license-list.html#FreeBSD'
|
137
|
+
},
|
138
|
+
'BSD-3-Clause' => {
|
139
|
+
'name' => 'BSD 3-clause "New" or "Revised" License',
|
140
|
+
'url' => 'https://www.gnu.org/licenses/license-list.html#ModifiedBSD'
|
141
|
+
},
|
142
|
+
'GPL-2.0' => {
|
143
|
+
'name' => 'GNU General Public License v2.0',
|
144
|
+
'url' => 'https://www.gnu.org/licenses/license-list.html#GPLv2'
|
145
|
+
},
|
146
|
+
'GPL-3.0' => {
|
147
|
+
'name' => 'GNU General Public License v3.0',
|
148
|
+
'url' => 'https://www.gnu.org/licenses/license-list.html#GNUGPLv3'
|
149
|
+
},
|
150
|
+
'ISC' => {
|
151
|
+
'name' => 'ISC License',
|
152
|
+
'url' => 'https://www.gnu.org/licenses/license-list.en.html#ISC'
|
153
|
+
},
|
154
|
+
'LGPL-2.1' => {
|
155
|
+
'name' => 'GNU Lesser General Public License v2.1',
|
156
|
+
'url' => 'https://www.gnu.org/licenses/license-list.html#LGPLv2.1'
|
157
|
+
},
|
158
|
+
'LGPL-3.0' => {
|
159
|
+
'name' => 'GNU Lesser General Public License v3.0',
|
160
|
+
'url' => 'https://www.gnu.org/licenses/license-list.html#LGPLv3'
|
161
|
+
},
|
162
|
+
'MIT' => {
|
163
|
+
'name' => 'MIT License',
|
164
|
+
'url' => 'https://www.gnu.org/licenses/license-list.html#X11License'
|
165
|
+
},
|
166
|
+
'MPL-1.1' => {
|
167
|
+
'name' => 'Mozilla Public License 1.1',
|
168
|
+
'url' => 'https://www.gnu.org/licenses/license-list.html#MPL'
|
169
|
+
},
|
170
|
+
'MPL-2.0' => {
|
171
|
+
'name' => 'Mozilla Public License 2.0',
|
172
|
+
'url' => 'https://www.gnu.org/licenses/license-list.html#MPL-2.0'
|
173
|
+
}
|
174
|
+
}
|
175
|
+
end
|
175
176
|
end
|
176
177
|
|
177
178
|
Liquid::Template.register_filter(
|
178
|
-
|
179
|
+
Jekyll::Filters
|
179
180
|
)
|
@@ -16,18 +16,16 @@
|
|
16
16
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
|
18
18
|
module Jekyll
|
19
|
+
class FDroidLastUpdatedPackagesTag < Liquid::Tag
|
20
|
+
def initialize(tag_name, text, tokens)
|
21
|
+
super
|
22
|
+
end
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
def render(context)
|
27
|
-
template = Liquid::Template.parse(IO.read((File.expand_path "../../_layouts/sidebar-lastupdated-packages.html", File.dirname(__FILE__))))
|
28
|
-
template.render(context)
|
29
|
-
end
|
30
|
-
end
|
24
|
+
def render(context)
|
25
|
+
template = Liquid::Template.parse(IO.read((File.expand_path "../../_layouts/sidebar-lastupdated-packages.html", File.dirname(__FILE__))))
|
26
|
+
template.render(context)
|
27
|
+
end
|
28
|
+
end
|
31
29
|
end
|
32
30
|
|
33
31
|
Liquid::Template.register_tag('fdroid_show_last_updated_packages', Jekyll::FDroidLastUpdatedPackagesTag)
|
@@ -16,18 +16,16 @@
|
|
16
16
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
|
18
18
|
module Jekyll
|
19
|
+
class FDroidLatestPackagesTag < Liquid::Tag
|
20
|
+
def initialize(tag_name, text, tokens)
|
21
|
+
super
|
22
|
+
end
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
def render(context)
|
27
|
-
template = Liquid::Template.parse(IO.read((File.expand_path "../../_layouts/sidebar-latest-packages.html", File.dirname(__FILE__))))
|
28
|
-
template.render(context)
|
29
|
-
end
|
30
|
-
end
|
24
|
+
def render(context)
|
25
|
+
template = Liquid::Template.parse(IO.read((File.expand_path "../../_layouts/sidebar-latest-packages.html", File.dirname(__FILE__))))
|
26
|
+
template.render(context)
|
27
|
+
end
|
28
|
+
end
|
31
29
|
end
|
32
30
|
|
33
31
|
Liquid::Template.register_tag('fdroid_show_latest_packages', Jekyll::FDroidLatestPackagesTag)
|
@@ -16,53 +16,52 @@
|
|
16
16
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
|
18
18
|
module Jekyll
|
19
|
+
class FDroidPackagesGenerator < Generator
|
20
|
+
attr_accessor :alreadyBuilt
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
+
safe true
|
23
|
+
priority :highest
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
+
def generate(site)
|
26
|
+
# generator will only run on first build, not because of auto-regeneration
|
27
|
+
if @alreadyBuilt != true
|
28
|
+
@alreadyBuilt = true
|
25
29
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
+
# Add plugin's SASS directory so site's list of SASS directories
|
31
|
+
if site.config["sass"].nil? || site.config["sass"].empty?
|
32
|
+
site.config["sass"] = Hash.new
|
33
|
+
end
|
34
|
+
if site.config["sass"]["load_paths"].nil? || site.config["sass"]["load_paths"].empty?
|
35
|
+
site.config["sass"]["load_paths"] = ["_sass", (File.expand_path "../../_sass", File.dirname(__FILE__))]
|
36
|
+
else
|
37
|
+
site.config["sass"]["load_paths"] << (File.expand_path "../../_sass", File.dirname(__FILE__))
|
38
|
+
end
|
30
39
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
site.config["sass"]["load_paths"] = ["_sass", (File.expand_path "../../_sass", File.dirname(__FILE__))]
|
37
|
-
else
|
38
|
-
site.config["sass"]["load_paths"] << (File.expand_path "../../_sass", File.dirname(__FILE__))
|
39
|
-
end
|
40
|
+
# Enable pagination
|
41
|
+
if site.config["pagination"].nil? || site.config["pagination"].empty?
|
42
|
+
site.config["pagination"] = Hash.new
|
43
|
+
end
|
44
|
+
site.config["pagination"]["enabled"] = true
|
40
45
|
|
41
|
-
|
42
|
-
if site.config["pagination"].nil? || site.config["pagination"].empty?
|
43
|
-
site.config["pagination"] = Hash.new
|
44
|
-
end
|
45
|
-
site.config["pagination"]["enabled"] = true
|
46
|
+
index = FDroid::IndexV1.download(site.config["fdroid-repo"], site.active_lang || 'en_US')
|
46
47
|
|
47
|
-
|
48
|
+
Jekyll::LunrJsSearch::Indexer.new.generate(site, index.apps)
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
67
|
-
end
|
50
|
+
# Generate detail page for every package
|
51
|
+
site.collections["packages"] = Collection.new(site, "packages")
|
52
|
+
index.apps.each do |package|
|
53
|
+
# This page needs to be created twice, once for site.pages, and once for site.collections.
|
54
|
+
# If not, then the i18n code in jekyll-polyglot will end up processing the page twice, as
|
55
|
+
# it iterates over all pages and all packages. The end result is a double prefix for "/en/en"
|
56
|
+
# for any links in the page.
|
57
|
+
# https://gitlab.com/fdroid/jekyll-fdroid/issues/38
|
58
|
+
site.pages << FDroidPackageDetailPage.new(site, site.source, package)
|
59
|
+
site.collections["packages"].docs << FDroidPackageDetailPage.new(site, site.source, package)
|
60
|
+
end
|
61
|
+
# Generate browsing pages
|
62
|
+
site.includes_load_paths << (File.expand_path "../../_includes", File.dirname(__FILE__))
|
63
|
+
site.pages << FDroidBrowsingPage.new(site, site.source)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
68
67
|
end
|
@@ -16,12 +16,10 @@
|
|
16
16
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
|
18
18
|
module Jekyll
|
19
|
-
|
20
19
|
class FDroidPackageDetailPage < ReadYamlPage
|
21
|
-
|
22
20
|
# @param [Jekyll::Site] site
|
23
21
|
# @param [string] base
|
24
|
-
# @param [
|
22
|
+
# @param [FDroid::App] package
|
25
23
|
def initialize(site, base, package)
|
26
24
|
@site = site
|
27
25
|
@base = base
|
@@ -18,22 +18,24 @@
|
|
18
18
|
require_relative '../fdroid/IndexV1'
|
19
19
|
|
20
20
|
module Jekyll
|
21
|
+
# Used to output the repo name/timestamp used to generate this F-Droid site.
|
22
|
+
class FDroidRepoInfoTag < Liquid::Tag
|
23
|
+
@@repotag = ''
|
21
24
|
|
22
|
-
|
23
|
-
|
25
|
+
def initialize(tag_name, text, tokens)
|
26
|
+
super
|
27
|
+
end
|
24
28
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
36
|
-
end
|
29
|
+
def render(context)
|
30
|
+
if @@repotag == ''
|
31
|
+
site = context.registers[:site]
|
32
|
+
url = site.config['fdroid-repo']
|
33
|
+
index = FDroid::IndexV1.download(url, 'en')
|
34
|
+
@@repotag = "#{index.repo.name} #{index.repo.date}"
|
35
|
+
end
|
36
|
+
return @@repotag
|
37
|
+
end
|
38
|
+
end
|
37
39
|
end
|
38
40
|
|
39
41
|
Liquid::Template.register_tag('fdroid_repo_info', Jekyll::FDroidRepoInfoTag)
|
@@ -16,71 +16,81 @@
|
|
16
16
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
|
18
18
|
module Jekyll
|
19
|
+
class SearchForm
|
20
|
+
def self.render_form(context, search_form_template_path, result_item_template_contents)
|
21
|
+
site = context.registers[:site]
|
22
|
+
repo_timestamp = FDroid::IndexV1.download(site.config['fdroid-repo'], 'en').repo.timestamp
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
24
|
+
context['result_item_template'] = result_item_template_contents
|
25
|
+
|
26
|
+
# If an app developer is able to guess this at the time that they write their app descriptions, then they could
|
27
|
+
# potentially try and inject a new template which hijacks the search results template. This is due to the way in
|
28
|
+
# which JS is used to find the relevant `<script type="x-tmpl-mustache" id="...-{{ search_id }}">` template.
|
29
|
+
# Thus, make it random, and include the repo timestamp. They'd need to guess a random number correctly, and it
|
30
|
+
# will change every day that the repo is republished.
|
31
|
+
context['search_id'] = "#{rand(1000000)}.#{repo_timestamp}"
|
32
|
+
|
33
|
+
context['repo_timestamp'] = repo_timestamp
|
34
|
+
|
35
|
+
template = Liquid::Template.parse(IO.read((File.expand_path(search_form_template_path, File.dirname(__FILE__)))))
|
36
|
+
template.render(context)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# As the user types, a list of results is shown below the text input (floating above other content).
|
41
|
+
# When an item is selected, it will navigate to that packages page.
|
42
|
+
# Designed to be used in a sidebar widget.
|
43
|
+
|
44
|
+
class DropDownWithTemplate < Liquid::Block
|
45
|
+
def render(context)
|
46
|
+
search_form_template_path = "../../_layouts/search-autocomplete.html"
|
47
|
+
SearchForm.render_form(context, search_form_template_path, super.to_s)
|
39
48
|
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class DefaultDropDown < Liquid::Tag
|
52
|
+
def render(context)
|
53
|
+
search_form_template_path = "../../_layouts/search-autocomplete.html"
|
54
|
+
|
55
|
+
result_item_template_path = "../../_includes/search-autocomplete-default-result-template.html"
|
56
|
+
result_item_template = IO.read((File.expand_path(result_item_template_path, File.dirname(__FILE__))))
|
40
57
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
result_item_template_path = "../../_includes/search-full-default-result-template.html"
|
78
|
-
result_item_template = IO.read((File.expand_path(result_item_template_path, File.dirname(__FILE__))))
|
79
|
-
|
80
|
-
context['empty_search_id'] = @empty_search_id
|
81
|
-
SearchForm.render_form(context, search_form_template_path, result_item_template)
|
82
|
-
end
|
83
|
-
end
|
58
|
+
SearchForm.render_form(context, search_form_template_path, result_item_template)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# As the user types, a div is populated with search results.
|
63
|
+
# Differs from DropDownAutocomplete in that once you move focus away from the text input, the results
|
64
|
+
# are still displayed.
|
65
|
+
# Designed for a fully fledged search form on its own page.
|
66
|
+
|
67
|
+
# For each result result, this will render the template found between
|
68
|
+
# the {% fdroid_search_full_with_template %}{% endfdroid_search_full_with_template %} tags.
|
69
|
+
class FullSearchWithTemplate < Liquid::Block
|
70
|
+
def render(context)
|
71
|
+
search_form_template_path = "../../_layouts/search-full.html"
|
72
|
+
SearchForm.render_form(context, search_form_template_path, super.to_s)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# For each search result, this will render the contents of
|
77
|
+
# "_includes/search-full-default-result-template.html" from this plugin.
|
78
|
+
class DefaultFullSearch < Liquid::Tag
|
79
|
+
def initialize(tag_name, argument, tokens)
|
80
|
+
super
|
81
|
+
@empty_search_id = argument.strip
|
82
|
+
end
|
83
|
+
|
84
|
+
def render(context)
|
85
|
+
search_form_template_path = "../../_layouts/search-full.html"
|
86
|
+
|
87
|
+
result_item_template_path = "../../_includes/search-full-default-result-template.html"
|
88
|
+
result_item_template = IO.read((File.expand_path(result_item_template_path, File.dirname(__FILE__))))
|
89
|
+
|
90
|
+
context['empty_search_id'] = @empty_search_id
|
91
|
+
SearchForm.render_form(context, search_form_template_path, result_item_template)
|
92
|
+
end
|
93
|
+
end
|
84
94
|
end
|
85
95
|
|
86
96
|
Liquid::Template.register_tag('fdroid_search_autocomplete', Jekyll::DefaultDropDown)
|
data/lib/jekyll/ReadYamlPage.rb
CHANGED
@@ -18,23 +18,22 @@
|
|
18
18
|
# Found at https://github.com/ggreer/jekyll-gallery-generator/blob/master/lib/jekyll-gallery-generator.rb#L69
|
19
19
|
|
20
20
|
module Jekyll
|
21
|
+
class ReadYamlPage < Page
|
22
|
+
# We need do define it ourself because the templates are in the plugin's directory
|
23
|
+
def read_yaml(base, name, opts = {})
|
24
|
+
begin
|
25
|
+
self.content = File.read(File.join(base.to_s, name.to_s), (site ? site.file_read_opts : {}).merge(opts))
|
26
|
+
if content =~ /\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m
|
27
|
+
self.content = $POSTMATCH
|
28
|
+
self.data = SafeYAML.load($1)
|
29
|
+
end
|
30
|
+
rescue SyntaxError => e
|
31
|
+
Jekyll.logger.warn "YAML Exception reading #{File.join(base.to_s, name.to_s)}: #{e.message}"
|
32
|
+
rescue Exception => e
|
33
|
+
Jekyll.logger.warn "Error reading file #{File.join(base.to_s, name.to_s)}: #{e.message}"
|
34
|
+
end
|
21
35
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
begin
|
26
|
-
self.content = File.read(File.join(base.to_s, name.to_s), (site ? site.file_read_opts : {}).merge(opts))
|
27
|
-
if content =~ /\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m
|
28
|
-
self.content = $POSTMATCH
|
29
|
-
self.data = SafeYAML.load($1)
|
30
|
-
end
|
31
|
-
rescue SyntaxError => e
|
32
|
-
Jekyll.logger.warn "YAML Exception reading #{File.join(base.to_s, name.to_s)}: #{e.message}"
|
33
|
-
rescue Exception => e
|
34
|
-
Jekyll.logger.warn "Error reading file #{File.join(base.to_s, name.to_s)}: #{e.message}"
|
35
|
-
end
|
36
|
-
|
37
|
-
self.data ||= {}
|
38
|
-
end
|
39
|
-
end
|
36
|
+
self.data ||= {}
|
37
|
+
end
|
38
|
+
end
|
40
39
|
end
|
data/lib/lunr/Javascript.rb
CHANGED
@@ -8,11 +8,11 @@ require "v8"
|
|
8
8
|
require "json"
|
9
9
|
|
10
10
|
class V8::Object
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
def to_json
|
12
|
+
@context['JSON']['stringify'].call(self)
|
13
|
+
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
15
|
+
def to_hash
|
16
|
+
JSON.parse(to_json, :max_nesting => false)
|
17
|
+
end
|
18
|
+
end
|
data/lib/lunr/LunrIndexer.rb
CHANGED
@@ -15,7 +15,6 @@ require 'v8'
|
|
15
15
|
module Jekyll
|
16
16
|
module LunrJsSearch
|
17
17
|
class Indexer
|
18
|
-
|
19
18
|
# @param [Jekyll::Site] site
|
20
19
|
# @param [Array<App>] packages
|
21
20
|
# @return [Object]
|
@@ -44,11 +43,11 @@ module Jekyll
|
|
44
43
|
|
45
44
|
packages.each_with_index do |package, i|
|
46
45
|
doc = {
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
46
|
+
'id' => i,
|
47
|
+
'packageName' => package.package_name,
|
48
|
+
'icon' => package.icon,
|
49
|
+
'name' => package.name,
|
50
|
+
'summary' => package.summary
|
52
51
|
}
|
53
52
|
|
54
53
|
ctx['builder'].add(doc)
|
@@ -63,22 +62,23 @@ module Jekyll
|
|
63
62
|
filename = File.join(@js_dir, 'index.json')
|
64
63
|
|
65
64
|
total = {
|
66
|
-
|
67
|
-
|
65
|
+
"docs" => @docs,
|
66
|
+
"index" => @index.to_hash
|
68
67
|
}
|
69
68
|
|
70
69
|
filepath = File.join(site.dest, filename)
|
71
|
-
File.open(filepath, "w") {|f| f.write(JSON.dump(total))}
|
70
|
+
File.open(filepath, "w") { |f| f.write(JSON.dump(total)) }
|
72
71
|
Jekyll.logger.info "Lunr:", "Index ready (lunr.js v#{@lunr_version})"
|
73
72
|
added_files = [filename]
|
74
73
|
|
75
74
|
site_js = File.join(site.dest, @js_dir)
|
76
75
|
extras = [
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
76
|
+
'assets/fdroid-search-autocomplete.js',
|
77
|
+
'assets/fdroid-search-autocomplete-init.js',
|
78
|
+
'bower_components/lunr.js/lunr.js',
|
79
|
+
'bower_components/mustache.js/mustache.min.js',
|
80
|
+
'bower_components/awesomplete/awesomplete.min.js',
|
81
|
+
'bower_components/awesomplete/awesomplete.css'
|
82
82
|
]
|
83
83
|
Jekyll.logger.info "Lunr:", "Added required assets to #{@js_dir}"
|
84
84
|
extras.each do |path|
|
data/lib/lunr/SearchIndexFile.rb
CHANGED
@@ -5,12 +5,12 @@
|
|
5
5
|
#
|
6
6
|
|
7
7
|
module Jekyll
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
8
|
+
module LunrJsSearch
|
9
|
+
class SearchIndexFile < Jekyll::StaticFile
|
10
|
+
# Override write as the index.json index file has already been created
|
11
|
+
def write(dest)
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jekyll-fdroid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: '1.1'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nico Alt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jekyll-include-cache
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.50.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.50.0
|
97
111
|
description: Browse packages of a F-Droid repository.
|
98
112
|
email: nicoalt@posteo.org
|
99
113
|
executables: []
|
@@ -138,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
152
|
version: '0'
|
139
153
|
requirements: []
|
140
154
|
rubyforge_project:
|
141
|
-
rubygems_version: 2.
|
155
|
+
rubygems_version: 2.7.7
|
142
156
|
signing_key:
|
143
157
|
specification_version: 4
|
144
158
|
summary: F-Droid - Free and Open Source Android App Repository
|