[yum] update to latest HEAD

Zdeněk Pavlas zpavlas at fedoraproject.org
Fri Dec 13 15:25:36 UTC 2013


commit dcb58953195d34f3704c59842411847b600267b1
Author: Zdenek Pavlas <zpavlas at redhat.com>
Date:   Fri Dec 13 16:25:36 2013 +0100

    update to latest HEAD
    
    - use the same "Total" formatting as urlgrabber.progress
    - fix the depsolve_loop_limit=0 case. BZ 1041395
    - yum.bash: skip pkglist completion when len(prefix) < 1. BZ 1040033
    - yum-cron: stderr/email: no output if no messages. BZ 1018068
    - yum-cron: use YumOutput.listTransaction(). BZ 1040109

 yum-HEAD.patch |  586 ++++++++------------------------------------------------
 yum.spec       |   10 +-
 2 files changed, 88 insertions(+), 508 deletions(-)
---
diff --git a/yum-HEAD.patch b/yum-HEAD.patch
index 2cc52b6..ac78e6a 100644
--- a/yum-HEAD.patch
+++ b/yum-HEAD.patch
@@ -3483,7 +3483,7 @@ index 1a8202a..dff88af 100644
  http://yum.baseurl.org/wiki/Faq
  yum search yum
 diff --git a/docs/yum.conf.5 b/docs/yum.conf.5
-index 515aa73..da13dc8 100644
+index 515aa73..48ced00 100644
 --- a/docs/yum.conf.5
 +++ b/docs/yum.conf.5
 @@ -64,7 +64,7 @@ options are: 'critical', 'emergency', 'error', 'warn' and 'debug'.
@@ -3971,7 +3971,7 @@ index 515aa73..da13dc8 100644
 +Set the number of times any attempt to depsolve before we just give up. This
 +shouldn't be needed as yum should always solve or fail, however it has been
 +observed that it can loop forever with very large system upgrades. Setting
-+this to `0' (or "forever") makes yum try forever. Default is `100'.
++this to `0' (or "<forever>") makes yum try forever. Default is `100'.
  
  
  .SH "[repository] OPTIONS"
@@ -4663,10 +4663,10 @@ index c60fa08..0000000
 -ts run
 -exit
 diff --git a/etc/yum.bash b/etc/yum.bash
-index f1e06e8..40541af 100644
+index f1e06e8..16d096c 100644
 --- a/etc/yum.bash
 +++ b/etc/yum.bash
-@@ -1,53 +1,25 @@
+@@ -1,53 +1,27 @@
  # bash completion for yum
  
 -# arguments:
@@ -4731,11 +4731,13 @@ index f1e06e8..40541af 100644
 -        -- "$2" ) )
 +    # Fail fast for things that look like paths or options.
 +    [[ $2 == */* || $2 == [.~-]* ]] && return
++    # Listing all available packages takes way too long
++    [[ $1 != "installed" && ${#2} -lt 1 ]] && return
 +    _yum_helper list "$@"
  }
  
  # arguments:
-@@ -56,7 +28,7 @@ _yum_grouplist()
+@@ -56,7 +30,7 @@ _yum_grouplist()
  _yum_plugins()
  {
      local val
@@ -4744,7 +4746,7 @@ index f1e06e8..40541af 100644
      COMPREPLY+=( $( compgen -W '$( command grep -il "^\s*enabled\s*=\s*$val" \
          /etc/yum/pluginconf.d/*.conf 2>/dev/null \
          | sed -ne "s|^.*/\([^/]\{1,\}\)\.conf$|\1|p" )' -- "$2" ) )
-@@ -75,9 +47,10 @@ _yum_baseopts()
+@@ -75,9 +49,10 @@ _yum_baseopts()
  {
      local opts='--help --tolerant --cacheonly --config --randomwait
          --debuglevel --showduplicates --errorlevel --rpmverbosity --quiet
@@ -4757,7 +4759,7 @@ index f1e06e8..40541af 100644
      [[ $COMP_LINE == *--noplugins* ]] || \
          opts+=" --disableplugin --enableplugin"
      printf %s "$opts"
-@@ -89,6 +62,16 @@ _yum_transactions()
+@@ -89,6 +64,16 @@ _yum_transactions()
          sed -ne 's/^[[:space:]]*\([0-9]\{1,\}\).*/\1/p' )" -- "$cur" ) )
  }
  
@@ -4774,7 +4776,7 @@ index f1e06e8..40541af 100644
  # arguments:
  #   1 = current word to be completed
  #   2 = previous word
-@@ -119,18 +102,20 @@ _yum_complete_baseopts()
+@@ -119,18 +104,20 @@ _yum_complete_baseopts()
              ;;
  
          --enablerepo)
@@ -4800,7 +4802,7 @@ index f1e06e8..40541af 100644
              return 0
              ;;
  
