Imported Upstream version 0.7.27
[platform/upstream/libsolv.git] / examples / pysolv
index fd5df47..b69234e 100755 (executable)
@@ -43,6 +43,7 @@ from optparse import OptionParser
 
 #import gc
 #gc.set_debug(gc.DEBUG_LEAK)
+#rpm.setVerbosity(rpm.RPMLOG_DEBUG)
 
 class repo_generic(dict):
     def __init__(self, name, type, attribs = {}):
@@ -68,16 +69,7 @@ class repo_generic(dict):
         chksum.add("1.1");
         chksum.add(cookie)
         chksum.add_fstat(f.fileno())
-        extcookie = chksum.raw()
-        if sys.version > '3':
-            # compatibility to c code
-            if extcookie[0] == 0:
-                extcookie[0] = 1
-        else:
-            # compatibility to c code
-            if ord(extcookie[0]) == 0:
-                extcookie[0] = chr(1)
-        return extcookie
+        return chksum.raw()
 
     def cachepath(self, ext = None):
         path = re.sub(r'^\.', '_', self.name)
@@ -100,6 +92,7 @@ class repo_generic(dict):
             except OSError:
                 pass
         self['cookie'] = ''
+        self['extcookie'] = ''
         if not dorefresh and self.usecachedrepo(None):
             print("repo: '%s': cached" % self.name)
             return True
@@ -237,7 +230,7 @@ class repo_generic(dict):
             return False
         return True
 
-    def writecachedrepo(self, ext, info=None):
+    def writecachedrepo(self, ext, repodata=None):
         if 'incomplete' in self:
             return
         tmpname = None
@@ -248,21 +241,21 @@ class repo_generic(dict):
             os.fchmod(fd, 0o444)
             f = os.fdopen(fd, 'wb+')
             f = solv.xfopen_fd(None, f.fileno())
-            if not info:
+            if not repodata:
                 self.handle.write(f)
             elif ext:
-                info.write(f)
-            else:       # rewrite_repos case
+                repodata.write(f)
+            else:       # rewrite_repos case, do not write stubs
                 self.handle.write_first_repodata(f)
             f.flush()
             if self.type != 'system' and not ext:
-                if 'extcookie' not in self:
+                if not self['extcookie']:
                     self['extcookie'] = self.calc_cookie_ext(f, self['cookie'])
-                os.write(f.fileno(), self['extcookie'])
+                f.write(self['extcookie'])
             if not ext:
-                os.write(f.fileno(), self['cookie'])
+                f.write(self['cookie'])
             else:
-                os.write(f.fileno(), self['extcookie'])
+                f.write(self['extcookie'])
             f.close
             if self.handle.iscontiguous():
                 # switch to saved repo to activate paging and save memory
@@ -270,17 +263,20 @@ class repo_generic(dict):
                 if not ext:
                     # main repo
                     self.handle.empty()
-                    if not self.handle.add_solv(nf, solv.Repo.SOLV_ADD_NO_STUBS):
+                    flags = solv.Repo.SOLV_ADD_NO_STUBS
+                    if repodata:
+                        flags = 0       # rewrite repos case, recreate stubs
+                    if not self.handle.add_solv(nf, flags):
                         sys.exit("internal error, cannot reload solv file")
                 else:
                     # extension repodata
                     # need to extend to repo boundaries, as this is how
-                    # info.write() has written the data
-                    info.extend_to_repo()
+                    # repodata.write() has written the data
+                    repodata.extend_to_repo()
                     flags = solv.Repo.REPO_EXTEND_SOLVABLES
                     if ext != 'DL':
                         flags |= solv.Repo.REPO_LOCALPOOL
-                    info.add_solv(nf, flags)
+                    repodata.add_solv(nf, flags)
             os.rename(tmpname, self.cachepath(ext))
         except (OSError, IOError):
             if tmpname:
@@ -307,6 +303,29 @@ class repo_generic(dict):
     def packagespath(self):
         return ''
 
