Placing Packages On Media: An Ugly Abuse of Smart

Darrin Thompson darrint at progeny.com
Thu Feb 16 09:01:52 PST 2006


All,

I wrote a script to snarf a apt-deb repository of packages and calculate
an order of packages appropriate for placing on physical media. At this
point all it does is dump out an order and any errors it found.

The method I use runs a little too slow on really large repositories and
is probably bad for other reasons.

Basically I create an isolated sandbox for smart and put a channel in
it. Then I attempt to install each package in an individual transaction.
The bad hack is that I've hijacked the commitChangeSet method and just
intercept the "callbacks" of the commitTransactionStepped.

I'd appreciate feedback on this.

--
Darrin

from smart.transaction import Transaction, PolicyInstall,
ChangeSetSplitter
from smart import init, hooks, sysconf, iface
from smart.const import NEVER, INSTALL, REMOVE
from smart.control import ChangeSet
from smart.cache import Cache
from smart.transaction import Failed as TransactionFailed

from pprint import pprint as pp
from optparse import OptionParser

control = init(datadir = 'smart-data')

def get_opts():
    usage = 'USAGE: testit.py [-a arch] url suite components...'

    parser = OptionParser(usage = usage)
    op = parser.add_option
    op('-a', '--arch', dest = 'arch',
       help = 'Debian architecture to scan', metavar = 'ARCH')
    opts, args = parser.parse_args()
    if len(args) < 3:
        parser.error("Too few arguments given.")
        sys.exit(1)
    return opts, args

opts, args = get_opts()

url = args[0]
suite = args[1]
components = ' '.join(args[2:])

sysconf.set(('channels', 'pdk'),
    { 'baseurl': url,
      'components': components,
      'disabled': False,
      'distribution': suite,
      'fingerprint': '',
      'manual': False,
      'name': 'Command Line',
      'priority': 0,
      'removable': False,
      'type': 'apt-deb'})
if opts.arch:
    sysconf.set('deb-arch', opts.arch)

pp(sysconf.get(('channels')))
pp(sysconf.get(('deb-arch')))
control.rebuildSysConfChannels()
control.reloadChannels(caching = NEVER)

cache = control.getCache()

packages = cache.getPackages()

class CommitFaker(object):
    def __init__(self):
        self.clusters = []
        self.already_installed = Cache()

    def fakeCommitChangeSet(self, changeset, **dummy):
        media_group = []
        for package, op in changeset.iteritems():
            if op is INSTALL:
                media_group.append(package)
                package.installed = True
            elif op is REMOVE:
                pass

        self.clusters.append(media_group)

    def attach(self, control):
        control.commitChangeSet = self.fakeCommitChangeSet

faker = CommitFaker()
faker.attach(control)

total = len(packages)
prog = iface.getProgress(cache)
prog.setTopic("Solving...")
prog.set(0, total)
prog.show()

errors = []
for count, package in enumerate(packages):
    prog.set(count, total)
    prog.show()
    trans = Transaction(cache, PolicyInstall)
    trans.enqueue(package, INSTALL)
    try:
        trans.run()
    except TransactionFailed, error:
        errors.append(str(error))
    control.commitTransactionStepped(trans, confirm=False)

prog.setDone()
prog.show()
prog.stop()

for cluster in faker.clusters:
    cluster.sort()
    print " ", cluster

pp(errors)





More information about the Smart mailing list