-@@ -183,16 +168,16 @@ _yum()
+@@ -183,16 +170,16 @@ _yum()
  
      # Commands offered as completions
      local cmds=( check check-update clean deplist distro-sync downgrade
@@ -4821,7 +4823,7 @@ index f1e06e8..40541af 100644
              [[ ${words[i]} == $c ]] && cmd=$c && break
          done
      done
-@@ -205,13 +190,12 @@ _yum()
+@@ -205,13 +192,12 @@ _yum()
              return 0
              ;;
  
@@ -4837,7 +4839,7 @@ index f1e06e8..40541af 100644
                  COMPREPLY=( $( compgen -W 'expire-cache packages headers
                      metadata cache dbcache all' -- "$cur" ) )
              return 0
-@@ -224,59 +208,83 @@ _yum()
+@@ -224,59 +210,83 @@ _yum()
              ;;
  
          distro-sync|distribution-synchronization)
@@ -4937,7 +4939,7 @@ index f1e06e8..40541af 100644
                      ;;
              esac
              return 0
-@@ -288,42 +296,66 @@ _yum()
+@@ -288,42 +298,66 @@ _yum()
              ;;
  
          install)
@@ -5011,7 +5013,7 @@ index f1e06e8..40541af 100644
                  COMPREPLY=( $( compgen -W 'all installed available nogroups
                      grouplist groupinfo' -- "$cur" ) )
              return 0
-@@ -337,7 +369,11 @@ _yum()
+@@ -337,7 +371,11 @@ _yum()
  
      $split && return 0
  
@@ -5025,7 +5027,7 @@ index f1e06e8..40541af 100644
  complete -F _yum -o filenames yum yummain.py
  
 diff --git a/output.py b/output.py
-index b6aa277..e42702e 100755
+index b6aa277..041910c 100755
 --- a/output.py
 +++ b/output.py
 @@ -1,6 +1,6 @@
@@ -6209,6 +6211,15 @@ index b6aa277..e42702e 100755
          if len(remote_pkgs) <= 1:
              return
          if not hasattr(urlgrabber.progress, 'TerminalLine'):
+@@ -1280,7 +1837,7 @@ to exit.
+         if dl_time <= 0: # This stops divide by zero, among other problems
+             dl_time = 0.01
+         ui_size = tl.add(' | %5sB' % self.format_number(remote_size))
+-        ui_time = tl.add(' %9s' % self.format_time(dl_time))
++        ui_time = tl.add('  %s' % self.format_time(dl_time, tl._llen > 80))
+         ui_end  = tl.add(' ' * 5)
+         ui_bs   = tl.add(' %5sB/s' % self.format_number(remote_size / dl_time))
+         msg = "%s%s%s%s%s" % (utf8_width_fill(_("Total"), tl.rest(), tl.rest()),
 @@ -1434,10 +1991,21 @@ to exit.
          return tids, printall
  
@@ -184587,10 +184598,10 @@ index 0000000..28e1964
 +- Check if we're running as root; exit nicely.
 diff --git a/yum-cron/yum-cron.py b/yum-cron/yum-cron.py
 new file mode 100755
-index 0000000..dd0a4c6
+index 0000000..a1fd10b
 --- /dev/null
 +++ b/yum-cron/yum-cron.py
-@@ -0,0 +1,1154 @@
+@@ -0,0 +1,721 @@
 +#!/usr/bin/python -tt
 +import os
 +import sys
@@ -184614,6 +184625,7 @@ index 0000000..dd0a4c6
 +
 +# FIXME: is it really sane to use this from here?
 +sys.path.append('/usr/share/yum-cli')
++from output import YumOutput
 +import callback
 +
 +default_config_file = '/etc/yum/yum-cron.conf'
@@ -184629,25 +184641,23 @@ index 0000000..dd0a4c6
 +        self.opts  = opts
 +        self.output = []
 +
-+    def updatesAvailable(self, tsInfo):
++    def updatesAvailable(self, summary):
 +        """Appends a message to the output list stating that there are
 +        updates available.
 +
-+        :param tsInfo: A :class:`yum.transactioninfo.TransactionData`
-+           instance that contains information about the transaction.
++        :param summary: A human-readable summary of the transaction.
 +        """
 +        self.output.append('The following updates are available on %s:' % self.opts.system_name)
-+        self.output.append(self._formatTransaction(tsInfo))
++        self.output.append(summary)
 +
-+    def updatesDownloading(self, tsInfo):
++    def updatesDownloading(self, summary):
 +        """Append a message to the output list stating that
 +        downloading updates has started.
 +
-+        :param tsInfo: A :class:`yum.transactioninfo.TransactionData`
-+           instance that contains information about the transaction.
++        :param summary: A human-readable summary of the transaction.
 +        """
 +        self.output.append('The following updates will be downloaded on %s:' % self.opts.system_name)
-+        self.output.append(self._formatTransaction(tsInfo))
++        self.output.append(summary)
 +
 +    def updatesDownloaded(self):
 +        """Append a message to the output list stating that updates
@@ -184655,15 +184665,14 @@ index 0000000..dd0a4c6
 +        """
 +        self.output.append("Updates downloaded successfully.")
 +
-+    def updatesInstalling(self, tsInfo):
++    def updatesInstalling(self, summary):
 +        """Append a message to the output list stating that
 +        installing updates has started.
 +
-+        :param tsInfo: A :class:`yum.transactioninfo.TransactionData`
-+           instance that contains information about the transaction.
++        :param summary: A human-readable summary of the transaction.
 +        """
 +        self.output.append('The following updates will be applied on %s:' % self.opts.system_name)
-+        self.output.append(self._formatTransaction(tsInfo))
++        self.output.append(summary)
 +
 +    def updatesInstalled(self):
 +        """Append a message to the output list stating that updates
@@ -184748,448 +184757,6 @@ index 0000000..dd0a4c6
 +        """
 +        pass
 +
-+    def _format_number(self, number, SI=0, space=' '):
-+        """Return a human-readable metric-like string representation
-+        of a number.
-+
-+        :param number: the number to be converted to a human-readable form
-+        :param SI: If is 0, this function will use the convention
-+           that 1 kilobyte = 1024 bytes, otherwise, the convention
-+           that 1 kilobyte = 1000 bytes will be used
-+        :param space: string that will be placed between the number
-+           and the SI prefix
-+        :return: a human-readable metric-like string representation of
-+           *number*
-+        """
-+        symbols = [ ' ', # (none)
-+                    'k', # kilo
-+                    'M', # mega
-+                    'G', # giga
-+                    'T', # tera
-+                    'P', # peta
-+                    'E', # exa
-+                    'Z', # zetta
-+                    'Y'] # yotta
-+    
-+        if SI: step = 1000.0
-+        else: step = 1024.0
-+    
-+        thresh = 999
-+        depth = 0
-+        max_depth = len(symbols) - 1
-+    
-+        # we want numbers between 0 and thresh, but don't exceed the length
-+        # of our list.  In that event, the formatting will be screwed up,
-+        # but it'll still show the right number.
-+        while number > thresh and depth < max_depth:
-+            depth  = depth + 1
-+            number = number / step
-+    
-+        if type(number) == type(1) or type(number) == type(1L):
-+            format = '%i%s%s'
-+        elif number < 9.95:
-+            # must use 9.95 for proper sizing.  For example, 9.99 will be
-+            # rounded to 10.0 with the .1f format string (which is too long)
-+            format = '%.1f%s%s'
-+        else:
-+            format = '%.0f%s%s'
-+    
-+        return(format % (float(number or 0), space, symbols[depth]))
-+
-+    def _fmtColumns(self, columns, msg=u'', end=u'', text_width=utf8_width):
-+        """Return a row of data formatted into a string for output.
-+        Items can overflow their columns. 
-+
-+        :param columns: a list of tuples containing the data to
-+           output.  Each tuple contains first the item to be output,
-+           then the amount of space allocated for the column, and then
-+           optionally a type of highlighting for the item
-+        :param msg: a string to begin the line of output with
-+        :param end: a string to end the line of output with
-+        :param text_width: a function to find the width of the items
-+           in the columns.  This defaults to utf8 but can be changed
-+           to len() if you know it'll be fine
-+        :return: a row of data formatted into a string for output
-+        """
-+        total_width = len(msg)
-+        data = []
-+        for col_data in columns[:-1]:
-+            (val, width) = col_data
-+
-+            if not width: # Don't count this column, invisible text
-+                msg += u"%s"
-+                data.append(val)
-+                continue
-+
-+            (align, width) = self._fmt_column_align_width(width)
-+            val_width = text_width(val)
-+            if val_width <= width:
-+                #  Don't use utf8_width_fill() because it sucks performance
-+                # wise for 1,000s of rows. Also allows us to use len(), when
-+                # we can.
-+                msg += u"%s%s "
-+                if (align == u'-'):
-+                    data.extend([val, " " * (width - val_width)])
-+                else:
-+                    data.extend([" " * (width - val_width), val])
-+            else:
-+                msg += u"%s\n" + " " * (total_width + width + 1)
-+                data.append(val)
-+            total_width += width
-+            total_width += 1
-+        (val, width) = columns[-1]
-+        (align, width) = self._fmt_column_align_width(width)
-+        val = utf8_width_fill(val, width, left=(align == u'-'))
-+        msg += u"%%s%s" % end
-+        data.append(val)
-+        return msg % tuple(data)
-+
-+    def _calcColumns(self, data, total_width, columns=None, remainder_column=0, indent=''):
-+        """Dynamically calculate the widths of the columns that the
-+        fields in data should be placed into for output.
-+        
-+        :param data: a list of dictionaries that represent the data to
-+           be output.  Each dictionary in the list corresponds to annn
-+           column of output. The keys of the dictionary are the
-+           lengths of the items to be output, and the value associated
-+           with a key is the number of items of that length.
-+        :param total_width: the total width of the output.
-+        :param columns: a list containing the minimum amount of space
-+           that must be allocated for each row. This can be used to
-+           ensure that there is space available in a column if, for
-+           example, the actual lengths of the items being output
-+           cannot be given in *data*
-+        :param remainder_column: number of the column to receive a few
-+           extra spaces that may remain after other allocation has
-+           taken place
-+        :param indent: string that will be prefixed to a line of
-+           output to create e.g. an indent
-+        :return: a list of the widths of the columns that the fields
-+           in data should be placed into for output
-+        """
-+        if total_width is None:
-+            total_width = self.term.columns
-+
-+        cols = len(data)
-+        # Convert the data to ascending list of tuples, (field_length, pkgs)
-+        pdata = data
-+        data  = [None] * cols # Don't modify the passed in data
-+        for d in range(0, cols):
-+            data[d] = sorted(pdata[d].items())
-+
-+        #  We start allocating 1 char to everything but the last column, and a
-+        # space between each (again, except for the last column). Because
-+        # at worst we are better with:
-+        # |one two three|
-+        # | four        |
-+        # ...than:
-+        # |one two three|
-+        # |            f|
-+        # |our          |
-+        # ...the later being what we get if we pre-allocate the last column, and
-+        # thus. the space, due to "three" overflowing it's column by 2 chars.
-+        if columns is None:
-+            columns = [1] * (cols - 1)
-+            columns.append(0)
-+
-+        total_width -= (sum(columns) + (cols - 1) +
-+                        utf8_width(indent))
-+        if not columns[-1]:
-+            total_width += 1
-+        while total_width > 0:
-+            # Find which field all the spaces left will help best
-+            helps = 0
-+            val   = 0
-+            for d in xrange(0, cols):
-+                thelps = self._calc_columns_spaces_helps(columns[d], data[d],
-+                                                         total_width)
-+                if not thelps:
-+                    continue
-+                #  We prefer to overflow: the last column, and then earlier
-+                # columns. This is so that in the best case (just overflow the
-+                # last) ... grep still "works", and then we make it prettier.
-+                if helps and (d == (cols - 1)) and (thelps / 2) < helps:
-+                    continue
-+                if thelps < helps:
-+                    continue
-+                helps = thelps
-+                val   = d
-+
-+            #  If we found a column to expand, move up to the next level with
-+            # that column and start again with any remaining space.
-+            if helps:
-+                diff = data[val].pop(0)[0] - columns[val]
-+                if not columns[val] and (val == (cols - 1)):
-+                    #  If we are going from 0 => N on the last column, take 1
-+                    # for the space before the column.
-+                    total_width  -= 1
-+                columns[val] += diff
-+                total_width  -= diff
-+                continue
-+
-+            overflowed_columns = 0
-+            for d in xrange(0, cols):
-+                if not data[d]:
-+                    continue
-+                overflowed_columns += 1
-+            if overflowed_columns:
-+                #  Split the remaining spaces among each overflowed column
-+                # equally
-+                norm = total_width / overflowed_columns
-+                for d in xrange(0, cols):
-+                    if not data[d]:
-+                        continue
-+                    columns[d] += norm
-+                    total_width -= norm
-+
-+            #  Split the remaining spaces among each column equally, except the
-+            # last one. And put the rest into the remainder column
-+            cols -= 1
-+            norm = total_width / cols
-+            for d in xrange(0, cols):
-+                columns[d] += norm
-+            columns[remainder_column] += total_width - (cols * norm)
-+            total_width = 0
-+
-+        return columns
-+
-+    @staticmethod
-+    def _fmt_column_align_width(width):
-+        if width < 0:
-+            return (u"-", -width)
-+        return (u"", width)
-+
-+    @staticmethod
-+    def _calc_columns_spaces_helps(current, data_tups, left):
-+        """ Spaces left on the current field will help how many pkgs? """
-+        ret = 0
-+        for tup in data_tups:
-+            if left < (tup[0] - current):
-+                break
-+            ret += tup[1]
-+        return ret
-+
-+    def _formatTransaction(self, tsInfo):
-+        """Return a string containing a human-readable formatted
-+        summary of the transaction.
-+        
-+        :param tsInfo: :class:`yum.transactioninfo.TransactionData`
-+           instance that contains information about the transaction
-+        :return: a string that contains a formatted summary of the
-+           transaction
-+           """
-+        # Sort the packages in the transaction into different lists,
-+        # e.g. installed, updated etc
-+        tsInfo.makelists(True, True)
-+
-+        # For each package list, pkglist_lines will contain a tuple
-+        # that contains the name of the list, and a list of tuples
-+        # with information about each package in the list
-+        pkglist_lines = []
-+        data  = {'n' : {}, 'v' : {}, 'r' : {}}
-+        a_wid = 0 # Arch can't get "that big" ... so always use the max.
-+
-+
-+        def _add_line(lines, data, a_wid, po, obsoletes=[]):
-+            # Create a tuple of strings that contain the name, arch,
-+            # version, repository, size, and obsoletes of the package
-+            # given in po.  Then, append this tuple to lines.  The
-+            # strings are formatted so that the tuple can be easily
-+            # joined together for output.
-+
-+            
-+            (n,a,e,v,r) = po.pkgtup
-+            
-+            # Retrieve the version, repo id, and size of the package
-+            # in human-readable form
-+            evr = po.printVer()
-+            repoid = po.ui_from_repo
-+            size = self._format_number(float(po.size))
-+
-+            if a is None: # gpgkeys are weird
-+                a = 'noarch'
-+
-+            lines.append((n, a, evr, repoid, size, obsoletes))
-+            #  Create a dict of field_length => number of packages, for
-+            # each field.
-+            for (d, v) in (("n",len(n)), ("v",len(evr)), ("r",len(repoid))):
-+                data[d].setdefault(v, 0)
-+                data[d][v] += 1
-+            a_wid = max(a_wid, len(a))
-+
-+            return a_wid
-+
-+        ninstalled = self.tsInfo.installed
-+        ginstalled = {}
-+        if self.conf.group_command == 'objects' and ninstalled:
-+            # Show new pkgs. that are installed via. a group.
-+            ninstalled = []
-+            for txmbr in self.tsInfo.installed:
-+                if not hasattr(txmbr, '_ugroup_member'):
-+                    ninstalled.append(txmbr)
-+                    continue
-+                if txmbr._ugroup_member not in ginstalled:
-+                    ginstalled[txmbr._ugroup_member] = []
-+                ginstalled[txmbr._ugroup_member].append(txmbr)
-+
-+        for grp in sorted(ginstalled, key=lambda x: x.ui_name):
-+            action = _('Installing for group upgrade "%s"') % grp.ui_name
-+            pkglist = ginstalled[grp]
-+
-+            lines = []
-+            for txmbr in pkglist:
-+                a_wid = _add_line(lines, data, a_wid, txmbr.po, txmbr.obsoletes)
-+
-+            pkglist_lines.append((action, lines))        
-+
-+        # Iterate through the different groups of packages
-+        for (action, pkglist) in [(_('Installing'), ninstalled),
-+                            (_('Updating'), tsInfo.updated),
-+                            (_('Removing'), tsInfo.removed),
-+                            (_('Reinstalling'), tsInfo.reinstalled),
-+                            (_('Downgrading'), tsInfo.downgraded),
-+                            (_('Installing for dependencies'), tsInfo.depinstalled),
-+                            (_('Updating for dependencies'), tsInfo.depupdated),
-+                            (_('Removing for dependencies'), tsInfo.depremoved)]:
-+            # Create a list to hold the tuples of strings for each package
-+            lines = []
-+
-+            # Append the tuple for each package to lines, and update a_wid
-+            for txmbr in pkglist:
-+                a_wid = _add_line(lines, data, a_wid, txmbr.po, txmbr.obsoletes)
-+
-+            # Append the lines instance for this package list to pkglist_lines
-+            pkglist_lines.append((action, lines))
-+
-+        # # Iterate through other package lists
-+        # for (action, pkglist) in [(_('Skipped (dependency problems)'),
-+        #                            self.skipped_packages),
-+        #                           (_('Not installed'), self._not_found_i.values()),
-+        #                           (_('Not available'), self._not_found_a.values())]:
-+        #     lines = []
-+        #     for po in pkglist:
-+        #         a_wid = _add_line(lines, data, a_wid, po)
-+
-+        #     pkglist_lines.append((action, lines))
-+
-+        if not data['n']:
-+            return u''
-+        else:
-+            # Change data to a list with the correct number of
-+            # columns, in the correct order
-+            data    = [data['n'],    {}, data['v'], data['r'], {}]
-+
-+            
-+             
-+            # Calculate the space needed for each column
-+            columns = [1,         a_wid,         1,         1,  5]
-+
-+            columns = self._calcColumns(data, self.opts.output_width,
-+                                        columns, remainder_column = 2, indent="  ")
-+
-+            (n_wid, a_wid, v_wid, r_wid, s_wid) = columns
-+            assert s_wid == 5
-+
-+            # out will contain the output as a list of strings, that
-+            # can be later joined together
-+            out = [u"""
-+%s
-+%s
-+%s
-+""" % ('=' * self.opts.output_width,
-+       self._fmtColumns(((_('Package'), -n_wid), (_('Arch'), -a_wid),
-+                        (_('Version'), -v_wid), (_('Repository'), -r_wid),
-+                        (_('Size'), s_wid)), u" "),
-+       '=' * self.opts.output_width)]
-+
-+        # Add output for each package list in pkglist_lines
-+        for (action, lines) in pkglist_lines:
-+            #If the package list is empty, skip it
-+            if not lines:
-+                continue
-+
-+            # Add the name of the package list
-+            totalmsg = u"%s:\n" % action
-+            # Add a line of output about an individual package
-+            for (n, a, evr, repoid, size, obsoletes) in lines:
-+                columns = ((n,   -n_wid), (a,      -a_wid),
-+                           (evr, -v_wid), (repoid, -r_wid), (size, s_wid))
-+                msg = self._fmtColumns(columns, u" ", u"\n")
-+                for obspo in sorted(obsoletes):
-+                    appended = _('     replacing  %s.%s %s\n')
-+                    appended %= (obspo.name,
-+                                 obspo.arch, obspo.printVer())
-+                    msg = msg+appended
-+                totalmsg = totalmsg + msg
-+
-+            # Append the line about the individual package to out
-+            out.append(totalmsg)
-+
-+        # Add a summary of the transaction
-+        out.append(_("""
-+Transaction Summary
-+%s
-+""") % ('=' * self.opts.output_width))
-+        summary_data =  (
-+            (_('Install'), len(tsInfo.installed),
-+             len(tsInfo.depinstalled)),
-+            (_('Upgrade'), len(tsInfo.updated),
-+             len(tsInfo.depupdated)),
-+            (_('Remove'), len(tsInfo.removed),
-+             len(tsInfo.depremoved)),
-+            (_('Reinstall'), len(tsInfo.reinstalled), 0),
-+            (_('Downgrade'), len(tsInfo.downgraded), 0),
-+            # (_('Skipped (dependency problems)'), len(self.skipped_packages), 0),
-+            # (_('Not installed'), len(self._not_found_i.values()), 0),
-+            # (_('Not available'), len(self._not_found_a.values()), 0),
-+        )
-+        max_msg_action   = 0
-+        max_msg_count    = 0
-+        max_msg_pkgs     = 0
-+        max_msg_depcount = 0
-+        for action, count, depcount in summary_data:
-+            if not count and not depcount:
-+                continue
-+
-+            msg_pkgs = P_('Package', 'Packages', count)
-+            len_msg_action   = utf8_width(action)
-+            len_msg_count    = utf8_width(str(count))
-+            len_msg_pkgs     = utf8_width(msg_pkgs)
-+
-+            if depcount:
-+                len_msg_depcount = utf8_width(str(depcount))
-+            else:
-+                len_msg_depcount = 0
-+
-+            max_msg_action   = max(len_msg_action,   max_msg_action)
-+            max_msg_count    = max(len_msg_count,    max_msg_count)
-+            max_msg_pkgs     = max(len_msg_pkgs,     max_msg_pkgs)
-+            max_msg_depcount = max(len_msg_depcount, max_msg_depcount)
-+
-+        for action, count, depcount in summary_data:
-+            msg_pkgs = P_('Package', 'Packages', count)
-+            if depcount:
-+                msg_deppkgs = P_('Dependent package', 'Dependent packages',
-+                                 depcount)
-+                if count:
-+                    msg = '%s  %*d %s (+%*d %s)\n'
-+                    out.append(msg % (utf8_width_fill(action, max_msg_action),
-+                                      max_msg_count, count,
-+                                      utf8_width_fill(msg_pkgs, max_msg_pkgs),
-+                                      max_msg_depcount, depcount, msg_deppkgs))
-+                else:
-+                    msg = '%s  %*s %s ( %*d %s)\n'
-+                    out.append(msg % (utf8_width_fill(action, max_msg_action),
-+                                      max_msg_count, '',
-+                                      utf8_width_fill('', max_msg_pkgs),
-+                                      max_msg_depcount, depcount, msg_deppkgs))
-+            elif count:
-+                msg = '%s  %*d %s\n'
-+                out.append(msg % (utf8_width_fill(action, max_msg_action),
-+                                  max_msg_count, count, msg_pkgs))
-+
-+        return ''.join(out)
-+
 +
 +class EmailEmitter(UpdateEmitter):
 +    """Emitter class to send messages via email."""
@@ -185198,14 +184765,13 @@ index 0000000..dd0a4c6
 +        super(EmailEmitter, self).__init__(opts)        
 +        self.subject = ""
 +
-+    def updatesAvailable(self, tsInfo):
++    def updatesAvailable(self, summary):
 +        """Appends a message to the output list stating that there are
 +        updates available, and set an appropriate subject line.
 +
-+        :param tsInfo: A :class:`yum.transactioninfo.TransactionData`
-+           instance that contains information about the transaction.
++        :param summary: A human-readable summary of the transaction.
 +        """
-+        super(EmailEmitter, self).updatesAvailable(tsInfo)
++        super(EmailEmitter, self).updatesAvailable(summary)
 +        self.subject = "Yum: Updates Available on %s" % self.opts.system_name
 +
 +    def updatesDownloaded(self):
@@ -185278,6 +184844,9 @@ index 0000000..dd0a4c6
 +        """Combine the stored messages that have been stored into a
 +        single email message, and send this message.
 +        """
++        # Don't send empty emails
++        if not self.output:
++            return
 +        # Build up the email to be sent
 +        msg = MIMEText(''.join(self.output))
 +        msg['Subject'] = self.subject
@@ -185301,6 +184870,9 @@ index 0000000..dd0a4c6
 +        """Combine the stored messages that have been stored into a
 +        single email message, and send this message to standard output.
 +        """
++        # Don't print blank lines
++        if not self.output:
++            return
 +        print "".join(self.output)
 +
 +
@@ -185325,7 +184897,7 @@ index 0000000..dd0a4c6
 +    group_package_types = ListOption(['mandatory', 'default'])
 +
 +
-+class YumCronBase(yum.YumBase):
++class YumCronBase(yum.YumBase, YumOutput):
 +    """Main class to check for and apply the updates."""
 +
 +    def __init__(self, config_file_name = None):
@@ -185335,9 +184907,12 @@ index 0000000..dd0a4c6
 +           config file to use.
 +        """
 +        yum.YumBase.__init__(self)
++        YumOutput.__init__(self)
 +
 +        # Read the config file
 +        self.readConfigFile(config_file_name)
++        self.term.reinit(color='never')
++        self.term.columns = self.opts.output_width
 +
 +
 +        # Create the emitters, and add them to the list
@@ -185675,11 +185250,13 @@ index 0000000..dd0a4c6
 +
 +    def emitAvailable(self):
 +        """Emit a notice stating whether updates are available."""
-+        map(lambda x: x.updatesAvailable(self.tsInfo), self.emitters)
++        summary = self.listTransaction()
++        map(lambda x: x.updatesAvailable(summary), self.emitters)
 +
 +    def emitDownloading(self):
 +        """Emit a notice stating that updates are downloading."""
-+        map(lambda x: x.updatesDownloading(self.tsInfo), self.emitters)
++        summary = self.listTransaction()
++        map(lambda x: x.updatesDownloading(summary), self.emitters)
 +
 +    def emitDownloaded(self):
 +        """Emit a notice stating that updates have downloaded."""
@@ -185689,7 +185266,8 @@ index 0000000..dd0a4c6
 +        """Emit a notice stating that automatic updates are about to
 +        be applied.
 +        """
-+        map(lambda x: x.updatesInstalling(self.tsInfo), self.emitters)
++        summary = self.listTransaction()
++        map(lambda x: x.updatesInstalling(summary), self.emitters)
 +
 +    def emitInstalled(self):
 +        """Emit a notice stating that automatic updates have been applied."""
@@ -186957,7 +186535,7 @@ index c1af4ad..70de539 100644
      pass
      
 diff --git a/yum/__init__.py b/yum/__init__.py
-index 99039e0..f212884 100644
+index 99039e0..caafae4 100644
 --- a/yum/__init__.py
 +++ b/yum/__init__.py
 @@ -21,6 +21,7 @@ The Yum RPM software updater.
@@ -187941,7 +187519,7 @@ index 99039e0..f212884 100644
          # check to see that the rpmdb and the tsInfo roughly matches
          # push package object metadata outside of rpmdb into yumdb
          # delete old yumdb metadata entries
-@@ -1584,9 +1913,16 @@ class YumBase(depsolve.Depsolve):
+@@ -1584,24 +1913,40 @@ class YumBase(depsolve.Depsolve):
          #    that there is not also an install of this pkg in the tsInfo (reinstall)
          # for any kind of install add from_repo to the yumdb, and the cmdline
          # and the install reason
@@ -187958,8 +187536,11 @@ index 99039e0..f212884 100644
          for txmbr in self.tsInfo:
              if txmbr.output_state in TS_INSTALL_STATES:
                  if not self.rpmdb.contains(po=txmbr.po):
-@@ -1596,12 +1932,21 @@ class YumBase(depsolve.Depsolve):
-                                            ' but is not!' % txmbr.po))
+                     # maybe a file log here, too
+                     # but raising an exception is not going to do any good
+                     self.logger.critical(_('%s was supposed to be installed' \
+-                                           ' but is not!' % txmbr.po))
++                                           ' but is not!') % txmbr.po)
                      # Note: Get Panu to do te.Failed() so we don't have to
                      txmbr.output_state = TS_FAILED
 +                    count = _call_txmbr_cb(txmbr, count)
@@ -193067,7 +192648,7 @@ index d09511f..c38d574 100644
  
          if name not in cfgOptions and option.default == value:
 diff --git a/yum/depsolve.py b/yum/depsolve.py
-index 6d744c0..8b438bb 100644
+index 6d744c0..95c21bc 100644
 --- a/yum/depsolve.py
 +++ b/yum/depsolve.py
 @@ -31,13 +31,15 @@ from transactioninfo import TransactionMember
@@ -193387,18 +192968,19 @@ index 6d744c0..8b438bb 100644
          if not len(self.tsInfo):
              return (0, [_('Success - empty transaction')])
  
-@@ -740,7 +869,9 @@ class Depsolve(object):
+@@ -740,7 +869,11 @@ class Depsolve(object):
  
          if self.dsCallback: self.dsCallback.start()
  
--        while True:
 +        depsolve_loop_count = 0
-+        while depsolve_loop_count < self.conf.depsolve_loop_limit:
+         while True:
++            if depsolve_loop_count == (self.conf.depsolve_loop_limit or -1):
++                return (1, [_("Depsolving loop limit reached.")] + unique(errors))
 +            depsolve_loop_count += 1
  
              CheckDeps = True
  
-@@ -778,6 +909,12 @@ class Depsolve(object):
+@@ -778,6 +911,12 @@ class Depsolve(object):
                      if checkdep:
                          break # The next conflict might be the same pkg
  
@@ -193411,17 +192993,7 @@ index 6d744c0..8b438bb 100644
                  if CheckDeps:
                      if self.dsCallback: self.dsCallback.restartLoop()
                      self.verbose_logger.log(logginglevels.DEBUG_1, _('Restarting Loop'))
-@@ -785,6 +922,9 @@ class Depsolve(object):
- 
-             break
- 
-+        if depsolve_loop_count >= self.conf.depsolve_loop_limit:
-+            return (1, [_("Depsolving loop limit reached.")] + unique(errors))
-+
-         # FIXME: this doesn't belong here at all...
-         for txmbr in self.tsInfo.getMembers():
-             if self.allowedMultipleInstalls(txmbr.po) and \
-@@ -920,9 +1060,12 @@ class Depsolve(object):
+@@ -920,9 +1059,12 @@ class Depsolve(object):
  
          # if this is an update, we should check what the old
          # requires were to make things faster
@@ -193436,7 +193008,7 @@ index 6d744c0..8b438bb 100644
          oldreqs = set(oldreqs)
  
          ret = []
-@@ -948,7 +1091,7 @@ class Depsolve(object):
+@@ -948,7 +1090,7 @@ class Depsolve(object):
                      continue
                  for member in self.tsInfo.getMembersWithState(
                      pkgtup=po.pkgtup, output_states=TS_INSTALL_STATES):
@@ -193445,7 +193017,7 @@ index 6d744c0..8b438bb 100644
  
          return ret
  
-@@ -974,12 +1117,36 @@ class Depsolve(object):
+@@ -974,12 +1116,36 @@ class Depsolve(object):
              # FIXME: This is probably the best place to fix the postfix rename
              # problem long term (post .21) ... see compare_providers.
              for pkg, hits in self.tsInfo.getRequires(*prov).iteritems():
@@ -193483,7 +193055,7 @@ index 6d744c0..8b438bb 100644
                      #  We don't undo anything else here ... hopefully that's
                      # fine.
                      self.tsInfo.remove(txmbr.pkgtup)
-@@ -1033,10 +1200,10 @@ class Depsolve(object):
+@@ -1033,10 +1199,10 @@ class Depsolve(object):
  
          # get file requirements from new packages
          for txmbr in self._tsInfo.getMembersWithState(output_states=TS_INSTALL_STATES):
@@ -193496,7 +193068,7 @@ index 6d744c0..8b438bb 100644
                      # check if file requires was already unresolved in update
                      if name in self.installedUnresolvedFileRequires:
                          already_broken = False
-@@ -1050,6 +1217,7 @@ class Depsolve(object):
+@@ -1050,6 +1216,7 @@ class Depsolve(object):
                          nfileRequires.add(name)
                      fileRequires.add(name)
                      reverselookup.setdefault(name, []).append(txmbr.po.pkgtup)
@@ -193504,7 +193076,7 @@ index 6d744c0..8b438bb 100644
  
          todel = []
          for fname in self.installedFileProviders:
-@@ -1149,7 +1317,74 @@ class Depsolve(object):
+@@ -1149,7 +1316,74 @@ class Depsolve(object):
          self.rpmdb.transactionCacheConflictPackages(cpkgs)
          return ret
  
@@ -193579,7 +193151,7 @@ index 6d744c0..8b438bb 100644
          lst = self.tsInfo.matchNaevr(name = pkgname)
          for txmbr in lst:
              if txmbr.output_state in TS_INSTALL_STATES:
-@@ -1166,7 +1401,7 @@ class Depsolve(object):
+@@ -1166,7 +1400,7 @@ class Depsolve(object):
          return True
      _isPackageInstalled = isPackageInstalled
  
@@ -193588,7 +193160,7 @@ index 6d744c0..8b438bb 100644
          """take the list of pkgs and score them based on the requesting package
             return a dictionary of po=score"""
          self.verbose_logger.log(logginglevels.DEBUG_4,
-@@ -1210,6 +1445,24 @@ class Depsolve(object):
+@@ -1210,6 +1444,24 @@ class Depsolve(object):
                  return None
              return x
  
@@ -193613,7 +193185,7 @@ index 6d744c0..8b438bb 100644
          #  Actual start of _compare_providers().
  
          # Do a NameArch filtering, based on repo. __cmp__
-@@ -1332,6 +1585,29 @@ class Depsolve(object):
+@@ -1332,6 +1584,29 @@ class Depsolve(object):
                          _('common prefix of %s between %s and %s' % (cpl, po, reqpo)))
                  
                      pkgresults[po] += cpl*2
@@ -193643,7 +193215,7 @@ index 6d744c0..8b438bb 100644
                  
          #  If we have more than one "best", see what would happen if we picked
          # each package ... ie. what things do they require that _aren't_ already
-@@ -1393,42 +1669,52 @@ class Depsolve(object):
+@@ -1393,42 +1668,52 @@ class Depsolve(object):
  
  
  class DepCheck(object):
diff --git a/yum.spec b/yum.spec
index dd81d8b..8a68136 100644
--- a/yum.spec
+++ b/yum.spec
@@ -60,7 +60,7 @@ BuildRequires: bash-completion
 Summary: RPM package installer/updater/manager
 Name: yum
 Version: 3.4.3
-Release: 121%{?dist}
+Release: 122%{?dist}
 License: GPLv2+
 Group: System Environment/Base
 Source0: http://yum.baseurl.org/download/3.4/%{name}-%{version}.tar.gz
@@ -444,6 +444,14 @@ exit 0
 %endif
 
 %changelog
+* Fri Dec 13 2013 Zdenek Pavlas <zpavlas at redhat.com> - 3.4.3-122
+- update to latest HEAD
+- use the same "Total" formatting as urlgrabber.progress
+- fix the depsolve_loop_limit=0 case. BZ 1041395
+- yum.bash: skip pkglist completion when len(prefix) < 1. BZ 1040033
+- yum-cron: stderr/email: no output if no messages. BZ 1018068
+- yum-cron: use YumOutput.listTransaction(). BZ 1040109
+
 * Fri Dec  6 2013 James Antill <james at fedoraproject.org> - 3.4.3-121
 - Fix cacheReq manipulation overwrite.
 - Only look at enabled repos. for cacheReq cookie comparisons. BZ 1039028.


More information about the scm-commits mailing list