b5d0b323293714b6eaadff54b700e847dde443cb
[tools/mic.git] / plugins / backend / zypppkgmgr.py
1 #!/usr/bin/python
2
3 import os
4 import sys
5 import glob
6 import re
7 import zypp
8 import rpm
9 import shutil
10 import tempfile
11 import urlparse
12 import urllib2 as u2
13 import pykickstart.parser
14 from micng.utils.errors import *
15 from micng.imager.baseimager import BaseImageCreator as ImageCreator
16 from micng.utils.fs_related import *
17 from micng.utils.misc import *
18 from micng.utils.rpmmisc import *
19 from micng.pluginbase.backend_plugin import BackendPlugin
20
21 class RepositoryStub:
22     def __init__(self):
23         self.name = None
24         self.baseurl = []
25         self.mirrorlist = None
26         self.proxy = None
27         self.proxy_username = None
28         self.proxy_password = None
29         self.includepkgs = None
30         self.includepkgs = None
31         self.exclude = None
32
33         self.enabled = True
34         self.autorefresh = True
35         self.keeppackages = True
36
37 class RepoError(CreatorError):
38     pass
39
40 class RpmError(CreatorError):
41     pass
42
43 class Zypp(BackendPlugin):
44     def __init__(self, creator = None, recording_pkgs=None):
45         if not isinstance(creator, ImageCreator):
46             raise CreatorError("Invalid argument: creator")
47
48         self.__recording_pkgs = recording_pkgs
49         self.__pkgs_content = {}
50         self.creator = creator
51         self.repos = []
52         self.packages = []
53         self.patterns = []
54         self.localpkgs = {}
55         self.repo_manager = None
56         self.repo_manager_options = None
57         self.Z = None
58         self.ts = None
59         self.probFilterFlags = []
60         self.bin_rpm = find_binary_path("rpm")
61         self.incpkgs = []
62         self.excpkgs = []
63
64     def doFileLogSetup(self, uid, logfile):
65         # don't do the file log for the livecd as it can lead to open fds
66         # being left and an inability to clean up after ourself
67         pass
68
69     def closeRpmDB(self):
70         pass
71
72     def close(self):
73         try:
74             os.unlink(self.installroot + "/yum.conf")
75         except:
76             pass
77         self.closeRpmDB()
78         if not os.path.exists("/etc/fedora-release") and not os.path.exists("/etc/meego-release"):
79             for i in range(3, os.sysconf("SC_OPEN_MAX")):
80                 try:
81                     os.close(i)
82                 except:
83                     pass
84         if self.ts:
85             self.ts.closeDB()
86             self.ts = None
87
88     def __del__(self):
89         self.close()
90
91     def _writeConf(self, confpath, installroot):
92         conf  = "[main]\n"
93         conf += "installroot=%s\n" % installroot
94         conf += "cachedir=/var/cache/yum\n"
95         conf += "plugins=0\n"
96         conf += "reposdir=\n"
97         conf += "failovermethod=priority\n"
98         conf += "http_caching=packages\n"
99
100         f = file(confpath, "w+")
101         f.write(conf)
102         f.close()
103
104         os.chmod(confpath, 0644)
105
106     def _cleanupRpmdbLocks(self, installroot):
107         # cleans up temporary files left by bdb so that differing
108         # versions of rpm don't cause problems
109         for f in glob.glob(installroot + "/var/lib/rpm/__db*"):
110             os.unlink(f)
111
112     def setup(self, confpath, installroot):
113         self._writeConf(confpath, installroot)
114         self._cleanupRpmdbLocks(installroot)
115         self.installroot = installroot
116
117     def selectPackage(self, pkg):
118         """ Select a given package or package pattern, can be specified with name.arch or name* or *name """
119         if not self.Z:
120             self.__initialize_zypp()
121         
122         found = False
123         startx = pkg.startswith("*")
124         endx = pkg.endswith("*")
125         ispattern = startx or endx
126         sp = pkg.rsplit(".", 2)
127         for item in self.Z.pool():
128             kind = "%s" % item.kind()
129             if kind == "package":
130                 name = "%s" % item.name()
131                 if not ispattern:
132                     if name in self.incpkgs or self.excpkgs:
133                         found = True
134                         break
135                     if len(sp) == 2:
136                         arch = "%s" % item.arch()
137                         if name == sp[0] and arch == sp[1]:
138                             found = True
139                             if name not in self.packages:
140                                 self.packages.append(name)
141                                 item.status().setToBeInstalled (zypp.ResStatus.USER)
142                             break
143                     else:
144                         if name == sp[0]:
145                             found = True
146                             if name not in self.packages:
147                                 self.packages.append(name)
148                                 item.status().setToBeInstalled (zypp.ResStatus.USER)
149                             break
150                 else:
151                     if name in self.incpkgs or self.excpkgs:
152                         found =  True
153                         continue
154                     if startx and name.endswith(sp[0][1:]):
155                         found = True
156                         if name not in self.packages:
157                             self.packages.append(name)
158                             item.status().setToBeInstalled (zypp.ResStatus.USER)
159
160                     if endx and name.startswith(sp[0][:-1]):
161                         found = True
162                         if name not in self.packages:
163                             self.packages.append(name)
164                             item.status().setToBeInstalled (zypp.ResStatus.USER)
165         if found:
166             return None
167         else:
168             e = CreatorError("Unable to find package: %s" % (pkg,))
169             return e
170
171     def deselectPackage(self, pkg):
172         """Deselect package.  Can be specified as name.arch or name*"""
173         
174         if not self.Z:
175             self.__initialize_zypp()
176         
177         startx = pkg.startswith("*")
178         endx = pkg.endswith("*")
179         ispattern = startx or endx
180         sp = pkg.rsplit(".", 2)
181         for item in self.Z.pool():
182             kind = "%s" % item.kind()
183             if kind == "package":
184                 name = "%s" % item.name()
185                 if not ispattern:
186                     if len(sp) == 2:
187                         arch = "%s" % item.arch()
188                         if name == sp[0] and arch == sp[1]:
189                             if item.status().isToBeInstalled():
190                                 item.status().resetTransact(zypp.ResStatus.USER)
191                             if name in self.packages:
192                                 self.packages.remove(name)
193                             break
194                     else:
195                         if name == sp[0]:
196                             if item.status().isToBeInstalled():
197                                 item.status().resetTransact(zypp.ResStatus.USER)
198                             if name in self.packages:
199                                 self.packages.remove(name)
200                             break                             
201                 else:
202                     if startx and name.endswith(sp[0][1:]):
203                         if item.status().isToBeInstalled():
204                             item.status().resetTransact(zypp.ResStatus.USER)
205                         if name in self.packages:
206                             self.packages.remove(name)
207
208                     if endx and name.startswith(sp[0][:-1]):
209                         if item.status().isToBeInstalled():
210                             item.status().resetTransact(zypp.ResStatus.USER)
211                         if name in self.packages:
212                             self.packages.remove(name)
213     
214     def __selectIncpkgs(self):        
215         found = False
216         for pkg in self.incpkgs:
217             for item in self.Z.pool():
218                 kind = "%s" % item.kind()
219                 if kind == "package":
220                     name = "%s" % item.name()
221                     repoalias = "%s" % item.repoInfo().alias()
222                     if name == pkg and repoalias.endswith("include"):
223                         found = True
224                         if name not in self.packages:
225                             self.packages.append(name)
226                             item.status().setToBeInstalled (zypp.ResStatus.USER)
227                         break         
228         if not found:
229             raise CreatorError("Unable to find package: %s" % (pkg,))
230     
231     def __selectExcpkgs(self):    
232         found = False        
233         for pkg in self.excpkgs:
234             for item in self.Z.pool():
235                 kind = "%s" % item.kind()
236                 if kind == "package":
237                     name = "%s" % item.name()
238                     repoalias = "%s" % item.repoInfo().alias()
239                     if name == pkg and not repoalias.endswith("exclude"):
240                         found = True
241                         if name not in self.packages:
242                             self.packages.append(name)
243                             item.status().setToBeInstalled (zypp.ResStatus.USER)
244                         break                     
245         if not found:
246             raise CreatorError("Unable to find package: %s" % (pkg,))
247
248         
249     def selectGroup(self, grp, include = pykickstart.parser.GROUP_DEFAULT):
250         if not self.Z:
251             self.__initialize_zypp()
252         found = False
253         for item in self.Z.pool():
254             kind = "%s" % item.kind()
255             if kind == "pattern":
256                 summary = "%s" % item.summary()
257                 name = "%s" % item.name()
258                 if name == grp or summary == grp:
259                     found = True
260                     if name not in self.patterns:
261                         self.patterns.append(name)
262                         item.status().setToBeInstalled (zypp.ResStatus.USER)
263                     break
264                 
265         if found:
266             if include == pykickstart.parser.GROUP_REQUIRED:
267                 map(lambda p: self.deselectPackage(p), grp.default_packages.keys())
268             elif include == pykickstart.parser.GROUP_ALL:
269                 map(lambda p: self.selectPackage(p), grp.optional_packages.keys())
270             return None
271         else:
272             e = CreatorError("Unable to find pattern: %s" % (grp,))
273             return e
274
275     def __checkAndDownloadURL(self, u2opener, url, savepath):
276         try:
277             if u2opener:
278                 f = u2opener.open(url)
279             else:
280                 f = u2.urlopen(url)
281         except u2.HTTPError, httperror:
282             if httperror.code in (404, 503):
283                 return None
284             else:
285                 raise CreatorError(httperror)
286         except OSError, oserr:
287             if oserr.errno == 2:
288                 return None
289             else:
290                 raise CreatorError(oserr)
291         except IOError, oserr:
292             if hasattr(oserr, "reason") and oserr.reason.errno == 2:
293                 return None
294             else:
295                 raise CreatorError(oserr)
296         except u2.URLError, err:
297             raise CreatorError(err)
298
299         # save to file
300         licf = open(savepath, "w")
301         licf.write(f.read())
302         licf.close()
303         f.close()
304
305         return savepath
306
307     def __pagerFile(self, savepath):
308         if os.path.splitext(savepath)[1].upper() in ('.HTM', '.HTML'):
309             pagers = ('w3m', 'links', 'lynx', 'less', 'more')
310         else:
311             pagers = ('less', 'more')
312
313         file_showed = None
314         for pager in pagers:
315             try:
316                 subprocess.call([pager, savepath])
317             except OSError:
318                 continue
319             else:
320                 file_showed = True
321                 break
322         if not file_showed:
323             f = open(savepath)
324             print f.read()
325             f.close()
326             raw_input('press <ENTER> to continue...')
327
328     def checkRepositoryEULA(self, name, repo):
329         """ This function is to check the LICENSE file if provided. """
330
331         # when proxy needed, make urllib2 follow it
332         proxy = repo.proxy
333         proxy_username = repo.proxy_username
334         proxy_password = repo.proxy_password
335
336         handlers = []
337         auth_handler = u2.HTTPBasicAuthHandler(u2.HTTPPasswordMgrWithDefaultRealm())
338         u2opener = None
339         if proxy:
340             if proxy_username:
341                 proxy_netloc = urlparse.urlsplit(proxy).netloc
342                 if proxy_password:
343                     proxy_url = 'http://%s:%s@%s' % (proxy_username, proxy_password, proxy_netloc)
344                 else:
345                     proxy_url = 'http://%s@%s' % (proxy_username, proxy_netloc)
346             else:
347                 proxy_url = proxy
348
349             proxy_support = u2.ProxyHandler({'http': proxy_url,
350                                              'ftp': proxy_url})
351             handlers.append(proxy_support)
352
353         # download all remote files to one temp dir
354         baseurl = None
355         repo_lic_dir = tempfile.mkdtemp(prefix = 'repolic')
356
357         for url in repo.baseurl:
358             if not url.endswith('/'):
359                 url += '/'
360             tmphandlers = handlers
361             (scheme, host, path, parm, query, frag) = urlparse.urlparse(url)
362             if scheme not in ("http", "https", "ftp", "ftps", "file"):
363                 raise CreatorError("Error: invalid url %s" % url)
364             if '@' in host:
365                 try:
366                     user_pass, host = host.split('@', 1)
367                     if ':' in user_pass:
368                         user, password = user_pass.split(':', 1)
369                 except ValueError, e:
370                     raise CreatorError('Bad URL: %s' % url)
371                 print "adding HTTP auth: %s, %s" %(user, password)
372                 auth_handler.add_password(None, host, user, password)
373                 tmphandlers.append(auth_handler)
374                 url = scheme + "://" + host + path + parm + query + frag
375             if len(tmphandlers) != 0:
376                 u2opener = u2.build_opener(*tmphandlers)
377             # try to download
378             repo_eula_url = urlparse.urljoin(url, "LICENSE.txt")
379             repo_eula_path = self.__checkAndDownloadURL(
380                                     u2opener,
381                                     repo_eula_url,
382                                     os.path.join(repo_lic_dir, repo.id + '_LICENSE.txt'))
383             if repo_eula_path:
384                 # found
385                 baseurl = url
386                 break
387
388         if not baseurl:
389             return True
390
391         # show the license file
392         print 'For the software packages in this yum repo:'
393         print '    %s: %s' % (name, baseurl)
394         print 'There is an "End User License Agreement" file that need to be checked.'
395         print 'Please read the terms and conditions outlined in it and answer the followed qustions.'
396         raw_input('press <ENTER> to continue...')
397
398         self.__pagerFile(repo_eula_path)
399
400         # Asking for the "Accept/Decline"
401         accept = True
402         while accept:
403             input_accept = raw_input('Would you agree to the terms and conditions outlined in the above End User License Agreement? (Yes/No): ')
404             if input_accept.upper() in ('YES', 'Y'):
405                 break
406             elif input_accept.upper() in ('NO', 'N'):
407                 accept = None
408                 print 'Will not install pkgs from this repo.'
409
410         if not accept:
411             #cleanup
412             shutil.rmtree(repo_lic_dir)
413             return None
414
415         # try to find support_info.html for extra infomation
416         repo_info_url = urlparse.urljoin(baseurl, "support_info.html")
417         repo_info_path = self.__checkAndDownloadURL(
418                                 u2opener,
419                                 repo_info_url,
420                                 os.path.join(repo_lic_dir, repo.id + '_support_info.html'))
421         if repo_info_path:
422             print 'There is one more file in the repo for additional support information, please read it'
423             raw_input('press <ENTER> to continue...')
424             self.__pagerFile(repo_info_path)
425
426         #cleanup
427         shutil.rmtree(repo_lic_dir)
428         return True
429
430     def addRepository(self, name, url = None, mirrorlist = None, proxy = None, proxy_username = None, proxy_password = None, inc = None, exc = None):
431         if not self.repo_manager:
432             self.__initialize_repo_manager()
433
434         repo = RepositoryStub()
435         repo.name = name
436         repo.id = name
437         repo.proxy = proxy
438         repo.proxy_username = proxy_username
439         repo.proxy_password = proxy_password
440         repo.baseurl.append(url)
441         repo_alias = repo.id
442         if inc:
443             repo_alias = name + "include"
444             self.incpkgs = inc
445         if exc:
446             repo_alias = name + "exclude"
447             self.excpkgs = exc
448
449         # check LICENSE files
450         if not self.checkRepositoryEULA(name, repo):
451             return None
452
453         if mirrorlist:
454             repo.mirrorlist = mirrorlist
455
456         # Enable gpg check for verifying corrupt packages
457         repo.gpgcheck = 1
458         self.repos.append(repo)
459
460
461         try:
462             repo_info = zypp.RepoInfo()
463             repo_info.setAlias(repo_alias)
464             repo_info.setName(repo.name)
465             repo_info.setEnabled(repo.enabled)
466             repo_info.setAutorefresh(repo.autorefresh)
467             repo_info.setKeepPackages(repo.keeppackages)
468             repo_info.addBaseUrl(zypp.Url(repo.baseurl[0]))
469             self.repo_manager.addRepository(repo_info)
470             self.__build_repo_cache(name)
471         except RuntimeError, e:
472             raise CreatorError("%s" % (e,))
473
474         return repo
475
476     def installHasFile(self, file):
477         return False
478
479     def runInstall(self, checksize = 0):
480         if self.incpkgs:
481             self.__selectIncpkgs()
482         if self.excpkgs:
483             self.__selectExcpkgs()
484         
485         os.environ["HOME"] = "/"
486         self.buildTransaction()
487
488         todo = zypp.GetResolvablesToInsDel(self.Z.pool())
489         installed_pkgs = todo._toInstall
490         dlpkgs = []
491         for item in installed_pkgs:
492             if not zypp.isKindPattern(item):
493                 dlpkgs.append(item)
494
495         # record the total size of installed pkgs
496         pkgs_total_size = sum(map(lambda x: int(x.installSize()), dlpkgs))
497
498         # check needed size before actually download and install
499         if checksize and pkgs_total_size > checksize:
500             raise CreatorError("Size of specified root partition in kickstart file is too small to install all selected packages.")
501
502         if self.__recording_pkgs:
503             # record all pkg and the content
504             for pkg in dlpkgs:
505                 pkg_long_name = "%s-%s.%s.rpm" % (pkg.name(), pkg.edition(), pkg.arch())
506                 self.__pkgs_content[pkg_long_name] = {} #TBD: to get file list
507
508         total_count = len(dlpkgs)
509         cached_count = 0
510         localpkgs = self.localpkgs.keys()
511         print "Checking packages cache and packages integrity..."
512         for po in dlpkgs:
513             """ Check if it is cached locally """
514             if po.name() in localpkgs:
515                 cached_count += 1
516             else:
517                 local = self.getLocalPkgPath(po)
518                 if os.path.exists(local):
519                     if self.checkPkg(local) != 0:
520                         os.unlink(local)
521                     else:
522                         cached_count += 1
523         print "%d packages to be installed, %d packages gotten from cache, %d packages to be downloaded" % (total_count, cached_count, total_count - cached_count)
524         try:
525             print "downloading packages..."
526             self.downloadPkgs(dlpkgs)
527             self.installPkgs(dlpkgs)
528     
529         except RepoError, e:
530             raise CreatorError("Unable to download from repo : %s" % (e,))
531         except RpmError, e:
532             raise CreatorError("Unable to install: %s" % (e,))
533
534     def getAllContent(self):
535         return self.__pkgs_content
536
537     def __initialize_repo_manager(self):
538         if self.repo_manager:
539             return
540
541         """ Clean up repo metadata """
542         shutil.rmtree(self.creator.cachedir + "/var", ignore_errors = True)
543         shutil.rmtree(self.creator.cachedir + "/etc", ignore_errors = True)
544         shutil.rmtree(self.creator.cachedir + "/raw", ignore_errors = True)
545         shutil.rmtree(self.creator.cachedir + "/solv", ignore_errors = True)
546         
547         zypp.KeyRing.setDefaultAccept( zypp.KeyRing.ACCEPT_UNSIGNED_FILE
548                                        | zypp.KeyRing.ACCEPT_VERIFICATION_FAILED
549                                        | zypp.KeyRing.ACCEPT_UNKNOWNKEY
550                                        | zypp.KeyRing.TRUST_KEY_TEMPORARILY
551                                      )
552         self.repo_manager_options = zypp.RepoManagerOptions(zypp.Pathname(self.creator._instroot))
553         self.repo_manager_options.knownReposPath = zypp.Pathname(self.creator.cachedir + "/etc/zypp/repos.d")
554         self.repo_manager_options.repoCachePath = zypp.Pathname(self.creator.cachedir + "/var/cache/zypp")
555         self.repo_manager_options.repoRawCachePath = zypp.Pathname(self.creator.cachedir + "/raw")
556         self.repo_manager_options.repoSolvCachePath = zypp.Pathname(self.creator.cachedir + "/solv")
557         self.repo_manager_options.repoPackagesCachePath = zypp.Pathname(self.creator.cachedir + "/packages")
558         
559         self.repo_manager = zypp.RepoManager(self.repo_manager_options)
560
561
562     def __build_repo_cache(self, name):
563         repos = self.repo_manager.knownRepositories()
564         for repo in repos:
565             if not repo.enabled():
566                 continue
567             reponame = "%s" % repo.name()
568             if reponame != name:
569                 continue
570             if self.repo_manager.isCached( repo ):
571                 return
572             #print "Retrieving repo metadata from %s ..." % repo.url()
573             self.repo_manager.buildCache( repo, zypp.RepoManager.BuildIfNeeded )
574
575
576     def __initialize_zypp(self):
577         if self.Z:
578             return
579
580         zconfig = zypp.ZConfig_instance()
581
582         """ Set system architecture """
583         if self.creator.target_arch and self.creator.target_arch.startswith("arm"):
584             arches = ["armv7l", "armv7nhl", "armv7hl"]
585             if self.creator.target_arch not in arches:
586                 raise CreatorError("Invalid architecture: %s" % self.creator.target_arch)
587             arch_map = {}
588             if self.creator.target_arch == "armv7l":
589                 arch_map["armv7l"] = zypp.Arch_armv7l()
590             elif self.creator.target_arch == "armv7nhl":
591                 arch_map["armv7nhl"] = zypp.Arch_armv7nhl()
592             elif self.creator.target_arch == "armv7hl":
593                 arch_map["armv7hl"] = zypp.Arch_armv7hl() 
594             zconfig.setSystemArchitecture(arch_map[self.creator.target_arch])
595
596         print "zypp architecture: %s" % zconfig.systemArchitecture()
597
598         """ repoPackagesCachePath is corrected by this """
599         self.repo_manager = zypp.RepoManager(self.repo_manager_options)
600         repos = self.repo_manager.knownRepositories()
601         for repo in repos:
602             if not repo.enabled():
603                 continue
604             if not self.repo_manager.isCached( repo ):
605                 print "Retrieving repo metadata from %s ..." % repo.url()
606                 self.repo_manager.buildCache( repo, zypp.RepoManager.BuildIfNeeded )
607             else:
608                 self.repo_manager.refreshMetadata(repo, zypp.RepoManager.BuildIfNeeded)
609             self.repo_manager.loadFromCache( repo );
610
611         self.Z = zypp.ZYppFactory_instance().getZYpp()
612         self.Z.initializeTarget( zypp.Pathname(self.creator._instroot) )
613         self.Z.target().load();
614
615
616     def buildTransaction(self):
617         if not self.Z.resolver().resolvePool():
618             print "Problem count: %d" % len(self.Z.resolver().problems())
619             for problem in self.Z.resolver().problems():
620                 print "Problem: %s, %s" % (problem.description().decode("utf-8"), problem.details().decode("utf-8"))
621
622     def getLocalPkgPath(self, po):
623         repoinfo = po.repoInfo()
624         name = po.name()
625         cacheroot = repoinfo.packagesPath()
626         arch =  po.arch()
627         edition = po.edition()
628         version = "%s-%s" % (edition.version(), edition.release())
629         pkgpath = "%s/%s/%s-%s.%s.rpm" % (cacheroot, arch, name, version, arch)
630         return pkgpath
631
632     def installLocal(self, pkg, po=None, updateonly=False):
633         if not self.ts:
634             self.__initialize_transaction()
635         pkgname = self.__get_pkg_name(pkg)
636         self.localpkgs[pkgname] = pkg
637         self.selectPackage(pkgname)
638
639     def __get_pkg_name(self, pkgpath):
640         h = readRpmHeader(self.ts, pkgpath)
641         return h["name"]
642
643     def downloadPkgs(self, package_objects):
644         localpkgs = self.localpkgs.keys()
645         for po in package_objects:
646             if po.name() in localpkgs:
647                 continue
648             filename = self.getLocalPkgPath(po)
649             if os.path.exists(filename):
650                 if self.checkPkg(filename) == 0:
651                     continue
652             dir = os.path.dirname(filename)
653             if not os.path.exists(dir):
654                 makedirs(dir)
655             baseurl = po.repoInfo().baseUrls()[0].__str__()
656             proxy = self.get_proxy(po.repoInfo())
657             proxies = {}
658             if proxy:
659                 proxies = {str(proxy.split(":")[0]):str(proxy)}
660           
661             location = zypp.asKindPackage(po).location()
662             location = location.filename().__str__()
663             if location.startswith("./"):
664                 location = location[2:]
665             url = baseurl + "/%s" % location
666             try:
667                 filename = myurlgrab(url, filename, proxies)
668             except CreatorError, e:
669                 self.close()
670                 raise CreatorError("%s" % e)
671
672     def installPkgs(self, package_objects):
673         if not self.ts:
674             self.__initialize_transaction()
675
676         """ Set filters """
677         probfilter = 0
678         for flag in self.probFilterFlags:
679             probfilter |= flag
680         self.ts.setProbFilter(probfilter)
681
682         localpkgs = self.localpkgs.keys()
683         for po in package_objects:
684             pkgname = po.name()
685             if pkgname in localpkgs:
686                 rpmpath = self.localpkgs[pkgname]
687             else:
688                 rpmpath = self.getLocalPkgPath(po)
689             if not os.path.exists(rpmpath):
690                 """ Maybe it is a local repo """
691                 baseurl = po.repoInfo().baseUrls()[0].__str__()
692                 baseurl = baseurl.strip()
693                 if baseurl.startswith("file:/"):
694                     rpmpath = baseurl[5:] + "/%s/%s" % (po.arch(), os.path.basename(rpmpath))
695             if not os.path.exists(rpmpath):
696                 raise RpmError("Error: %s doesn't exist" % rpmpath)
697             h = readRpmHeader(self.ts, rpmpath)
698             self.ts.addInstall(h, rpmpath, 'u')
699
700         unresolved_dependencies = self.ts.check()
701         if not unresolved_dependencies:
702             self.ts.order()
703             cb = RPMInstallCallback(self.ts)
704             self.ts.run(cb.callback, '')
705             self.ts.closeDB()
706             self.ts = None
707         else:
708             print unresolved_dependencies
709             raise RepoError("Error: Unresolved dependencies, transaction failed.")
710
711     def __initialize_transaction(self):
712         if not self.ts:
713             self.ts = rpm.TransactionSet(self.creator._instroot)
714             # Set to not verify DSA signatures.
715             self.ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS)
716
717     def checkPkg(self, pkg):
718         ret = 1
719         if not os.path.exists(pkg):
720             return ret
721         ret = checkRpmIntegrity(self.bin_rpm, pkg)
722         if ret != 0:
723             print "Package %s is damaged: %s" % (os.path.basename(pkg), pkg)
724         return ret
725
726     def zypp_install(self):
727         policy = zypp.ZYppCommitPolicy()
728         policy.downloadMode(zypp.DownloadInAdvance)
729         policy.dryRun( False )
730         policy.syncPoolAfterCommit( False )
731         result = self.Z.commit( policy )
732         print result
733
734     def _add_prob_flags(self, *flags):
735         for flag in flags:
736            if flag not in self.probFilterFlags:
737                self.probFilterFlags.append(flag)
738
739     def get_proxy(self, repoinfo):
740         proxy = None
741         reponame = "%s" % repoinfo.name()
742         for repo in self.repos:
743             if repo.name == reponame:
744                 proxy = repo.proxy
745                 break
746         if proxy:
747             return proxy
748         else:
749             repourl = repoinfo.baseUrls()[0].__str__()
750             return get_proxy(repourl)
751
752 mic_plugin = ["zypp", Zypp]
753