!C99Shell v. 1.0 pre-release build #16!

Software: Apache/2.0.54 (Fedora). PHP/5.0.4 

uname -a: Linux mina-info.me 2.6.17-1.2142_FC4smp #1 SMP Tue Jul 11 22:57:02 EDT 2006 i686 

uid=48(apache) gid=48(apache) groups=48(apache)
context=system_u:system_r:httpd_sys_script_t
 

Safe-mode: OFF (not secure)

/usr/share/rhn/up2date_client/   drwxr-xr-x
Free 3.84 GB of 27.03 GB (14.21%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     packageList.py (29.13 KB)      -rwxr-xr-x
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
#!/usr/bin/python
#
# Package list mangling
#
# $Id: packageList.py,v 1.70 2005/05/17 17:43:25 alikins Exp $

import os
import fnmatch
import string
import sys
sys.path.insert(0, "/usr/share/rhn/")
sys.path.insert(1,"/usr/share/rhn/up2date_client")

import rpm
# temp home for all the package list related functions
# move this to a class
import up2dateUtils
import up2dateLog
import up2dateErrors
import up2dateComps
import config
import rpmUtils
import headers
import rhnPackageInfo
import transaction

from rhpl.translate import _
import rhpl.arch

#grab an instance of the config class shared
cfg = config.initUp2dateConfig()

# get a reference to the log file object
log = up2dateLog.initLog()



# idea... a class to wrap everything in here...
#   we add all the info we need, and then call PackageList.getTransaction or
#    PackageList.runTransaction or something
#
#   needs to be able to handle adding packages for install/update/remove
#   and some set of standard options for those (--force?, --nodeps, --justdb,etc)
#
#   At the very least, this needs to be able to do what getUpdatedPackageList does
#
#
class PackageList:
    def __init__(self):
        # rpm transaction set flags
        self.nodeps = None
        self.force = None
        self.justdb = None
        # A hash keyed on the package name, and with a list of all the
        # packages with that name as a value
        self.__instPackagesHash = {}
        # A list of available packages
        self.__availPackagesList = []
        # A hash keyed on the package name, None as value
        self.__forcePackagesHash = {}
        # A hash keyed on the package (n, v, r, e, a), a list of
        # (n, v, r, e, a, obsol name, obsol ver, obsol sense) as values
        self.__obsolPackagesHash = {}
        # list of packages we should update but are marked to
        # be skipped for some reason. for ui stuff
        # (names with possible wildcards)
        self.__skipPatternList = []
        # Skipped packages
        self.__skippedPackagesList = []
        self.__obsoletedPackagesList = []
        self.__installedObsoletingPackageList = []

        self.noMatchesForComps = []
        self.noMatchesForGlobs = []


        self.msgCallback = None
        self.progressCallback = None
        self.refreshCallback = None
        # bit of a kluge to make a better ui
        self.ignoreMsgCallback = 1

    def __findLatestVersionAllArch(self, package_list):
        availPkgsDict = {}
        for pkg in package_list:
            pkgName = pkg[0]

            if not availPkgsDict.has_key(pkgName):
                availPkgsDict[pkgName] = [pkg]
                continue

            # Already seen this name
            ret = up2dateUtils.comparePackages(availPkgsDict[pkgName][0][:4], pkg[:4])
            if ret > 0:
                # don't care, we already have a better version
                continue
            if ret < 0:
                # Better version, replace the existing one
                if availPkgsDict.has_key(pkgName):
                    availPkgsDict[pkgName] =  [pkg]
                continue
            # same version, different arch
            if ret == 0:
                if availPkgsDict.has_key(pkgName):
                    availPkgsDict[pkgName].append(pkg)
                else:
                    availPkgsDict[pkgName] =  [pkg]
                continue
            # Package with a better architecture
            availPkgsDict[pkgName] = [pkg]


        values = availPkgsDict.values()
        tmplist = []
        for value in values:
            for i in value:
                tmplist.append(i)
        return tmplist

    def run(self):
        # based on getpdatedPackageList
        installedPackageList = rpmUtils.getInstalledPackageList(getArch=1)
        self.addInstalledPackages(installedPackageList)

        availList = rhnPackageInfo.getAvailableAllArchPackageList(self.msgCallback,
                                                                  self.progressCallback)
        if availList:
            self.addAvailablePackages(availList)

        obsList = rhnPackageInfo.obsoletesList(
            msgCallback = self.msgCallback,
            progressCallback = self.progressCallback )
        self.addObsoletePackages(obsList)

        if not cfg["forceInstall"]:
            self.addSkipPatterns(cfg["pkgSkipList"])

        
        # skipped packages and the packages to install
        # are self.getSkippedPackages and self.getPackagesToInstall

        
        
    def addInstalledPackages(self, installedPackages):
        for p in installedPackages:
            pName = p[0]
            if not self.__instPackagesHash.has_key(pName):
                self.__instPackagesHash[pName] = []
            self.__instPackagesHash[pName].append(p)

    def addAvailablePackages(self, availablePackages):
        for p in availablePackages:
            self.__availPackagesList.append(p)
        #print self.__availPackagesList

    def addForcePackages(self, forcePackages):
        for p in forcePackages:
            self.__forcePackagesHash[p] = None

    def addGlobs(self, listOfGlobs):
        availList = rhnPackageInfo.getAvailablePackageList()
        availNames = map(lambda a: a[0], availList)
       
        matches = []
        # list of stuff to ignore even if the user specified
        # glob strings tells us to, aka, "*-debuginfo" since
        # thats not what most users mean... I hope...
        if cfg.has_key('globStoppers'):
            unglobs = cfg['globStoppers']
        else:
            unglobs = ['*-debuginfo']

        # use a dict so we dont have to uniq later
        noMatches = {}
        for glob in listOfGlobs:
            for name in availNames:
                if fnmatch.fnmatch(name, glob):
                    for unglob in unglobs:
                        if not fnmatch.fnmatch(name, unglob):
                            matches.append(name)
                        else:
                # no point it adding it to the hash over and over
                if not noMatches.has_key(glob):
                                noMatches[glob] = None    
                else:
            if not noMatches.has_key(glob):
                        noMatches[glob] = None    
                        


        self.noMatchesForGlobs = noMatches.keys()

        if matches:
#            self.noMatchesForGlobs = 0
            self.addForcePackages(matches)

    def addComps(self, listOfComps):
        comps = up2dateComps.initComps()
        matches = []
        for comp in listOfComps:
            try:
                matches = matches + comps.pkgTree(comp)
            except KeyError:
                self.noMatchesForComps.append(comp)
                
        #uniq the list
        d = {}
        for i in matches:
            d[i] = i
        matches = d.keys()
        matches.sort()

        if matches:
            self.addForcePackages(matches)
            
    def addObsoletePackages(self, obsoletePackages):
        if obsoletePackages == None or len(obsoletePackages) == 0:
            return
        for p in obsoletePackages:
            key = tuple(p[:5])
            if not self.__obsolPackagesHash.has_key(key):
                self.__obsolPackagesHash[key] = []
            self.__obsolPackagesHash[key].append(p)

        self.__obsoletedPackageHash = {}
        for key in self.__obsolPackagesHash.keys():
            for obsInfo in self.__obsolPackagesHash[key]:
                if not self.__obsoletedPackageHash.has_key(obsInfo[5]):
                    self.__obsoletedPackageHash[obsInfo[5]] = []
                self.__obsoletedPackageHash[obsInfo[5]].append(obsInfo)
            # foo[obsoletingpackage] = (obs info, with [5] being the thing obsoleted)
            # ugh

    def addSkipPatterns(self, skipPatterns):
        for p in skipPatterns:
            self.__skipPatternList.append(p)

    def getInstalledPackages(self):
        return self.__instPackagesHash

    def getForcedPackages(self):
        return self.__forcePackagesHash
    
    def getObsoletedPackages(self):
        return self.__obsoletedPackagesList

    def getInstalledObsoletingPackages(self):
        return self.__installedObsoletingPackageList
    


    def getSkippedPackages(self):
        """
        Returns a list of packages that have been skipped, together with the
        reason why they've been skipped
        """
        # XXX
        return self.__skippedPackagesList

    # Is this package outdated by a an already installed package?
    def __outdatedByInstalledPackage(self, p):
        for inst in self.__instPackagesHash[p[0]]:
            ret = up2dateUtils.comparePackages(inst, p)
            if ret < 0:
                log.log_debug("p: %s is newer than inst: %s" % (
                    p, inst))
            else:
                # at least one of the installed versions is
                # new enough
                return 1

        # No installed package is newer than p
        return 0


    def __findOutdatedPackages(self):
        for p in self.__availPackagesList:
            pName = p[0]

            # is this package already installed?
            if self.__instPackagesHash.has_key(pName):
                # if so, we need to do version compare stuff

                # Installed
                # If the package is not outdated by an already installed
                # package, mark it as available for updates

                # FIXME: we dont have color info here, but we really
                # need it. In the meantime, we kind of sorta pretend that
                # same arch is the same as same color. This works, but it
                # means that upgrades from i386 to i686 will fail. For the
                # moment, proper behaviour in the face of multilib is more
                # important, so we use that workaround.


                # split packages into groups by arch
                archDict = {}
                for instPkg in self.__instPackagesHash[pName]:
                    if archDict.has_key(instPkg[4]):
                        archDict[instPkg[4]].append(instPkg)
                    else:
                        archDict[instPkg[4]]= [instPkg]

                # find any updates need on a per arch basis
                # handling cases where the different arches have different
                # versions installed, and the upstream has different versions
                # available for each arch, or they match
                for arch in archDict.keys():
                    packagesToAdd = []
                    for pkg in archDict[arch]:
                        if arch == p[4]:
                            ret = up2dateUtils.comparePackages(pkg, p)
                        elif arch == "noarch" or p[4] == "noarch":
                            ret = up2dateUtils.comparePackages(pkg, p)
                        else:
                            continue
                        if ret < 0:
                            packagesToAdd.append(p)
                        else:
                            # some package of this arch installed is
                            # newer than the package available of the same arch
                            # so, dont upgrade it
                            packagesToAdd = []
                break
                    for pkg in packagesToAdd:
                        self.__addPackageToUpdate(pkg)    
                
                        
                    

    # this could well get called _alot_
    def __findLatestPackage(self, name):
        pkgVersions = []
        for p in self.__availPackagesList:
            if p[0] == name:
                pkgVersions.append(p)

        pkgVersions.sort(up2dateUtils.comparePackages)
        pkgVersions.reverse()
        return pkgVersions[0]


    def __findLatestPackages(self, name):
        pkgVersions = []
        for p in self.__availPackagesList:
            if p[0] == name:
                pkgVersions.append(p)

        latest = pkgVersions[0]
        latestlist = []
        for pkgVersion in pkgVersions:
            ret = up2dateUtils.comparePackages(latest, pkgVersion)
            if ret < 0:
                #pkgVersion newer than latest
                latestlist = [pkgVersion]
            if ret == 0:
                latestlist.append(pkgVersion)
            
        return latestlist
            
    # is the package one of the packages we are installing/force upgrading?
    # assume we want to install the most recent
    def __findForcedPackages(self):
        fpHash = self.__forcePackagesHash
        for p in self.__availPackagesList:
            pName = p[0]

            if self.packagesToUpdate.has_key(pName):
                # we've got this package installed, continue
                continue
            
            if fpHash.has_key(pName):
                # if a version of the package is installed
                # look at all the available versions and pick the most recent
                latestpkgs = self.__findLatestPackages(pName)
                for latest in latestpkgs:
                    if self.__instPackagesHash.has_key(latest[0]):
                        # and the installed version isnt the same or newer than
                        # what we are forcing
                        for instPkg in self.__instPackagesHash[latest[0]]:
                            packagesToAdd = []
                            ret = up2dateUtils.comparePackages(instPkg, latest)
                            if cfg['forcedArch']:
                                arches = cfg['forcedArch']
                                if latest[4] in arches:
                    if ret <= 0:
                                        packagesToAdd.append(latest)
                            else:
                                # see if the arches are the same, this would fall out
                                # later in the arch selection code anyway
                                if instPkg[4] == latest[4]:
                                    if ret < 0:
                                        packagesToAdd.append(latest)
                                    else:
                                        packagesToAdd = []
                                    continue
                        for pkg in packagesToAdd:
                            self.__addPackageToUpdate(pkg)
                    # package insnt installed, install the latest version
                    else:
                        #FIXME: replace with color info when we get it
                        if cfg['forcedArch']:
                            arches = cfg['forcedArch']
                            if latest[4] in arches:
                                self.__addPackageToUpdate(latest)
                        else:
                            # this seems wrong, but the arch selection stuff later
                            # on takes care of making sure the best arch is picked
                            self.__addPackageToUpdate(latest)

    def __addPackageToUpdate(self,p):
        pName = p[0]
        if not self.packagesToUpdate.has_key(pName):
            self.packagesToUpdate[pName] = []
        # if we havent already added it to the list
        pkgsNVREA = map(lambda a: a[:5], self.packagesToUpdate[pName])
        if not p[:5] in pkgsNVREA:
            # see if we flagged this as something not to update (aka,
            # something with mulitple installed versions, one of which is new enough
            # need to be per arch, and later per color
            self.packagesToUpdate[pName].append(p)
#        else:
#            print "wtf: %s" % p

    def __findObsoletingPackages(self):
        for p in self.__availPackagesList:
            pName = p[0]

            if self.packagesToUpdate.has_key(pName):
                # we're already updating this package
                found = 0
                for packageToUpdate in self.packagesToUpdate[pName]:
                    if p[:5]  == packageToUpdate[:5]:
                        found = 1
                if found:
                    # were already updating this package
                    continue


            key = tuple(p[:5])
            if not self.__obsolPackagesHash.has_key(key):
                # Nothing to do here
                continue

            # this package obsoletes something
            for obs in self.__obsolPackagesHash[key]:
                obsName, obsVersion, obsSense = obs[5:]
                if obsSense == "0" or obsSense == 0:
                    # this package obsoletes all versions of
                    # obsName
                    if not self.__instPackagesHash.has_key(obsName):
                        continue
                    self.__addPackageToUpdate(p)
                    # any given one package can obsolete multiple packages
                    for obsP in self.__instPackagesHash[obsName]:
                        self.__obsoletedPackagesList.append((obsP,self.__obsoletedPackageHash[obsName]))
                    continue

                # loop over all the installed versions
                if not self.__instPackagesHash.has_key(obsName):
                    # Nothing to do
                    continue
                
                # obsName is installed
                for inst in self.__instPackagesHash[obsName]:
                    if up2dateUtils.isObsoleted(obs, inst, package=p):
                        self.__addPackageToUpdate(p)
                        for obsP in self.__instPackagesHash[obsName]:
                            self.__obsoletedPackagesList.append((obsP,self.__obsoletedPackageHash[obsName]))


    def isIa32E(self):
        # heh, dont ask. But if you must, see bz #155583
        if rhpl.arch.getBaseArch() == "ia32e":
            return 1
        return 0

    def __findBestArch(self, plist):
        bestArchP = None
        for p in plist:
            archscore = rpm.archscore(p[4])
            log.log_debug("archscore", archscore)
            if archscore <= 0:
                # Unsupported architecture
                continue
            # Dirty Dirty Dirty hack, see bz #155583
            # basically, rpm.archscore thinks that "x86_64" is a compatiable arch for
            # ia32e boxes. Which it is. Unless it is a kernel. So if someome says "up2date kernel-smp", up2date
            # will let them. Because aside from telling you, there is no way to tell that that is not going to
            # get you a bootable kernel. So we hardcode around it. Ugh.
          
            if p[0] == "kernel-smp":
                if p[4] == "x86_64":
                    if self.isIa32E():
                        # Haha! Fooled ya! Thats not actually a valid arch! Skip it. See above.
                        continue
            if bestArchP and rpm.archscore(bestArchP[4]) <= archscore:
                # The currently best arch is better than (or the same as)
                # this one
                continue

            # This is a better architecture
            bestArchP = p
        if bestArchP == None:
            log.log_me("Could not find an approriate arch for package %s, skipping" % plist)
            return None

        if bestArchP:
            return [bestArchP]
        return None

    def __findMatchingArch(self, plist, arches):
        bestArchPList = []
        for p in plist:
            if p[4] in arches:
                bestArchPList.append(p)
        return bestArchPList

            
    def __findBestArchPackages(self):
        hash = {}

        
        for pkey, plist in self.packagesToUpdate.items():
            # find all the packages that match the forced arch
            if cfg['forcedArch']:
                arches = cfg['forcedArch']
                matches = []
                for p in plist:
                    if p[4] in arches:
                        matches.append(p)
                for match in matches:
                    self.packagesToUpdate[pkey] = matches
                continue

            

            # ugly new mulitlib kluge... see if a particular arch
            # of a package is pulled in via a obsolete, if so, make sure
            # we don't remove it from the obs set
            added = 0
            packagesToAdd = []
            for p in plist:
                if self.__obsolPackagesHash.has_key(tuple(p[:5])):
                    obsPkgs = self.__obsolPackagesHash[tuple(p[:5])]
                    for obsPkg in obsPkgs:
                        if p not in packagesToAdd:
                            packagesToAdd.append(p)
                                                                                
            # try to pick only applicable arches of the packages were
            # adding because of obsoletes. This should handle the i686/athlon
            # kernel issues as well as the GDB/GDB64 issues.
            if len(packagesToAdd):
                arches = []
                if self.__instPackagesHash.has_key(pkey):
                     pkgs = self.__instPackagesHash[pkey]
                else:
                     pkgs = []

                for pkg in pkgs:
                     if pkg[4] not in arches:
                        arches.append(pkg[4])

                if arches == []:
                    newp = self.__findBestArch(packagesToAdd)
                else:
                    newp = self.__findMatchingArch(packagesToAdd, arches)

                if newp:
                    self.packagesToUpdate[pkey] = newp
                # we had to add this because of wacky obs, so skip the rest
                continue
                                                                                                                                                               

                
            if self.__instPackagesHash.has_key(pkey):
                pkgs = self.__instPackagesHash[pkey]
                if len(pkgs) > 1:
                    # we've currently got more than one copy of
                    # a package installed...
                    arches = []
                    for p in pkgs:
                        if p[4] not in arches:
                            arches.append(p[4])

                    # if we have more than one arch installed,
                    # then just choose the updates for the approriate matching
                    # arches
                    if len(arches) > 1:
                        newp = self.__findMatchingArch(plist,arches)
                        self.packagesToUpdate[pkey] = newp
                        continue
                elif len(pkgs) == 1:
                    newp = self.__findMatchingArch(plist, [pkgs[0][4]])
                    # we might not have a matching arch anymore
                    if not newp:
                        newp = self.__findBestArch(plist)
                    if newp:
                        self.packagesToUpdate[pkey] = newp
                        continue
                        
            newp = self.__findBestArch(plist)
            # newp can be None at this point, if no packages apply to this
            # system
            if newp:
                self.packagesToUpdate[pkey] = newp
            # if we dont have an approriate arch, delete it from available packages
            else:
                log.log_me("The latest version of %s was not available for this arch. Skipping" % pkey)
                del self.packagesToUpdate[pkey]


    # with the new mulitple repos we can have different versions of the same package
    # in different channels, we need to find the latest of the whole set
            

    def __sortPackageList(self):
        # FIXME: change this so the values of self.packagesToUpdate can be lists?
        values = self.packagesToUpdate.values()
        tmplist = []
        # flatten lists of lists
        for i in values:
            for j in i:
                tmplist.append(j)
        result = tmplist
        if len(result):
            result.sort(lambda a, b: cmp(a[0], b[0]))
        return result
            
    def getPackagesToInstall(self):
        # We put stuff in a hash to easily find packages
        hash = {}

        # hash of packages we need to update
        self.packagesToUpdate = {}

        self.__findOutdatedPackages()
        self.__findForcedPackages()
        self.__findObsoletingPackages()
#        self.__findLatestPackages()

        self.__findBestArchPackages()
#        self.__handleForcePackages()
        result = self.__sortPackageList()
        result = self.__skipPackages(result)
#        print result
        return result



    # list of failed deps if any
    # for ui stuff
    def failedDeps(self):
        pass

    # either return a rpm.TransactionSet object
    # or some similar representation
    def getTransaction(self):
        pass

    def __skipPackages(self, packageList):
        self.__skippedPackagesList = []

        for p_i in range(len(packageList)):
            for pattern in self.__skipPatternList:
                if fnmatch.fnmatch(packageList[p_i][0], pattern):
                    self.__skippedPackagesList.append((packageList[p_i], _("Pkg name/pattern")))

                    break

        for p in self.__skippedPackagesList:
            packageList.remove(p[0])

        packageList = self.__skipFiles(packageList)
        return packageList

    def __skipFiles(self, packageList):
        removedList = []
        if cfg['forceInstall']:
            return packageList

        # need the db for the checkHeaderFiles
    ts = transaction.initReadOnlyTransaction()
#        ts = rpm.TransactionSet()
#    ts.setVerifySigFlags(8)

        p_i = 0
    # FIXME: something seems wrong here, when we are
    # are checking for FileConfigExcludes, we try to load the
    # header of the installed version, which doesnt make sence
    # for the new package case
        h_list = buildHeaderList(packageList, msgCallback = self.msgCallback,
                                 progressCallback = self.progressCallback,
                                 refreshCallback = self.refreshCallback,
                                 ignoreMsgCallback = self.ignoreMsgCallback)
        for i in h_list:
            tmp_list = None
            tmp_list = rpmUtils.checkHeaderForFileConfigExcludes(i,packageList[p_i],ts)
            p_i = p_i + 1
            if tmp_list:
                removedList = removedList + tmp_list


        d = {}
        for i in removedList:
            d[tuple(i[0])] = i
        removedList = d.values()

        for p in removedList:
            packageList.remove(p[0])

        self.__skippedPackagesList = self.__skippedPackagesList + removedList
        return packageList



def getArchesOfAvailablePackages(availablePkgList,pkgName):
    archList = []
    for pkg in availablePkgList:
        if pkgName == pkg[0]:
            archList.append(pkg[4])

    return archList

def buildHeaderList(pkgList,msgCallback = None, progressCallback = None,
                            refreshCallback = None, ignoreMsgCallback=None):
    headerList = headers.initHeaderList()
    h_list = []
    count = 1
    total = len(pkgList)
    if msgCallback:
        msgCallback(_("Fetching rpm headers"))
    for pkg in pkgList:
        hdr = headerList[pkg]
        if hdr:
            h_list.append(hdr)
        # I dont want to do this in the batch mode, but it's nice
        # for the gui. Ugly, but better ui...
        if msgCallback and not ignoreMsgCallback:
            msgCallback(_("Fetching rpm header: %s-%s-%s") % (hdr['name'],hdr['version'],hdr['release']))
        if progressCallback:
            progressCallback(count, total)
        count = count + 1
    return h_list
            

# side effects on pkgList
# REFACTOR: this probabaly needs to stay module scope, as
# depSolver.__skip calls it
def removeSkipPackagesFromList(pkgList, msgCallback = None,
                               progressCallback = None):
    removedList = []
    pkgCount = len(pkgList)

    if cfg["forceInstall"]:
        return removedList

    if msgCallback != None:
        msgCallback(_("Removing packages marked to skip from list"))

    
    pkgSkipList = cfg["pkgSkipList"]
    if cfg["forceInstall"]:
        pkgSkipList = []

    for index in range(pkgCount):
        for pattern in pkgSkipList:
            if fnmatch.fnmatch(pkgList[index][0], pattern):
                removedList.append((pkgList[index], _("Pkg name/pattern")))
                break

        if progressCallback != None:
            progressCallback(index+1, pkgCount)

    for pkg in removedList:
        pkgList.remove(pkg[0])

    # just do a side effect on pkgList here, and return removedList
    # since we actually need the results of it
    return removedList


if __name__ == '__main__':
    installedPackageList = []
    pList = PackageList()
    for i in range(20):
        installedPackageList.append("a%04d" % i, '1.0', '1', '', 'noarch')
    pList.addInstalledPackages(installedPackageList)
    availablePackageList = []
    for i in range(30):
        for arch in ['noarch', 'i386', 'i586', 'i686', 'athlon']:
            availablePackageList.append("a%04d" % i, '2.0', '1', '', arch)

    print len(installedPackageList), len(availablePackageList)
    pList.addAvailablePackages(availablePackageList)

    forcePackageList = []
    for i in range(10):
        forcePackageList.append("a%04d" % (20 + 5 * i))
    
#    pList.addForcePackages(forcePackageList)

    obsList = [
        ('a0021', '2.0', '1', '', 'i686', 'a0019', '', 0),
        ('a0022', '2.0', '1', '', 'i686', 'a0018', '2.0-1', 2),
    ]
    pList.addObsoletePackages(obsList)

    pList.addSkipPatterns(["a0017", "a001[3-5]"])
    
    import time
    start = time.time()
    res = pList.getPackagesToInstall()
    print "Total time: %f" % (time.time() - start)
    print len(res)
    print res

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #16 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0062 ]--