#!/usr/bin/python

import urllib2
import urlparse
import gzip
import sets
import re
import StringIO
import os

seeds = { 'base' : sets.Set(), 'desktop' : sets.Set() }
architectures = ['i386', 'amd64', 'powerpc']
archive_base = 'http://archive.ubuntu.com/ubuntu/'
dist = 'warty'
seed_base = 'http://wiki.ubuntu.com/WartyWarthog/'
seed_entry = re.compile(' *\* *(?P<package>\S+) *(#.*)?')
components = ['main', 'restricted']
debootstrap_version_file = 'debootstrap-version'
metapackages = map(lambda seed: 'ubuntu-' + seed, seeds.keys())
seed_package_blacklist = sets.Set(metapackages)
print seed_package_blacklist

def get_debootstrap_version():
    version = os.popen("dpkg-query -W --showformat '${Version}' debootstrap").read()
    if not version:
        raise RuntimeError('debootstrap does not appear to be installed')

    return version

def debootstrap_packages(arch):
    debootstrap = os.popen('debootstrap --arch %s --print-debs %s debootstrap-dir %s' % (arch,dist,archive_base))
    packages = debootstrap.read().split(' ')
    
    # sometimes debootstrap gives empty packages / multiple separators
    packages = filter(None, packages)
    
    packages.sort()

    return packages

def check_debootstrap_version():
    if os.path.exists(debootstrap_version_file):
        old_debootstrap_version = open(debootstrap_version_file).read().strip()
        debootstrap_version = get_debootstrap_version()
        failed = os.system("dpkg --compare-versions '%s' ge '%s'" % (debootstrap_version,
                                                                     old_debootstrap_version))
        if failed:
            raise RuntimeError('Installed debootstrap is older than in the previous version! (%s < %s)' % (
                debootstrap_version,
                old_debootstrap_version
                ))

def update_debootstrap_version():
    open(debootstrap_version_file, 'w').write(get_debootstrap_version() + '\n')

check_debootstrap_version()

print "Loading seed lists..."
for seed_name, seed in seeds.items():
    for line in urllib2.urlopen('http://wiki.ubuntu.com/WartyWarthog/%sSeed?action=raw' % seed_name.capitalize()):
        m = seed_entry.match(line)
        if m:
            package = m.group('package')
            if package not in seed_package_blacklist:
                seed.add(package)

print "Merging with available package lists..."
changes = []
for architecture in architectures:
    packages = sets.Set()
    debootstrap_base = sets.Set(debootstrap_packages(architecture))

    # Download Packages files
    for component in components:
        packages_url = urlparse.urljoin(archive_base,
                                        'dists/%s/%s/binary-%s/Packages.gz' % (dist, component, architecture))
        packages_file = StringIO.StringIO(urllib2.urlopen(packages_url).read())
        
        for line in gzip.GzipFile(fileobj=packages_file):
            if line.startswith('Package: '):
                package = line[9:].strip()
                packages.add(package)


    # Merge with seeds
    for seed_name, seed in seeds.items():
        output_filename = '%s-%s' % (seed_name,architecture)
        old_list = None
        if os.path.exists(output_filename):
            old_list = sets.Set(map(str.strip,open(output_filename).readlines()))
            os.rename(output_filename, output_filename + '.old')

        new_list = []
        for package in seed:
            if seed_name == 'base' and package not in debootstrap_base:
                continue
            
            if package in packages:
                new_list.append(package)

        new_list.sort()
        output = open(output_filename, 'w')
        for package in new_list:
            output.write(package)
            output.write('\n')
        output.close()
        

        # Calculate deltas
        if old_list is not None:
            merged = {}
            for package in new_list:
                merged.setdefault(package, 0)
                merged[package] += 1
            for package in old_list:
                merged.setdefault(package, 0)
                merged[package] -= 1

            for package, value in merged.items():
                #print package, value
                if value == 1:
                    changes.append('Added %s to %s' % (package, output_filename))
                elif value == -1:
                    changes.append('Removed %s from %s' % (package, output_filename))

if changes:
    os.system("dch -i 'Refreshed from seed lists and package archive'")
    for change in changes:
        print change
        os.system("dch -a '%s'" % change)
    update_debootstrap_version()
else:
    print "No changes found"
