Searching for Updates without emerge

The normal way to see which installed packages have available updates on Gentoo is running

$ emerge -puv world

And then you usually select the packages you really want to update and emerge them. However this workflow has several downsides:

  1. It’s slow. When portage checks for updates this way it fully resolves all the dependencies. This process is unnecessary, as in many cases you aren’t interested in updating all the packages, furthermore in their dependencies.
  2. It may fail. When portage fails to resolve the dependencies, it will either complain or completely fail. If it complains, it isn’t really that bad, except for the time used for resolving the unanswered dependencies. Sometimes it fails completely (usually when masking is involved) and won’t display any of the available packages, hence leaving the user in the dark (except for some dependency error message).
  3. It displays lot’s of output. Many times you’re not interesting in seeing the dependencies that will be updated if you emerge every package in the world file. It’s just confusing and distract you from the interesting updates for packages in the world file.

The following scripts tries to work around these problems. It works by querying the portage API for the best version available for each package in the world file. If that version isn’t installed it reports that there are updates waiting for that package. The script runs faster then emerge -pvu world and only displays the packages from the world file. If you find a package that you want to upgrade you can emerge it separately to see the required dependencies.

#! /usr/bin/env python

#   Copyright 2010 Guy Rutenberg

#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.

#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.

#   You should have received a copy of the GNU General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.


import portage
import logging
import subprocess
from optparse import OptionParser

class MainApp:
    def __init__(self,args=None):
        usage = "Usage: %prog [options]"
        version = "0.1"
        parser = OptionParser(usage,version=version)
        parser.add_option("","--kde", dest="kde",default=False,
                          action="store_true",
                          help="Post a notification with the number of update")
        parser.add_option("-q","--quiet", dest="quiet",default=False,
                          action="store_true",
                          help="Make as little output as possible")
        (self.options, self.args) = parser.parse_args(args=args)
    
    def run(self):
        self.updatable = set()
        for atom in self.get_world_entries():
            if self.get_best_version(atom) not in self.get_installed_versions(atom):
                self.updatable.add(atom)
                print atom
        if self.options.kde:
            self.notify_kde()
        if not self.options.quiet:
            print "Total:",len(self.updatable)

    def notify_kde(self):
        if len(self.updatable):
            text = "There are %i updates" % len(self.updatable)
        else:
            text = "There are no updates"
        subprocess.call(["kdialog", "--passivepopup", text, "--title", "Portage Updates"])
        
    @staticmethod
    def get_world_entries():
        """
        parses the world file and returns a set of all the atoms
        """
        f = open("/"+portage.WORLD_FILE, "r")
        atoms = set()
        for line in f.readlines():
            atom = line[:-1]
            if portage.isvalidatom(line[:-1]):
                atoms.add(atom)
        f.close()
        return atoms
    
    @staticmethod
    def get_installed_versions(atom):
        return portage.db['/']['vartree'].dbapi.match(atom)
    
    @staticmethod
    def get_best_version(atom):
        """
        Returns the best available version taking into account masking and
        keywords
        """
        available = portage.db['/']['porttree'].dbapi.match(atom)
        return portage.best(available)


if __name__ == "__main__":
    app = MainApp()
    app.run()


# vim: filetype=python ai ts=5 sts=4 et sw=4

One thought on “Searching for Updates without emerge”

  1. Thank you for the script, very useful! Just a small note: my version of python (3.2.2) requires passing the the arguments to print statement inside round brackets, but it’s easy to fix.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.