zypper-onlinesearch 1.0.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.
@@ -0,0 +1,130 @@
1
+ module Zypper
2
+ module Onlinesearch
3
+
4
+ class ::String
5
+ def black; "\033[30m#{self}\033[0m" end
6
+ def red; "\033[31m#{self}\033[0m" end
7
+ def green; "\033[32m#{self}\033[0m" end
8
+ def yellow; "\033[33m#{self}\033[0m" end
9
+ def blue; "\033[34m#{self}\033[0m" end
10
+ def magenta; "\033[35m#{self}\033[0m" end
11
+ def cyan; "\033[36m#{self}\033[0m" end
12
+ def gray; "\033[37m#{self}\033[0m" end
13
+ def bg_black; "\033[40m#{self}\0330m" end
14
+ def bg_red; "\033[41m#{self}\033[0m" end
15
+ def bg_green; "\033[42m#{self}\033[0m" end
16
+ def bg_brown; "\033[43m#{self}\033[0m" end
17
+ def bg_blue; "\033[44m#{self}\033[0m" end
18
+ def bg_magenta; "\033[45m#{self}\033[0m" end
19
+ def bg_cyan; "\033[46m#{self}\033[0m" end
20
+ def bg_gray; "\033[47m#{self}\033[0m" end
21
+ def bold; "\033[1m#{self}\033[22m" end
22
+ def reverse_color; "\033[7m#{self}\033[27m" end
23
+ def cr; "\r#{self}" end
24
+ def clean; "\e[K#{self}" end
25
+ def new_line; "\n#{self}" end
26
+ def none; self end
27
+ end
28
+
29
+ class ::Float
30
+ def to_human
31
+ conv = {
32
+ 1024=>'B',
33
+ 1024*1024=>'KB',
34
+ 1024*1024*1024=>'MB',
35
+ 1024*1024*1024*1024=>'GB',
36
+ 1024*1024*1024*1024*1024=>'TB',
37
+ 1024*1024*1024*1024*1024*1024=>'PB',
38
+ 1024*1024*1024*1024*1024*1024*1024=>'EB'
39
+ }
40
+ conv.keys.sort.each { |mult|
41
+ next if self >= mult
42
+ suffix=conv[mult]
43
+ return "%.2f %s" % [ self / (mult / 1024), suffix ]
44
+ }
45
+ end
46
+ end
47
+
48
+ class ::Array
49
+ def max_column(field)
50
+ self.max_by { |x| x[field].to_s.length }[field].to_s.length
51
+ end
52
+ end
53
+
54
+ class ::StandardError
55
+ def error_code
56
+ 1
57
+ end
58
+ end
59
+
60
+ class Messages
61
+
62
+ def self.error(e)
63
+ if e.class == String
64
+ puts ' [E] '.bold.red + e
65
+ else
66
+ STDERR.puts 'Error! '.bold.red + e.message
67
+ end
68
+ end
69
+ end
70
+
71
+ class QueryStringTooShort < StandardError
72
+ def initialize(query)
73
+ super "The query string '#{query}' is too short, be sure to use more than 3 characters."
74
+ end
75
+
76
+ def error_code
77
+ 2
78
+ end
79
+ end
80
+
81
+ class TooManyRedirections < StandardError
82
+ def initialize(url)
83
+ super "#{url} generates too many redirections!"
84
+ end
85
+ end
86
+
87
+ class InvalidEngine < StandardError
88
+ def initialize(engine)
89
+ super "#{engine} is not a valid engine!"
90
+ end
91
+
92
+ def error_code
93
+ 4
94
+ end
95
+ end
96
+
97
+ class MissingItemNumber < StandardError
98
+ def initialize
99
+ super 'No item number has been provided!'
100
+ end
101
+ end
102
+
103
+ class EmptyCache < StandardError
104
+ def initialize
105
+ super 'The cache folder is already empty!'
106
+ end
107
+ end
108
+
109
+ class NoConnection < StandardError
110
+ def initialize
111
+ super 'Internet connection has some trouble'
112
+ end
113
+
114
+ def error_code
115
+ 6
116
+ end
117
+ end
118
+
119
+ class Interruption < StandardError
120
+ def initialize
121
+ super 'Ok ok... Exiting!'
122
+ end
123
+ end
124
+
125
+ Signal.trap('INT') { raise Interruption }
126
+
127
+ Signal.trap('TERM') { raise Interruption }
128
+
129
+ end
130
+ end
@@ -0,0 +1,5 @@
1
+ module Zypper
2
+ module Onlinesearch
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,296 @@
1
+ module Zypper
2
+ module Onlinesearch
3
+
4
+ module View
5
+
6
+ TYPE_COLORS = { experimental: :yellow, supported: :green, community: :red }
7
+ SEPARATOR_LENGTH = 100
8
+
9
+
10
+ class CacheClean
11
+ def self.reset(size)
12
+ puts "Cache cleared! " + size.to_f.to_human.bold.red + ' freed.'
13
+ end
14
+ end
15
+
16
+
17
+ module Search
18
+
19
+ class Common
20
+
21
+ def self.separator
22
+ puts '-' * SEPARATOR_LENGTH
23
+ end
24
+
25
+ def self.no_packages
26
+ puts (' ' * 3) + ' - | No packages found!'
27
+ self.separator
28
+ end
29
+
30
+ def self.no_compatible_packages
31
+ puts (' ' * 3) + ' - | No compatible packages found!'
32
+ self.separator
33
+ end
34
+
35
+ def self.parameters(args)
36
+ puts ''
37
+ puts '=' * SEPARATOR_LENGTH
38
+ puts 'Parameters: '.bold + 'Engine: ' + args[:engine].to_s.bold.red + ' | ' +
39
+ 'Query: ' + args[:query].bold + ' | ' +
40
+ 'Cache: ' + (args[:cached] ? "#{'On'.bold.yellow} (#{args[:cache_time] ? args[:cache_time].strftime('%Y-%m-%d %H:%M') : 'Now'})" : 'Off'.bold)
41
+ puts '=' * SEPARATOR_LENGTH
42
+ end
43
+ end
44
+
45
+ class Report < Common
46
+
47
+ def self.header(args)
48
+ puts ' ' * 3 + ' # | Info '
49
+ self.separator
50
+ end
51
+
52
+ def self.package(args)
53
+ name = args[:name]
54
+ name = (name =~ / /) ? (name.split(' ').map.with_index { |x, i| x = x.bold if i == 0; x }.join ' ') : name.bold
55
+
56
+ puts "#{' ' * (5 - args[:num].to_s.length)}" + args[:num].to_s + ' | Page: ' + name
57
+ puts "#{' ' * 5}" + ' | Description: ' + args[:description].to_s
58
+ self.separator
59
+ end
60
+ end
61
+
62
+
63
+ class Table < Common
64
+
65
+ def self.header(args)
66
+ @@first_col = args[:first_col]
67
+ n_length = ( args[:first_col] - 4 ) / 2
68
+
69
+ puts (' ' * 4) + '#' +
70
+ ' | ' + (' ' * n_length) + 'Page' + (' ' * n_length) +
71
+ ' | Description '
72
+ self.separator
73
+ end
74
+
75
+ def self.package(args)
76
+ name = args[:name]
77
+ name = (name =~ / /) ? (name.split(' ').map.with_index { |x, i| x = x.bold if i == 0; x }.join ' ') : name.bold
78
+
79
+ puts (' ' * (5 - args[:num].to_s.length)) + args[:num].to_s +
80
+ ' | ' + name + (' ' * (@@first_col - args[:name].length)) +
81
+ ' | ' + args[:description]
82
+ self.separator
83
+ end
84
+
85
+ end
86
+
87
+ class Urls < Table
88
+
89
+ end
90
+
91
+ end
92
+
93
+
94
+ module Page
95
+
96
+ class Common
97
+
98
+ def self.separator
99
+ puts '-' * SEPARATOR_LENGTH
100
+ end
101
+
102
+ def self.general(args)
103
+ puts ''
104
+ puts '=' * SEPARATOR_LENGTH
105
+ puts 'Parameters: '.bold +
106
+ 'Engine: ' + args[:engine].bold.red + ' | ' +
107
+ 'OS: ' + args[:distro].bold.blue + ' | ' +
108
+ 'Architecture: ' + PageData::FORMATS[args[:architecture]].bold + ' | ' +
109
+ 'Cache: ' + (args[:refresh] ? 'Off'.bold : "#{'On'.bold.yellow} (#{args[:cache_time] ? args[:cache_time].strftime('%Y-%m-%d %H:%M') : args[:cache_time].strftime('%Y-%m-%d %H:%M')})")
110
+ puts '=' * SEPARATOR_LENGTH
111
+ puts 'Name: '.bold + args[:name]
112
+ puts 'Summary: '.bold + args[:short_description] if args[:short_description]
113
+ puts 'Description: '.bold + args[:description].chomp if args[:description]
114
+
115
+ end
116
+
117
+ def self.no_packages(compatible)
118
+ self.separator
119
+ puts (' ' * 3) + ' - | No ' + (compatible ? 'compatible ' : '' ) + 'packages found!'
120
+ self.separator
121
+ end
122
+
123
+ def self.no_item(num)
124
+ self.separator
125
+ puts (' ' * 3) + ' - | Invalid item number ' + num.to_s
126
+ end
127
+ end
128
+
129
+
130
+ class Table < Common
131
+
132
+ def self.header(args)
133
+ @@first_col = args[:first_col]
134
+ @@second_col = args[:second_col]
135
+ first_col = ((args[:first_col] - 4) / 2)
136
+ second_col = (args[:second_col] > 0) ? ((args[:second_col] - 6) / 2) : 0
137
+
138
+ self.separator
139
+ if second_col > 0
140
+ puts "#{' ' * 3} # | Version | #{' ' * first_col}Repo #{' ' * first_col} | #{' ' * second_col} Distro #{' ' * second_col}" # | Formats"
141
+ else
142
+ puts "#{' ' * 3} # | Version | #{' ' * first_col}Repo #{' ' * first_col}" # | Formats"
143
+ end
144
+ self.separator
145
+ end
146
+
147
+ def self.package(args)
148
+ r_length = @@first_col - args[:pack][:repo].to_s.length
149
+ n_length = args[:num].to_s.length
150
+ d_length = @@second_col > 0 ? @@second_col - args[:pack][:distro].to_s.length : 0
151
+
152
+ num = args[:num].to_s.bold.send(TYPE_COLORS[args[:pack][:type]])
153
+ repo = args[:pack][:repo].bold.send(TYPE_COLORS[args[:pack][:type]])
154
+ distro = (args[:args][:distro] == args[:pack][:distro] ? args[:pack][:distro].bold.blue : args[:pack][:distro])
155
+ version = args[:pack][:version].to_s[0..6]
156
+
157
+ if @@second_col > 0
158
+ puts (' ' * (5 - n_length)) + num +
159
+ ' | ' + (' ' * ( 7 - version.length )) + version +
160
+ ' | ' + repo.to_s + (' ' * r_length) +
161
+ ' | ' + distro + (' ' * d_length) # +
162
+ else
163
+ puts (' ' * (5 - n_length)) + num +
164
+ ' | ' + (' ' * ( 7 - version.length )) + version +
165
+ ' | ' + repo.to_s + (' ' * r_length) #+
166
+ end
167
+
168
+ self.separator
169
+ end
170
+
171
+ end
172
+
173
+
174
+ class Report < Common
175
+
176
+ def self.header(args)
177
+ @@second_col = args[:second_col]
178
+ self.separator
179
+ puts "#{' ' * 3} # | Info"
180
+ self.separator
181
+ end
182
+
183
+ def self.package(args)
184
+ n_length = args[:num].to_s.length
185
+
186
+ #p args
187
+ num = args[:num].to_s.bold.send(TYPE_COLORS[args[:pack][:type]])
188
+ repo = args[:pack][:repo].bold.send(TYPE_COLORS[args[:pack][:type]])
189
+ distro = (args[:args][:distro] == args[:pack][:distro] ? args[:pack][:distro].bold.blue : args[:pack][:distro])
190
+ version = args[:pack][:version].to_s
191
+
192
+ puts (' ' * (5 - n_length)) + num.to_s + ' | Version: ' + version
193
+ puts (' ' * 5) + ' | Repository: ' + repo
194
+ puts (' ' * 5) + ' | Distribution: ' + distro if @@second_col > 0
195
+ #puts (' ' * 5) + ' | Formats: ' + args[:formats].join(', ')
196
+ puts (' ' * 5) + ' | Type: ' + args[:pack][:type].to_s.capitalize.bold.send(TYPE_COLORS[args[:pack][:type]])
197
+ self.separator
198
+ end
199
+
200
+ end
201
+
202
+
203
+ class Urls < Table
204
+
205
+ end
206
+
207
+ end # Module Page
208
+
209
+
210
+ module Links
211
+
212
+ class Common < Page::Common
213
+
214
+ def self.info_package(args)
215
+ self.separator
216
+ puts 'Selected Item: '.bold +
217
+ 'Repository: ' + args[:repo].bold.send(TYPE_COLORS[args[:type]]) + ' | ' +
218
+ 'Distribution: ' + args[:distro].bold + ' | ' +
219
+ 'Version: ' + args[:version].bold
220
+ self.separator
221
+ end
222
+
223
+ def self.header(args)
224
+ @@first_col = args[:first_col]
225
+ end
226
+ end
227
+
228
+ class Table < Common
229
+
230
+ def self.header(args)
231
+ super args
232
+ self.separator
233
+ puts (' ' * 3) + ' # | Format | Link'
234
+ self.separator
235
+ end
236
+
237
+ def self.package(args)
238
+ end
239
+
240
+ def self.link(args)
241
+ #puts args,@@first_col
242
+ n_length = args[:num].to_s.length
243
+ puts (' ' * (5 - n_length)) + args[:num].to_s + ' | ' +
244
+ (' ' * (6 - args[:pack][:format].to_s.length)) + args[:pack][:format].to_s + ' | ' + args[:pack][:link]
245
+ self.separator
246
+ end
247
+ end
248
+
249
+ class Report < Common
250
+
251
+ def self.header(args)
252
+ self.separator
253
+ puts "#{' ' * 3} # | Links"
254
+ self.separator
255
+ end
256
+
257
+ def self.link(args)
258
+ alt_format = args[:pack][:format].to_s == PageData::FORMATS[args[:pack][:format]] ? '' : " (#{PageData::FORMATS[args[:pack][:format]]})"
259
+ n_length = args[:num].to_s.length
260
+ puts (' ' * (5 - n_length)) + args[:num].to_s + ' | Format: ' + args[:pack][:format].to_s.bold + alt_format
261
+ puts (' ' * 5) + ' | Distribution: ' + args[:pack][:distro]
262
+ puts (' ' * 5) + ' | Link: ' + args[:pack][:link]
263
+
264
+ self.separator
265
+ end
266
+ end
267
+
268
+ class Urls
269
+ def self.general(args)
270
+ end
271
+
272
+ def self.info_package(args)
273
+ end
274
+
275
+ def self.header(args)
276
+ end
277
+
278
+ def self.separator
279
+ end
280
+
281
+ def self.package(args)
282
+ end
283
+
284
+ def self.link(args)
285
+ puts args[:pack][:link]
286
+ end
287
+
288
+ def self.no_packages(args)
289
+ end
290
+ end
291
+
292
+ end # Module Links
293
+
294
+ end
295
+ end
296
+ end
@@ -0,0 +1,195 @@
1
+ require 'zypper/onlinesearch/cache'
2
+ require 'zypper/onlinesearch/request'
3
+ require 'zypper/onlinesearch/data'
4
+ require 'zypper/onlinesearch/release'
5
+ require 'zypper/onlinesearch/utils'
6
+ require 'zypper/onlinesearch/view'
7
+
8
+ module Zypper
9
+ module Onlinesearch
10
+
11
+ class Builder
12
+ def initialize(options)
13
+
14
+
15
+ if options.operation != :cache_clean
16
+ @search = RequestList.new operation: options.operation == :links ? :page : options.operation,
17
+ engine: options.engine,
18
+ timeout: options.timeout,
19
+ refresh: options.refresh,
20
+ query: options.query
21
+
22
+ @release = Release.new
23
+ @formats = options.formats
24
+ @distributions = options.distributions
25
+
26
+ @format = options.format
27
+ @types = options.types
28
+ @num = options.number
29
+
30
+ @view_class = Zypper::Onlinesearch::View.const_get options.operation.to_s.split('_').map(&:capitalize).join
31
+ @view_class = @view_class.const_get options.view.to_s.capitalize
32
+ end
33
+ end
34
+
35
+ def search
36
+ raise QueryStringTooShort, @search.query if @search.query.length < 3
37
+ @search.engines.each do |k, v|
38
+
39
+ @view_class.parameters engine: k,
40
+ cached: !@search.refresh,
41
+ query: @search.query,
42
+ cache_time: v.cache_time
43
+
44
+ if v.available?
45
+ data = v.to_data
46
+
47
+ if data.empty?
48
+ @view_class.no_packages if data.empty?
49
+ else
50
+ @view_class.header first_col: data.max_column(:name)
51
+
52
+ data.each_with_index do |i, idx|
53
+ next if @num > 0 && idx.next != @num
54
+
55
+ @view_class.package num: idx.next,
56
+ name: i[:name],
57
+ description: i[:description],
58
+ url: i[:url]
59
+
60
+ end
61
+ end
62
+ else
63
+ @view_class.no_packages
64
+ end
65
+ end
66
+ end
67
+
68
+ def page
69
+ @search.engines.each do |engine, x|
70
+ packages = []
71
+ next unless x.available?
72
+ data = x.to_data
73
+ versions = data[:versions].select { |y| package_select?(y) }
74
+ .group_by { |v| v[:repo] + '#' + v[:distro] + '#' + v[:version] }
75
+
76
+ versions.each.each_with_index do |collection, idx|
77
+ collection = collection.pop
78
+ packages << collection.pop
79
+ end
80
+
81
+ print_packages(data, packages, first_col: :repo, second_col: :distro, view: :package,
82
+ engine: engine, distro: @release.pretty_name, cache_time: x.cache_time)
83
+ end
84
+ end
85
+
86
+
87
+ def links
88
+ raise MissingItemNumber unless @num > 0
89
+ @search.engines.each do |engine, x|
90
+ packages = []
91
+ next unless x.available?
92
+ data = x.to_data
93
+
94
+ versions = data[:versions].select { |y| package_select?(y) }
95
+ .group_by { |v| v[:repo] + '#' + v[:distro] + '#' + v[:version] }
96
+
97
+ versions.each.each_with_index do |collection, idx|
98
+ next if idx.next != @num
99
+ collection = collection.pop
100
+ collection.each do |pack|
101
+ unless (pack[:link] =~ /rpm$/) || (pack[:format] == :ymp)
102
+
103
+ result = RequestList.new operation: :links,
104
+ engine: engine,
105
+ timeout: @search.timeout,
106
+ refresh: @search.refresh,
107
+ query: pack[:link]
108
+
109
+ result.engines.each do |k, v|
110
+ if v.available?
111
+ v.to_data[:versions].each_with_index do |f, i|
112
+ f[:type] = pack[:type]
113
+ f[:repo] = pack[:repo]
114
+ f[:version] ||= pack[:version]
115
+ f[:distro] ||= pack[:distro]
116
+ #puts f
117
+ packages << f if package_select?(f)
118
+ end
119
+ end
120
+ end
121
+ else
122
+ packages << pack
123
+ end
124
+ end
125
+ end
126
+ print_packages(data, packages, first_col: :format, second_col: :link,
127
+ view: :link, engine: engine, cache_time: x.cache_time)
128
+ end
129
+ end
130
+
131
+ def cache_clean
132
+ View::CacheClean.reset Cache.reset!
133
+ end
134
+
135
+
136
+ private
137
+
138
+ def print_packages(data, packages, args)
139
+
140
+ @view_class.general name: data[:name] || @search.query,
141
+ short_description: data[:short_description] || '',
142
+ description: data[:description] || '',
143
+ engine: args[:engine],
144
+ distro: (@distributions == :compatible) ? @release.pretty_name : 'All',
145
+ architecture: architecture,
146
+ refresh: @search.refresh,
147
+ cache_time: args[:cache_time]
148
+
149
+ if packages.count > 0
150
+
151
+ @view_class.header first_col: packages.max_column(args[:first_col]),
152
+ second_col: packages.max_column(args[:second_col])
153
+
154
+ packages.each.each_with_index do |pack, idx|
155
+ @view_class.send args[:view], { num: idx.next,
156
+ pack: pack,
157
+ args: args }
158
+ end
159
+ else
160
+ @view_class.no_packages(!data[:versions].empty?)
161
+ end
162
+ end
163
+
164
+ def pretty_name
165
+ (@distributions == :compatible) ? @release.pretty_name : 'All'
166
+ end
167
+
168
+ def architecture
169
+ (@formats == :compatible) ? @release.arch : :all
170
+ end
171
+
172
+ def package_select?(package)
173
+ res = true
174
+
175
+ if (@formats == :compatible)
176
+ res = ([:ymp, :src, :extra, @release.arch].include?(package[:format]))
177
+ end
178
+
179
+ unless (@format == :all)
180
+ res = res && (@format == package[:format])
181
+ end
182
+
183
+ if (@distributions == :compatible)
184
+ res = res && ((:current == package[:distro]) || package[:distro].match?(Regexp.new(@release.pretty_name, 'i')))
185
+ end
186
+
187
+ res = false unless @types.include?(package[:type])
188
+
189
+ res
190
+ end
191
+
192
+ end
193
+
194
+ end
195
+ end
@@ -0,0 +1,40 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'zypper/onlinesearch/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "zypper-onlinesearch"
7
+ spec.version = Zypper::Onlinesearch::VERSION
8
+ spec.authors = ["Fabio Mucciante"]
9
+ spec.email = ["fabio.mucciante@gmail.com"]
10
+
11
+ spec.summary = %q{Zypper addon to search packages online through the openSUSE software search website.}
12
+ spec.description = %q{This is just a complement to zypper command which search for packages through the online openSUSE software search website.}
13
+ spec.homepage = "https://github.com/fabiomux/zypper-onlinesearch"
14
+ spec.license = 'GPL-3.0'
15
+
16
+ spec.metadata = {
17
+ "bug_tracker_uri" => 'https://github.com/fabiomux/zypper-onlinesearch/issues',
18
+ "changelog_uri" => 'https://freeaptitude.altervista.org/projects/zypper-onlinesearch.html#changelog',
19
+ "documentation_uri" => "https://www.rubydoc.info/gems/zypper-onlinesearch/#{spec.version}",
20
+ "homepage_uri" => 'https://freeaptitude.altervista.org/projects/zypper-onlinesearch.html',
21
+ #"mailing_list_uri" => "",
22
+ "source_code_uri" => 'https://github.com/fabiomux/zypper-onlinesearch',
23
+ "wiki_uri" => 'https://github.com/fabiomux/zypper-onlinesearch/wiki'
24
+ }
25
+ # Specify which files should be added to the gem when it is released.
26
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
27
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
28
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|.github|.gitignore)/}) }
29
+ end
30
+ spec.bindir = "exe"
31
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ spec.add_development_dependency "bundler", "~> 2.0"
35
+ spec.add_development_dependency "rake", "~> 12.0"
36
+ spec.add_development_dependency "rspec", "~> 3.0"
37
+
38
+ spec.add_runtime_dependency "nokogiri"
39
+ spec.add_runtime_dependency "iniparse"
40
+ end