zypper-upgraderepo 1.0.1 → 1.4.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,200 @@
1
+ require 'delegate'
2
+ require 'net/http'
3
+
4
+ module Zypper
5
+ module Upgraderepo
6
+
7
+
8
+ class PageRequest < SimpleDelegator
9
+
10
+ attr_reader :page
11
+
12
+ USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0'
13
+
14
+ def initialize(obj, timeout = 60)
15
+ super obj
16
+ @timeout = timeout
17
+ end
18
+
19
+ def available?
20
+ ping.is_a?(Net::HTTPSuccess)
21
+ end
22
+
23
+ def redirected?
24
+ ping.is_a?(Net::HTTPRedirection)
25
+ end
26
+
27
+ def redirected_to
28
+ ping['location']
29
+ end
30
+
31
+ def not_found?
32
+ ping.is_a?(Net::HTTPNotFound)
33
+ end
34
+
35
+ def forbidden?
36
+ ping.is_a?(Net::HTTPForbidden)
37
+ end
38
+
39
+ def timeout?
40
+ ping.is_a?(Net::HTTPRequestTimeOut)
41
+ end
42
+
43
+ def status
44
+ ping.class.to_s
45
+ end
46
+
47
+ def cache!
48
+ @page = nil
49
+ end
50
+
51
+
52
+ private
53
+
54
+ def get_request(uri, head)
55
+ uri ||= repodata_uri
56
+
57
+ if head
58
+ request = Net::HTTP::Head.new(uri.request_uri)
59
+ else
60
+ request = Net::HTTP::Get.new(uri.request_uri)
61
+ end
62
+
63
+ request['User-Agent'] = USER_AGENT
64
+
65
+ http = Net::HTTP.new(uri.host, uri.port)
66
+ http.use_ssl = (uri.scheme == "https")
67
+ http.open_timeout = @timeout
68
+
69
+ http.request(request)
70
+ end
71
+
72
+ def ping(uri = nil, head = true)
73
+ begin
74
+ if @page.nil? || uri
75
+ @page = get_request(uri, head)
76
+ end
77
+ rescue SocketError
78
+ raise NoConnection
79
+ rescue Net::OpenTimeout
80
+ @page = Net::HTTPRequestTimeOut.new('1.1', '', '')
81
+ end
82
+ @page
83
+ end
84
+
85
+ end
86
+
87
+
88
+ class RepositoryRequest < PageRequest
89
+
90
+ def evaluate_alternative(version)
91
+
92
+ if not_found?
93
+ return traverse_url(URI(url), version)
94
+ elsif redirected?
95
+ return { url: redirected_to, message: 'Redirected to:' }
96
+ end
97
+ end
98
+
99
+
100
+ private
101
+
102
+ def traverse_url(uri, version)
103
+ ping(uri)
104
+
105
+ if forbidden?
106
+ res = { url: url, message: 'Can\'t navigate through the repository!' }
107
+ elsif available? && uri.to_s =~ /#{version}/
108
+ res = traverse_url_forward(uri, version)
109
+ else
110
+ res = traverse_url_backward(uri, version)
111
+ end
112
+
113
+ res || { url: '', message: 'Can\'t find a valid alternative, try manually!' }
114
+ end
115
+
116
+ def traverse_url_backward(uri, version)
117
+ uri.path = File.dirname(uri.path)
118
+
119
+ return nil if uri.path == '/' || uri.path == '.'
120
+
121
+ uri.path += '/' if uri.path[-1] != '/'
122
+ ping(uri, false)
123
+
124
+ if not_found?
125
+ return traverse_url_backward(uri, version)
126
+ elsif available?
127
+
128
+ if uri.path =~ /#{version}/ && repodata?
129
+ return {url: uri.to_s, message: 'Override with this one' }
130
+ elsif res = traverse_url_forward(uri, version, !(uri.path =~ /#{version}/))
131
+ return res
132
+ else
133
+ return traverse_url_backward(uri, version)
134
+ end
135
+
136
+ elsif forbidden?
137
+ return { url: uri.to_s, message: 'Try to replace with this one' } if repodata?(uri)
138
+
139
+ return traverse_url_backward(uri, version)
140
+ end
141
+
142
+ nil
143
+ end
144
+
145
+ def traverse_url_forward(uri, version, check_version = false)
146
+ uri.path += '/' if uri.path[-1] != '/'
147
+ ping(uri, false)
148
+
149
+ subfolders(version, check_version).each do |dir|
150
+ u = URI(uri.to_s)
151
+ u.path += dir
152
+
153
+ if repodata?(u)
154
+ return {url: u.to_s, message: 'Override with this one' }
155
+ else
156
+ res = traverse_url_forward(u, version)
157
+ return res if res.class == Hash
158
+ end
159
+ end
160
+
161
+ nil
162
+ end
163
+
164
+ def repodata_uri(uri = nil)
165
+ if uri
166
+ uri = URI(uri.to_s)
167
+ else
168
+ uri = URI(url)
169
+ end
170
+
171
+ uri.path = uri.path.gsub(/\/$/, '') + '/repodata/repomd.xml'
172
+
173
+ uri
174
+ end
175
+
176
+ def repodata?(uri = nil)
177
+ if uri.nil?
178
+ return ping.body.to_s.scan(Regexp.new("href=\"repodata/")).empty?
179
+ else
180
+ ping(repodata_uri(uri))
181
+ return available?
182
+ end
183
+ end
184
+
185
+ def subfolders(version, check_version)
186
+ res = ping.body.to_s.scan(Regexp.new('href=[\'\"][^\/\"]+\/[\'\"]')).delete_if do |x|
187
+ x =~ /^\// || x =~ /^\.\./ || x =~ /\:\/\// || x =~ /href=[\"\'](media\.1|boot|EFI)\/[\"\']/
188
+ end.uniq.map do |d|
189
+ d.scan(/href=[\"\']([^"]+)[\'\"]/).pop.pop
190
+ end
191
+
192
+ res = res.delete_if { |x| !(x =~ /#{version}/) } if check_version
193
+
194
+ res
195
+ end
196
+ end
197
+
198
+
199
+ end
200
+ end
@@ -25,12 +25,19 @@ module Zypper
25
25
  def new_line; "\n#{self}" end
26
26
  end
27
27
 
28
+ class ::StandardError
29
+ def error_code
30
+ 1
31
+ end
32
+ end
28
33
 
29
34
  class Messages
30
35
 
31
36
  def self.error(e)
32
37
  if e.class == String
33
38
  puts ' [E] '.bold.red + e
39
+ elsif e.class == Interruption
40
+ STDERR.puts e.message =~ /\(/ ? e.message.gsub(/.*\((.*)\).*/, '\1').green : e.message.green
34
41
  else
35
42
  STDERR.puts 'Error! '.bold.red + e.message
36
43
  end
@@ -44,59 +51,83 @@ module Zypper
44
51
  puts ' [W] '.bold.yellow + m
45
52
  end
46
53
 
47
- def self.available(num, name, url, max_col)
48
- Messages.ok("| #{num.to_s.rjust(2)} | #{name.ljust(max_col, ' ')} |")
54
+ end
55
+
56
+ class FileNotFound < StandardError
57
+ def initialize(filename)
58
+ super "The File #{filename} doesn't exist."
49
59
  end
60
+ end
50
61
 
51
- def self.redirected(num, name, url, max_col, redirected)
52
- Messages.warning("| #{num.to_s.rjust(2)} | #{name.ljust(max_col, ' ')} | Redirection of #{url} ")
53
- puts " #{' ' * 3} | #{' ' * 2} | #{ ' ' * max_col} | #{'To:'.bold.yellow} #{redirected}"
62
+ class ReleaseFileNotFound < StandardError
63
+ def initialize
64
+ super 'The release file is not found.'
54
65
  end
66
+ end
55
67
 
56
- def self.not_found(num, name, url, max_col)
57
- Messages.error("| #{num.to_s.rjust(2)} | #{name.ljust(max_col, ' ')}")
68
+ class InvalidVersion < StandardError
69
+ def initialize(version)
70
+ super "The version #{version} is not valid"
58
71
  end
72
+ end
59
73
 
60
- def self.alternative(num, name, url, max_col, res)
61
- Messages.error("| #{num.to_s.rjust(2)} | #{name.ljust(max_col, ' ')} | #{res[:message].bold.yellow}")
62
- puts " #{' ' * 3} | #{' ' * 2} | #{' ' * max_col} | #{res[:url]}" unless res[:url].to_s.empty?
74
+ class InvalidWritePermissions < StandardError
75
+ def initialize(filename)
76
+ super "Don't have the right permission to write #{filename}"
63
77
  end
64
78
 
65
- def self.separator
66
- puts '-' * 90
79
+ def error_code
80
+ 4
67
81
  end
82
+ end
68
83
 
69
- def self.header(max_col)
70
- puts " St. | # | #{'Name'.ljust(max_col, ' ')} | Hint"
84
+ class SystemUpdateRunning < StandardError
85
+ def initialize(args)
86
+ super "The application #{args[:process].bold} with pid #{args[:pid].bold} is running a system update!"
71
87
  end
72
88
 
73
- def self.footer
74
- self.separator
89
+ def error_code
90
+ 5
75
91
  end
76
92
  end
77
93
 
94
+ class UnableToUpgrade < StandardError
95
+ def initialize(args)
96
+ super "The repository n.#{args[:num].to_s.bold.red} named #{args[:repo].name.bold.red} can't be upgraded, a manual check is required!"
97
+ end
78
98
 
79
- class ReleaseFileNotFound < StandardError
80
- def initialize
81
- super 'The release file is not found.'
99
+ def error_code
100
+ 7
82
101
  end
83
102
  end
84
-
85
- class InvalidVersion < StandardError
86
- def initialize(version)
87
- super "The version #{version} is not valid"
103
+
104
+ class MissingOverride < StandardError
105
+ def initialize(args)
106
+ super "The repository n.#{args[:num].to_s.bold.red} named #{args[:ini]['name'].bold.red} doesn't contain the URL key!"
107
+ end
108
+
109
+ def error_code
110
+ 8
88
111
  end
89
112
  end
90
113
 
91
- class InvalidPermissions < StandardError
92
- def initialize(filename)
93
- super "Don't have the right permission to write #{filename}"
114
+ class UnmatchingOverrides < StandardError
115
+ def initialize(args)
116
+ super "The repository n.#{args[:num]} named #{args[:repo].name.bold.red} doesn't match with the repository named #{args[:ini]['name'].bold.red} in the ini file"
117
+ end
118
+
119
+ def error_code
120
+ 9
94
121
  end
95
122
  end
96
123
 
97
124
  class AlreadyUpgraded < StandardError
98
125
  def initialize(version)
99
- super "The system is already upgraded to #{version}"
126
+ super "The system is already upgraded to the #{version} version"
127
+ end
128
+
129
+ def error_code
130
+ 2
100
131
  end
101
132
  end
102
133
 
@@ -104,6 +135,20 @@ module Zypper
104
135
  def initialize
105
136
  super 'Internet connection has some trouble'
106
137
  end
138
+
139
+ def error_code
140
+ 6
141
+ end
142
+ end
143
+
144
+ class Interruption < StandardError
145
+ def initialize
146
+ super 'Ok ok... Exiting!'
147
+ end
107
148
  end
149
+
150
+ Signal.trap('INT') { raise Interruption }
151
+
152
+ Signal.trap('TERM') { raise Interruption }
108
153
  end
109
154
  end
@@ -1,5 +1,5 @@
1
1
  module Zypper
2
2
  module Upgraderepo
3
- VERSION = "1.0.1"
3
+ VERSION = "1.4.0"
4
4
  end
5
5
  end
@@ -0,0 +1,236 @@
1
+ module Zypper
2
+ module Upgraderepo
3
+
4
+ module View
5
+
6
+ class Report
7
+
8
+ def self.available(num, repo, max_col)
9
+ puts " #{num.to_s.rjust(2).bold.green} | Status: #{'Ok'.bold.green}"
10
+ self.info(repo)
11
+ end
12
+
13
+ def self.redirected(num, repo, max_col, redirected)
14
+ puts " #{num.to_s.rjust(2).bold.yellow} | Status: #{'Redirected'.bold.yellow}"
15
+ puts " #{' ' * 2} | #{'To:'.bold.yellow} #{redirected}"
16
+ self.info(repo)
17
+ end
18
+
19
+ def self.not_found(num, repo, max_col)
20
+ puts " #{num.to_s.rjust(2).bold.red} | Status: #{'Not Found'.bold.red}"
21
+ self.info(repo)
22
+ end
23
+
24
+ def self.alternative(num, repo, max_col, alt)
25
+ puts " #{num.to_s.rjust(2).bold.red} | Status: #{'Not Found'.bold.red}"
26
+ puts " #{' ' * 2} | Hint: #{alt[:message].bold.yellow}"
27
+ puts " #{' ' * 2} | #{'Suggested:'.bold.yellow} #{alt[:url]}" unless alt[:url].to_s.empty?
28
+ self.info(repo)
29
+ end
30
+
31
+ def self.timeout(num, repo, max_col)
32
+ puts " #{num.to_s.rjust(2).bold.yellow} | Status: #{'Server Timeout'.bold.yellow}"
33
+ self.info(repo)
34
+ end
35
+
36
+ def self.upgraded(num, repo, max_col)
37
+ puts " #{num.to_s.rjust(2).bold.green} | #{'Upgraded'.bold.green}"
38
+ self.info(repo)
39
+ end
40
+
41
+ def self.untouched(num, repo, max_col)
42
+ puts " #{num.to_s.rjust(2).bold.yellow} | #{'Untouched'.bold.yellow}"
43
+ self.info(repo)
44
+ end
45
+
46
+ def self.separator
47
+ puts '-' * 90
48
+ end
49
+
50
+ def self.header(max_col, upgrade = false)
51
+ puts " # | Report"
52
+ end
53
+
54
+ def self.footer
55
+ self.separator
56
+ end
57
+
58
+
59
+ private
60
+
61
+ def self.info(repo)
62
+ puts " #{ ' ' * 2 } | Name: #{repo.name} #{repo.upgraded?(:name) ? '(' + repo.old_name.yellow + ')' : '' }"
63
+ puts " #{ ' ' * 2 } | Alias: #{repo.alias} #{repo.upgraded?(:alias) ? '(' + repo.old_alias.yellow + ')' : ''}"
64
+ puts " #{ ' ' * 2 } | Url: #{repo.url}"
65
+ puts " #{ ' ' * 2 } | (#{repo.old_url.yellow})" if repo.upgraded?
66
+ puts " #{ ' ' * 2 } | Priority: #{repo.priority}"
67
+ puts " #{ ' ' * 2 } | #{repo.enabled? ? 'Enabled: Yes' : 'Enabled: No'.yellow}"
68
+ puts " #{ ' ' * 2 } | Filename: #{repo.filename}"
69
+ end
70
+ end
71
+
72
+
73
+ class Table
74
+
75
+ def self.available(num, repo, max_col)
76
+ Messages.ok("| #{num.to_s.rjust(2)} | #{repo.name.ljust(max_col, ' ')} | #{repo.enabled? ? ' Y ' : ' N '.yellow} |")
77
+ end
78
+
79
+ def self.redirected(num, repo, max_col, redirected)
80
+ Messages.warning("| #{num.to_s.rjust(2)} | #{repo.name.ljust(max_col, ' ')} | #{repo.enabled? ? ' Y ' : ' N '.yellow} | #{'Redirection'.bold.yellow} of #{repo.url} ")
81
+ puts " #{' ' * 3} | #{' ' * 2} | #{ ' ' * max_col} | #{ ' ' * 3 } | #{'To:'.bold.yellow} #{redirected}"
82
+ end
83
+
84
+ def self.not_found(num, repo, max_col)
85
+ Messages.error("| #{num.to_s.rjust(2)} | #{repo.name.ljust(max_col, ' ')} | #{repo.enabled? ? ' Y ' : ' N '.yellow} |")
86
+ end
87
+
88
+ def self.alternative(num, repo, max_col, alt)
89
+ Messages.error("| #{num.to_s.rjust(2)} | #{repo.name.ljust(max_col, ' ')} | #{repo.enabled? ? ' Y ' : ' N '.yellow} | #{alt[:message].bold.yellow}")
90
+ puts " #{' ' * 3} | #{' ' * 2} | #{' ' * max_col} | #{' ' * 3} | #{alt[:url]}" unless alt[:url].to_s.empty?
91
+ end
92
+
93
+ def self.timeout(num, repo, max_col)
94
+ Messages.error("| #{num.to_s.rjust(2)} | #{repo.name.ljust(max_col, ' ')} | #{repo.enabled? ? ' Y ' : ' N '.yellow} | #{'Server Timeout'.bold.yellow}")
95
+ end
96
+
97
+ def self.upgraded(num, repo, max_col) #, old_data)
98
+ Messages.ok("| #{num.to_s.rjust(2)} | #{repo.name.ljust(max_col, ' ')} | #{repo.enabled? ? ' Y ' : ' N '.yellow} | #{'From:'.bold.green} #{repo.old_url}")
99
+ puts " #{' ' * 3} | #{' ' * 2} | #{' ' * max_col} | #{' ' * 3} | #{'To:'.bold.green} #{repo.url}"
100
+ end
101
+
102
+ def self.untouched(num, repo, max_col)
103
+ Messages.warning("| #{num.to_s.rjust(2)} | #{repo.name.ljust(max_col, ' ')} | #{repo.enabled? ? ' Y ' : ' N '.yellow} | #{'Untouched:'.bold.yellow} #{repo.old_url}")
104
+ end
105
+
106
+ def self.separator
107
+ puts '-' * 90
108
+ end
109
+
110
+ def self.header(max_col, upgrade = false)
111
+ puts " St. | # | #{'Name'.ljust(max_col, ' ')} | En. | #{upgrade ? 'Details' : 'Hint' }"
112
+ end
113
+
114
+ def self.footer
115
+ self.separator
116
+ end
117
+ end
118
+
119
+
120
+ class Quiet
121
+
122
+ def self.available(num, repo, max_col)
123
+ end
124
+
125
+ def self.redirected(num, repo, max_col, redirected)
126
+ end
127
+
128
+ def self.not_found(num, repo, max_col)
129
+ end
130
+
131
+ def self.alternative(num, repo, max_col, alt)
132
+ end
133
+
134
+ def self.timeout(num, repo, max_col)
135
+ end
136
+
137
+ def self.upgraded(num, repo, max_col) #, old_data)
138
+ end
139
+
140
+ def self.untouched(num, repo, max_col)
141
+ end
142
+
143
+ def self.separator
144
+ end
145
+
146
+ def self.header(max_col, upgrade = false)
147
+ end
148
+
149
+ def self.footer
150
+ end
151
+
152
+ end
153
+
154
+
155
+ class Ini
156
+
157
+ def self.available(num, repo, max_col)
158
+ self.info num, 'Ok', repo
159
+ end
160
+
161
+ def self.redirected(num, repo, max_col, redirected)
162
+ self.info num, 'Redirected', repo, false
163
+ puts "redirected_to=#{redirected}"
164
+ end
165
+
166
+ def self.not_found(num, repo, max_col)
167
+ self.info num, 'Not Found', repo, false
168
+ end
169
+
170
+ def self.alternative(num, repo, max_col, alt)
171
+ self.info num, 'Not Found', repo, false
172
+ puts "hint=#{alt[:message]}"
173
+ puts "suggested_url=#{alt[:url]}" unless alt[:url].to_s.empty?
174
+ end
175
+
176
+ def self.timeout(num, repo, max_col)
177
+ self.info num, 'Server Timeout', repo, false
178
+ end
179
+
180
+ def self.upgraded(num, repo, max_col)
181
+ self.info num, 'Upgraded', repo
182
+ end
183
+
184
+ def self.untouched(num, repo, max_col)
185
+ self.info num, 'Untouched', repo
186
+ end
187
+
188
+ def self.separator
189
+ puts ''
190
+ end
191
+
192
+ def self.header(max_col, upgrade = false)
193
+ end
194
+
195
+ def self.footer
196
+ end
197
+
198
+
199
+ private
200
+
201
+ def self.info(num, status, repo, valid = true)
202
+ @@number = num
203
+ puts "[repository_#{num}]"
204
+ puts "name=#{repo.name}"
205
+ puts "alias=#{repo.alias}"
206
+ puts "old_url=#{repo.old_url}"
207
+ if valid
208
+ puts "url=#{repo.url}"
209
+ elsif repo.enabled?
210
+ puts <<-'HEADER'.gsub(/^ +/, '')
211
+ # The interpolated URL is invalid, try overriding with the one suggested
212
+ # in the fields below or find it manually starting from the old_url.
213
+ # The alternatives are:
214
+ # 1. Waiting for a repository upgrade;
215
+ # 2. Change the provider for the related installed packages;
216
+ # 3. Disable the repository putting the enabled status to 'No'.
217
+ #
218
+ url=
219
+ HEADER
220
+ else
221
+ puts <<-'HEADER'.gsub(/^ +/, '')
222
+ # The interpolated URL is invalid, but being the repository disabled you can
223
+ # keep the old_url in the field below, it will be ignored anyway during the
224
+ # normal update and upgrade process.
225
+ HEADER
226
+ puts "url=#{repo.old_url}"
227
+ end
228
+ puts "priority=#{repo.priority}"
229
+ puts "enabled=#{repo.enabled? ? 'Yes' : 'No'}"
230
+ puts "status=#{status}"
231
+ end
232
+ end
233
+
234
+ end
235
+ end
236
+ end