summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS3
-rw-r--r--TODO5
-rw-r--r--aptsources/__init__.py1
-rw-r--r--aptsources/distinfo.py241
-rw-r--r--aptsources/distro.py430
-rw-r--r--aptsources/sourceslist.py428
-rw-r--r--data/templates/Debian.info.in98
-rw-r--r--data/templates/Debian.mirrors797
-rw-r--r--data/templates/README.templates46
-rw-r--r--data/templates/Ubuntu.info.in279
-rw-r--r--data/templates/Ubuntu.mirrors267
-rw-r--r--debian/control9
-rw-r--r--debian/python-apt.docs1
-rwxr-xr-xdebian/rules78
-rw-r--r--po/POTFILES.in3
-rw-r--r--po/python-apt.pot269
-rw-r--r--setup.cfg8
-rwxr-xr-x[-rw-r--r--]setup.py27
-rw-r--r--tests/data/sources.list6
-rw-r--r--tests/data/sources.list.testDistribution11
-rw-r--r--tests/test_aptsources.py127
-rwxr-xr-xutils/get_debian_mirrors.py71
-rwxr-xr-xutils/get_ubuntu_mirrors.py61
-rwxr-xr-xutils/get_ubuntu_mirrors_from_lp.py85
-rwxr-xr-xutils/mirrortest100
25 files changed, 3371 insertions, 80 deletions
diff --git a/AUTHORS b/AUTHORS
index 8a0feb1d..dc247ef8 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,3 +1,6 @@
jgg Jason Gunthorpe <jgg@debian.org>
mdz Matt Zimmerman <mdz@debian.org>
mvo Michael Vogt <mvo@debian.org>
+Michiel Sikkes <michiel@eyesopened.nl>
+Sebastian Heinlein <glatzor@ubuntu.com>
+Sean Wheller <sean@inwords.co.za>
diff --git a/TODO b/TODO
index f3f6a995..9fbf27c8 100644
--- a/TODO
+++ b/TODO
@@ -2,3 +2,8 @@
- change all candidateInstalledSize() to installSize(useCandidate=True)
same for candidateOrigin() (see downloadable for a example).
- might be better to have "Package.candidate.{downloadable,size,etc}
+
+* aptsources:
+ - make the distro detection in sources.list more clever by using the
+ origin informaton to avoid adding full uris to (unofficial/internal)
+ mirrors
diff --git a/aptsources/__init__.py b/aptsources/__init__.py
new file mode 100644
index 00000000..8d1c8b69
--- /dev/null
+++ b/aptsources/__init__.py
@@ -0,0 +1 @@
+
diff --git a/aptsources/distinfo.py b/aptsources/distinfo.py
new file mode 100644
index 00000000..d7289b4b
--- /dev/null
+++ b/aptsources/distinfo.py
@@ -0,0 +1,241 @@
+#!/usr/bin/env python
+#
+# distinfo.py - provide meta information for distro repositories
+#
+# Copyright (c) 2005 Gustavo Noronha Silva
+# 2006-2007 Sebastian Heinlein
+#
+# Author: Gustavo Noronha Silva <kov@debian.org>
+# Sebastian Heinlein <glatzor@ubuntu.com>
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+
+import os
+import gettext
+from os import getenv
+import ConfigParser
+import string
+
+from gettext import gettext as _
+
+import re
+
+class Template:
+ def __init__(self):
+ self.name = None
+ self.child = False
+ self.match_name = None
+ self.description = None
+ self.base_uri = None
+ self.type = None
+ self.components = []
+ self.children = []
+ self.match_uri = None
+ self.mirror_set = {}
+ self.distribution = None
+ self.available = True
+
+ def has_component(self, comp):
+ ''' Check if the distribution provides the given component '''
+ return comp in map(lambda c: c.name, self.components)
+
+ def is_mirror(self, url):
+ ''' Check if a given url of a repository is a valid mirror '''
+ proto, hostname, dir = split_url(url)
+ if self.mirror_set.has_key(hostname):
+ return self.mirror_set[hostname].has_repository(proto, dir)
+ else:
+ return False
+
+class Component:
+ def __init__(self, name, desc=None, long_desc=None):
+ self.name = name
+ self.description = desc
+ self.description_long = long_desc
+ def get_description(self):
+ if self.description_long != None:
+ return self.description_long
+ elif self.description != None:
+ return self.description
+ else:
+ return None
+ def set_description(self, desc):
+ self.description = desc
+ def set_description_long(self, desc):
+ self.description_long = desc
+ def get_description_long(self):
+ return self.description_long
+
+class Mirror:
+ ''' Storage for mirror related information '''
+ def __init__(self, proto, hostname, dir, location=None):
+ self.hostname = hostname
+ self.repositories = []
+ self.add_repository(proto, dir)
+ self.location = location
+ def add_repository(self, proto, dir):
+ self.repositories.append(Repository(proto, dir))
+ def get_repositories_for_proto(self, proto):
+ return filter(lambda r: r.proto == proto, self.repositories)
+ def has_repository(self, proto, dir):
+ return len(filter(lambda r: (r.proto == proto) and dir in r.dir,
+ self.repositories)) > 0
+ def get_repo_urls(self):
+ return map(lambda r: r.get_url(self.hostname), self.repositories)
+ def get_location(self):
+ return self.location
+ def set_location(self, location):
+ self.location = location
+
+class Repository:
+ def __init__(self, proto, dir):
+ self.proto = proto
+ self.dir = dir
+ def get_info(self):
+ return self.proto, self.dir
+ def get_url(self, hostname):
+ return "%s://%s/%s" % (self.proto, hostname, self.dir)
+
+def split_url(url):
+ ''' split a given URL into the protocoll, the hostname and the dir part '''
+ return map(lambda a,b: a, re.split(":*\/+", url, maxsplit=2),
+ [None, None, None])
+
+class DistInfo:
+ def __init__(self,
+ dist = None,
+ base_dir = "/usr/share/python-apt/templates"):
+ self.metarelease_uri = ''
+ self.templates = []
+
+ location = None
+ match_loc = re.compile(r"^#LOC:(.+)$")
+ match_mirror_line = re.compile(r"^(#LOC:.+)|(((http)|(ftp)|(rsync)|(file)|(https))://[A-Za-z/\.:\-_]+)$")
+ #match_mirror_line = re.compile(r".+")
+
+ if not dist:
+ pipe = os.popen("lsb_release -i -s")
+ dist = pipe.read().strip()
+ pipe.close()
+ del pipe
+
+ self.dist = dist
+
+
+ map_mirror_sets = {}
+
+ dist_fname = "%s/%s.info" % (base_dir, dist)
+ dist_file = open (dist_fname)
+ if not dist_file:
+ return
+ template = None
+ component = None
+ for line in dist_file:
+ tokens = line.split (':', 1)
+ if len (tokens) < 2:
+ continue
+ field = tokens[0].strip ()
+ value = tokens[1].strip ()
+ if field == 'ChangelogURI':
+ self.changelogs_uri = _(value)
+ elif field == 'MetaReleaseURI':
+ self.metarelease_uri = value
+ elif field == 'Suite':
+ if template:
+ if component and not template.has_component(component.name):
+ template.components.append(component)
+ component = None
+ self.templates.append(template)
+ template = Template()
+ template.name = value
+ template.distribution = dist
+ template.match_name = "^%s$" % value
+ elif field == 'MatchName':
+ template.match_name = value
+ elif field == 'ParentSuite':
+ template.child = True
+ for nanny in self.templates:
+ if nanny.name == value:
+ nanny.children.append(template)
+ # reuse some properties of the parent template
+ if template.match_uri == None:
+ template.match_uri = nanny.match_uri
+ if template.mirror_set == {}:
+ template.mirror_set = nanny.mirror_set
+ if template.base_uri == None:
+ template.base_uri = nanny.base_uri
+ elif field == 'Available':
+ template.available = value
+ elif field == 'RepositoryType':
+ template.type = value
+ elif field == 'BaseURI':
+ template.base_uri = value
+ template.match_uri = value
+ elif field == 'MatchURI':
+ template.match_uri = value
+ elif field == 'MirrorsFile':
+ if not map_mirror_sets.has_key(value):
+ mirror_set = {}
+ try:
+ mirror_data = filter(match_mirror_line.match,
+ map(string.strip, open(value)))
+ except:
+ print "ERROR: Failed to read mirror file"
+ mirrors = []
+ for line in mirror_data:
+ if line.startswith("#LOC:"):
+ location = match_loc.sub(r"\1", line)
+ continue
+ (proto, hostname, dir) = split_url(line)
+ if mirror_set.has_key(hostname):
+ mirror_set[hostname].add_repository(proto, dir)
+ else:
+ mirror_set[hostname] = Mirror(proto, hostname, dir, location)
+ map_mirror_sets[value] = mirror_set
+ template.mirror_set = map_mirror_sets[value]
+ elif field == 'Description':
+ template.description = _(value)
+ elif field == 'Component':
+ if component and not template.has_component(component.name):
+ template.components.append(component)
+ component = Component(value)
+ elif field == 'CompDescription':
+ component.set_description(_(value))
+ elif field == 'CompDescriptionLong':
+ component.set_description_long(_(value))
+ if template:
+ if component:
+ template.components.append(component)
+ component = None
+ self.templates.append(template)
+ template = None
+
+if __name__ == "__main__":
+ d = DistInfo ("Ubuntu", "/usr/share/python-apt/templates")
+ print d.changelogs_uri
+ for template in d.templates:
+ print "\nSuite: %s" % template.name
+ print "Desc: %s" % template.description
+ print "BaseURI: %s" % template.base_uri
+ print "MatchURI: %s" % template.match_uri
+ if template.mirror_set != {}:
+ print "Mirrors: %s" % template.mirror_set.keys()
+ for comp in template.components:
+ print " %s -%s -%s" % (comp.name,
+ comp.description,
+ comp.description_long)
+ for child in template.children:
+ print " %s" % child.description
diff --git a/aptsources/distro.py b/aptsources/distro.py
new file mode 100644
index 00000000..5b4c6522
--- /dev/null
+++ b/aptsources/distro.py
@@ -0,0 +1,430 @@
+# distro.py - Provide a distro abstraction of the sources.list
+#
+# Copyright (c) 2004-2007 Canonical Ltd.
+# 2006-2007 Sebastian Heinlein
+#
+# Authors: Sebastian Heinlein <glatzor@ubuntu.com>
+# Michael Vogt <mvo@debian.org>
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+
+import string
+import gettext
+import re
+import os
+import sys
+from gettext import gettext as _
+
+
+class Distribution:
+ def __init__(self, id, codename, description, release):
+ """ Container for distribution specific informations """
+ # LSB information
+ self.id = id
+ self.codename = codename
+ self.description = description
+ self.release = release
+
+ self.binary_type = "deb"
+ self.source_type = "deb-src"
+
+ def get_sources(self, sourceslist):
+ """
+ Find the corresponding template, main and child sources
+ for the distribution
+ """
+
+ self.sourceslist = sourceslist
+ # corresponding sources
+ self.source_template = None
+ self.child_sources = []
+ self.main_sources = []
+ self.disabled_sources = []
+ self.cdrom_sources = []
+ self.download_comps = []
+ self.enabled_comps = []
+ self.cdrom_comps = []
+ self.used_media = []
+ self.get_source_code = False
+ self.source_code_sources = []
+
+ # location of the sources
+ self.default_server = ""
+ self.main_server = ""
+ self.nearest_server = ""
+ self.used_servers = []
+
+ # find the distro template
+ for template in self.sourceslist.matcher.templates:
+ if self.is_codename(template.name) and\
+ template.distribution == self.id:
+ #print "yeah! found a template for %s" % self.description
+ #print template.description, template.base_uri, template.components
+ self.source_template = template
+ break
+ if self.source_template == None:
+ print "Error: could not find a distribution template"
+ # FIXME: will go away - only for debugging issues
+ sys.exit(1)
+
+ # find main and child sources
+ media = []
+ comps = []
+ cdrom_comps = []
+ enabled_comps = []
+ source_code = []
+ for source in self.sourceslist.list:
+ if source.invalid == False and\
+ self.is_codename(source.dist) and\
+ source.template and\
+ self.is_codename(source.template.name):
+ #print "yeah! found a distro repo: %s" % source.line
+ # cdroms need do be handled differently
+ if source.uri.startswith("cdrom:") and \
+ source.disabled == False:
+ self.cdrom_sources.append(source)
+ cdrom_comps.extend(source.comps)
+ elif source.uri.startswith("cdrom:") and \
+ source.disabled == True:
+ self.cdrom_sources.append(source)
+ elif source.type == self.binary_type and \
+ source.disabled == False:
+ self.main_sources.append(source)
+ comps.extend(source.comps)
+ media.append(source.uri)
+ elif source.type == self.binary_type and \
+ source.disabled == True:
+ self.disabled_sources.append(source)
+ elif source.type == self.source_type and source.disabled == False:
+ self.source_code_sources.append(source)
+ elif source.type == self.source_type and source.disabled == True:
+ self.disabled_sources.append(source)
+ if source.invalid == False and\
+ source.template in self.source_template.children:
+ if source.disabled == False and source.type == self.binary_type:
+ self.child_sources.append(source)
+ elif source.disabled == False and source.type == self.source_type:
+ self.source_code_sources.append(source)
+ else:
+ self.disabled_sources.append(source)
+ self.download_comps = set(comps)
+ self.cdrom_comps = set(cdrom_comps)
+ enabled_comps.extend(comps)
+ enabled_comps.extend(cdrom_comps)
+ self.enabled_comps = set(enabled_comps)
+ self.used_media = set(media)
+
+ self.get_mirrors()
+
+ def get_mirrors(self):
+ """
+ Provide a set of mirrors where you can get the distribution from
+ """
+ # the main server is stored in the template
+ self.main_server = self.source_template.base_uri
+
+ # other used servers
+ for medium in self.used_media:
+ if not medium.startswith("cdrom:"):
+ # seems to be a network source
+ self.used_servers.append(medium)
+
+ if len(self.main_sources) == 0:
+ self.default_server = self.main_server
+ else:
+ self.default_server = self.main_sources[0].uri
+
+ def add_source(self, type=None,
+ uri=None, dist=None, comps=None, comment=""):
+ """
+ Add distribution specific sources
+ """
+ if uri == None:
+ # FIXME: Add support for the server selector
+ uri = self.default_server
+ if dist == None:
+ dist = self.codename
+ if comps == None:
+ comps = list(self.enabled_comps)
+ if type == None:
+ type = self.binary_type
+ new_source = self.sourceslist.add(type, uri, dist, comps, comment)
+ # if source code is enabled add a deb-src line after the new
+ # source
+ if self.get_source_code == True and tpye == self.binary_type:
+ self.sourceslist.add(self.source_type, uri, dist, comps, comment,
+ file=new_source.file,
+ pos=self.sourceslist.list.index(new_source)+1)
+
+ def enable_component(self, comp):
+ """
+ Enable a component in all main, child and source code sources
+ (excluding cdrom based sources)
+
+ sourceslist: an aptsource.sources_list
+ comp: the component that should be enabled
+ """
+ def add_component_only_once(source, comps_per_dist):
+ """
+ Check if we already added the component to the repository, since
+ a repository could be splitted into different apt lines. If not
+ add the component
+ """
+ # if we don't that distro, just reutnr (can happen for e.g.
+ # dapper-update only in deb-src
+ if not comps_per_dist.has_key(source.dist):
+ return
+ # if we have seen this component already for this distro,
+ # return (nothing to do
+ if comp in comps_per_dist[source.dist]:
+ return
+ # add it
+ source.comps.append(comp)
+ comps_per_dist[source.dist].add(comp)
+
+ sources = []
+ sources.extend(self.main_sources)
+ sources.extend(self.child_sources)
+ # store what comps are enabled already per distro (where distro is
+ # e.g. "dapper", "dapper-updates")
+ comps_per_dist = {}
+ comps_per_sdist = {}
+ for s in sources:
+ if s.type == self.binary_type:
+ if not comps_per_dist.has_key(s.dist):
+ comps_per_dist[s.dist] = set()
+ map(comps_per_dist[s.dist].add, s.comps)
+ for s in self.source_code_sources:
+ if s.type == self.source_type:
+ if not comps_per_sdist.has_key(s.dist):
+ comps_per_sdist[s.dist] = set()
+ map(comps_per_sdist[s.dist].add, s.comps)
+
+ # check if there is a main source at all
+ if len(self.main_sources) < 1:
+ # create a new main source
+ self.add_source(comps=["%s"%comp])
+ else:
+ # add the comp to all main, child and source code sources
+ for source in sources:
+ add_component_only_once(source, comps_per_dist)
+
+ # check if there is a main source code source at all
+ if self.get_source_code == True:
+ if len(self.source_code_sources) < 1:
+ # create a new main source
+ self.add_source(type=self.source_type, comps=["%s"%comp])
+ else:
+ # add the comp to all main, child and source code sources
+ for source in self.source_code_sources:
+ add_component_only_once(source, comps_per_sdist)
+
+ def disable_component(self, comp):
+ """
+ Disable a component in all main, child and source code sources
+ (excluding cdrom based sources)
+ """
+ sources = []
+ sources.extend(self.main_sources)
+ sources.extend(self.child_sources)
+ sources.extend(self.source_code_sources)
+ if comp in self.cdrom_comps:
+ sources = []
+ sources.extend(self.main_sources)
+
+ for source in sources:
+ if comp in source.comps:
+ source.comps.remove(comp)
+ if len(source.comps) < 1:
+ self.sourceslist.remove(source)
+
+ def change_server(self, uri):
+ ''' Change the server of all distro specific sources to
+ a given host '''
+ sources = []
+ seen = []
+ self.default_server = uri
+ sources.extend(self.main_sources)
+ sources.extend(self.child_sources)
+ sources.extend(self.source_code_sources)
+ for source in sources:
+ # Avoid creating duplicate entries
+ source.uri = uri
+ for comp in source.comps:
+ if [source.uri, source.dist, comp] in seen:
+ source.comps.remove(comp)
+ else:
+ seen.append([source.uri, source.dist, comp])
+ if len(source.comps) < 1:
+ self.sourceslist.remove(source)
+
+ def is_codename(self, name):
+ ''' Compare a given name with the release codename. '''
+ if name == self.codename:
+ return True
+ else:
+ return False
+
+ def get_server_list(self):
+ ''' Return a list of used and suggested servers '''
+ # Store all available servers:
+ # Name, URI, active
+ mirrors = []
+
+ mirrors.append([_("Main server"), self.main_server,
+ len(self.used_servers) == 1 and
+ self.used_servers[0] == self.main_server])
+
+ if len(self.used_servers) == 1 and not re.match(self.used_servers[0],
+ self.main_server):
+ # Only one server is used
+ server = self.used_servers[0]
+ mirrors.append([server, server, True])
+ elif len(self.used_servers) > 1:
+ # More than one server is used. Since we don't handle this case
+ # in the user interface we set "custom servers" to true and
+ # append a list of all used servers
+ mirrors.append([_("Custom servers"), None, True])
+ for server in self.used_servers:
+ if not [server, server, False] in mirrors:
+ mirrors.append([server, server, False])
+
+ return mirrors
+
+ if len(self.used_servers) == 1 and not is_single_server(self.main_server):
+ mirrors.append(["%s" % self.used_servers[0],
+ self.used_servers[0], True])
+ elif len(self.used_servers) > 1 or not is_single_server(self.main_server):
+ mirrors.append([_("Custom servers"), None, True])
+
+ return mirrors
+
+
+class DebianDistribution(Distribution):
+ ''' Class to support specific Debian features '''
+
+ def is_codename(self, name):
+ ''' Compare a given name with the release codename and check if
+ if it can be used as a synonym for a development releases '''
+ if name == self.codename or self.release in ("testing", "unstable"):
+ return True
+ else:
+ return False
+
+class UbuntuDistribution(Distribution):
+ ''' Class to support specific Ubuntu features '''
+ def get_mirrors(self):
+ Distribution.get_mirrors(self)
+ # get a list of country codes and real names
+ self.countries = {}
+ try:
+ f = open("/usr/share/iso-codes/iso_3166.tab", "r")
+ lines = f.readlines()
+ for line in lines:
+ parts = line.split("\t")
+ self.countries[parts[0].lower()] = parts[1].strip()
+ except:
+ print "could not open file '%s'" % file
+ else:
+ f.close()
+
+ # try to guess the nearest mirror from the locale
+ self.country = None
+ self.country_code = None
+ locale = os.getenv("LANG", default="en.UK")
+ a = locale.find("_")
+ z = locale.find(".")
+ if z == -1:
+ z = len(locale)
+ country_code = locale[a+1:z].lower()
+ self.nearest_server = "http://%s.archive.ubuntu.com/ubuntu/" % \
+ country_code
+ if self.countries.has_key(country_code):
+ self.country = self.countries[country_code]
+ self.country_code = country_code
+
+ def get_server_list(self):
+ ''' Return a list of used and suggested servers '''
+
+ def get_mirror_name(server):
+ ''' Try to get a human readable name for the main mirror of a country'''
+ country = None
+ i = server.find("://")
+ l = server.find(".archive.ubuntu.com")
+ if i != -1 and l != -1:
+ country = server[i+len("://"):l]
+ if self.countries.has_key(country):
+ # TRANSLATORS: %s is a country
+ return _("Server for %s") % \
+ gettext.dgettext("iso-3166",
+ self.countries[country].rstrip()).rstrip()
+ else:
+ return("%s" % server)
+
+ # Store all available servers:
+ # Name, URI, active
+ mirrors = []
+ if len(self.used_servers) < 1 or \
+ (len(self.used_servers) == 1 and \
+ self.used_servers[0] == self.main_server):
+ mirrors.append([_("Main server"), self.main_server, True])
+ mirrors.append([get_mirror_name(self.nearest_server),
+ self.nearest_server, False])
+ elif len(self.used_servers) == 1 and not re.match(self.used_servers[0],
+ self.main_server):
+ mirrors.append([_("Main server"), self.main_server, False])
+ # Only one server is used
+ server = self.used_servers[0]
+
+ # Append the nearest server if it's not already used
+ if not re.match(server, self.nearest_server):
+ mirrors.append([get_mirror_name(self.nearest_server),
+ self.nearest_server, False])
+ mirrors.append([get_mirror_name(server), server, True])
+
+ elif len(self.used_servers) > 1:
+ # More than one server is used. Since we don't handle this case
+ # in the user interface we set "custom servers" to true and
+ # append a list of all used servers
+ mirrors.append([_("Main server"), self.main_server, False])
+ mirrors.append([get_mirror_name(self.nearest_server),
+ self.nearest_server, False])
+ mirrors.append([_("Custom servers"), None, True])
+ for server in self.used_servers:
+ if re.match(server, self.nearest_server):
+ continue
+ elif not [get_mirror_name(server), server, False] in mirrors:
+ mirrors.append([get_mirror_name(server), server, False])
+
+ return mirrors
+
+def get_distro():
+ ''' Check the currently used distribution and return the corresponding
+ distriubtion class that supports distro specific features. '''
+ lsb_info = []
+ for lsb_option in ["-i", "-c", "-d", "-r"]:
+ pipe = os.popen("lsb_release %s -s" % lsb_option)
+ lsb_info.append(pipe.read().strip())
+ del pipe
+ (id, codename, description, release) = lsb_info
+ if id == "Ubuntu":
+ return UbuntuDistribution(id, codename, description,
+ release)
+ elif id == "Debian":
+ return DebianDistribution(id, codename, description,
+ release)
+ else:
+ return Distribution(id, codename, description, relase)
diff --git a/aptsources/sourceslist.py b/aptsources/sourceslist.py
new file mode 100644
index 00000000..14c2a0ea
--- /dev/null
+++ b/aptsources/sourceslist.py
@@ -0,0 +1,428 @@
+# aptsource.py - Provide an abstraction of the sources.list
+#
+# Copyright (c) 2004-2007 Canonical Ltd.
+# 2004 Michiel Sikkes
+# 2006-2007 Sebastian Heinlein
+#
+# Author: Michiel Sikkes <michiel@eyesopened.nl>
+# Michael Vogt <mvo@debian.org>
+# Sebastian Heinlein <glatzor@ubuntu.com>
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+
+import string
+import gettext
+import re
+import apt_pkg
+import glob
+import shutil
+import time
+import os.path
+import sys
+from gettext import gettext as _
+#import pdb
+
+#from UpdateManager.Common.DistInfo import DistInfo
+from distinfo import DistInfo
+
+# some global helpers
+def is_mirror(master_uri, compare_uri):
+ """check if the given add_url is idential or a mirror of orig_uri
+ e.g. master_uri = archive.ubuntu.com
+ compare_uri = de.archive.ubuntu.com
+ -> True
+ """
+ # remove traling spaces and "/"
+ compare_uri = compare_uri.rstrip("/ ")
+ master_uri = master_uri.rstrip("/ ")
+ # uri is identical
+ if compare_uri == master_uri:
+ #print "Identical"
+ return True
+ # add uri is a master site and orig_uri has the from "XX.mastersite"
+ # (e.g. de.archive.ubuntu.com)
+ try:
+ compare_srv = compare_uri.split("//")[1]
+ master_srv = master_uri.split("//")[1]
+ #print "%s == %s " % (add_srv, orig_srv)
+ except IndexError: # ok, somethings wrong here
+ #print "IndexError"
+ return False
+ # remove the leading "<country>." (if any) and see if that helps
+ if "." in compare_srv and \
+ compare_srv[compare_srv.index(".")+1:] == master_srv:
+ #print "Mirror"
+ return True
+ return False
+
+def uniq(s):
+ """ simple and efficient way to return uniq list """
+ return list(set(s))
+
+class SourceEntry:
+ """ single sources.list entry """
+ def __init__(self, line,file=None):
+ self.invalid = False # is the source entry valid
+ self.disabled = False # is it disabled ('#' in front)
+ self.type = "" # what type (deb, deb-src)
+ self.uri = "" # base-uri
+ self.dist = "" # distribution (dapper, edgy, etc)
+ self.comps = [] # list of available componetns (may empty)
+ self.comment = "" # (optional) comment
+ self.line = line # the original sources.list line
+ if file == None:
+ file = apt_pkg.Config.FindDir("Dir::Etc")+apt_pkg.Config.Find("Dir::Etc::sourcelist")
+ self.file = file # the file that the entry is located in
+ self.parse(line)
+ self.template = None # type DistInfo.Suite
+ self.children = []
+
+ def __eq__(self, other):
+ """ equal operator for two sources.list entries """
+ return (self.disabled == other.disabled and
+ self.type == other.type and
+ self.uri == other.uri and
+ self.dist == other.dist and
+ self.comps == other.comps)
+
+
+ def mysplit(self, line):
+ """ a split() implementation that understands the sources.list
+ format better and takes [] into account (for e.g. cdroms) """
+ line = string.strip(line)
+ pieces = []
+ tmp = ""
+ # we are inside a [..] block
+ p_found = False
+ space_found = False
+ for i in range(len(line)):
+ if line[i] == "[":
+ p_found=True
+ tmp += line[i]
+ elif line[i] == "]":
+ p_found=False
+ tmp += line[i]
+ elif space_found and not line[i].isspace(): # we skip one or more space
+ space_found = False
+ pieces.append(tmp)
+ tmp = line[i]
+ elif line[i].isspace() and not p_found: # found a whitespace
+ space_found = True
+ else:
+ tmp += line[i]
+ # append last piece
+ if len(tmp) > 0:
+ pieces.append(tmp)
+ return pieces
+
+ def parse(self,line):
+ """ parse a given sources.list (textual) line and break it up
+ into the field we have """
+ line = string.strip(self.line)
+ #print line
+ # check if the source is enabled/disabled
+ if line == "" or line == "#": # empty line
+ self.invalid = True
+ return
+ if line[0] == "#":
+ self.disabled = True
+ pieces = string.split(line[1:])
+ # if it looks not like a disabled deb line return
+ if not pieces[0] in ("rpm", "rpm-src", "deb", "deb-src"):
+ self.invalid = True
+ return
+ else:
+ line = line[1:]
+ # check for another "#" in the line (this is treated as a comment)
+ i = line.find("#")
+ if i > 0:
+ self.comment = line[i+1:]
+ line = line[:i]
+ # source is ok, split it and see what we have
+ pieces = self.mysplit(line)
+ # Sanity check
+ if len(pieces) < 3:
+ self.invalid = True
+ return
+ # Type, deb or deb-src
+ self.type = string.strip(pieces[0])
+ # Sanity check
+ if self.type not in ("deb", "deb-src", "rpm", "rpm-src"):
+ self.invalid = True
+ return
+ # URI
+ self.uri = string.strip(pieces[1])
+ if len(self.uri) < 1:
+ self.invalid = True
+ # distro and components (optional)
+ # Directory or distro
+ self.dist = string.strip(pieces[2])
+ if len(pieces) > 3:
+ # List of components
+ self.comps = pieces[3:]
+ else:
+ self.comps = []
+
+ def set_enabled(self, new_value):
+ """ set a line to enabled or disabled """
+ self.disabled = not new_value
+ # enable, remove all "#" from the start of the line
+ if new_value == True:
+ i=0
+ self.line = string.lstrip(self.line)
+ while self.line[i] == "#":
+ i += 1
+ self.line = self.line[i:]
+ else:
+ # disabled, add a "#"
+ if string.strip(self.line)[0] != "#":
+ self.line = "#" + self.line
+
+ def __str__(self):
+ """ debug helper """
+ return self.str().strip()
+
+ def str(self):
+ """ return the current line as string """
+ if self.invalid:
+ return self.line
+ line = ""
+ if self.disabled:
+ line = "# "
+ line += "%s %s %s" % (self.type, self.uri, self.dist)
+ if len(self.comps) > 0:
+ line += " " + " ".join(self.comps)
+ if self.comment != "":
+ line += " #"+self.comment
+ line += "\n"
+ return line
+
+class NullMatcher(object):
+ """ a Matcher that does nothing """
+ def match(self, s):
+ return True
+
+class SourcesList:
+ """ represents the full sources.list + sources.list.d file """
+ def __init__(self,
+ withMatcher=True,
+ matcherPath="/usr/share/python-aptsources/templates/"):
+ self.list = [] # the actual SourceEntries Type
+ if withMatcher:
+ self.matcher = SourceEntryMatcher(matcherPath)
+ else:
+ self.matcher = NullMatcher()
+ self.refresh()
+
+ def refresh(self):
+ """ update the list of known entries """
+ self.list = []
+ # read sources.list
+ dir = apt_pkg.Config.FindDir("Dir::Etc")
+ file = apt_pkg.Config.Find("Dir::Etc::sourcelist")
+ self.load(dir+file)
+ # read sources.list.d
+ partsdir = apt_pkg.Config.FindDir("Dir::Etc::sourceparts")
+ for file in glob.glob("%s/*.list" % partsdir):
+ self.load(file)
+ # check if the source item fits a predefined template
+ for source in self.list:
+ if source.invalid == False:
+ self.matcher.match(source)
+
+ def __iter__(self):
+ """ simple iterator to go over self.list, returns SourceEntry
+ types """
+ for entry in self.list:
+ yield entry
+ raise StopIteration
+
+ def add(self, type, uri, dist, comps, comment="", pos=-1, file=None):
+ """
+ Add a new source to the sources.list.
+ The method will search for existing matching repos and will try to
+ reuse them as far as possible
+ """
+ # check if we have this source already in the sources.list
+ for source in self.list:
+ if source.disabled == False and source.invalid == False and \
+ source.type == type and uri == source.uri and \
+ source.dist == dist:
+ for new_comp in comps:
+ if new_comp in source.comps:
+ # we have this component already, delete it from the new_comps
+ # list
+ del comps[comps.index(new_comp)]
+ if len(comps) == 0:
+ return source
+ for source in self.list:
+ # if there is a repo with the same (type, uri, dist) just add the
+ # components
+ if source.disabled == False and source.invalid == False and \
+ source.type == type and uri == source.uri and \
+ source.dist == dist:
+ comps = uniq(source.comps + comps)
+ source.comps = comps
+ return source
+ # if there is a corresponding repo which is disabled, enable it
+ elif source.disabled == True and source.invalid == False and \
+ source.type == type and uri == source.uri and \
+ source.dist == dist and \
+ len(set(source.comps) & set(comps)) == len(comps):
+ source.disabled = False
+ return source
+ # there isn't any matching source, so create a new line and parse it
+ line = "%s %s %s" % (type,uri,dist)
+ for c in comps:
+ line = line + " " + c;
+ if comment != "":
+ line = "%s #%s\n" %(line,comment)
+ line = line + "\n"
+ new_entry = SourceEntry(line)
+ if file != None:
+ new_entry.file = file
+ self.matcher.match(new_entry)
+ self.list.insert(pos, new_entry)
+ return new_entry
+
+ def remove(self, source_entry):
+ """ remove the specified entry from the sources.list """
+ self.list.remove(source_entry)
+
+ def restoreBackup(self, backup_ext):
+ " restore sources.list files based on the backup extension "
+ dir = apt_pkg.Config.FindDir("Dir::Etc")
+ file = apt_pkg.Config.Find("Dir::Etc::sourcelist")
+ if os.path.exists(dir+file+backup_ext) and \
+ os.path.exists(dir+file):
+ shutil.copy(dir+file+backup_ext,dir+file)
+ # now sources.list.d
+ partsdir = apt_pkg.Config.FindDir("Dir::Etc::sourceparts")
+ for file in glob.glob("%s/*.list" % partsdir):
+ if os.path.exists(file+backup_ext):
+ shutil.copy(file+backup_ext,file)
+
+ def backup(self, backup_ext=None):
+ """ make a backup of the current source files, if no backup extension
+ is given, the current date/time is used (and returned) """
+ already_backuped = set()
+ if backup_ext == None:
+ backup_ext = time.strftime("%y%m%d.%H%M")
+ for source in self.list:
+ if not source.file in already_backuped and os.path.exists(source.file):
+ shutil.copy(source.file,"%s%s" % (source.file,backup_ext))
+ return backup_ext
+
+ def load(self,file):
+ """ (re)load the current sources """
+ try:
+ f = open(file, "r")
+ lines = f.readlines()
+ for line in lines:
+ source = SourceEntry(line,file)
+ self.list.append(source)
+ except:
+ print "could not open file '%s'" % file
+ else:
+ f.close()
+
+ def save(self):
+ """ save the current sources """
+ files = {}
+ for source in self.list:
+ if not files.has_key(source.file):
+ files[source.file]=open(source.file,"w")
+ files[source.file].write(source.str())
+ for f in files:
+ files[f].close()
+
+ def check_for_relations(self, sources_list):
+ """get all parent and child channels in the sources list"""
+ parents = []
+ used_child_templates = {}
+ for source in sources_list:
+ # try to avoid checking uninterressting sources
+ if source.template == None:
+ continue
+ # set up a dict with all used child templates and corresponding
+ # source entries
+ if source.template.child == True:
+ key = source.template
+ if not used_child_templates.has_key(key):
+ used_child_templates[key] = []
+ temp = used_child_templates[key]
+ temp.append(source)
+ else:
+ # store each source with children aka. a parent :)
+ if len(source.template.children) > 0:
+ parents.append(source)
+ #print self.used_child_templates
+ #print self.parents
+ return (parents, used_child_templates)
+
+# matcher class to make a source entry look nice
+# lots of predefined matchers to make it i18n/gettext friendly
+class SourceEntryMatcher:
+ def __init__(self, matcherPath):
+ self.templates = []
+ # Get the human readable channel and comp names from the channel .infos
+ spec_files = glob.glob("%s/*.info" % matcherPath)
+ for f in spec_files:
+ f = os.path.basename(f)
+ i = f.find(".info")
+ f = f[0:i]
+ dist = DistInfo(f,base_dir=matcherPath)
+ for template in dist.templates:
+ if template.match_uri != None:
+ self.templates.append(template)
+ return
+
+ def match(self, source):
+ """Add a matching template to the source"""
+ _ = gettext.gettext
+ found = False
+ for template in self.templates:
+ if (re.search(template.match_uri, source.uri) and
+ re.match(template.match_name, source.dist)):
+ found = True
+ source.template = template
+ break
+ elif (template.is_mirror(source.uri) and
+ re.match(template.match_name, source.dist)):
+ found = True
+ source.template = template
+ break
+ return found
+
+
+# some simple tests
+if __name__ == "__main__":
+ apt_pkg.InitConfig()
+ sources = SourcesList()
+
+ for entry in sources:
+ print entry.str()
+ #print entry.uri
+
+ mirror = is_mirror("http://archive.ubuntu.com/ubuntu/",
+ "http://de.archive.ubuntu.com/ubuntu/")
+ print "is_mirror(): %s" % mirror
+
+ print is_mirror("http://archive.ubuntu.com/ubuntu",
+ "http://de.archive.ubuntu.com/ubuntu/")
+ print is_mirror("http://archive.ubuntu.com/ubuntu/",
+ "http://de.archive.ubuntu.com/ubuntu")
+
diff --git a/data/templates/Debian.info.in b/data/templates/Debian.info.in
new file mode 100644
index 00000000..8a2eead3
--- /dev/null
+++ b/data/templates/Debian.info.in
@@ -0,0 +1,98 @@
+_ChangelogURI: http://packages.debian.org/changelogs/pool/%s/%s/%s/%s_%s/changelog
+
+Suite: etch
+RepositoryType: deb
+BaseURI: http://http.us.debian.org/debian/
+MatchUri: ftp[0-9]*\.[a-z]\.debian\.org
+MirrorsFile: /usr/share/python-aptsources/templates/Debian.mirrors
+_Description: Debian 4.0 'Etch'
+Component: main
+_CompDescription: Officially supported
+Component: contrib
+_CompDescription: DFSG-compatible Software with Non-Free Dependencies
+Component: non-free
+_CompDescription: Non-DFSG-compatible Software
+
+Suite: etch-proposed-updates
+RepositoryType: deb
+ParentSuite: etch
+_Description: Proposed updates
+
+Suite: etch/updates
+RepositoryType: deb
+ParentSuite: etch
+_Description: Security updates
+
+Suite: sarge
+RepositoryType: deb
+BaseURI: http://http.us.debian.org/debian/
+MatchUri: ftp[0-9]*\.[a-z]\.debian\.org
+MirrorsFile: /usr/share/python-aptsources/templates/Debian.mirrors
+_Description: Debian 3.1 'Sarge'
+Component: main
+_CompDescription: Officially supported
+Component: contrib
+_CompDescription: DFSG-compatible Software with Non-Free Dependencies
+Component: non-free
+_CompDescription: Non-DFSG-compatible Software
+
+Suite: sarge-proposed-updates
+RepositoryType: deb
+ParentSuite: sarge
+_Description: Proposed updates
+
+Suite: sarge/updates
+RepositoryType: deb
+ParentSuite: sarge
+_Description: Security updates
+
+Suite: stable
+RepositoryType: deb
+BaseURI: http://http.us.debian.org/debian/
+MatchUri: ftp[0-9]*\.[a-z]\.debian\.org
+MirrorsFile: /usr/share/python-aptsources/templates/Debian.mirrors
+_Description: Debian current stable release
+Component: main
+_CompDescription: Officially supported
+Component: contrib
+_CompDescription: DFSG-compatible Software with Non-Free Dependencies
+Component: non-free
+_CompDescription: Non-DFSG-compatible Software
+
+Suite: testing
+RepositoryType: deb
+BaseURI: http://http.us.debian.org/debian/
+MatchUri: ftp[0-9]*\.[a-z]\.debian\.org
+MirrorsFile: /usr/share/python-aptsources/templates/Debian.mirrors
+_Description: Debian testing
+Component: main
+_CompDescription: Officially supported
+Component: contrib
+_CompDescription: DFSG-compatible Software with Non-Free Dependencies
+Component: non-free
+_CompDescription: Non-DFSG-compatible Software
+
+Suite: sid
+RepositoryType: deb
+BaseURI: http://http.us.debian.org/debian/
+MatchUri: ftp[0-9]*\.[a-z]\.debian\.org
+MirrorsFile: /usr/share/python-aptsources/templates/Debian.mirrors
+_Description: Debian 'Sid' (unstable)
+Component: main
+_CompDescription: Officially supported
+Component: contrib
+_CompDescription: DFSG-compatible Software with Non-Free Dependencies
+Component: non-free
+_CompDescription: Non-DFSG-compatible Software
+
+Suite: unstable
+RepositoryType: deb
+BaseURI: http://http.us.debian.org/debian/
+MirrorsFile: /usr/share/python-aptsources/templates/Debian.mirrors
+_Description: Debian 'Sid' (unstable)
+Component: main
+_CompDescription: Officially supported
+Component: contrib
+_CompDescription: DFSG-compatible Software with Non-Free Dependencies
+Component: non-free
+_CompDescription: Non-DFSG-compatible Software
diff --git a/data/templates/Debian.mirrors b/data/templates/Debian.mirrors
new file mode 100644
index 00000000..3e92cdc8
--- /dev/null
+++ b/data/templates/Debian.mirrors
@@ -0,0 +1,797 @@
+#LOC:AR
+http://debian.logiclinux.com/debian/
+ftp://ftp.ccc.uba.ar/pub/linux/debian/debian/
+http://ftp.ccc.uba.ar/pub/linux/debian/debian/
+#LOC:AT
+ftp://ftp.at.debian.org/debian/
+ftp://debian.sil.at/debian/
+ftp://ftp.debian.at/debian/
+http://ftp.at.debian.org/debian/
+http://debian.sil.at/debian/
+http://ftp.debian.at/debian/
+ftp://gd.tuwien.ac.at/opsys/linux/debian/
+ftp://ftp.tuwien.ac.at/opsys/linux/debian/
+http://gd.tuwien.ac.at/opsys/linux/debian/
+http://ftp.tuwien.ac.at/opsys/linux/debian/
+ftp://debian.mur.at/debian/
+ftp://algo.mur.at/debian/
+ftp://spider.mur.at/debian/
+http://debian.mur.at/debian/
+http://algo.mur.at/debian/
+http://spider.mur.at/debian/
+ftp://ftp.tu-graz.ac.at/mirror/debian/
+ftp://ftp.tugraz.at/mirror/debian/
+http://ftp.tu-graz.ac.at/mirror/debian/
+http://ftp.tugraz.at/mirror/debian/
+ftp://ftp.univie.ac.at/systems/linux/debian/debian/
+http://ftp.univie.ac.at/systems/linux/debian/debian/
+ftp://debian.inode.at/debian/
+http://debian.inode.at/debian/
+#LOC:AU
+ftp://ftp.wa.au.debian.org/debian/
+ftp://ftp.it.net.au/debian/
+ftp://poledra.it.net.au/debian/
+http://ftp.wa.au.debian.org/debian/
+http://ftp.it.net.au/debian/
+http://poledra.it.net.au/debian/
+ftp://ftp.au.debian.org/debian/
+ftp://planetmirror.com/debian/
+http://ftp.au.debian.org/debian/
+http://planetmirror.com/debian/
+ftp://mirror.aarnet.edu.au/debian/
+http://mirror.aarnet.edu.au/debian/
+ftp://ftp.monash.edu.au/pub/linux/debian/
+http://ftp.monash.edu.au/pub/linux/debian/
+ftp://ftp.uwa.edu.au/debian/
+http://ftp.uwa.edu.au/debian/
+ftp://mirror.eftel.com/debian/
+ftp://mirror.q-net.net.au/debian/
+http://mirror.eftel.com/debian/
+http://mirror.q-net.net.au/debian/
+ftp://mirror.pacific.net.au/debian/
+http://mirror.pacific.net.au/debian/
+ftp://ftp.iinet.net.au/debian/debian/
+http://ftp.iinet.net.au/debian/debian/
+ftp://mirror.datafast.net.au/debian/
+http://mirror.datafast.net.au/debian/
+http://mirror.optus.net/debian/
+http://mirror.optusnet.com.au/debian/
+#LOC:BE
+ftp://ftp.kulnet.kuleuven.ac.be/debian/
+http://ftp.kulnet.kuleuven.ac.be/debian/
+ftp://ftp.easynet.be/debian/
+http://ftp.easynet.be/ftp/debian/
+ftp://ftp.belnet.be/debian/
+ftp://dalet.belnet.be/debian/
+http://ftp.belnet.be/debian/
+http://dalet.belnet.be/debian/
+ftp://ftp.debian.skynet.be/debian/
+http://ftp.debian.skynet.be/ftp/debian/
+ftp://ftp.scarlet.be/pub/debian/
+http://ftp.scarlet.be/pub/debian/
+#LOC:BG
+ftp://ftp.bg.debian.org/debian/
+ftp://debian.spnet.net/debian/
+http://ftp.bg.debian.org/debian/
+http://debian.spnet.net/debian/
+ftp://debian.ludost.net/debian/
+ftp://marla.ludost.net/debian/
+http://debian.ludost.net/debian/
+http://marla.ludost.net/debian/
+ftp://ftp.uni-sofia.bg/debian/
+http://ftp.uni-sofia.bg/debian/
+ftp://debian.telecoms.bg/debian/
+http://debian.telecoms.bg/debian/
+#LOC:BR
+ftp://ftp.br.debian.org/debian/
+ftp://ftp.inf.ufpr.br/debian/
+ftp://www.inf.ufpr.br/debian/
+http://ftp.br.debian.org/debian/
+http://ftp.inf.ufpr.br/debian/
+http://www.inf.ufpr.br/debian/
+http://sft.if.usp.br/debian/
+http://fma.if.usp.br/debian/
+ftp://linorg.usp.br/debian/
+http://linorg.usp.br/debian/
+http://linux.iq.usp.br/debian/
+http://torio.iq.usp.br/debian/
+ftp://ftp.pucpr.br/debian/
+http://ftp.pucpr.br/debian/
+ftp://www.las.ic.unicamp.br/pub/debian/
+ftp://seraph.las.ic.unicamp.br/pub/debian/
+ftp://ftp.las.ic.unicamp.br/pub/debian/
+http://www.las.ic.unicamp.br/pub/debian/
+http://seraph.las.ic.unicamp.br/pub/debian/
+http://ftp.las.ic.unicamp.br/pub/debian/
+http://debian.pop-sc.rnp.br/debian/
+http://mirror.pop-sc.rnp.br/debian/
+#LOC:BY
+ftp://linux.org.by/debian/
+http://linux.org.by/debian/
+ftp://ftp.mgts.by/debian/
+http://ftp.mgts.by/debian/
+#LOC:CA
+http://debian.yorku.ca/debian/
+ftp://ftp3.nrc.ca/debian/
+http://ftp3.nrc.ca/debian/
+ftp://gulus.usherbrooke.ca/debian/
+http://gulus.usherbrooke.ca/debian/
+ftp://mirror.cpsc.ucalgary.ca/debian/
+http://mirror.cpsc.ucalgary.ca/debian/
+http://mirror.peer1.net/debian/
+ftp://debian.mirror.rafal.ca/debian/
+http://debian.mirror.rafal.ca/debian/
+ftp://debian.savoirfairelinux.net/debian/
+ftp://gpl.savoirfairelinux.net/debian/
+http://debian.savoirfairelinux.net/debian/
+http://gpl.savoirfairelinux.net/debian/
+ftp://debian.mirror.iweb.ca/debian/
+http://debian.mirror.iweb.ca/debian/
+#LOC:CH
+ftp://ftp.ch.debian.org/debian/
+ftp://debian.ethz.ch/debian/
+ftp://kaerpf.ethz.ch/debian/
+http://ftp.ch.debian.org/debian/
+http://debian.ethz.ch/debian/
+http://kaerpf.ethz.ch/debian/
+ftp://mirror.switch.ch/mirror/debian/
+http://mirror.switch.ch/ftp/mirror/debian/
+#LOC:CL
+http://debian.ubiobio.cl/debian/
+#LOC:CN
+ftp://ftp.linuxforum.net/debian/
+ftp://www2.linuxforum.net/debian/
+ftp://mirrors.geekbone.org/debian/
+http://mirrors.geekbone.org/debian/
+ftp://debian.cn99.com/debian/
+ftp://mirrors.cn99.com/debian/
+http://debian.cn99.com/debian/
+http://mirrors.cn99.com/debian/
+#LOC:CO
+http://fatboy.umng.edu.co/debian/
+#LOC:CZ
+ftp://ftp.cz.debian.org/debian/
+ftp://ftp.debian.cz/debian/
+ftp://www.debian.cz/debian/
+http://ftp.cz.debian.org/debian/
+http://ftp.debian.cz/debian/
+http://www.debian.cz/debian/
+ftp://debian.sh.cvut.cz/debian/
+ftp://ftp.sh.cvut.cz/debian/
+http://debian.sh.cvut.cz/debian/
+http://ftp.sh.cvut.cz/debian/
+ftp://ftp.zcu.cz/mirrors/debian/
+http://ftp.zcu.cz/mirrors/debian/
+#LOC:DE
+ftp://ftp.de.debian.org/debian/
+ftp://ftp1.de.debian.org/debian/
+ftp://debian.inf.tu-dresden.de/debian/
+http://ftp.de.debian.org/debian/
+http://ftp1.de.debian.org/debian/
+http://debian.inf.tu-dresden.de/debian/
+ftp://ftp2.de.debian.org/debian/
+ftp://ftp.rfc822.org/debian/
+ftp://source.rfc822.org/debian/
+http://ftp2.de.debian.org/debian/
+http://ftp.rfc822.org/debian/
+http://source.rfc822.org/debian/
+ftp://ftp.tu-clausthal.de/pub/linux/debian/
+ftp://pegasus.rz.tu-clausthal.de/pub/linux/debian/
+ftp://debian.uni-essen.de/debian/
+ftp://debian.physik.uni-essen.de/debian/
+http://debian.uni-essen.de/debian/
+http://debian.physik.uni-essen.de/debian/
+ftp://ftp.freenet.de/pub/ftp.debian.org/debian/
+http://ftp.freenet.de/debian/
+ftp://ftp.uni-erlangen.de/pub/Linux/debian/
+http://ftp.uni-erlangen.de/pub/Linux/debian/
+ftp://sunsite.informatik.rwth-aachen.de/pub/Linux/debian/
+http://sunsite.informatik.rwth-aachen.de/ftp/pub/Linux/debian/
+ftp://ftp-stud.fht-esslingen.de/debian/
+http://ftp-stud.fht-esslingen.de/debian/
+ftp://ftp.stw-bonn.de/debian/
+http://ftp.stw-bonn.de/debian/
+ftp://ftp.fu-berlin.de/pub/unix/linux/mirrors/debian/
+ftp://Hefe.ZEDAT.FU-Berlin.DE/pub/unix/linux/mirrors/debian/
+ftp://debian.tu-bs.de/debian/
+http://debian.tu-bs.de/debian/
+ftp://ftp.uni-koeln.de/debian/
+http://ftp.uni-koeln.de/debian/
+ftp://debian.pffa.de/pub/mirrors/debian/
+ftp://debian.ipv6.fhtw-berlin.de/pub/mirrors/debian/
+http://debian.pffa.de/mirrors/debian/
+http://debian.ipv6.fhtw-berlin.de/mirrors/debian/
+ftp://ftp.mpi-sb.mpg.de/pub/linux/distributions/debian/debian/
+ftp://ftp.tiscali.de/pub/debian/debian/
+ftp://pandemonium.tiscali.de/pub/debian/debian/
+http://ftp.tiscali.de/pub/debian/debian/
+http://pandemonium.tiscali.de/pub/debian/debian/
+ftp://ftp.tu-chemnitz.de/pub/linux/debian/debian/
+http://ftp.tu-chemnitz.de/pub/linux/debian/debian/
+ftp://ftp.uni-kl.de/debian/
+http://ftp.uni-kl.de/debian/
+ftp://ftp.uni-bayreuth.de/pub/linux/Debian/debian/
+ftp://rsync.uni-bayreuth.de/pub/linux/Debian/debian/
+ftp://btr0x2.rz.uni-bayreuth.de/pub/linux/Debian/debian/
+ftp://btr0qx.rz.uni-bayreuth.de/pub/linux/Debian/debian/
+http://ftp.uni-bayreuth.de/linux/Debian/debian/
+http://rsync.uni-bayreuth.de/linux/Debian/debian/
+http://btr0x2.rz.uni-bayreuth.de/linux/Debian/debian/
+http://btr0qx.rz.uni-bayreuth.de/linux/Debian/debian/
+ftp://ftp.informatik.hu-berlin.de/pub/Mirrors/ftp.de.debian.org/debian/
+ftp://ftp.gwdg.de/pub/linux/debian/debian/
+http://ftp.gwdg.de/pub/linux/debian/debian/
+ftp://ftp.hosteurope.de/pub/linux/debian/
+http://ftp.hosteurope.de/pub/linux/debian/
+ftp://ftp.informatik.uni-frankfurt.de/pub/linux/Mirror/ftp.debian.org/debian/
+ftp://ftp.cs.uni-frankfurt.de/pub/linux/Mirror/ftp.debian.org/debian/
+http://ftp.informatik.uni-frankfurt.de/debian/
+http://ftp.cs.uni-frankfurt.de/debian/
+ftp://debian.netcologne.de/debian/
+http://debian.netcologne.de/debian/
+ftp://artfiles.org/debian/
+http://artfiles.org/debian/
+http://debian.intergenia.de/debian/
+http://debian.server4you.de/debian/
+http://debian.vserver.de/debian/
+http://debian.plusserver.de/debian/
+ftp://debian.swordcoast.net/debian/
+http://debian.swordcoast.net/debian/
+#LOC:DK
+ftp://ftp.dk.debian.org/debian/
+ftp://mirrors.dotsrc.org/debian/
+http://ftp.dk.debian.org/debian/
+http://mirrors.dotsrc.org/debian/
+ftp://ftp.dkuug.dk/pub/debian/
+http://ftp.dkuug.dk/debian/
+http://mirror.here.dk/debian/
+http://debian.uni-c.dk/debian/
+http://ymer.uni-c.dk/debian/
+ftp://mirrors.telianet.dk/debian/
+ftp://mirrors.dk.telia.net/debian/
+http://mirrors.telianet.dk/debian/
+http://mirrors.dk.telia.net/debian/
+#LOC:EE
+ftp://ftp.ee.debian.org/debian/
+ftp://ftp.linux.ee/debian/
+ftp://linux.ee/debian/
+http://ftp.ee.debian.org/debian/
+http://ftp.linux.ee/debian/
+http://linux.ee/debian/
+#LOC:ES
+ftp://ftp.es.debian.org/debian/
+ftp://ulises.adi.uam.es/debian/
+http://ftp.es.debian.org/debian/
+http://ulises.adi.uam.es/debian/
+ftp://ftp.rediris.es/debian/
+http://ftp.rediris.es/debian/
+ftp://ftp.caliu.info/debian/
+http://ftp.caliu.info/debian/
+ftp://ftp.gva.es/pub/mirror/debian/
+ftp://frigga.gva.es/pub/mirror/debian/
+http://ftp.gva.es/mirror/debian/
+http://frigga.gva.es/mirror/debian/
+ftp://ftp.gul.uc3m.es/debian/
+ftp://ftp.gul.es/debian/
+http://ftp.gul.uc3m.es/debian/
+http://ftp.gul.es/debian/
+#LOC:FI
+ftp://ftp.fi.debian.org/debian/
+ftp://trumpetti.atm.tut.fi/debian/
+http://ftp.fi.debian.org/debian/
+http://trumpetti.atm.tut.fi/debian/
+ftp://ftp.funet.fi/pub/linux/mirrors/debian/
+http://ftp.funet.fi/pub/linux/mirrors/debian/
+ftp://ftp.jyu.fi/debian/
+ftp://lennon.cc.jyu.fi/debian/
+http://ftp.jyu.fi/debian/
+http://lennon.cc.jyu.fi/debian/
+#LOC:FR
+ftp://ftp.fr.debian.org/debian/
+ftp://debian.proxad.net/debian/
+ftp://ftpmirror.proxad.net/debian/
+http://ftp.fr.debian.org/debian/
+http://debian.proxad.net/debian/
+http://ftpmirror.proxad.net/debian/
+ftp://ftp2.fr.debian.org/debian/
+ftp://ftp.oleane.net/debian/
+http://ftp2.fr.debian.org/debian/
+http://ftp.oleane.net/debian/
+ftp://ftp.iut-bm.univ-fcomte.fr/debian/
+http://ftp.iut-bm.univ-fcomte.fr/debian/
+ftp://ftp.proxad.net/mirrors/ftp.debian.org/
+ftp://ftp.free.fr/mirrors/ftp.debian.org/
+ftp://ftp.online.fr/mirrors/ftp.debian.org/
+ftp://ftp.proxad.fr/mirrors/ftp.debian.org/
+ftp://ftp.lip6.fr/pub/linux/distributions/debian/
+http://ftp.lip6.fr/pub/linux/distributions/debian/
+ftp://debian.ens-cachan.fr/debian/
+ftp://ftp.ens-cachan.fr/debian/
+http://debian.ens-cachan.fr/ftp/debian/
+http://ftp.ens-cachan.fr/ftp/debian/
+ftp://ftp.u-picardie.fr/mirror/debian/
+http://ftp.u-picardie.fr/mirror/debian/
+ftp://debian.mirrors.easynet.fr/debian/
+ftp://tengu.easynet.fr/debian/
+http://debian.mirrors.easynet.fr/
+http://tengu.easynet.fr/
+ftp://ftp.u-strasbg.fr/debian/
+http://ftp.u-strasbg.fr/debian/
+ftp://debian.ibisc.univ-evry.fr/debian/
+http://debian.ibisc.univ-evry.fr/debian/
+ftp://mir1.ovh.net/debian/
+http://mir1.ovh.net/debian/
+http://mir2.ovh.net/debian/
+http://mirror.ovh.net/debian/
+ftp://ftp.nerim.net/debian/
+http://ftp.nerim.net/debian/
+ftp://ftp.crihan.fr/debian/
+http://ftp.crihan.fr/debian/
+ftp://debian.mines.inpl-nancy.fr/debian/
+ftp://ftp.mines.inpl-nancy.fr/debian/
+http://debian.mines.inpl-nancy.fr/debian/
+http://ftp.mines.inpl-nancy.fr/debian/
+ftp://ftp.debian.ikoula.com/debian/
+ftp://webb.ens-cachan.fr/debian/
+ftp://debian.ens-cachan.fr/debian/
+http://webb.ens-cachan.fr/debian/
+http://debian.ens-cachan.fr/debian/
+ftp://mirrors.ircam.fr/pub/debian/
+http://mirrors.ircam.fr/pub/debian/
+#LOC:GB
+ftp://ftp.uk.debian.org/debian/
+ftp://debian.hands.com/debian/
+http://ftp.uk.debian.org/debian/
+http://debian.hands.com/debian/
+ftp://debian.hands.com/debian/
+ftp://open.hands.com/debian/
+http://debian.hands.com/debian/
+http://open.hands.com/debian/
+ftp://ftp.demon.co.uk/pub/mirrors/linux/debian/
+ftp://ftp.demon.net/pub/mirrors/linux/debian/
+ftp://ftp.mcc.ac.uk/pub/linux/distributions/Debian/
+ftp://www.mirrorservice.org/sites/ftp.debian.org/debian/
+ftp://ftp.mirrorservice.org/sites/ftp.debian.org/debian/
+http://www.mirrorservice.org/sites/ftp.debian.org/debian/
+http://ftp.mirrorservice.org/sites/ftp.debian.org/debian/
+ftp://download.mirror.ac.uk/sites/ftp.debian.org/debian/
+ftp://ftp.mirror.ac.uk/sites/ftp.debian.org/debian/
+http://download.mirror.ac.uk/sites/ftp.debian.org/debian/
+http://ftp.mirror.ac.uk/sites/ftp.debian.org/debian/
+ftp://ftp.ticklers.org/debian/
+ftp://rib.ticklers.org/debian/
+http://ftp.ticklers.org/debian/
+http://rib.ticklers.org/debian/
+ftp://debian.blueyonder.co.uk/pub/debian/
+ftp://mirror2.blueyonder.co.uk/pub/debian/
+http://debian.blueyonder.co.uk/
+http://mirror2.blueyonder.co.uk/
+ftp://mirror.positive-internet.com/debian/
+http://mirror.positive-internet.com/debian/
+ftp://the.earth.li/debian/
+http://the.earth.li/debian/
+ftp://mirror.ox.ac.uk/debian/
+http://mirror.ox.ac.uk/debian/
+#LOC:GR
+ftp://debian.otenet.gr/pub/linux/debian/
+http://debian.otenet.gr/debian/
+ftp://ftp.ntua.gr/pub/linux/debian/
+http://ftp.ntua.gr/pub/linux/debian/
+ftp://ftp.duth.gr/debian/
+http://ftp.duth.gr/debian/
+ftp://ftp.softnet.tuc.gr/pub/linux/debian/
+ftp://antirix.softnet.tuc.gr/pub/linux/debian/
+http://ftp.softnet.tuc.gr/ftp/linux/debian/
+http://antirix.softnet.tuc.gr/ftp/linux/debian/
+ftp://debian.internet.gr/debian/
+http://debian.internet.gr/debian/
+#LOC:HK
+ftp://ftp.hk.debian.org/debian/
+ftp://ftp.debian.org.hk/debian/
+http://ftp.hk.debian.org/debian/
+http://ftp.debian.org.hk/debian/
+http://www.zentek-international.com/mirrors/debian/
+#LOC:HR
+ftp://ftp.hr.debian.org/debian/
+ftp://debian.carnet.hr/debian/
+http://ftp.hr.debian.org/debian/
+http://debian.carnet.hr/debian/
+ftp://ftp.irb.hr/debian/
+http://ftp.irb.hr/debian/
+ftp://ftp.carnet.hr/debian/
+http://ftp.carnet.hr/debian/
+ftp://debian.iskon.hr/debian/
+http://debian.iskon.hr/debian/
+#LOC:HU
+ftp://ftp.hu.debian.org/debian/
+ftp://ftp.fsn.hu/debian/
+http://ftp.hu.debian.org/debian/
+http://ftp.fsn.hu/debian/
+ftp://debian.inf.elte.hu/debian/
+http://debian.inf.elte.hu/debian/
+ftp://ftp.bme.hu/OS/Linux/dist/debian/
+http://ftp.bme.hu/OS/Linux/dist/debian/
+#LOC:ID
+ftp://kebo.vlsm.org/debian/
+ftp://surabaya.vlsm.org/debian/
+ftp://katmai.its.ac.id/debian/
+http://kebo.vlsm.org/debian/
+http://surabaya.vlsm.org/debian/
+http://katmai.its.ac.id/debian/
+http://debian.indika.net.id/debian/
+#LOC:IE
+ftp://ftp.ie.debian.org/debian/
+ftp://debian.heanet.ie/debian/
+ftp://debian.ipv6.heanet.ie/debian/
+ftp://canyonero.heanet.ie/debian/
+http://ftp.ie.debian.org/debian/
+http://debian.heanet.ie/debian/
+http://debian.ipv6.heanet.ie/debian/
+http://canyonero.heanet.ie/debian/
+ftp://ftp.esat.net/pub/linux/debian/
+http://ftp.esat.net/pub/linux/debian/
+#LOC:IL
+http://mirror.hamakor.org.il/pub/mirrors/debian/
+#LOC:IN
+ftp://ftp.iitm.ac.in/debian/
+http://ftp.iitm.ac.in/debian/
+#LOC:IS
+ftp://ftp.is.debian.org/debian/
+ftp://ftp.rhnet.is/debian/
+http://ftp.is.debian.org/debian/
+http://ftp.rhnet.is/debian/
+#LOC:IT
+ftp://ftp.it.debian.org/debian/
+ftp://ftp.bofh.it/debian/
+ftp://vlad-tepes.bofh.it/debian/
+http://ftp.it.debian.org/debian/
+http://ftp.bofh.it/debian/
+http://vlad-tepes.bofh.it/debian/
+ftp://ftp.bononia.it/debian/
+http://ftp.bononia.it/debian/
+ftp://freedom.dicea.unifi.it/pub/linux/debian/
+http://freedom.dicea.unifi.it/ftp/pub/linux/debian/
+ftp://ftp.eutelia.it/pub/Debian_Mirror/
+ftp://mi.mirror.garr.it/mirrors/debian/
+http://mi.mirror.garr.it/mirrors/debian/
+ftp://debian.fastweb.it/debian/
+http://debian.fastweb.it/debian/
+ftp://ftp.unina.it/pub/linux/distributions/debian/
+http://ftp.unina.it/pub/linux/distributions/debian/
+ftp://debian.fastbull.org/debian/
+ftp://bull02.fastbull.org/debian/
+http://debian.fastbull.org/debian/
+http://bull02.fastbull.org/debian/
+#LOC:JP
+ftp://ftp.jp.debian.org/debian/
+ftp://ftp.nara.wide.ad.jp/debian/
+ftp://ftp.aist-nara.ac.jp/debian/
+http://ftp.jp.debian.org/debian/
+http://ftp.nara.wide.ad.jp/debian/
+http://ftp.aist-nara.ac.jp/debian/
+ftp://ftp2.jp.debian.org/debian/
+ftp://ftp.debian.or.jp/debian/
+ftp://http.debian.or.jp/debian/
+http://ftp2.jp.debian.org/debian/
+http://ftp.debian.or.jp/debian/
+http://http.debian.or.jp/debian/
+ftp://ring.asahi-net.or.jp/pub/linux/debian/debian/
+http://ring.asahi-net.or.jp/archives/linux/debian/debian/
+ftp://ftp.dti.ad.jp/pub/Linux/debian/
+http://ftp.dti.ad.jp/pub/Linux/debian/
+ftp://dennou-k.gfd-dennou.org/library/Linux/debian/
+ftp://dennou-k.gaia.h.kyoto-u.ac.jp/library/Linux/debian/
+http://dennou-k.gfd-dennou.org/library/Linux/debian/
+http://dennou-k.gaia.h.kyoto-u.ac.jp/library/Linux/debian/
+ftp://dennou-q.gfd-dennou.org/library/Linux/debian/
+ftp://dennou-q.geo.kyushu-u.ac.jp/library/Linux/debian/
+http://dennou-q.gfd-dennou.org/library/Linux/debian/
+http://dennou-q.geo.kyushu-u.ac.jp/library/Linux/debian/
+ftp://ftp.yz.yamagata-u.ac.jp/debian/
+ftp://linux.yz.yamagata-u.ac.jp/debian/
+http://ftp.yz.yamagata-u.ac.jp/debian/
+http://linux.yz.yamagata-u.ac.jp/debian/
+ftp://sb.itc.u-tokyo.ac.jp/DEBIAN/debian/
+ftp://ftp.ecc.u-tokyo.ac.jp/DEBIAN/debian/
+ftp://ftp.riken.go.jp/pub/Linux/debian/debian/
+http://ftp.riken.go.jp/pub/Linux/debian/debian/
+http://debian.shimpinomori.net/debian/
+ftp://www.ring.gr.jp/pub/linux/debian/debian/
+ftp://ftp.ring.gr.jp/pub/linux/debian/debian/
+http://www.ring.gr.jp/archives/linux/debian/debian/
+http://ftp.ring.gr.jp/archives/linux/debian/debian/
+ftp://ftp.jaist.ac.jp/pub/Linux/Debian/
+http://ftp.jaist.ac.jp/pub/Linux/Debian/
+#LOC:KR
+ftp://ftp.kr.debian.org/debian/
+ftp://ftp.kaist.ac.kr/debian/
+http://ftp.kr.debian.org/debian/
+http://ftp.kaist.ac.kr/debian/
+#LOC:LT
+ftp://ameba.sc-uni.ktu.lt/debian/
+http://ameba.sc-uni.ktu.lt/debian/
+ftp://debian.balt.net/debian/
+http://debian.balt.net/debian/
+#LOC:LV
+ftp://ftp.latnet.lv/linux/debian/
+ftp://milzis.latnet.lv/linux/debian/
+http://ftp.latnet.lv/linux/debian/
+http://milzis.latnet.lv/linux/debian/
+#LOC:MX
+ftp://nisamox.fciencias.unam.mx/debian/
+http://nisamox.fciencias.unam.mx/debian/
+#LOC:NI
+http://debian.uni.edu.ni/debian/
+#LOC:NL
+ftp://ftp.nl.debian.org/debian/
+ftp://slagroom.snt.utwente.nl/debian/
+http://ftp.nl.debian.org/debian/
+http://slagroom.snt.utwente.nl/debian/
+ftp://ftp.nluug.nl/pub/os/Linux/distr/debian/
+http://ftp.nluug.nl/pub/os/Linux/distr/debian/
+ftp://ftp.surfnet.nl/pub/os/Linux/distr/debian/
+http://ftp.surfnet.nl/os/Linux/distr/debian/
+ftp://download.xs4all.nl/pub/mirror/debian/
+ftp://dl.xs4all.nl/pub/mirror/debian/
+ftp://ftp.debian.nl/debian/
+ftp://morpheus.hoho.nl/debian/
+http://ftp.debian.nl/debian/
+http://morpheus.hoho.nl/debian/
+ftp://ftp.tiscali.nl/pub/mirrors/debian/
+http://ftp.tiscali.nl/debian/
+ftp://debian.essentkabel.com/debian/
+http://debian.essentkabel.com/debian/
+#LOC:NO
+ftp://ftp.no.debian.org/debian/
+ftp://ftp.uninett.no/debian/
+http://ftp.no.debian.org/debian/
+http://ftp.uninett.no/debian/
+#LOC:NZ
+ftp://ftp.nz.debian.org/debian/
+ftp://ftp.citylink.co.nz/debian/
+http://ftp.nz.debian.org/debian/
+http://ftp.citylink.co.nz/debian/
+ftp://debian.ihug.co.nz/debian/
+http://debian.ihug.co.nz/debian/
+#LOC:PL
+ftp://ftp.pl.debian.org/debian/
+ftp://ftp.task.gda.pl/debian/
+http://ftp.pl.debian.org/debian/
+http://ftp.task.gda.pl/debian/
+ftp://ftp.icm.edu.pl/pub/Linux/debian/
+ftp://sunsite.icm.edu.pl/pub/Linux/debian/
+http://ftp.icm.edu.pl/pub/Linux/debian/
+http://sunsite.icm.edu.pl/pub/Linux/debian/
+ftp://ftp.man.szczecin.pl/pub/Linux/debian/
+ftp://rubycon.man.szczecin.pl/pub/Linux/debian/
+#LOC:PT
+ftp://ftp.uevora.pt/debian/
+ftp://khaverna.sc.uevora.pt/debian/
+http://ftp.uevora.pt/debian/
+http://khaverna.sc.uevora.pt/debian/
+ftp://ftp.eq.uc.pt/pub/software/Linux/debian/
+http://ftp.eq.uc.pt/software/Linux/debian/
+ftp://debian.ua.pt/debian/
+ftp://ftp.ua.pt/debian/
+http://debian.ua.pt/debian/
+http://ftp.ua.pt/debian/
+ftp://ftp.linux.pt/pub/mirrors/debian/
+http://ftp.linux.pt/pub/mirrors/debian/
+#LOC:RO
+ftp://ftp.ro.debian.org/debian/
+ftp://ftp.iasi.roedu.net/debian/
+http://ftp.ro.debian.org/debian/
+http://ftp.iasi.roedu.net/debian/
+ftp://ftp.lug.ro/debian/
+http://ftp.lug.ro/debian/
+#LOC:RU
+ftp://ftp.ru.debian.org/debian/
+ftp://ftp.chg.ru/debian/
+http://ftp.ru.debian.org/debian/
+http://ftp.chg.ru/debian/
+ftp://debian.nsu.ru/debian/
+http://debian.nsu.ru/debian/
+ftp://debian.udsu.ru/debian/
+ftp://ftp.udsu.ru/debian/
+http://debian.udsu.ru/debian/
+http://ftp.udsu.ru/debian/
+ftp://ftp.psn.ru/debian/
+ftp://server.psn.ru/debian/
+http://ftp.psn.ru/debian/
+http://server.psn.ru/debian/
+ftp://ftp.corbina.ru/pub/Linux/debian/
+ftp://earth.corbina.net/pub/Linux/debian/
+ftp://ftp.mipt.ru/debian/
+ftp://petrel.telecom.mipt.ru/debian/
+#LOC:SE
+ftp://ftp.se.debian.org/debian/
+ftp://ftp.acc.umu.se/debian/
+http://ftp.se.debian.org/debian/
+http://ftp.acc.umu.se/debian/
+ftp://ftp.sunet.se/pub/os/Linux/distributions/debian/
+http://ftp.sunet.se/pub/os/Linux/distributions/debian/
+ftp://ftp.du.se/debian/
+http://ftp.du.se/debian/
+ftp://ftp.port80.se/debian/
+http://ftp.port80.se/debian/
+ftp://ftp.ds.hj.se/pub/os/linux/debian/
+http://ftp.ds.hj.se/pub/os/linux/debian/
+#LOC:SG
+ftp://mirror.nus.edu.sg/pub/Debian/
+ftp://mirror.comp.nus.edu.sg/pub/Debian/
+http://mirror.nus.edu.sg/Debian/
+http://mirror.comp.nus.edu.sg/Debian/
+ftp://debian.wow-vision.com.sg/debian/
+http://debian.wow-vision.com.sg/debian/
+#LOC:SI
+ftp://ftp.si.debian.org/debian/
+ftp://ftp.camtp.uni-mb.si/debian/
+ftp://debian.camtp.uni-mb.si/debian/
+http://ftp.si.debian.org/debian/
+http://ftp.camtp.uni-mb.si/debian/
+http://debian.camtp.uni-mb.si/debian/
+ftp://ftp.arnes.si/packages/debian/
+#LOC:SK
+ftp://ftp.sk.debian.org/debian/
+ftp://ftp.tuke.sk/debian/
+ftp://ccfrog.ke.sanet.sk/debian/
+http://ftp.sk.debian.org/debian/
+http://ftp.tuke.sk/debian/
+http://ccfrog.ke.sanet.sk/debian/
+#LOC:TH
+ftp://ftp.nectec.or.th/pub/linux-distributions/Debian/
+ftp://download.nectec.or.th/pub/linux-distributions/Debian/
+ftp://ftp.coe.psu.ac.th/debian/
+ftp://debian.coe.psu.ac.th/debian/
+http://ftp.coe.psu.ac.th/debian/
+http://debian.coe.psu.ac.th/debian/
+#LOC:TR
+ftp://ftp.tr.debian.org/debian/
+ftp://debian.ankara.edu.tr/debian/
+ftp://ftp.ankara.edu.tr/debian/
+http://ftp.tr.debian.org/debian/
+http://debian.ankara.edu.tr/debian/
+http://ftp.ankara.edu.tr/debian/
+ftp://ftp.linux.org.tr/pub/mirrors/debian/
+#LOC:TW
+ftp://ftp.tw.debian.org/debian/
+ftp://debian.linux.org.tw/debian/
+http://ftp.tw.debian.org/debian/
+http://debian.linux.org.tw/debian/
+ftp://debian.csie.ntu.edu.tw/pub/debian/
+http://debian.csie.ntu.edu.tw/debian/
+ftp://linux.cdpa.nsysu.edu.tw/debian/
+http://linux.cdpa.nsysu.edu.tw/debian/
+ftp://opensource.nchc.org.tw/debian/
+ftp://os.nchc.org.tw/debian/
+http://opensource.nchc.org.tw/debian/
+http://os.nchc.org.tw/debian/
+http://debian.nctu.edu.tw/debian/
+http://debian.ntcu.net/debian/
+ftp://mirror.nttu.edu.tw/debian/
+http://mirror.nttu.edu.tw/debian/
+#LOC:UA
+ftp://debian.osdn.org.ua/pub/Debian/debian/
+http://debian.osdn.org.ua/debian/
+ftp://debian.org.ua/debian/
+ftp://mirror.3logic.net/debian/
+ftp://mirror.debian.org.ua/debian/
+http://debian.org.ua/debian/
+http://mirror.3logic.net/debian/
+http://mirror.debian.org.ua/debian/
+ftp://ftp.3logic.net/debian/
+#LOC:US
+ftp://ftp.us.debian.org/debian/
+ftp://http.us.debian.org/debian/
+http://ftp.us.debian.org/debian/
+http://http.us.debian.org/debian/
+ftp://ftp.debian.org/debian/
+http://ftp.debian.org/debian/
+ftp://ftp.gtlib.gatech.edu/pub/debian/
+http://ftp.gtlib.gatech.edu/debian/
+ftp://ftp.egr.msu.edu/debian/
+ftp://ike.egr.msu.edu/debian/
+http://ftp.egr.msu.edu/debian/
+http://ike.egr.msu.edu/debian/
+ftp://distro.ibiblio.org/pub/linux/distributions/debian/
+http://distro.ibiblio.org/pub/linux/distributions/debian/
+ftp://ftp-mirror.internap.com/pub/debian/
+http://ftp-mirror.internap.com/pub/debian/
+ftp://ftp.cerias.purdue.edu/pub/os/debian/
+ftp://ftp9.freebsd.org/pub/os/debian/
+ftp://ftp8.usa.openbsd.org/pub/os/debian/
+ftp://omelas.cerias.purdue.edu/pub/os/debian/
+http://ftp.cerias.purdue.edu/pub/os/debian/
+http://ftp9.freebsd.org/pub/os/debian/
+http://ftp8.usa.openbsd.org/pub/os/debian/
+http://omelas.cerias.purdue.edu/pub/os/debian/
+ftp://ftp.cs.unm.edu/mirrors/debian/
+ftp://thelma.cs.unm.edu/mirrors/debian/
+ftp://mirrors.cs.unm.edu/mirrors/debian/
+ftp://mirror.cs.wisc.edu/pub/mirrors/linux/debian/
+http://mirror.cs.wisc.edu/pub/mirrors/linux/debian/
+ftp://ftp.uwsg.indiana.edu/linux/debian/
+ftp://uwsg.iu.edu/linux/debian/
+http://ftp.uwsg.indiana.edu/linux/debian/
+http://uwsg.iu.edu/linux/debian/
+ftp://ftp.ndlug.nd.edu/debian/
+http://ftp.ndlug.nd.edu/mirrors/debian/
+ftp://debian.uchicago.edu/debian/
+ftp://linux.uchicago.edu/debian/
+http://debian.uchicago.edu/debian/
+http://linux.uchicago.edu/debian/
+ftp://carroll.aset.psu.edu/pub/linux/distributions/debian/
+ftp://carroll.cac.psu.edu/pub/linux/distributions/debian/
+http://carroll.aset.psu.edu/pub/linux/distributions/debian/
+http://carroll.cac.psu.edu/pub/linux/distributions/debian/
+ftp://debian.fifi.org/pub/debian/
+ftp://ftp.fifi.org/pub/debian/
+http://debian.fifi.org/debian/
+http://ftp.fifi.org/debian/
+ftp://gladiator.real-time.com/linux/debian/
+ftp://mirrors.kernel.org/debian/
+ftp://rsync.kernel.org/debian/
+ftp://zeus1.kernel.org/debian/
+ftp://zeus2.kernel.org/debian/
+http://mirrors.kernel.org/debian/
+http://rsync.kernel.org/debian/
+http://zeus1.kernel.org/debian/
+http://zeus2.kernel.org/debian/
+ftp://ftp.keystealth.org/debian/
+http://ftp.keystealth.org/debian/
+ftp://debian.lcs.mit.edu/debian/
+ftp://debian.ipv6.lcs.mit.edu/debian/
+http://debian.lcs.mit.edu/debian/
+http://debian.ipv6.lcs.mit.edu/debian/
+ftp://linux.csua.berkeley.edu/debian/
+ftp://screwdriver.csua.berkeley.edu/debian/
+http://linux.csua.berkeley.edu/debian/
+http://screwdriver.csua.berkeley.edu/debian/
+ftp://debian.secsup.org/pub/linux/debian/
+http://debian.secsup.org/
+ftp://techweb.rfa.org/debian/
+ftp://chameleon.techweb.rfa.org/debian/
+http://techweb.rfa.org/debian/
+http://chameleon.techweb.rfa.org/debian/
+ftp://debian.osuosl.org/debian/
+ftp://debian.oregonstate.edu/debian/
+ftp://ftp.oregonstate.edu/debian/
+ftp://ftp.osuosl.org/debian/
+http://debian.osuosl.org/debian/
+http://debian.oregonstate.edu/debian/
+http://ftp.oregonstate.edu/debian/
+http://ftp.osuosl.org/debian/
+ftp://mirror.anl.gov/pub/debian/
+http://mirror.anl.gov/debian/
+ftp://sluglug.ucsc.edu/debian/
+http://sluglug.ucsc.edu/debian/
+ftp://mirrors.geeks.org/debian/
+http://mirrors.geeks.org/debian/
+http://debian.midco.net/debian/
+ftp://mirrors.usc.edu/pub/linux/distributions/debian/
+http://mirrors.usc.edu/pub/linux/distributions/debian/
+ftp://debian.mirrors.pair.com/
+http://debian.mirrors.pair.com/
+ftp://lug.mtu.edu/debian/
+http://lug.mtu.edu/debian/
+ftp://debian.mirrors.tds.net/debian/
+http://debian.mirrors.tds.net/debian/
+ftp://debian.cites.uiuc.edu/pub/debian/
+ftp://bazaar.cites.uiuc.edu/pub/debian/
+ftp://cosmos.cites.uiuc.edu/pub/debian/
+http://debian.cites.uiuc.edu/pub/debian/
+http://bazaar.cites.uiuc.edu/pub/debian/
+http://cosmos.cites.uiuc.edu/pub/debian/
+ftp://mirrors.tummy.com/pub/ftp.debian.org/
+http://mirrors.tummy.com/debian/
+ftp://debian.mirror.frontiernet.net/debian/
+http://debian.mirror.frontiernet.net/debian/
+ftp://cudlug.cudenver.edu/debian/
+http://cudlug.cudenver.edu/debian/
+#LOC:VE
+http://debian.unesr.edu.ve/debian/
+#LOC:ZA
+ftp://ftp.sun.ac.za/debian/
+ftp://archive.sun.ac.za/debian/
+http://ftp.sun.ac.za/ftp/debian/
+http://archive.sun.ac.za/ftp/debian/
diff --git a/data/templates/README.templates b/data/templates/README.templates
new file mode 100644
index 00000000..414148ed
--- /dev/null
+++ b/data/templates/README.templates
@@ -0,0 +1,46 @@
+Channel Definition
+------------------
+
+The .info files allow to specify a set of default channels that is available
+in the dialog "add channel". The .info file whose name corresponds to the
+LSB release name is used, e.g. 'Ubuntu.info' on a Ubuntu system.
+
+Furthermore all .info files are used to render the channels presented in the
+sources list more user friendly.
+
+
+Tags
+----
+
+Suite: the name of the dist used in the repository
+
+MatchSuite: mainly used for cdroms. defaults to Suite
+
+ParentSuite: the channel only appears as a component of the parent suite in
+ the add dialog
+ the components/sections of the suite correspond to the ones of
+ the parent suite. specified components of the suite itself
+ are ignored
+
+Available: determs the availabilty of the suite in the add dialog.
+ defaults to False
+
+RepositoryType: does the repository contain binary or source packages
+
+BaseURI: the base URI of the repository
+
+MatchURI: used for identifing mirrors
+
+Description: description of the suite. the translation is done through
+ gettext at runtime
+
+Component: a component/section of the suite (ignored if ParentSuite is
+ set)
+
+CompDescription: humand readable description of the component/section
+ (ignored if ParentSuite is set). the translation is done
+ through gettext at runtime
+
+ValidMirros: A file that contains a list of mirrors
+
+
diff --git a/data/templates/Ubuntu.info.in b/data/templates/Ubuntu.info.in
new file mode 100644
index 00000000..fa76879f
--- /dev/null
+++ b/data/templates/Ubuntu.info.in
@@ -0,0 +1,279 @@
+_ChangelogURI: http://changelogs.ubuntu.com/changelogs/pool/%s/%s/%s/%s_%s/changelog
+
+Suite: feisty
+RepositoryType: deb
+BaseURI: http://archive.ubuntu.com/ubuntu/
+MatchURI: archive.ubuntu.com/ubuntu
+MirrorsFile: /usr/share/python-aptsources/templates/Ubuntu.mirrors
+_Description: Ubuntu 7.04 'Feisty Fawn'
+Component: main
+_CompDescription: Officially supported
+_CompDescriptionLong: Canonical-supported Open Source software
+Component: universe
+_CompDescription: Community-maintained
+_CompDescriptionLong: Community-maintained Open Source software
+Component: restricted
+_CompDescription: Non-free drivers
+_CompDescriptionLong: Proprietary drivers for devices
+Component: multiverse
+_CompDescription: Restricted software
+_CompDescriptionLong: Software restricted by copyright or legal issues
+
+Suite: feisty
+MatchName: .*
+BaseURI: cdrom:\[Ubuntu.*7.04
+_Description: Cdrom with Ubuntu 7.04 'Feisty Fawn'
+Available: False
+Component: main
+_CompDescription: Officially supported
+Component: restricted
+_CompDescription: Restricted copyright
+
+Suite: feisty-security
+ParentSuite: feisty
+RepositoryType: deb
+BaseURI: http://security.ubuntu.com/ubuntu/
+MatchURI: archive.ubuntu.com/ubuntu|security.ubuntu.com
+_Description: Important security updates
+
+Suite: feisty-updates
+ParentSuite: feisty
+RepositoryType: deb
+_Description: Recommended updates
+
+Suite: feisty-proposed
+ParentSuite: feisty
+RepositoryType: deb
+_Description: Proposed updates
+
+Suite: feisty-backports
+ParentSuite: feisty
+RepositoryType: deb
+_Description: Backported updates
+
+Suite: edgy
+RepositoryType: deb
+BaseURI: http://archive.ubuntu.com/ubuntu/
+MatchURI: archive.ubuntu.com/ubuntu
+MirrorsFile: /usr/share/python-aptsources/templates/Ubuntu.mirrors
+_Description: Ubuntu 6.10 'Edgy Eft'
+Component: main
+_CompDescription: Officially supported
+_CompDescriptionLong: Canonical-supported Open Source software
+Component: universe
+_CompDescription: Community-maintained
+_CompDescriptionLong: Community-maintained Open Source software
+Component: restricted
+_CompDescription: Non-free drivers
+_CompDescriptionLong: Proprietary drivers for devices
+Component: multiverse
+_CompDescription: Restricted software
+_CompDescriptionLong: Software restricted by copyright or legal issues
+
+Suite: edgy
+MatchName: .*
+BaseURI: cdrom:\[Ubuntu.*6.10
+_Description: Cdrom with Ubuntu 6.10 'Edgy Eft'
+Available: False
+Component: main
+_CompDescription: Officially supported
+Component: restricted
+_CompDescription: Restricted copyright
+
+Suite: edgy-security
+ParentSuite: edgy
+RepositoryType: deb
+BaseURI: http://security.ubuntu.com/ubuntu/
+MatchURI: archive.ubuntu.com/ubuntu|security.ubuntu.com
+_Description: Important security updates
+
+Suite: edgy-updates
+ParentSuite: edgy
+RepositoryType: deb
+_Description: Recommended updates
+
+Suite: edgy-proposed
+ParentSuite: edgy
+RepositoryType: deb
+_Description: Proposed updates
+
+Suite: edgy-backports
+ParentSuite: edgy
+RepositoryType: deb
+_Description: Backported updates
+
+Suite: dapper
+RepositoryType: deb
+BaseURI: http://archive.ubuntu.com/ubuntu/
+MatchURI: archive.ubuntu.com/ubuntu
+MirrorsFile: /usr/share/python-aptsources/templates/Ubuntu.mirrors
+_Description: Ubuntu 6.06 LTS 'Dapper Drake'
+Component: main
+_CompDescription: Officially supported
+_CompDescriptionLong: Canonical-supported Open Source software
+Component: universe
+_CompDescription: Community-maintained (universe)
+_CompDescriptionLong: Community-maintained Open Source software
+Component: restricted
+_CompDescription: Non-free drivers
+_CompDescriptionLong: Proprietary drivers for devices
+Component: multiverse
+_CompDescription: Restricted software (Multiverse)
+_CompDescriptionLong: Software restricted by copyright or legal issues
+
+Suite: dapper
+MatchName: .*
+BaseURI: cdrom:\[Ubuntu.*6.06
+_Description: Cdrom with Ubuntu 6.06 LTS 'Dapper Drake'
+Available: False
+Component: main
+_CompDescription: Officially supported
+Component: restricted
+_CompDescription: Restricted copyright
+
+Suite: dapper-security
+ParentSuite: dapper
+RepositoryType: deb
+BaseURI: http://security.ubuntu.com/ubuntu/
+MatchURI: archive.ubuntu.com/ubuntu|security.ubuntu.com
+_Description: Important security updates
+
+Suite: dapper-updates
+ParentSuite: dapper
+RepositoryType: deb
+_Description: Recommended updates
+
+Suite: dapper-proposed
+ParentSuite: dapper
+RepositoryType: deb
+_Description: Proposed updates
+
+Suite: dapper-backports
+ParentSuite: dapper
+RepositoryType: deb
+_Description: Backported updates
+
+Suite: breezy
+RepositoryType: deb
+BaseURI: http://archive.ubuntu.com/ubuntu/
+MatchURI: archive.ubuntu.com/ubuntu
+MirrorsFile: /usr/share/python-aptsources/templates/Ubuntu.mirrors
+_Description: Ubuntu 5.10 'Breezy Badger'
+Component: main
+_CompDescription: Officially supported
+Component: restricted
+_CompDescription: Restricted copyright
+Component: universe
+_CompDescription: Community-maintained (Universe)
+Component: multiverse
+_CompDescription: Non-free (Multiverse)
+
+Suite: breezy
+MatchName: .*
+BaseURI: cdrom:\[Ubuntu.*5.10
+_Description: Cdrom with Ubuntu 5.10 'Breezy Badger'
+Available: False
+Component: main
+_CompDescription: Officially supported
+Component: restricted
+_CompDescription: Restricted copyright
+
+Suite: breezy-security
+ParentSuite: breezy
+RepositoryType: deb
+BaseURI: http://security.ubuntu.com/ubuntu/
+MatchURI: archive.ubuntu.com/ubuntu|security.ubuntu.com
+_Description: Ubuntu 5.10 Security Updates
+
+Suite: breezy-updates
+ParentSuite: breezy
+RepositoryType: deb
+_Description: Ubuntu 5.10 Updates
+
+Suite: breezy-backports
+ParentSuite: breezy
+RepositoryType: deb
+_Description: Ubuntu 5.10 Backports
+
+Suite: hoary
+RepositoryType: deb
+BaseURI: http://archive.ubuntu.com/ubuntu/
+MatchURI: archive.ubuntu.com/ubuntu
+MirrorsFile: /usr/share/python-aptsources/templates/Ubuntu.mirrors
+_Description: Ubuntu 5.04 'Hoary Hedgehog'
+Component: main
+_CompDescription: Officially supported
+Component: restricted
+_CompDescription: Restricted copyright
+Component: universe
+_CompDescription: Community-maintained (Universe)
+Component: multiverse
+_CompDescription: Non-free (Multiverse)
+
+Suite: hoary
+MatchName: .*
+BaseURI: cdrom:\[Ubuntu.*5.04
+_Description: Cdrom with Ubuntu 5.04 'Hoary Hedgehog'
+Available: False
+Component: main
+_CompDescription: Officially supported
+Component: restricted
+_CompDescription: Restricted copyright
+
+Suite: hoary-security
+ParentSuite: hoary
+RepositoryType: deb
+BaseURI: http://security.ubuntu.com/ubuntu/
+MatchURI: archive.ubuntu.com/ubuntu|security.ubuntu.com
+_Description: Ubuntu 5.04 Security Updates
+
+Suite: hoary-updates
+ParentSuite: hoary
+RepositoryType: deb
+_Description: Ubuntu 5.04 Updates
+
+Suite: hoary-backports
+ParentSuite: hoary
+RepositoryType: deb
+_Description: Ubuntu 5.04 Backports
+
+Suite: warty
+RepositoryType: deb
+BaseURI: http://archive.ubuntu.com/ubuntu/
+MatchURI: archive.ubuntu.com/ubuntu
+_Description: Ubuntu 4.10 'Warty Warthog'
+Component: main
+_CompDescription: No longer officially supported
+Component: restricted
+_CompDescription: Restricted copyright
+Component: universe
+_CompDescription: Community-maintained (Universe)
+Component: multiverse
+_CompDescription: Non-free (Multiverse)
+
+Suite: warty
+MatchName: .*
+BaseURI: cdrom:\[Ubuntu.*4.10
+_Description: Cdrom with Ubuntu 4.10 'Warty Warthog'
+Available: False
+Component: main
+_CompDescription: No longer officially supported
+Component: restricted
+_CompDescription: Restricted copyright
+
+Suite: warty-security
+ParentSuite: warty
+RepositoryType: deb
+BaseURI: http://security.ubuntu.com/ubuntu/
+MatchURI: archive.ubuntu.com/ubuntu|security.ubuntu.com
+_Description: Ubuntu 4.10 Security Updates
+
+Suite: warty-updates
+ParentSuite: warty
+RepositoryType: deb
+_Description: Ubuntu 4.10 Updates
+
+Suite: warty-backports
+ParentSuite: warty
+RepositoryType: deb
+_Description: Ubuntu 4.10 Backports
diff --git a/data/templates/Ubuntu.mirrors b/data/templates/Ubuntu.mirrors
new file mode 100644
index 00000000..72b2b434
--- /dev/null
+++ b/data/templates/Ubuntu.mirrors
@@ -0,0 +1,267 @@
+#LOC:AU
+http://mirror.optus.net/ubuntu/
+http://mirror.pacific.net.au/linux/ubuntu
+#LOC:AT
+http://ubuntu.inode.at/ubuntu/
+ftp://ubuntu.inode.at/ubuntu/
+rsync://ubuntu.inode.at/ubuntu/ubuntu/
+http://gd.tuwien.ac.at/opsys/linux/ubuntu/archive/
+#LOC:BE
+http://ftp.belnet.be/linux/ubuntu/ubuntu/
+http://ubuntu.mirrors.skynet.be/pub/ubuntu.com/ubuntu/
+#LOC:BR
+http://br.archive.ubuntu.com/ubuntu/
+ftp://br.archive.ubuntu.com/ubuntu/
+rsync://br.archive.ubuntu.com/ubuntu/
+http://espelhos.edugraf.ufsc.br/ubuntu/
+http://ubuntu.c3sl.ufpr.br/ubuntu/
+#LOC:BG
+http://ubuntu.linux-bg.org/ubuntu/
+ftp://ubuntu.linux-bg.org/ubuntu/
+rsync://ubuntu.linux-bg.org::ubuntu
+http://ubuntu.ipacct.com/ubuntu/
+ftp://ubuntu.ipacct.com/ubuntu/
+#LOC:CA
+http://gulus.USherbrooke.ca/ubuntu/
+ftp://gulus.USherbrooke.ca/ubuntu/
+http://mirror.cpsc.ucalgary.ca/mirror/ubuntu.com/
+ftp://mirror.cpsc.ucalgary.ca/mirror/ubuntu.com/
+rsync://mirror.cpsc.ucalgary.ca/mirror/ubuntu.com/
+ftp://ftp.cs.mun.ca/pub/mirror/ubuntu/
+ftp://ftp.cs.mun.ca/pub/mirror/ubuntu/
+http://gulus.usherbrooke.ca/pub/distro/ubuntu/
+http://mirror.arcticnetwork.ca/pub/ubuntu/packages
+http://ubuntu.mirror.rafal.ca/ubuntu/
+#LOC:CL
+http://cl.archive.ubuntu.com/ubuntu/
+ftp://cl.archive.ubuntu.com/ubuntu/
+rsync://cl.archive.ubuntu.com/ubuntu/
+#LOC:CN
+http://ubuntu.cn99.com/ubuntu/
+http://mirror.lupaworld.com/ubuntu/archive/
+#LOC:CR
+http://ftp.ucr.ac.cr/ubuntu/
+#LOC:HR
+http://hr.archive.ubuntu.com/ubuntu
+ftp://hr.archive.ubuntu.com/ubuntu
+rsync://hr.archive.ubuntu.com/ubuntu
+#LOC:CZ
+http://ubuntu.supp.name/ubuntu/
+http://ubuntu.sh.cvut.cz/
+http://ubuntu.supp.name/ubuntu
+#LOC:DK
+http://dk.archive.ubuntu.com/ubuntu/
+http://klid.dk/ftp/ubuntu/
+ftp://klid.dk/ubuntu
+http://mirror.uni-c.dk/ubuntu/
+http://mirrors.dotsrc.org/ubuntu
+#LOC:EE
+http://ftp.estpak.ee/ubuntu/
+ftp://ftp.estpak.ee/ubuntu/
+rsync://ftp.estpak.ee/ubuntu/
+http://ftp.estpak.ee/pub/ubuntu/
+#LOC:FI
+http://www.nic.funet.fi/pub/mirrors/archive.ubuntu.com/
+ftp://ftp.funet.fi/pub/mirrors/archive.ubuntu.com/
+rsync://rsync.nic.funet.fi/ftp/pub/mirrors/archive.ubuntu.com/
+http://mirrors.nic.funet.fi/ubuntu/
+#LOC:FR
+ftp://ftp.free.fr/mirrors/ftp.ubuntu.com/ubuntu/
+ftp://ftp.free.fr/mirrors/ftp.ubuntu.com/ubuntu/
+http://ftp.crihan.fr/ubuntu
+ftp://ftp.crihan.fr/ubuntu/
+rsync://ftp.crihan.fr/ubuntu/
+http://ftp.oleane.net/ubuntu
+ftp://ftp.oleane.net/ubuntu
+http://ftp.u-picardie.fr/mirror/ubuntu/ubuntu/
+ftp://ftp.u-picardie.fr/mirror/ubuntu/ubuntu/
+ftp://ubuntu.univ-nantes.fr/ubuntu
+ftp://ubuntu.univ-nantes.fr/ubuntu
+http://ftp.crihan.fr/mirrors/archive.ubuntu.com/
+ftp://ftp.free.fr/mirrors/ftp.ubuntu.com/ubuntu
+ftp://ftp.free.fr/mirrors/ftp.ubuntu.com/ubuntu
+#LOC:GE
+http://ubuntu.eriders.ge/ubuntu
+#LOC:DE
+http://ubuntu.intergenia.de/ubuntu/
+rsync://ubuntu.intergenia.de/ubuntu-linux/ubuntu/
+ftp://ftp.fu-berlin.de/linux/ubuntu/
+ftp://ftp.fu-berlin.de/linux/ubuntu/
+http://ftp.halifax.rwth-aachen.de/ubuntu/
+ftp://ftp.halifax.rwth-aachen.de/ubuntu/
+http://ftp.stw-bonn.de/ubuntu/
+ftp://ftp.stw-bonn.de/ubuntu/
+rsync://ftp.stw-bonn.de/ubuntu/
+http://debian.charite.de/ubuntu/
+http://de.archive.ubuntu.com/ubuntu/
+ftp://ftp.cw.net/pub/linux/ftp.ubuntu.com/ubuntu/
+ftp://ftp.cw.net/pub/linux/ftp.ubuntu.com/ubuntu/
+http://ftp-stud.fht-esslingen.de/Mirrors/ubuntu
+http://ftp.stw-bonn.de/ubuntu
+http://ftp.tu-chemnitz.de/pub/linux/ubuntu/
+http://ftp.uni-muenster.de/pub/mirrors/ftp.ubuntu.com/ubuntu/
+http://snert.mi.hs-heilbronn.de/pub/ubuntu/ubuntu/
+#LOC:GR
+http://ftp.duth.gr/pub/ubuntu/
+ftp://ftp.duth.gr/pub/ubuntu/
+rsync://ftp.duth.gr/ubuntu/
+http://ftp.ntua.gr/pub/linux/ubuntu/
+ftp://ftp.ntua.gr/pub/linux/ubuntu/
+http://gr.archive.ubuntu.com/ubuntu/
+ftp://gr.archive.ubuntu.com/ubuntu/
+#LOC:HU
+ftp://ftp.fsn.hu/pub/linux/distributions/ubuntu
+ftp://ftp.fsn.hu/pub/linux/distributions/ubuntu
+#LOC:IS
+http://ubuntu.lhi.is/ubuntu
+#LOC:IE
+http://ie.archive.ubuntu.com/ubuntu/
+ftp://ie.archive.ubuntu.com/ubuntu/
+rsync://ie.archive.ubuntu.com/ubuntu/
+http://ftp.esat.net/mirrors/archive.ubuntu.com/
+http://ftp.heanet.ie/pub/ubuntu/
+#LOC:IT
+http://na.mirror.garr.it/mirrors/ubuntu-archive/
+ftp://na.mirror.garr.it/mirrors/ubuntu-archive/
+rsync://na.mirror.garr.it::ubuntu-archive/
+http://ubuntu.fastbull.org/ubuntu/
+ftp://ubuntu.fastbull.org/ubuntu/
+http://na.mirror.garr.it/mirrors/ubuntu-archive
+#LOC:JP
+http://ftp.ecc.u-tokyo.ac.jp/ubuntu/
+#LOC:KR
+http://kr.archive.ubuntu.com/ubuntu/
+ftp://kr.archive.ubuntu.com/ubuntu/
+rsync://kr.archive.ubuntu.com/ubuntu
+http://ftp.kaist.ac.kr/pub/ubuntu
+http://mirror.letsopen.com/os/ubuntu
+#LOC:LV
+http://ftp.linux.edu.lv/ubuntu/
+#LOC:LT
+http://ftp.litnet.lt/pub/ubuntu
+#LOC:MN
+http://archive.mnosi.org/ubuntu/
+ftp://archive.mnosi.org/ubuntu/
+#LOC:NL
+http://nl.archive.ubuntu.com/ubuntu/
+ftp://nl.archive.ubuntu.com/ubuntu/
+rsync://nl.archive.ubuntu.com/ubuntu/
+http://ftp.tiscali.nl/ubuntu/
+ftp://ftp.tiscali.nl/pub/mirror/ubuntu
+ftp://ftp.tudelft.nl/pub/Linux/archive.ubuntu.com/
+ftp://ftp.tudelft.nl/pub/Linux/archive.ubuntu.com/
+ftp://ftpserv.tudelft.nl/pub/Linux/archive.ubuntu.com/
+ftp://ftpserv.tudelft.nl/pub/Linux/archive.ubuntu.com/
+http://ubuntu.bit.nl/ubuntu/
+#LOC:NZ
+http://ftp.citylink.co.nz/ubuntu/
+#LOC:NO
+http://ftp.uninett.no/ubuntu/
+ftp://ftp.uninett.no/ubuntu/
+rsync://ftp.uninett.no/ubuntu/
+http://no.archive.ubuntu.com/ubuntu/
+ftp://no.archive.ubuntu.com/ubuntu/
+http://no.archive.ubuntu.com/ubuntu
+ftp://no.archive.ubuntu.com/ubuntu
+ftp://ftp.uninett.no/linux/ubuntu
+ftp://ftp.uninett.no/linux/ubuntu
+http://mirror.trivini.no/ubuntu/
+#LOC:PL
+http://ftp.vectranet.pl/ubuntu
+ftp://ftp.vectranet.pl/ubuntu
+rsync://ftp.vectranet.pl/ubuntu
+ftp://ftp.man.szczecin.pl/pub/Linux/ubuntu/
+ftp://ftp.man.szczecin.pl/pub/Linux/ubuntu/
+http://ubuntu.task.gda.pl/ubuntu/
+#LOC:PT
+http://ftp.dei.uc.pt/pub/linux/ubuntu/archive/
+ftp://ftp.dei.uc.pt/pub/linux/ubuntu/archive/
+http://ubuntu.dcc.fc.up.pt/
+http://ftp.gil.di.uminho.pt/ubuntu/
+ftp://ftp.gil.di.uminho.pt/ubuntu/
+rsync://ftp.gil.di.uminho.pt/ubuntu/
+http://ubuntu.dcc.fc.up.pt
+#LOC:RO
+http://ftp.lug.ro/ubuntu/
+#LOC:RU
+http://ftp.chg.ru/pub/Linux/ubuntu/archive/
+#LOC:CS
+http://yu.archive.ubuntu.com/ubuntu
+ftp://yu.archive.ubuntu.com/ubuntu
+rsync://yu.archive.ubuntu.com/ubuntu
+http://mirror.etf.bg.ac.yu/distributions/ubuntu/ubuntu-archive/
+http://mirror2.etf.bg.ac.yu/distributions/ubuntu/ubuntu-archive/
+#LOC:SK
+http://ubuntu.ynet.sk/ubuntu/
+#LOC:ZA
+http://ubuntu.mirror.ac.za/
+ftp://ubuntu.mirror.ac.za
+rsync://ubuntu.mirror.ac.za/Ubuntu
+http://ftp.leg.uct.ac.za/pub/linux/ubuntu/
+ftp://ftp.leg.uct.ac.za/pub/linux/ubuntu/
+rsync://ftp.leg.uct.ac.za/pub/linux/ubuntu/
+#LOC:ES
+http://ftp.gui.uva.es/sites/ubuntu.com/ubuntu/
+ftp://ftp.um.es/mirror/ubuntu/
+ftp://ftp.um.es/mirror/ubuntu/
+#LOC:SE
+http://se.archive.ubuntu.com/ubuntu/
+ftp://se.archive.ubuntu.com/ubuntu/
+rsync://se.archive.ubuntu.com/ubuntu/
+http://ftp.ds.karen.hj.se/pub/os/linux/ubuntu/
+ftp://ftp.ds.karen.hj.se/pub/os/linux/ubuntu/
+http://ftp.port80.se/ubuntu/
+#LOC:CH
+http://mirror.switch.ch/ftp/mirror/ubuntu/
+ftp://mirror.switch.ch/mirror/ubuntu/
+#LOC:TW
+http://ftp.cse.yzu.edu.tw/pub/Linux/Ubuntu/ubuntu/
+ftp://ftp.cse.yzu.edu.tw/pub/Linux/Ubuntu/ubuntu/
+http://ftp.twaren.net/Linux/Ubuntu/ubuntu/
+ftp://ftp.twaren.net/Linux/Ubuntu/ubuntu/
+http://mirror.nttu.edu.tw/ubuntu/
+ftp://mirror.nttu.edu.tw/ubuntu/
+http://tw.archive.ubuntu.com/ubuntu
+ftp://tw.archive.ubuntu.com/ubuntu
+rsync://tw.archive.ubuntu.com/ubuntu
+http://debian.linux.org.tw/ubuntu
+http://ftp.cse.yzu.edu.tw/ubuntu/
+#LOC:GB
+http://www.mirrorservice.org/sites/archive.ubuntu.com/ubuntu/
+ftp://ftp.mirrorservice.org/sites/archive.ubuntu.com/ubuntu/
+rsync://rsync.mirrorservice.org/archive.ubuntu.com/ubuntu/
+http://archive.ubuntu.com/ubuntu/
+ftp://archive.ubuntu.com/ubuntu/
+rsync://archive.ubuntu.com/ubuntu
+http://ftp.ticklers.org/archive.ubuntu.org/ubuntu/
+ftp://ftp.ticklers.org/archive.ubuntu.org/ubuntu/
+rsync://ftp0.ticklers.org/archive.ubuntu.org/ubuntu/
+#LOC:US
+http://mirror.anl.gov/pub/ubuntu/
+ftp://mirror.anl.gov/pub/ubuntu/
+rsync://mirror.anl.gov/ubuntu/
+http://mirrors.cat.pdx.edu/ubuntu/
+ftp://mirrors.cat.pdx.edu/ubuntu/
+rsync://mirrors.cat.pdx.edu/ubuntu/
+http://www.gtlib.gatech.edu/pub/ubuntu
+ftp://ftp.gtlib.gatech.edu/pub/ubuntu
+rsync://rsync.gtlib.gatech.edu/ubuntu
+http://mirror.cc.columbia.edu/pub/linux/ubuntu/archive/
+ftp://mirror.cc.columbia.edu/pub/linux/ubuntu/archive/
+http://mirror.cs.umn.edu/ubuntu/
+rsync://mirror.cs.umn.edu/ubuntu/
+http://carroll.cac.psu.edu/pub/linux/distributions/ubuntu/
+http://ftp.unina.it/pub/linux/distributions/ubuntu
+http://ftp.ussg.iu.edu/linux/ubuntu/
+http://lug.mtu.edu/ubuntu/
+ftp://lug.mtu.edu/ubuntu/
+rsync://lug.mtu.edu/ubuntu/
+http://mirror.mcs.anl.gov/pub/ubuntu/
+http://mirrors.cs.wmich.edu/ubuntu/
+http://tamago.cs.ucr.edu/ubuntu/ubuntu/
+http://ubuntu.cs.utah.edu/ubuntu
+http://ubuntu.secs.oakland.edu/
+#LOC:UZ
+http://ubuntu.uz/ubuntu/
+http://ubuntu.snet.uz/ubuntu/
+ftp://ubuntu.snet.uz/ubuntu/
diff --git a/debian/control b/debian/control
index 765c3914..4ea3a31c 100644
--- a/debian/control
+++ b/debian/control
@@ -5,18 +5,18 @@ Maintainer: APT Development Team <deity@lists.debian.org>
Uploaders: Matt Zimmerman <mdz@debian.org>, Michael Vogt <mvo@debian.org>
Standards-Version: 3.7.2
XS-Python-Version: all
-Build-Depends: debhelper (>= 5.0.37.1), libapt-pkg-dev (>= 0.6.45ubuntu3), apt-utils, python-all-dev, python-central
+Build-Depends: debhelper (>= 5.0.37.1), libapt-pkg-dev (>= 0.6.45), apt-utils, python-all-dev, python-central, python-distutils-extra, cdbs
Package: python-apt
Architecture: any
-Depends: ${python:Depends}, ${shlibs:Depends}, ${misc:Depends}
+Depends: ${python:Depends}, ${shlibs:Depends}, ${misc:Depends}, lsb-release
Priority: optional
Replaces: python2.3-apt (<< 0.6.18), python2.4-apt (<< 0.6.18)
Conflicts: python2.3-apt (<< 0.6.18), python2.4-apt (<< 0.6.18)
Provides: ${python:Provides}
XB-Python-Version: ${python:Versions}
Description: Python interface to libapt-pkg
- The apt-pkg Python interface will provide full access to the internal
+ The apt_pkg Python interface will provide full access to the internal
libapt-pkg structures allowing Python programs to easily perform a
variety of functions, such as:
.
@@ -24,3 +24,6 @@ Description: Python interface to libapt-pkg
- Access to the APT package information database
- Parsing of Debian package control files, and other files with a
similar structure
+ .
+ The included 'aptsources' Python interface provides an abstraction of
+ the sources.list configuration on the repository and the distro level.
diff --git a/debian/python-apt.docs b/debian/python-apt.docs
index f7756d28..208050c5 100644
--- a/debian/python-apt.docs
+++ b/debian/python-apt.docs
@@ -1,2 +1,3 @@
README
apt/README.apt
+data/templates/README.templates
diff --git a/debian/rules b/debian/rules
index 7299f554..6367c02f 100755
--- a/debian/rules
+++ b/debian/rules
@@ -1,76 +1,8 @@
#!/usr/bin/make -f
-# Made with the aid of dh_make, by Craig Small
-# Sample debian/rules that uses debhelper. GNU copyright 1997 by Joey Hess.
-# Some lines taken from debmake, by Cristoph Lameter.
-# This has to be exported to make some magic below work.
-export DH_OPTIONS
+DEB_AUTO_CLEANUP_RCS := yes
+DEB_PYTHON_SYSTEM=pycentral
-DEBVER=$(shell dpkg-parsechangelog |sed -n -e '/^Version:/s/^Version: //p')
-DEB_BUILD_PROG:=debuild --preserve-envvar PATH --preserve-envvar CCACHE_DIR -us -uc $(DEB_BUILD_PROG_OPTS)
-
-# Uncomment this to turn on verbose mode.
-#export DH_VERBOSE=1
-
-PYTHON=$(shell pyversions -r debian/control)
-
-build: build-stamp
-build-stamp:
- dh_testdir
-
- for PY in $(PYTHON); do \
- /usr/bin/$$PY setup.py build; \
- done
-
- touch build-stamp
-
-clean:
- dh_testdir
- dh_testroot
- rm -f build-stamp
-
- for PY in $(PYTHON); do \
- /usr/bin/$$PY setup.py clean --all; \
- done
-
- dh_clean
-
-# Build architecture-independent files here.
-binary-indep: DH_OPTIONS=-i
-binary-indep: build
-
-# Build architecture-dependent files here.
-binary-arch: DH_OPTIONS=-a
-binary-arch: build
- dh_testdir
- dh_testroot
- dh_clean -k
-
- for PY in $(PYTHON); do \
- /usr/bin/$$PY setup.py install --prefix=`pwd`/debian/python-apt/usr; \
- done
-
- dh_installdocs
- dh_installchangelogs
- dh_installexamples
- dh_pycentral
- dh_strip
- dh_compress
- dh_fixperms
- dh_installdeb
- dh_shlibdeps
- dh_gencontrol
- dh_md5sums
- dh_builddeb
-
-source diff:
- @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false
-
-arch-build:
- rm -rf debian/arch-build
- mkdir -p debian/arch-build/python-apt-$(DEBVER)
- tar -c --exclude=arch-build --no-recursion -f - `bzr inventory` | (cd debian/arch-build/python-apt-$(DEBVER);tar xf -)
- (cd debian/arch-build/python-apt-$(DEBVER); $(DEB_BUILD_PROG))
-
-binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary
+# Add here any variable or target overrides you need
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/python-distutils.mk
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644
index 00000000..d5a84db2
--- /dev/null
+++ b/po/POTFILES.in
@@ -0,0 +1,3 @@
+[encoding: UTF-8]
+[type: gettext/rfc822deb] data/templates/Ubuntu.info.in
+[type: gettext/rfc822deb] data/templates/Debian.info.in
diff --git a/po/python-apt.pot b/po/python-apt.pot
new file mode 100644
index 00000000..ba144165
--- /dev/null
+++ b/po/python-apt.pot
@@ -0,0 +1,269 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-01-26 14:17+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. ChangelogURI
+#: ../data/templates/Ubuntu.info.in.h:4
+#, no-c-format
+msgid "http://changelogs.ubuntu.com/changelogs/pool/%s/%s/%s/%s_%s/changelog"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:8
+msgid "Ubuntu 7.04 'Feisty Fawn'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:25
+msgid "Cdrom with Ubuntu 7.04 'Feisty Fawn'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:59
+msgid "Ubuntu 6.10 'Edgy Eft'"
+msgstr ""
+
+#. CompDescription
+#: ../data/templates/Ubuntu.info.in:64
+msgid "Community-maintained"
+msgstr ""
+
+#. CompDescriptionLong
+#: ../data/templates/Ubuntu.info.in:68
+msgid "Proprietary drivers for devices"
+msgstr ""
+
+#. CompDescription
+#: ../data/templates/Ubuntu.info.in:70
+msgid "Restricted software"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:76
+msgid "Cdrom with Ubuntu 6.10 'Edgy Eft'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:110
+msgid "Ubuntu 6.06 LTS 'Dapper Drake'"
+msgstr ""
+
+#. CompDescriptionLong
+#: ../data/templates/Ubuntu.info.in:113
+msgid "Canonical-supported Open Source software"
+msgstr ""
+
+#. CompDescription
+#: ../data/templates/Ubuntu.info.in:115
+msgid "Community-maintained (universe)"
+msgstr ""
+
+#. CompDescriptionLong
+#: ../data/templates/Ubuntu.info.in:116
+msgid "Community-maintained Open Source software"
+msgstr ""
+
+#. CompDescription
+#: ../data/templates/Ubuntu.info.in:118
+msgid "Non-free drivers"
+msgstr ""
+
+#. CompDescriptionLong
+#: ../data/templates/Ubuntu.info.in:119
+msgid "Proprietary drivers for devices "
+msgstr ""
+
+#. CompDescription
+#: ../data/templates/Ubuntu.info.in:121
+msgid "Restricted software (Multiverse)"
+msgstr ""
+
+#. CompDescriptionLong
+#: ../data/templates/Ubuntu.info.in:122
+msgid "Software restricted by copyright or legal issues"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:127
+msgid "Cdrom with Ubuntu 6.06 LTS 'Dapper Drake'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:139
+msgid "Important security updates"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:144
+msgid "Recommended updates"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:149 ../data/templates/Debian.info.in:42
+msgid "Proposed updates"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:154
+msgid "Backported updates"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:161
+msgid "Ubuntu 5.10 'Breezy Badger'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:174
+msgid "Cdrom with Ubuntu 5.10 'Breezy Badger'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:186
+msgid "Ubuntu 5.10 Security Updates"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:191
+msgid "Ubuntu 5.10 Updates"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:196
+msgid "Ubuntu 5.10 Backports"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:203
+msgid "Ubuntu 5.04 'Hoary Hedgehog'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:216
+msgid "Cdrom with Ubuntu 5.04 'Hoary Hedgehog'"
+msgstr ""
+
+#. CompDescription
+#: ../data/templates/Ubuntu.info.in:219 ../data/templates/Debian.info.in:94
+msgid "Officially supported"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:228
+msgid "Ubuntu 5.04 Security Updates"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:233
+msgid "Ubuntu 5.04 Updates"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:238
+msgid "Ubuntu 5.04 Backports"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:244
+msgid "Ubuntu 4.10 'Warty Warthog'"
+msgstr ""
+
+#. CompDescription
+#: ../data/templates/Ubuntu.info.in:250
+msgid "Community-maintained (Universe)"
+msgstr ""
+
+#. CompDescription
+#: ../data/templates/Ubuntu.info.in:252
+msgid "Non-free (Multiverse)"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:257
+msgid "Cdrom with Ubuntu 4.10 'Warty Warthog'"
+msgstr ""
+
+#. CompDescription
+#: ../data/templates/Ubuntu.info.in:260
+msgid "No longer officially supported"
+msgstr ""
+
+#. CompDescription
+#: ../data/templates/Ubuntu.info.in:262
+msgid "Restricted copyright"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:269
+msgid "Ubuntu 4.10 Security Updates"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:274
+msgid "Ubuntu 4.10 Updates"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:279
+msgid "Ubuntu 4.10 Backports"
+msgstr ""
+
+#. ChangelogURI
+#: ../data/templates/Debian.info.in.h:4
+#, no-c-format
+msgid "http://packages.debian.org/changelogs/pool/%s/%s/%s/%s_%s/changelog"
+msgstr ""
+
+#. Description
+#: ../data/templates/Debian.info.in:8
+msgid "Debian 4.0 'Etch' "
+msgstr ""
+
+#. Description
+#: ../data/templates/Debian.info.in:31
+msgid "Debian 3.1 'Sarge'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Debian.info.in:47
+msgid "Security updates"
+msgstr ""
+
+#. Description
+#: ../data/templates/Debian.info.in:54
+msgid "Debian current stable release"
+msgstr ""
+
+#. Description
+#: ../data/templates/Debian.info.in:67
+msgid "Debian testing"
+msgstr ""
+
+#. Description
+#: ../data/templates/Debian.info.in:92
+msgid "Debian 'Sid' (unstable)"
+msgstr ""
+
+#. CompDescription
+#: ../data/templates/Debian.info.in:96
+msgid "DFSG-compatible Software with Non-Free Dependencies"
+msgstr ""
+
+#. CompDescription
+#: ../data/templates/Debian.info.in:98
+msgid "Non-DFSG-compatible Software"
+msgstr ""
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 00000000..718b6e23
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,8 @@
+[build]
+l10n=True
+
+[build_l10n]
+domain=python-apt
+
+[sdist]
+formats = bztar
diff --git a/setup.py b/setup.py
index 5adb0376..99bc62c6 100644..100755
--- a/setup.py
+++ b/setup.py
@@ -3,8 +3,8 @@
from distutils.core import setup, Extension
from distutils.sysconfig import parse_makefile
-import string, glob
-
+from DistUtilsExtra.distutils_extra import build_extra, build_l10n
+import glob, os, string
# The apt_pkg module
files = map(lambda source: "python/"+source,
@@ -16,6 +16,18 @@ files = map(lambda source: "python/"+source,
string.split(parse_makefile("python/makefile")["APT_INST_SRC"]))
apt_inst = Extension("apt_inst", files, libraries=["apt-pkg","apt-inst"]);
+# Replace the leading _ that is used in the templates for translation
+templates = []
+if not os.path.exists("build/data/templates/"):
+ os.makedirs("build/data/templates")
+for template in glob.glob('data/templates/*.info.in'):
+ source = open(template, "r")
+ build = open(os.path.join("build", template[:-3]), "w")
+ lines = source.readlines()
+ for line in lines:
+ build.write(line.lstrip("_"))
+ source.close()
+ build.close()
setup(name="python-apt",
version="0.6.17",
@@ -23,6 +35,13 @@ setup(name="python-apt",
author="APT Development Team",
author_email="deity@lists.debian.org",
ext_modules=[apt_pkg,apt_inst],
- packages=['apt']
+ packages=['apt', 'aptsources'],
+ data_files = [('share/python-apt/templates',
+ glob.glob('build/data/templates/*.info')),
+ ('share/python-apt/templates',
+ glob.glob('data/templates/*.mirrors'))],
+ cmdclass = { "build" : build_extra,
+ "build_l10n" : build_l10n },
+ license = 'GNU GPL',
+ platforms = 'posix'
)
-
diff --git a/tests/data/sources.list b/tests/data/sources.list
new file mode 100644
index 00000000..5481d4f0
--- /dev/null
+++ b/tests/data/sources.list
@@ -0,0 +1,6 @@
+# comment 1
+deb http://de.archive.ubuntu.com/ubuntu/ edgy main
+# comment 2
+deb http://de.archive.ubuntu.com/ubuntu/ edgy restricted
+# comment 3
+deb http://de.archive.ubuntu.com/ubuntu/ edgy universe \ No newline at end of file
diff --git a/tests/data/sources.list.testDistribution b/tests/data/sources.list.testDistribution
new file mode 100644
index 00000000..1687c504
--- /dev/null
+++ b/tests/data/sources.list.testDistribution
@@ -0,0 +1,11 @@
+deb http://de.archive.ubuntu.com/ubuntu/ edgy main
+deb http://de.archive.ubuntu.com/ubuntu/ edgy restricted
+deb http://de.archive.ubuntu.com/ubuntu/ edgy universe
+deb http://de.archive.ubuntu.com/ubuntu/ edgy-updates universe multiverse
+deb http://de.archive.ubuntu.com/ubuntu/ edgy-updates restricted
+deb http://de.archive.ubuntu.com/ubuntu/ edgy-security main
+deb http://de.archive.ubuntu.com/ubuntu/ edgy-security multiverse
+deb http://ftp.debian.org/debian sid main
+deb ftp://ubuntu.cs.utah.edu/pub/ubuntu/ubuntu/ breezy main
+deb ftp://ubuntu.cs.utah.edu/pub/ubuntu/ubuntu/ breezy-backports main
+deb http://archive.ubuntu.com/ubuntu/ hoary main
diff --git a/tests/test_aptsources.py b/tests/test_aptsources.py
new file mode 100644
index 00000000..3ee106be
--- /dev/null
+++ b/tests/test_aptsources.py
@@ -0,0 +1,127 @@
+#!/usr/bin/env python
+
+import UpdateManager.Common.aptsources as aptsources
+import unittest
+import apt_pkg
+import os
+import copy
+
+class TestAptSources(unittest.TestCase):
+ def __init__(self, methodName):
+ unittest.TestCase.__init__(self, methodName)
+ apt_pkg.init()
+ apt_pkg.Config.Set("Dir::Etc", os.getcwd())
+ apt_pkg.Config.Set("Dir::Etc::sourceparts",".")
+
+ def testIsMirror(self):
+ self.assertTrue(aptsources.is_mirror("http://archive.ubuntu.com",
+ "http://de.archive.ubuntu.com"))
+ self.assertFalse(aptsources.is_mirror("http://archive.ubuntu.com",
+ "http://ftp.debian.org"))
+
+ def testSourcesListReading(self):
+ apt_pkg.Config.Set("Dir::Etc::sourcelist","data/sources.list")
+ sources = aptsources.SourcesList()
+ self.assertEqual(len(sources.list), 6)
+ # test load
+ sources.list = []
+ sources.load("data/sources.list")
+ self.assertEqual(len(sources.list), 6)
+
+ def testSourcesListAdding(self):
+ apt_pkg.Config.Set("Dir::Etc::sourcelist","data/sources.list")
+ sources = aptsources.SourcesList()
+ # test to add something that is already there (main)
+ before = copy.deepcopy(sources)
+ sources.add("deb","http://de.archive.ubuntu.com/ubuntu/",
+ "edgy",
+ ["main"])
+ self.assertTrue(sources.list == before.list)
+ # test to add something that is already there (restricted)
+ before = copy.deepcopy(sources)
+ sources.add("deb","http://de.archive.ubuntu.com/ubuntu/",
+ "edgy",
+ ["restricted"])
+ self.assertTrue(sources.list == before.list)
+ # test to add something new: multiverse
+ sources.add("deb","http://de.archive.ubuntu.com/ubuntu/",
+ "edgy",
+ ["multiverse"])
+ found = False
+ for entry in sources:
+ if (entry.type == "deb" and
+ entry.uri == "http://de.archive.ubuntu.com/ubuntu/" and
+ entry.dist == "edgy" and
+ "multiverse" in entry.comps):
+ found = True
+ self.assertTrue(found)
+ # test to add something new: multiverse *and*
+ # something that is already there
+ before = copy.deepcopy(sources)
+ sources.add("deb","http://de.archive.ubuntu.com/ubuntu/",
+ "edgy",
+ ["universe", "something"])
+ found_universe = 0
+ found_something = 0
+ for entry in sources:
+ if (entry.type == "deb" and
+ entry.uri == "http://de.archive.ubuntu.com/ubuntu/" and
+ entry.dist == "edgy"):
+ for c in entry.comps:
+ if c == "universe":
+ found_universe += 1
+ if c == "something":
+ found_something += 1
+ #print "\n".join([s.str() for s in sources])
+ self.assertEqual(found_something, 1)
+ self.assertEqual(found_universe, 1)
+
+ def testDistribution(self):
+ apt_pkg.Config.Set("Dir::Etc::sourcelist","data/sources.list.testDistribution")
+ sources = aptsources.SourcesList()
+ distro = aptsources.Distribution()
+ distro.get_sources(sources)
+ # test if all suits of the current distro were detected correctly
+ dist_templates = set()
+ for s in sources:
+ if s.template:
+ dist_templates.add(s.template.name)
+ #print dist_templates
+ for d in ["edgy","edgy-security","edgy-updates","hoary","breezy", "breezy-backports"]:
+ self.assertTrue(d in dist_templates)
+ # test enable
+ comp = "restricted"
+ distro.enable_component(sources, comp)
+ found = {}
+ for entry in sources:
+ if (entry.type == "deb" and
+ entry.uri == "http://de.archive.ubuntu.com/ubuntu/" and
+ "edgy" in entry.dist):
+ for c in entry.comps:
+ if c == comp:
+ if not found.has_key(entry.dist):
+ found[entry.dist] = 0
+ found[entry.dist] += 1
+ #print "".join([s.str() for s in sources])
+ for key in found:
+ self.assertEqual(found[key], 1)
+
+ # add a not-already available component
+ comp = "multiverse"
+ distro.enable_component(sources, comp)
+ found = {}
+ for entry in sources:
+ if (entry.type == "deb" and
+ entry.template and
+ entry.template.name == "edgy"):
+ for c in entry.comps:
+ if c == comp:
+ if not found.has_key(entry.dist):
+ found[entry.dist] = 0
+ found[entry.dist] += 1
+ #print "".join([s.str() for s in sources])
+ for key in found:
+ self.assertEqual(found[key], 1)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/utils/get_debian_mirrors.py b/utils/get_debian_mirrors.py
new file mode 100755
index 00000000..ccddf8ed
--- /dev/null
+++ b/utils/get_debian_mirrors.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+#
+# get_debian_mirrors.py
+#
+# Download the latest list with available mirrors from the Debian
+# website and extract the hosts from the raw page
+#
+# Copyright (c) 2006 Free Software Foundation Europe
+#
+# Author: Sebastian Heinlein <glatzor@ubuntu.com>
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+
+import urllib2
+import re
+import os
+import commands
+import sys
+
+# the list of official Ubuntu servers
+mirrors = []
+# path to the local mirror list
+list_path = "../data/templates/Debian.mirrors"
+
+req = urllib2.Request("http://www.debian.org/mirror/mirrors_full")
+match = re.compile("^.*>([A-Za-z0-9-.\/_]+)<\/a>.*\n$")
+match_location = re.compile('^<strong><a name="([A-Z]+)">.*')
+
+def add_sites(line, proto, sites, mirror_type):
+ path = match.sub(r"\1", line)
+ for site in sites:
+ mirror_type.append("%s://%s%s\n" % (proto, site.lstrip(), path))
+
+try:
+ print "Downloading mirrors list from the Debian website..."
+ uri=urllib2.urlopen(req)
+ for line in uri.readlines():
+ if line.startswith('<strong><a name="'):
+ location = match_location.sub(r"\1", line)
+ if location:
+ mirrors.append("#LOC:%s" % location)
+ if line.startswith("Site:"):
+ sites = line[6:-1].split(",")
+ elif line.startswith('Packages over HTTP'):
+ add_sites(line, "http", sites, mirrors)
+ elif line.startswith('Packages over FTP'):
+ add_sites(line, "ftp", sites, mirrors)
+ uri.close()
+except:
+ print "Failed to download or to extract the mirrors list!"
+ sys.exit(1)
+
+print "Writing local mirrors list: %s" % list_path
+list = open(list_path, "w")
+for mirror in mirrors:
+ list.write("%s" % mirror)
+list.close()
+print "Done."
diff --git a/utils/get_ubuntu_mirrors.py b/utils/get_ubuntu_mirrors.py
new file mode 100755
index 00000000..62b18ba6
--- /dev/null
+++ b/utils/get_ubuntu_mirrors.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+#
+# get_ubuntu_mirrors.py
+#
+# Download the latest list with available mirrors from the Ubuntu
+# wiki and extract the hosts from the raw page
+#
+# Copyright (c) 2006 Free Software Foundation Europe
+#
+# Author: Sebastian Heinlein <glatzor@ubuntu.com>
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+
+import urllib2
+import re
+import os
+import commands
+import sys
+
+# the list of official Ubuntu servers
+mirrors = []
+# path to the local mirror list
+list_path = "../data/templates/Ubuntu.mirrors"
+
+req = urllib2.Request("https://wiki.ubuntu.com/Archive?action=raw")
+
+try:
+ print "Downloading mirrors list from the Ubuntu wiki..."
+ uri=urllib2.urlopen(req)
+ p = re.compile('^.*((http|ftp):\/\/[A-Za-z0-9-.:\/_]+).*\n*$')
+ for line in uri.readlines():
+ if r"[[Anchor(dvd-images)]]" in line:
+ break
+ if "http://" in line or "ftp://" in line:
+ mirrors.append(p.sub(r"\1", line))
+ uri.close()
+except:
+ print "Failed to download or extract the mirrors list!"
+ sys.exit(1)
+
+print "Writing local mirrors list: %s" % list_path
+list = open(list_path, "w")
+for mirror in mirrors:
+ list.write("%s\n" % mirror)
+list.close()
+print "Done."
+
+
diff --git a/utils/get_ubuntu_mirrors_from_lp.py b/utils/get_ubuntu_mirrors_from_lp.py
new file mode 100755
index 00000000..fad495b5
--- /dev/null
+++ b/utils/get_ubuntu_mirrors_from_lp.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+#
+# get_ubuntu_lp_mirrors.py
+#
+# Download the latest list with available Ubuntu mirrors from Launchpad.net
+# and extract the hosts from the raw page
+#
+# Copyright (c) 2006 Free Software Foundation Europe
+#
+# Author: Sebastian Heinlein <glatzor@ubuntu.com>
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+
+import urllib2
+import re
+import sys
+
+# the list of official Ubuntu servers
+mirrors = []
+# path to the local mirror list
+list_path = "../data/templates/Ubuntu.mirrors"
+
+
+try:
+ f = open("/usr/share/iso-codes/iso_3166.tab", "r")
+ lines = f.readlines()
+ f.close()
+except:
+ print "Could not read country information"
+ sys.exit(1)
+
+countries = {}
+for line in lines:
+ parts = line.split("\t")
+ countries[parts[1].strip()] = parts[0].lower()
+
+req = urllib2.Request("https://launchpad.net/ubuntu/+archivemirrors")
+print "Downloading mirrors list from the Ubuntu wiki..."
+try:
+ uri=urllib2.urlopen(req)
+ content = uri.read()
+ uri.close()
+except:
+ print "Failed to download or extract the mirrors list!"
+ sys.exit(1)
+
+content = content.replace("\n", "")
+
+content_splits = re.split(r'<tr class="highlighted"',
+ re.findall(r'<table class="listing">.+?</table>',
+ content)[0])
+lines=[]
+def find(split):
+ country = re.search(r"<strong>(.+?)</strong>", split)
+ if not country:
+ return
+ urls = re.findall(r'<a href="(?![a-zA-Z:/_\-]+launchpad.+?">)(.+?)">',
+ split)
+ if countries.has_key(country.group(1)):
+ lines.append("#LOC:%s" % countries[country.group(1)].upper())
+ else:
+ lines.append("#LOC:%s" % country.group(1))
+ map(lines.append, urls)
+
+map(find, content_splits)
+
+print "Writing local mirrors list: %s" % list_path
+list = open(list_path, "w")
+for line in lines:
+ list.write("%s\n" % line)
+list.close()
+print "Done."
diff --git a/utils/mirrortest b/utils/mirrortest
new file mode 100755
index 00000000..75ef917b
--- /dev/null
+++ b/utils/mirrortest
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+import threading, Queue, time, re, os, tempfile
+import aptsources.sourceslist
+import aptsources.distro
+from timeit import Timer
+import urllib
+import socket
+import random
+socket.setdefaulttimeout(2)
+
+class MirrorTest:
+ class PingWorker(threading.Thread):
+ def __init__(self, jobs, results, id):
+ self.id = id
+ self.jobs = jobs
+ self.results = results
+ self.match_result = re.compile(r"^rtt .* = [\.\d]+/([\.\d]+)/.*")
+ threading.Thread.__init__(self)
+ def run(self):
+ result = None
+ while MirrorTest.completed_pings < MirrorTest.todo:
+ try:
+ mirror = self.jobs.get(True, 1)
+ host = mirror.hostname
+ except:
+ continue
+ print "Pinging (Worker %s) %s (%s) ..." % (self.id,
+ host,
+ MirrorTest.completed_pings)
+ commando = os.popen("ping -q -c 4 -W 2 -i 0.3 %s" % host,
+ "r")
+ while True:
+ line = commando.readline()
+ if not line:
+ break
+ result = re.findall(self.match_result, line)
+ MirrorTest.completed_pings_lock.acquire()
+ MirrorTest.completed_pings += 1
+ if result:
+ self.results.append([float(result[0]), host, mirror])
+ MirrorTest.completed_pings_lock.release()
+
+ def speed_test(self, mirror):
+ url = "%s/%s" % (mirror.get_repo_urls()[0],
+ self.test_file)
+ print "Downloading %s ..." % url
+ start = time.time()
+ try:
+ data = urllib.urlopen(url).read(51200)
+ return 50 / (time.time() - start)
+ except:
+ return 0
+
+ def __init__(self, hosts, test_file):
+ self.test_file = test_file
+ jobs = Queue.Queue()
+ results = []
+ for h in hosts:
+ jobs.put(h)
+ self.threads = []
+ MirrorTest.completed_pings = 0
+ MirrorTest.completed_pings_lock = threading.Lock()
+ MirrorTest.todo = len(hosts)
+
+ for i in range(10):
+ t = MirrorTest.PingWorker(jobs, results, i)
+ self.threads.append(t)
+ t.start()
+
+ for t in self.threads:
+ t.join()
+
+ results.sort()
+ print "\n\nTop ten RTTs:"
+ for r in results[0:10]:
+ print "%s: %s" % (r[1], r[0])
+ print "\n\n"
+
+ results.insert(0, [0, "rand", hosts[random.randint(1, len(hosts))]])
+ results.insert(0, [0, "rand", hosts[random.randint(1, len(hosts))]])
+
+ final = map(lambda r: (self.speed_test(r[2]), r[2]),
+ results[0:12])
+ final.sort()
+ final.reverse()
+ print "\n\nBest mirrors:"
+ for f in final:
+ print "%s: %s KByte/s" % (f[1].hostname, int(f[0]))
+
+if __name__ == "__main__":
+ distro = aptsources.distro.get_distro()
+ distro.get_sources(aptsources.sourceslist.SourcesList())
+ pipe = os.popen("dpkg --print-architecture")
+ arch = pipe.read().strip()
+ test_file = "dists/%s/%s/binary-%s/Packages.gz" % \
+ (distro.source_template.name,
+ distro.source_template.components[0].name,
+ arch)
+ app = MirrorTest(distro.source_template.mirror_set.values(),
+ test_file)