+    def add_ext_keys(self, ext, repodata, handle):
+        if ext == 'DL':
+            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOSITORY_DELTAINFO)
+            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_FLEXARRAY)
+        elif ext == 'DU':
+            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_DISKUSAGE)
+            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRNUMNUMARRAY)
+        elif ext == 'FL':
+            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_FILELIST)
+            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRSTRARRAY)
+        else:
+            for langtag, langtagtype in [
+                (solv.SOLVABLE_SUMMARY, solv.REPOKEY_TYPE_STR),
+                (solv.SOLVABLE_DESCRIPTION, solv.REPOKEY_TYPE_STR),
+                (solv.SOLVABLE_EULA, solv.REPOKEY_TYPE_STR),
+                (solv.SOLVABLE_MESSAGEINS, solv.REPOKEY_TYPE_STR),
+                (solv.SOLVABLE_MESSAGEDEL, solv.REPOKEY_TYPE_STR),
+                (solv.SOLVABLE_CATEGORY, solv.REPOKEY_TYPE_ID)
+            ]:
+                repodata.add_idarray(handle, solv.REPOSITORY_KEYS, self.handle.pool.id2langid(langtag, ext, 1))
+                repodata.add_idarray(handle, solv.REPOSITORY_KEYS, langtagtype)
+        
+
 class repo_repomd(repo_generic):
     def load(self, pool):
         if super(repo_repomd, self).load(pool):
@@ -344,7 +363,7 @@ class repo_repomd(repo_generic):
         return True
 
     def find(self, what):
-        di = self.handle.Dataiterator(solv.SOLVID_META, solv.REPOSITORY_REPOMD_TYPE, what, solv.Dataiterator.SEARCH_STRING)
+        di = self.handle.Dataiterator_meta(solv.REPOSITORY_REPOMD_TYPE, what, solv.Dataiterator.SEARCH_STRING)
         di.prepend_keyname(solv.REPOSITORY_REPOMD)
         for d in di:
             dp = d.parentpos()
@@ -368,16 +387,12 @@ class repo_repomd(repo_generic):
         repodata.set_poolstr(handle, solv.REPOSITORY_REPOMD_TYPE, what)
         repodata.set_str(handle, solv.REPOSITORY_REPOMD_LOCATION, filename)
         repodata.set_checksum(handle, solv.REPOSITORY_REPOMD_CHECKSUM, chksum)
-        if ext == 'DL':
-            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOSITORY_DELTAINFO)
-            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_FLEXARRAY)
-        elif ext == 'FL':
-            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_FILELIST)
-            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRSTRARRAY)
+        self.add_ext_keys(ext, repodata, handle)
         repodata.add_flexarray(solv.SOLVID_META, solv.REPOSITORY_EXTERNAL, handle)
 
     def add_exts(self):
         repodata = self.handle.add_repodata(0)
+        repodata.extend_to_repo()
         self.add_ext(repodata, 'deltainfo', 'DL')
         self.add_ext(repodata, 'filelists', 'FL')
         repodata.internalize()
@@ -453,7 +468,7 @@ class repo_susetags(repo_generic):
         return True
 
     def find(self, what):
-        di = self.handle.Dataiterator(solv.SOLVID_META, solv.SUSETAGS_FILE_NAME, what, solv.Dataiterator.SEARCH_STRING)
+        di = self.handle.Dataiterator_meta(solv.SUSETAGS_FILE_NAME, what, solv.Dataiterator.SEARCH_STRING)
         di.prepend_keyname(solv.SUSETAGS_FILE)
         for d in di:
             dp = d.parentpos()
@@ -469,31 +484,15 @@ class repo_susetags(repo_generic):
         repodata.set_str(handle, solv.SUSETAGS_FILE_NAME, filename)
         if chksum:
             repodata.set_checksum(handle, solv.SUSETAGS_FILE_CHECKSUM, chksum)
