#!/usr/bin/python


#nice apt-get -s -o Debug::NoLocking=true upgrade | grep ^Inst 

import apt_pkg
import os
import sys
from optparse import OptionParser
from gettext import gettext as _
import gettext
SYNAPTIC_PINFILE = "/var/lib/synaptic/preferences"

def clean(cache,depcache):
    # mvo: looping is too inefficient with the new auto-mark code
    #for pkg in cache.Packages:
    #    depcache.MarkKeep(pkg)
    depcache.Init()

def saveDistUpgrade(cache,depcache):
    """ this functions mimics a upgrade but will never remove anything """
    depcache.Upgrade(True)
    if depcache.DelCount > 0:
        clean(cache,depcache)
    depcache.Upgrade()

def _handleException(type, value, tb):
    sys.stderr.write("E: "+ "Unkown Error: '%s' (%s)" % (type,value))
    sys.exit(-1)


def isSecurityUpgrade(ver):
    " check if the given version is a security update (or masks one) "
    for (file, index) in ver.FileList:
        if (file.Archive.endswith("-security") and
            file.Origin == "Ubuntu"):
            return True
    return False
    

# -------------------- main ---------------------
        
# be nice
os.nice(19)

# setup a exception handler to make sure that uncaught stuff goes
# to the notifier
sys.excepthook = _handleException

# gettext
APP="update-notifier"
DIR="/usr/share/locale"
gettext.bindtextdomain(APP, DIR)
gettext.textdomain(APP)

# check arguments
parser = OptionParser()
parser.add_option("-p",
                  "--package-names",
                  action="store_true",
                  dest="show_package_names",
                  help="show the packages that are going to be installed/upgraded")
(options, args) = parser.parse_args()
#print options.security_only

# init
apt_pkg.init()

# get caches
try:
    cache = apt_pkg.GetCache()
except SystemError, e:
    sys.stderr.write("E: "+ _("Error: Opening the cache (%s)") % e)
    sys.exit(-1)
depcache = apt_pkg.GetDepCache(cache)

# read the pin files
depcache.ReadPinFile()
# read the synaptic pins too
if os.path.exists(SYNAPTIC_PINFILE):
    depcache.ReadPinFile(SYNAPTIC_PINFILE)

# init the depcache
depcache.Init()

if depcache.BrokenCount > 0:
    sys.stderr.write("E: "+ _("Error: BrokenCount > 0"))
    sys.exit(-1)

# do the upgrade (not dist-upgrade!)
try:
    saveDistUpgrade(cache,depcache)
except SystemError, e:
    sys.stderr.write("E: "+ _("Error: Marking the upgrade (%s)") % e)
    sys.exit(-1)

# check for upgrade packages, we need to do it this way
# because of ubuntu #7907
upgrades = 0
security_updates = 0
for pkg in cache.Packages:
    if depcache.MarkedInstall(pkg) or depcache.MarkedUpgrade(pkg):
        inst_ver = pkg.CurrentVer
        cand_ver = depcache.GetCandidateVer(pkg)
        # check if this is really a upgrade or a false positive
        # (workaround for ubuntu #7907)
	if cand_ver != inst_ver:
            # check for security upgrades
            upgrades = upgrades + 1	
            if isSecurityUpgrade(cand_ver):
                security_updates += 1
            # now check for security updates that are masked by a 
            # canidate version from another repo (-proposed or -updates)
            for ver in pkg.VersionList:
                if (inst_ver and apt_pkg.VersionCompare(ver.VerStr, inst_ver.VerStr) <= 0):
                    #print "skipping '%s' " % ver.VerStr
                    continue
                if isSecurityUpgrade(ver):
                    security_updates += 1
                    break

# print the number of upgrades
if options.show_package_names:
    pkgs = filter(lambda pkg: depcache.MarkedInstall(pkg) or depcache.MarkedUpgrade(pkg), cache.Packages)
    sys.stderr.write("\n".join(map(lambda p: p.Name, pkgs)))
else:
    # print the number of regular upgrades and the number of 
    # security upgrades
    sys.stderr.write("%s;%s" % (upgrades,security_updates))

sys.exit(0)
