- more ruby code, better array handling in solv.i
[platform/upstream/libsolv.git] / examples / rbsolv
1 #!/usr/bin/ruby
2
3 #  bool: method?
4 #  inplace mod: method!
5 #  set method: method=
6
7 # map  => collect
8 # grep => find_all
9
10 require 'solv'
11 require 'rubygems'
12 require 'inifile'
13
14 class Repo_generic
15   def initialize(name, type, attribs = {})
16     @name = name
17     @type = type
18     @attribs = attribs.dup
19   end
20
21   def enabled?
22     return @attribs['enabled'].to_i != 0
23   end
24
25   def autorefresh?
26     return @attribs['autorefresh'].to_i != 0
27   end
28
29   def calc_cookie_fp(f)
30     chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
31     chksum.add_fp(f)
32     return chksum.raw
33   end
34
35   def calc_cookie_file(filename)
36     chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
37     chksum.add("1.1")
38     chksum.add_stat(filename)
39     return chksum.raw
40   end
41
42   def cachepath(ext = nil)
43     path = @name.sub(/^\./, '_')
44     path += ext ? "_#{ext}.solvx" : '.solv'
45     return '/var/cache/solv/' + path.gsub(/\//, '_')
46   end
47
48   def load(pool)
49     @handle = pool.add_repo(@name)
50     @handle.appdata = self
51     @handle.priority = 99 - @attribs['priority'] if @attribs['priority']
52     dorefresh = autorefresh?
53     if dorefresh
54       begin
55         s = File.stat(cachepath)
56         dorefresh = false if s && Time.now - s.mtime < @attribs['metadata_expire']
57       rescue SystemCallError
58       end
59     end
60     @cookie = nil
61     if !dorefresh && usecachedrepo()
62       puts "repo: '#{@name}' cached"
63       return true
64     end
65     return load_if_changed()
66   end
67
68   def load_ext
69     return false
70   end
71
72   def load_if_changed
73     return false
74   end
75
76   def download(file, uncompress, chksum, markincomplete = false)
77     return nil
78   end
79
80   def usecachedrepo(ext, mark = false)
81     cookie = ext ? @extcookie : @cookie
82     begin
83       repopath = cachepath(ext)
84       @handle.add_solv(repopath)
85     rescue
86       return false
87     end
88     return true
89   end
90
91   def genextcookie(f)
92   end
93
94   def writecachedrepo(ext, info = nil)
95   end
96
97 end
98
99 class Repo_rpmmd < Repo_generic
100
101   def load_if_changed
102     print "rpmmd repo '#{@attribs['alias']}: "
103     f = download("repodata/repomd.xml", false, nil, nil)
104     if !f
105       puts "no repomd.xml file, skipped"
106       @handle.free(true)
107       @handle = nil
108       return false
109     end
110     @cookie = calc_cookie_fp(f)
111     if usecachedrepo(nil, true)
112       puts "cached"
113       Solv.xfclose(f)
114       return true
115     end
116     return false
117   end
118
119 end
120
121 class Repo_susetags < Repo_generic
122
123   def load_if_changed
124     print "susetags repo '#{@attribs['alias']}: "
125     f = download("content", false, nil, nil)
126     if !f
127       puts "no content file, skipped"
128       @handle.free(true)
129       @handle = nil
130       return false
131     end
132     @cookie = calc_cookie_fp(f)
133     if usecachedrepo(nil, true)
134       puts "cached"
135       Solv.xfclose(f)
136       return true
137     end
138     return false
139   end
140
141 end
142
143 class Repo_unknown < Repo_generic
144   def load(pool)
145     puts "unsupported repo '#{@attribs['alias']}: skipped"
146     return false
147   end
148 end
149
150 class Repo_system < Repo_generic
151   def load(pool)
152     @handle = pool.add_repo(@name)
153     @handle.appdata = self
154     pool.installed = @handle
155     print "rpm database: "
156     @cookie = calc_cookie_file("/var/lib/rpm/Packages")
157     if usecachedrepo(nil)
158       puts "cached"
159       return true
160     end
161     puts "reading"
162     @handle.add_products("/etc/products.d", Solv::Repo::REPO_NO_INTERNALIZE)
163     @handle.add_rpmdb(nil, Solv::Repo::REPO_REUSE_REPODATA)
164     writecachedrepo(nil)
165     return true
166   end
167 end
168
169 def depglob(pool, name, globname, globdep)
170   id = pool.str2id(name, false)
171   if id != 0
172     match = false
173     providers = pool.providers(id)
174     if globname && providers.find {|s| s.nameid == id }
175       return [ pool.Job(Solv::Job::SOLVER_SOLVABLE_NAME, id) ]
176     end
177     if !providers.empty?
178       puts "[using capability match for '#{name}']" if globname && globdep
179       return [ pool.Job(Solv::Job::SOLVER_SOLVABLE_PROVIDES, id) ]
180     end
181   end
182   return [] unless name =~ /[\[*?]/;
183   if globname
184     idmatches = {}
185     for d in pool.Dataiterator(0, Solv::SOLVABLE_NAME, name, Solv::Dataiterator::SEARCH_GLOB)
186       s = d.solvable
187       idmatches[s.nameid] = 1 if s.installable?
188     end
189     if !idmatches.empty?
190       return idmatches.keys.sort.collect { |id| pool.Job(Solv::Job::SOLVER_SOLVABLE_NAME, id) }
191     end
192   end
193   if globdep
194     idmatches = pool.matchprovidingids(name, Solv::Dataiterator::SEARCH_GLOB);
195     if !idmatches.empty?
196       puts "[using capability match for '#{name}']"
197       return idmatches.sort.collect { |id| pool.Job(Solv::Job::SOLVER_SOLVABLE_PROVIDES, id) }
198     end
199   end
200   return []
201 end
202
203
204 args = ARGV
205 cmd = args.shift
206 cmd = 'list' if cmd == 'li'
207 cmd = 'install' if cmd == 'in'
208 cmd = 'erase' if cmd == 'rm'
209 cmd = 'verify' if cmd == 've'
210 cmd = 'search' if cmd == 'se'
211
212 repos = []
213 for reposdir in [ '/etc/zypp/repos.d' ] do
214   next unless FileTest.directory?(reposdir)
215   for reponame in Dir["#{reposdir}/*.repo"].sort do
216     cfg = IniFile.new(reponame)
217     cfg.each_section do |ali|
218       repoattr = { 'alias' => ali, 'enabled' => 0, 'priority' => 99, 'autorefresh' => 1, 'type' => 'rpm-md', 'metadata_expire' => 900}
219       repoattr.update(cfg[ali])
220       if repoattr['type'] == 'rpm-md'
221         repo = Repo_rpmmd.new(ali, 'repomd', repoattr)
222       elsif repoattr['type'] == 'yast2'
223         repo = Repo_susetags.new(ali, 'susetags', repoattr)
224       else
225         repo = Repo_unknown.new(ali, 'unknown', repoattr)
226       end
227       repos.push(repo)
228     end
229   end
230 end
231
232 pool = Solv::Pool.new()
233 # require 'sys/uname' ; sysarch = Sys::Uname.machine
234 sysarch = `uname -p`.strip
235 pool.setarch(sysarch)
236
237 sysrepo = Repo_system.new('@System', 'system')
238 sysrepo.load(pool)
239 for repo in repos
240   repo.load(pool) if repo.enabled?
241 end
242
243 if cmd == 'search'
244   matches = {}
245   for di in pool.Dataiterator(0, Solv::SOLVABLE_NAME, args[0], Solv::Dataiterator::SEARCH_SUBSTRING | Solv::Dataiterator::SEARCH_NOCASE)
246     matches[di.solvid] = true
247   end
248   for solvid in matches.keys.sort
249     s = pool.solvables[solvid]
250     puts "- #{s.str} [#{s.repo.name}]"
251   end
252   exit
253 end
254
255 pool.addfileprovides
256 pool.createwhatprovides
257
258 jobs = []
259 for arg in args
260   njobs = depglob(pool, ARGV[0], true, true)
261   abort("nothing matches '#{arg}'") if njobs.empty?
262   jobs += njobs
263 end
264
265 for job in jobs
266   job.how |= Solv::Job::SOLVER_ERASE
267 end
268
269 solver = pool.Solver
270 problems = solver.solve(jobs)
271 for problem in problems
272   puts "Problem #{problem.id}:"
273   puts problem.findproblemrule.info.problemstr
274   solutions = problem.solutions
275   for solution in solutions
276     puts "  Solution #{solution.id}:"
277     elements = solution.elements
278     for element in elements:
279       puts "  - type #{element.type}"
280     end
281   end
282 end