zypper-onlinesearch 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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