-        if ext == 'DU':
-            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_DISKUSAGE)
-            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRNUMNUMARRAY)
-        elif ext == 'FL':
-            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_FILELIST)
-            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRSTRARRAY)
-        else:
-            for langtag, langtagtype in [
-                (solv.SOLVABLE_SUMMARY, solv.REPOKEY_TYPE_STR),
-                (solv.SOLVABLE_DESCRIPTION, solv.REPOKEY_TYPE_STR),
-                (solv.SOLVABLE_EULA, solv.REPOKEY_TYPE_STR),
-                (solv.SOLVABLE_MESSAGEINS, solv.REPOKEY_TYPE_STR),
-                (solv.SOLVABLE_MESSAGEDEL, solv.REPOKEY_TYPE_STR),
-                (solv.SOLVABLE_CATEGORY, solv.REPOKEY_TYPE_ID)
-            ]:
-                repodata.add_idarray(handle, solv.REPOSITORY_KEYS, self.handle.pool.id2langid(langtag, ext, 1))
-                repodata.add_idarray(handle, solv.REPOSITORY_KEYS, langtagtype)
+        self.add_ext_keys(ext, repodata, handle)
         repodata.add_flexarray(solv.SOLVID_META, solv.REPOSITORY_EXTERNAL, handle)
         
     def add_exts(self):
         repodata = self.handle.add_repodata(0)
-        di = self.handle.Dataiterator(solv.SOLVID_META, solv.SUSETAGS_FILE_NAME, None, 0)
+        di = self.handle.Dataiterator_meta(solv.SUSETAGS_FILE_NAME, None, 0)
         di.prepend_keyname(solv.SUSETAGS_FILE)
         for d in di:
-            filename = d.str()
+            filename = d.str
             if not filename:
                 continue
             if filename[0:9] != "packages.":
@@ -658,7 +657,7 @@ if options.repos:
 if cmd == 'search':
     pool.createwhatprovides()
     sel = pool.Selection()
-    di = pool.Dataiterator(0, solv.SOLVABLE_NAME, args[0], solv.Dataiterator.SEARCH_SUBSTRING|solv.Dataiterator.SEARCH_NOCASE)
+    di = pool.Dataiterator(solv.SOLVABLE_NAME, args[0], solv.Dataiterator.SEARCH_SUBSTRING|solv.Dataiterator.SEARCH_NOCASE)
     for d in di:
         sel.add_raw(solv.Job.SOLVER_SOLVABLE, d.solvid)
     if repofilter:
@@ -668,7 +667,7 @@ if cmd == 'search':
     sys.exit(0)
 
 if cmd not in cmdactionmap:
-    print("unknown command", cmd)
+    print("unknown command %s" % cmd)
     sys.exit(1)
 
 cmdlinerepo = None
@@ -719,9 +718,9 @@ for arg in args:
         if sel.isempty():
             print("nothing matches '%s'" % arg)
             sys.exit(1)
-        if sel.flags() & solv.Selection.SELECTION_FILELIST:
+        if sel.flags & solv.Selection.SELECTION_FILELIST:
             print("[using file list match for '%s']" % arg)
-        if sel.flags() & solv.Selection.SELECTION_PROVIDES:
+        if sel.flags & solv.Selection.SELECTION_PROVIDES:
             print("[using capability match for '%s']" % arg)
         jobs += sel.jobs(cmdactionmap[cmd])
 
@@ -749,7 +748,7 @@ if cmd == 'list' or cmd == 'info':
                 if str:
                     print("License:     %s" % str)
                 print("Description:\n%s" % s.lookup_str(solv.SOLVABLE_DESCRIPTION))
-                print()
+                print('')
             else:
                 print("  - %s [%s]" % (s, s.repo))
                 print("    %s" % s.lookup_str(solv.SOLVABLE_SUMMARY))
@@ -783,12 +782,17 @@ while True:
             elements = solution.elements(True)
             for element in elements:
                 print("  - %s" % element.str())
-            print()
+            print('')
         sol = ''
         while not (sol == 's' or sol == 'q' or (sol.isdigit() and int(sol) >= 1 and int(sol) <= len(solutions))):
             sys.stdout.write("Please choose a solution: ")
             sys.stdout.flush()
             sol = sys.stdin.readline().strip()
+            if sol == 'p':
+                print('')
+                for decisionset in problem.get_decisionsetlist():
+                    print("%s: %s" % (decisionset, decisionset.reasonstr()))
+                print('')
         if sol == 's':
             continue        # skip problem
         if sol == 'q':
