zypper-upgraderepo 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,47 @@
1
+ # Zypper-Upgraderepo
2
+
3
+ Zypper-Upgraderepo helps to check and upgrade the repositories used in your system
4
+ without have to do it manually.
5
+
6
+ It can be used stand-alone or installed as _zypper_ plugin.
7
+
8
+ ## Installation
9
+
10
+ Install it as:
11
+
12
+ $ gem install zypper-upgraderepo
13
+
14
+ If you want to install it as zypper plugin watch the _zypper-upgraderepo-plugin_ project linked below.
15
+
16
+ ## Usage
17
+
18
+ To check the availability of the current repositories:
19
+
20
+ $ zypper-upgraderepo -c
21
+
22
+ To check the availability of the next version repositories:
23
+
24
+ $ zypper-upgraderepo -n
25
+
26
+ To upgrade the repositories to the next version:
27
+
28
+ $ sudo zypper-upgraderepo -u
29
+
30
+ ## Get help
31
+
32
+ Where to start:
33
+
34
+ $ zypper-upgraderepo --help
35
+
36
+ More Help:
37
+
38
+ - The wiki page: https://github.com/fabiomux/zypper-upgraderepo
39
+ - zypper-upgraderepo-plugin project: https://github.com/fabiomux/zypper-upgraderepo-plugin
40
+
41
+ ## Contributing
42
+
43
+ Bug reports and pull requests are welcome on GitHub at https://github.com/fabiomux/zypper-upgraderepo. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
44
+
45
+ ## Code of Conduct
46
+
47
+ Everyone interacting in the Zypper::Upgraderepo project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/fabiomux/zypper-upgraderepo/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "zypper/upgraderepo"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "zypper/upgraderepo/cli"
4
+
5
+ Zypper::Upgraderepo::CLI.start
@@ -0,0 +1,72 @@
1
+ require 'zypper/upgraderepo/repository'
2
+ require 'zypper/upgraderepo/os_release'
3
+ require 'zypper/upgraderepo/utils'
4
+
5
+
6
+ module Zypper
7
+ module Upgraderepo
8
+
9
+ class Builder
10
+ def initialize(options)
11
+ @os_release = OsRelease.new(options)
12
+ @repos = RepositoryList.new(options)
13
+ @print_hint = options.hint
14
+ end
15
+
16
+ def backup
17
+ @repos.backup
18
+ Messages.ok 'Repository backup executed!'
19
+ end
20
+
21
+ def check_current
22
+ check_repos(@os_release.current)
23
+ end
24
+
25
+ def check_next
26
+ @repos.upgrade(@os_release.next) unless @os_release.last?
27
+ check_repos(@os_release.next)
28
+ end
29
+
30
+ def check_to
31
+ @repos.upgrade(@os_release.custom)
32
+ check_repos(@os_release.custom)
33
+ end
34
+
35
+ def upgrade
36
+ @repos.upgrade(@os_release.next) unless @os_release.last?
37
+ @repos.save
38
+ Messages.ok 'Repositories upgraded!'
39
+ end
40
+
41
+ def upgrade_to
42
+ @repos.upgrade(@os_release.custom)
43
+ @repos.save
44
+ Messages.ok 'Repositories upgraded!'
45
+ end
46
+
47
+
48
+ private
49
+
50
+ def check_repos(version)
51
+ Messages.header(@repos.max_col)
52
+ @repos.list.each_with_index do |r, i|
53
+ Messages.separator
54
+ if r.available?
55
+ Messages.available i.next, r.name, r.url, @repos.max_col
56
+ elsif r.redirected?
57
+ Messages.redirect i.next, r.name, r.url, @repos.max_col, r.redirected_to
58
+ elsif r.not_found?
59
+ if @print_hint
60
+ Messages.alternative i.next, r.name, r.url, @repos.max_col, r.evaluate_alternative(version)
61
+ else
62
+ Messages.not_found i.next, r.name, r.url, @repos.max_col
63
+ end
64
+ end
65
+ end
66
+ Messages.footer
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,120 @@
1
+ require 'optparse'
2
+ require 'ostruct'
3
+ require 'zypper/upgraderepo'
4
+ require 'zypper/upgraderepo/version'
5
+
6
+ module Zypper
7
+
8
+ module Upgraderepo
9
+
10
+ class OptParseMain
11
+
12
+ def self.parse(args)
13
+ options = OpenStruct.new
14
+ options.operation = :check_current
15
+ options.backup_path = ENV['HOME']
16
+ options.only_enabled = true
17
+ options.alias = true
18
+ options.name = true
19
+ options.hint = true
20
+ options.overrides = {}
21
+ options.version = nil
22
+
23
+ OptionParser.new do |opt|
24
+
25
+ if ENV['ZYPPER_UPGRADEREPO']
26
+ opt.banner = 'Usage: zypper upgraderepo [OPTIONS] [OPERATION]'
27
+ else
28
+ opt.banner = 'Usage: zypper-upgraderepo [OPTIONS] [OPERATION]'
29
+ end
30
+
31
+ opt.separator ''
32
+ opt.separator 'Operations:'
33
+
34
+ opt.on('-b', '--backup <PATH>', 'Create a Tar backup of all the repositories under PATH') do |o|
35
+ options.operation = :backup
36
+ options.only_enabled = false
37
+ options.backup_path = o
38
+ end
39
+
40
+ opt.on('-c', '--check-current', 'Check the repositories for the current version (Default)') do |o|
41
+ options.operation = :check_current
42
+ end
43
+
44
+ opt.on('-N', '--check-next', 'Check the repositories for the next version') do |o|
45
+ options.operation = :check_next
46
+ end
47
+
48
+ opt.on('-C', '--check-to <VERSION>', 'Check for a custom VERSION') do |v|
49
+ options.version = v
50
+ options.operation = :check_to
51
+ end
52
+
53
+ opt.on('-u', '--upgrade', 'Upgrade to the last version available') do |o|
54
+ options.operation = :upgrade
55
+ end
56
+
57
+ opt.on('-U', '--upgrade-to <VERSION>', 'Upgrade to a specific VERSION') do |v|
58
+ options.version = v
59
+ options.operation = :upgrade_to
60
+ end
61
+
62
+ opt.separator ''
63
+ opt.separator 'Options:'
64
+
65
+ opt.on('--[no-]only-enabled', 'Include or not the disabled repositories') do |o|
66
+ options.only_enabled = o
67
+ end
68
+
69
+ opt.on('--[no-]name', 'Upgrade or not the name') do |o|
70
+ options.name = o
71
+ end
72
+
73
+ opt.on('--[no-]alias', 'Upgrade or not the alias') do |o|
74
+ options.alias = o
75
+ end
76
+
77
+ opt.on('--[no-]hint', 'Suggest a new url when the current is not found') do |o|
78
+ options.hint = o
79
+ end
80
+
81
+ opt.on('--override-url <NUMBER>,<URL>', Array, 'Overwrite the repository\'s url NUMBER with URL') do |r|
82
+ options.overrides[r[0]] = r[1]
83
+ end
84
+
85
+ unless ENV['ZYPPER_UPGRADEREPO']
86
+ opt.separator ''
87
+ opt.separator 'Other:'
88
+
89
+ opt.on_tail('-h', '--help', 'Show this message') do |o|
90
+ puts opt
91
+ exit
92
+ end
93
+
94
+ opt.on_tail('-v', '--version', 'Show version') do |o|
95
+ puts VERSION
96
+ exit
97
+ end
98
+ end
99
+
100
+ end.parse!(ARGV)
101
+
102
+ options
103
+ end
104
+
105
+ end
106
+
107
+
108
+ class CLI
109
+ def self.start
110
+ begin
111
+ options = OptParseMain.parse(ARGV)
112
+ Upgraderepo::Builder.new(options).send(options.operation)
113
+ rescue => e
114
+ Messages.error e
115
+ exit 1
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,67 @@
1
+ require 'iniparse'
2
+
3
+ module Zypper
4
+ module Upgraderepo
5
+
6
+
7
+ class OsRelease
8
+
9
+ attr_reader :custom
10
+
11
+ OS_VERSIONS = ['13.1', '13.2', '42.1', '42.2', '42.3', '15.0']
12
+
13
+
14
+ def initialize(options)
15
+ fname = if File.exist? '/etc/os-release'
16
+ '/etc/os-release'
17
+ elsif File.exist? '/etc/SuSE-release'
18
+ '/etc/SuSE-release'
19
+ else
20
+ raise ReleaseFileNotFound
21
+ end
22
+ @release = IniParse.parse(File.read(fname))
23
+ @current_idx = OS_VERSIONS.index(@release['__anonymous__']['VERSION'].delete('"'))
24
+
25
+ if options.version
26
+ raise InvalidVersion, options.version unless OS_VERSIONS.include?(options.version)
27
+ raise AlreadyUpgraded, options.version unless OS_VERSIONS.index(options.version) != @current_idx
28
+ @custom = options.version
29
+ end
30
+ end
31
+
32
+ def current
33
+ OS_VERSIONS[@current_idx]
34
+ end
35
+
36
+ def next
37
+ unless last?
38
+ OS_VERSIONS[@current_idx.next]
39
+ else
40
+ nil
41
+ end
42
+ end
43
+
44
+ def previous
45
+ unless first?
46
+ OS_VERSIONS[@current_idx.pred]
47
+ else
48
+ nil
49
+ end
50
+ end
51
+
52
+ def last?
53
+ @current_idx == (OS_VERSIONS.count - 1)
54
+ end
55
+
56
+ def first?
57
+ @current_idx == 0
58
+ end
59
+
60
+ def valid?(version)
61
+ OS_VERSIONS.include? version
62
+ end
63
+ end
64
+
65
+
66
+ end
67
+ end
@@ -0,0 +1,171 @@
1
+ require 'iniparse'
2
+ require 'net/http'
3
+ require 'zlib'
4
+ require 'minitar'
5
+
6
+ module Zypper
7
+ module Upgraderepo
8
+
9
+
10
+ class RepositoryList
11
+ attr_reader :list, :max_col
12
+
13
+ def initialize(options)
14
+ @alias = options.alias
15
+ @name = options.name
16
+ @overrides = options.overrides
17
+ @list = []
18
+ @backup_path = options.backup_path
19
+
20
+ Dir.glob('/etc/zypp/repos.d/*.repo').sort.each do |i|
21
+ r = Repository.new(i)
22
+ next if options.only_enabled && (!r.enabled?)
23
+ @list << r
24
+ end
25
+ @max_col = @list.max_by { |x| x.name.length }.name.length
26
+ end
27
+
28
+ def backup
29
+ filename = File.join(@backup_path, "repos-backup-#{Time.now.to_s.delete(': +-')[0..-5]}.tgz")
30
+ raise InvalidPermissions, filename unless File.writable? @backup_path
31
+ Minitar.pack('/etc/zypp/repos.d',
32
+ Zlib::GzipWriter.new(File.open(filename, 'wb')))
33
+ end
34
+
35
+ def upgrade(version)
36
+ @list.each_with_index do |repo, i|
37
+ if @overrides.has_key? i.next.to_s
38
+ repo.url = @overrides[i.next.to_s]
39
+ else
40
+ repo.url = repo.url.gsub(/\d\d\.\d/, version)
41
+ end
42
+ repo.alias = repo.alias.gsub(/\d\d\.\d/, version) if @alias
43
+ repo.name = repo.name.gsub(/\d\d\.\d/, version) if @name
44
+ end
45
+ end
46
+
47
+ def save
48
+ @list.each do |i|
49
+ i.save
50
+ end
51
+ end
52
+ end
53
+
54
+
55
+ class Repository
56
+ attr_reader :filename
57
+
58
+ def initialize(filename)
59
+ @filename = filename
60
+ @repo = IniParse.parse(File.read(filename))
61
+ @key = get_key
62
+ @res = nil
63
+ end
64
+
65
+ def enabled?
66
+ @repo[@key]['enabled'].to_i == 1
67
+ end
68
+
69
+ def type
70
+ @repo[@key]['type']
71
+ end
72
+
73
+ def name
74
+ @repo[@key]['name'] || @key
75
+ end
76
+
77
+ def name=(value)
78
+ @repo[@key]['name'] = value
79
+ end
80
+
81
+ def url
82
+ @repo[@key]['baseurl']
83
+ end
84
+
85
+ def url=(value)
86
+ @repo[@key]['baseurl'] = value
87
+ end
88
+
89
+ def alias
90
+ @key
91
+ end
92
+
93
+ def alias=(value)
94
+ @repo = IniParse.parse(@repo.to_ini.sub(/\[[^\]]+\]/, "[#{value}]"))
95
+ @key = get_key
96
+ end
97
+
98
+ def available?
99
+ ping.is_a?(Net::HTTPSuccess)
100
+ end
101
+
102
+ def redirected?
103
+ ping.is_a?(Net::HTTPRedirection)
104
+ end
105
+
106
+ def redirected_to
107
+ ping['location']
108
+ end
109
+
110
+ def not_found?
111
+ ping.is_a?(Net::HTTPNotFound)
112
+ end
113
+
114
+ def save
115
+ raise InvalidPermissions, @filename unless File.writable? @filename
116
+ @repo.save(@filename)
117
+ end
118
+
119
+ def evaluate_alternative(version)
120
+ if url =~ /dl\.google\.com/
121
+ return { url: '', message: 'Just Google security, use this repo anyway ;)'}
122
+ elsif not_found?
123
+ return traverse_url(URI(url.clone), version)
124
+ elsif redirected?
125
+ return { url: redirected_to, message: 'Redirected to:' }
126
+ end
127
+ end
128
+
129
+ private
130
+
131
+ def ping(uri = URI(url), force = false)
132
+ begin
133
+ @res = Net::HTTP.get_response(uri) if @res.nil? || force
134
+ rescue SocketError
135
+ raise NoConnection
136
+ end
137
+ @res
138
+ end
139
+
140
+ def get_key
141
+ @repo.to_hash.keys.delete_if {|k| k == '0'}.pop
142
+ end
143
+
144
+ def traverse_url(uri, version)
145
+ uri.path = File.dirname(uri.path)
146
+
147
+ return {url: '', message: 'None, try to find it manually'} if uri.path == '/'
148
+
149
+ uri.path += '/'
150
+ ping(uri, true)
151
+
152
+ if not_found?
153
+ return traverse_url(uri, version)
154
+ elsif available?
155
+ return {url: uri.to_s, message: 'Override with this one' } if uri.path =~ Regexp.new(version)
156
+
157
+ path = ping.body.to_s.scan(Regexp.new("href=\"[^\"]*#{version}[^\"]*\"")).uniq
158
+ unless path.empty?
159
+ uri.path += "#{path.pop.scan(/href="(.*)"/).pop.pop }"
160
+ return {url: uri.to_s, message: 'Override with this one' }
161
+ end
162
+
163
+ return {url: url, message: 'Can\'t find anything similar, try manually!' }
164
+ end
165
+
166
+ end
167
+ end
168
+
169
+
170
+ end
171
+ end