zypper-upgraderepo 1.0.2 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
1
+ require 'delegate'
2
+ require_relative 'traversable.rb'
3
+ require_relative 'requests/local.rb'
4
+ require_relative 'requests/http.rb'
5
+
6
+ module Zypper
7
+ module Upgraderepo
8
+
9
+
10
+ class Request
11
+
12
+ def self.build(repo, timeout)
13
+ @@registry ||= self.load_requests
14
+
15
+ raise InvalidProtocol, repo unless @@registry.include? repo.protocol
16
+
17
+ Object.const_get(@@registry[repo.protocol]).new(repo, timeout)
18
+ end
19
+
20
+ def self.protocols
21
+ self.load_requests.keys
22
+ end
23
+
24
+ private
25
+
26
+ def self.load_requests
27
+ res = {}
28
+ Requests.constants.each do |klass|
29
+ Object.const_get("Zypper::Upgraderepo::Requests::#{klass}").register_protocol.each do |protocol|
30
+ res[protocol] = "Zypper::Upgraderepo::Requests::#{klass}"
31
+ end
32
+ end
33
+
34
+ res
35
+ end
36
+
37
+ end
38
+
39
+
40
+
41
+ end
42
+ end
@@ -0,0 +1,131 @@
1
+ require 'delegate'
2
+ require 'net/http'
3
+
4
+ module Zypper
5
+ module Upgraderepo
6
+
7
+ class PageRequest < SimpleDelegator
8
+
9
+ attr_reader :page
10
+
11
+ USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0'
12
+
13
+ def initialize(obj, timeout = 60)
14
+ super obj
15
+ @timeout = timeout
16
+ end
17
+
18
+ def available?
19
+ ping.is_a?(Net::HTTPSuccess)
20
+ end
21
+
22
+ def redirected?
23
+ ping.is_a?(Net::HTTPRedirection)
24
+ end
25
+
26
+ def redirected_to
27
+ ping['location']
28
+ end
29
+
30
+ def not_found?
31
+ ping.is_a?(Net::HTTPNotFound)
32
+ end
33
+
34
+ def forbidden?
35
+ ping.is_a?(Net::HTTPForbidden)
36
+ end
37
+
38
+ def timeout?
39
+ ping.is_a?(Net::HTTPRequestTimeOut)
40
+ end
41
+
42
+ def status
43
+ ping.class.to_s
44
+ end
45
+
46
+ def cache!
47
+ @page = nil
48
+ end
49
+
50
+
51
+ private
52
+
53
+ def get_request(uri, head)
54
+
55
+ if head
56
+ request = Net::HTTP::Head.new(uri.request_uri)
57
+ else
58
+ request = Net::HTTP::Get.new(uri.request_uri)
59
+ end
60
+
61
+ request['User-Agent'] = USER_AGENT
62
+
63
+ http = Net::HTTP.new(uri.host, uri.port)
64
+ http.use_ssl = (uri.scheme == 'https')
65
+ http.open_timeout = @timeout
66
+
67
+ http.request(request)
68
+ end
69
+
70
+ def ping(uri = nil, head = true)
71
+ begin
72
+ if @page.nil? || uri
73
+ @page = get_request(uri, head)
74
+ end
75
+ rescue SocketError
76
+ raise NoConnection
77
+ rescue Net::OpenTimeout
78
+ @page = Net::HTTPRequestTimeOut.new('1.1', '', '')
79
+ end
80
+ @page
81
+ end
82
+
83
+ end
84
+
85
+
86
+ module Requests
87
+
88
+ class HttpRequest < PageRequest
89
+
90
+ include Traversable
91
+
92
+ def max_drop_back; 0; end
93
+
94
+ def self.register_protocol; ['https', 'http'] end
95
+
96
+ def evaluate_alternative(version)
97
+ if not_found?
98
+ return traverse_url(URI(url), version)
99
+ elsif redirected?
100
+ return { url: redirected_to, message: 'Redirected to:' }
101
+ end
102
+ end
103
+
104
+
105
+ private
106
+
107
+ def get_request(uri, head)
108
+ #super uri || URI(url), head
109
+ super uri || repodata_uri, head
110
+ end
111
+
112
+ def has_repodata?(uri)
113
+ ping(repodata_uri(uri))
114
+ available?
115
+ end
116
+
117
+ def subfolders
118
+ res = ping.body.to_s.scan(Regexp.new('href=[\'\"][^\/\"]+\/[\'\"]')).delete_if do |x|
119
+ x =~ /^\// || x =~ /^\.\./ || x =~ /\:\/\// || x =~ /href=[\"\'](media\.1|boot|EFI)\/[\"\']/
120
+ end.uniq.map do |d|
121
+ d.scan(/href=[\"\']([^"]+)[\'\"]/).pop.pop
122
+ end
123
+
124
+ res
125
+ end
126
+ end
127
+
128
+ end
129
+
130
+ end
131
+ end
@@ -0,0 +1,94 @@
1
+ require 'delegate'
2
+
3
+ module Zypper
4
+ module Upgraderepo
5
+
6
+
7
+ class DirRequest < SimpleDelegator
8
+
9
+ attr_reader :dir_path
10
+
11
+ def initialize(obj, timeout)
12
+ super obj
13
+ end
14
+
15
+ def available?
16
+ Dir.exist? ping
17
+ end
18
+
19
+ def redirected?
20
+ File.symlink? ping
21
+ end
22
+
23
+ def redirected_to
24
+ File.realpath ping
25
+ end
26
+
27
+ def not_found?
28
+ !available?
29
+ end
30
+
31
+ def forbidden?
32
+ File.readable? ping
33
+ end
34
+
35
+ def timeout?
36
+ false
37
+ end
38
+
39
+ def status
40
+ File.stat ping
41
+ end
42
+
43
+ def cache!
44
+ @dir_path = nil
45
+ end
46
+
47
+
48
+ private
49
+
50
+ def ping(uri = nil, head = true)
51
+ @dir_path ||= URI(url).path
52
+
53
+ @dir_path = uri.to_s =~ /^\// ? uri.to_s : URI(uri.to_s).path if uri
54
+
55
+ URI.unescape(@dir_path)
56
+ end
57
+
58
+ end
59
+
60
+
61
+ module Requests
62
+
63
+ class LocalRequest < DirRequest
64
+
65
+ include Traversable
66
+
67
+ def max_drop_back; 1 end
68
+
69
+ def self.register_protocol; ['dir'] end
70
+
71
+ def evaluate_alternative(version)
72
+ if not_found?
73
+ return traverse_url(URI(url), version)
74
+ elsif redirected?
75
+ return { url: redirected_to, message: 'Linked to' }
76
+ end
77
+ end
78
+
79
+
80
+ private
81
+
82
+ def has_repodata?(uri)
83
+ File.exist? URI.unescape(repodata_uri(uri).path)
84
+ end
85
+
86
+ def subfolders
87
+ Dir.glob(ping.gsub(/\/$/, '') + '/*/').map { |x| URI.escape(x.gsub(/\/$/, '').gsub(ping, '').gsub(/^\//, '')) }
88
+ end
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+ end
@@ -0,0 +1,93 @@
1
+ module Zypper
2
+ module Upgraderepo
3
+
4
+ module Traversable
5
+
6
+ def traverse_url(uri, version)
7
+ ping(uri)
8
+
9
+ if forbidden?
10
+ res = { url: url, message: 'Can\'t navigate through the repository!' }
11
+ elsif available? && uri.to_s =~ /#{version}/
12
+ res = traverse_url_forward(uri, version)
13
+ else
14
+ res = traverse_url_backward(uri, version)
15
+ end
16
+
17
+ res || { url: '', message: 'Can\'t find a valid alternative, try manually!' }
18
+ end
19
+
20
+
21
+ private
22
+
23
+ def traverse_url_backward(uri, version)
24
+ uri.path = File.dirname(uri.path)
25
+
26
+ return nil if uri.path == '/' || uri.path == '.' || (versioned? && (drop_back_level(uri) > max_drop_back))
27
+
28
+ uri.path += '/' if uri.path[-1] != '/'
29
+ ping(uri, false)
30
+
31
+ if not_found?
32
+ return traverse_url_backward(uri, version)
33
+ elsif available?
34
+ if res = traverse_url_forward(uri, version)
35
+ return res
36
+ else
37
+ return traverse_url_backward(uri, version)
38
+ end
39
+ elsif forbidden?
40
+ return { url: uri.to_s, message: 'Try to replace with this one' } if has_repodata?(uri)
41
+
42
+ return traverse_url_backward(uri, version)
43
+ end
44
+
45
+ nil
46
+ end
47
+
48
+ def traverse_url_forward(uri, version)
49
+ uri.path += '/' if uri.path[-1] != '/'
50
+ ping(uri, false)
51
+
52
+ subfolders.each do |dir|
53
+ u = URI(uri.to_s)
54
+ u.path += dir
55
+
56
+ if has_repodata?(u)
57
+ if (versioned?) && (u.to_s =~ /#{version}/)
58
+ return { url: u.to_s, message: 'Override with this one' }
59
+ end
60
+ else
61
+ res = traverse_url_forward(u, version)
62
+ return res if res.class == Hash
63
+ end
64
+ end
65
+
66
+ nil
67
+ end
68
+
69
+ def repodata_uri(uri = nil)
70
+ if uri
71
+ uri = URI(uri.to_s)
72
+ else
73
+ uri = URI(url)
74
+ end
75
+
76
+ uri.path = uri.path.gsub(/\/$/, '') + '/repodata/repomd.xml'
77
+
78
+ uri
79
+ end
80
+
81
+ def drop_back_level(uri)
82
+ URI(url).path.split('/').index { |x| x =~ /\d\d.\d/ } - uri.path.split('/').count
83
+ end
84
+
85
+ # to implement on each repository type class
86
+ #
87
+ # def has_repodata?(uri)
88
+ #
89
+ # def subfolders
90
+
91
+ end
92
+ end
93
+ 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,89 @@ 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."
59
+ end
60
+ end
61
+
62
+ class ReleaseFileNotFound < StandardError
63
+ def initialize
64
+ super 'The release file is not found.'
49
65
  end
66
+ end
50
67
 
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}"
68
+ class InvalidProtocol < StandardError
69
+ def initialize(repo)
70
+ super "The repository #{repo.name} has an unknown protocol: #{repo.protocol}; disable it to continue."
54
71
  end
72
+ end
55
73
 
56
- def self.not_found(num, name, url, max_col)
57
- Messages.error("| #{num.to_s.rjust(2)} | #{name.ljust(max_col, ' ')}")
74
+ class InvalidVersion < StandardError
75
+ def initialize(version)
76
+ super "The version #{version} is not valid"
58
77
  end
78
+ end
59
79
 
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?
80
+ class InvalidWritePermissions < StandardError
81
+ def initialize(filename)
82
+ super "Don't have the right permission to write #{filename}"
63
83
  end
64
84
 
65
- def self.separator
66
- puts '-' * 90
85
+ def error_code
86
+ 4
67
87
  end
88
+ end
68
89
 
69
- def self.header(max_col)
70
- puts " St. | # | #{'Name'.ljust(max_col, ' ')} | Hint"
90
+ class SystemUpdateRunning < StandardError
91
+ def initialize(args)
92
+ super "The application #{args[:process].bold} with pid #{args[:pid].bold} is running a system update!"
71
93
  end
72
94
 
73
- def self.footer
74
- self.separator
95
+ def error_code
96
+ 5
75
97
  end
76
98
  end
77
99
 
100
+ class UnableToUpgrade < StandardError
101
+ def initialize(args)
102
+ 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!"
103
+ end
78
104
 
79
- class ReleaseFileNotFound < StandardError
80
- def initialize
81
- super 'The release file is not found.'
105
+ def error_code
106
+ 7
82
107
  end
83
108
  end
84
-
85
- class InvalidVersion < StandardError
86
- def initialize(version)
87
- super "The version #{version} is not valid"
109
+
110
+ class MissingOverride < StandardError
111
+ def initialize(args)
112
+ super "The repository n.#{args[:num].to_s.bold.red} named #{args[:ini]['name'].bold.red} doesn't contain the URL key!"
113
+ end
114
+
115
+ def error_code
116
+ 8
88
117
  end
89
118
  end
90
119
 
91
- class InvalidPermissions < StandardError
92
- def initialize(filename)
93
- super "Don't have the right permission to write #{filename}"
120
+ class UnmatchingOverrides < StandardError
121
+ def initialize(args)
122
+ 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"
123
+ end
124
+
125
+ def error_code
126
+ 9
94
127
  end
95
128
  end
96
129
 
97
130
  class AlreadyUpgraded < StandardError
98
131
  def initialize(version)
99
- super "The system is already upgraded to #{version}"
132
+ super "The system is already upgraded to the #{version} version"
133
+ end
134
+
135
+ def error_code
136
+ 2
100
137
  end
101
138
  end
102
139
 
@@ -104,6 +141,20 @@ module Zypper
104
141
  def initialize
105
142
  super 'Internet connection has some trouble'
106
143
  end
144
+
145
+ def error_code
146
+ 6
147
+ end
107
148
  end
149
+
150
+ class Interruption < StandardError
151
+ def initialize
152
+ super 'Ok ok... Exiting!'
153
+ end
154
+ end
155
+
156
+ Signal.trap('INT') { raise Interruption }
157
+
158
+ Signal.trap('TERM') { raise Interruption }
108
159
  end
109
160
  end