@@ -804,13 +808,12 @@ while True:
                     
 # no problems, show transaction
 trans = solver.transaction()
-del solver
 if trans.isempty():
     print("Nothing to do.")
     sys.exit(0)
-print()
+print('')
 print("Transaction summary:")
-print()
+print('')
 for cl in trans.classify(solv.Transaction.SOLVER_TRANSACTION_SHOW_OBSOLETES | solv.Transaction.SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE):
     if cl.type == solv.Transaction.SOLVER_TRANSACTION_ERASE:
         print("%d erased packages:" % cl.count)
@@ -836,9 +839,23 @@ for cl in trans.classify(solv.Transaction.SOLVER_TRANSACTION_SHOW_OBSOLETES | so
             print("  - %s -> %s" % (p, op))
         else:
             print("  - %s" % p)
-    print()
+    print('')
 print("install size change: %d K" % trans.calc_installsizechange())
-print()
+print('')
+
+alternatives = solver.alternatives()
+if alternatives:
+    print('Alternatives:')
+    for a in alternatives:
+        print('')
+        print(a)
+        aidx = 1
+        for ac in a.choices():
+            print("%6d: %s" % (aidx, ac))
+            aidx = aidx + 1
+    print('')
+
+del solver
 
 while True:
     sys.stdout.write("OK to continue (y/n)? ")
@@ -852,7 +869,7 @@ if newpkgs:
     downloadsize = 0
     for p in newpkgs:
         downloadsize += p.lookup_num(solv.SOLVABLE_DOWNLOADSIZE)
-    print("Downloading %d packages, %d K" % (len(newpkgs), downloadsize))
+    print("Downloading %d packages, %d K" % (len(newpkgs), downloadsize / 1024))
     for p in newpkgs:
         repo = p.repo.appdata
         location, medianr = p.lookup_location()
@@ -866,7 +883,7 @@ if newpkgs:
             continue
         if not sysrepo.handle.isempty() and os.access('/usr/bin/applydeltarpm', os.X_OK):
             pname = p.name
-            di = p.repo.Dataiterator(solv.SOLVID_META, solv.DELTA_PACKAGE_NAME, pname, solv.Dataiterator.SEARCH_STRING)
+            di = p.repo.Dataiterator_meta(solv.DELTA_PACKAGE_NAME, pname, solv.Dataiterator.SEARCH_STRING)
             di.prepend_keyname(solv.REPOSITORY_DELTAINFO)
             for d in di:
                 dp = d.parentpos()
@@ -893,6 +910,7 @@ if newpkgs:
                     continue
                 nf = tempfile.TemporaryFile()
                 nf = os.dup(nf.fileno())   # get rid of CLOEXEC
+                f.cloexec(0)
                 st = subprocess.call(['/usr/bin/applydeltarpm', '-a', p.arch, "/dev/fd/%d" % f.fileno(), "/dev/fd/%d" % nf])
                 if st:
                     os.close(nf)
@@ -914,9 +932,9 @@ if newpkgs:
         newpkgsfp[p.id] = f
         sys.stdout.write(".")
         sys.stdout.flush()
-    print()
+    print('')
 print("Committing transaction:")
-print()
+print('')
 ts = rpm.TransactionSet('/')
 ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES)
 erasenamehelper = {}
@@ -945,14 +963,16 @@ if checkproblems:
 ts.order()
 def runCallback(reason, amount, total, p, d):
     if reason == rpm.RPMCALLBACK_INST_OPEN_FILE:
-        return newpkgsfp[p.id].fileno()
+        f = newpkgsfp[p.id]
+        os.lseek(f.fileno(), 0, os.SEEK_SET)
+        return f.fileno()
     if reason == rpm.RPMCALLBACK_INST_START:
-        print("install", p)
+        print("install %s" % p)
     if reason == rpm.RPMCALLBACK_UNINST_START:
         # argh, p is just the name of the package
         if p in erasenamehelper:
             p = erasenamehelper[p]
-            print("erase", p)
+            print("erase %s" % p)
 runproblems = ts.run(runCallback, '')
 if runproblems:
     print(runproblems)