diff options
| author | Michael Vogt <michael.vogt@ubuntu.com> | 2011-05-26 18:01:26 +0200 |
|---|---|---|
| committer | Michael Vogt <michael.vogt@ubuntu.com> | 2011-05-26 18:01:26 +0200 |
| commit | 19e2e0f210da3fb4cb87cfe1ddd4bbc6c61d8cd1 (patch) | |
| tree | 917dd7e06549e3ac7efffdae3c8e9d02788ac81d | |
| parent | e0b2560ab0fab5716187b7a1f93052373f5cbd23 (diff) | |
| download | python-apt-19e2e0f210da3fb4cb87cfe1ddd4bbc6c61d8cd1.tar.gz | |
merge from debian, omit disable of the 0.7 API
46 files changed, 1964 insertions, 397 deletions
diff --git a/apt/cache.py b/apt/cache.py index bfa41edc..be137b76 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -66,7 +66,11 @@ class Cache(object): self._weakref = weakref.WeakValueDictionary() self._set = set() self._fullnameset = set() + self._changes_count = -1 self._sorted_set = None + + self.connect("cache_post_open", self._inc_changes_count) + self.connect("cache_post_change", self._inc_changes_count) if memonly: # force apt to build its caches in memory apt_pkg.config.set("Dir::Cache::pkgcache", "") @@ -87,6 +91,11 @@ class Cache(object): # recognized (LP: #320665) apt_pkg.init_system() self.open(progress) + + + def _inc_changes_count(self): + """Increase the number of changes""" + self._changes_count += 1 def _check_and_create_required_dirs(self, rootdir): """ @@ -107,7 +116,7 @@ class Cache(object): os.makedirs(rootdir + d) for f in files: if not os.path.exists(rootdir + f): - open(rootdir + f, "w") + open(rootdir + f, "w").close() def _run_callbacks(self, name): """ internal helper to run a callback """ @@ -288,6 +297,30 @@ class Cache(object): finally: os.close(lock) + def fetch_archives(self, progress=None, fetcher=None): + """Fetch the archives for all packages marked for install/upgrade. + + You can specify either an :class:`apt.progress.base.AcquireProgress()` + object for the parameter *progress*, or specify an already + existing :class:`apt_pkg.Acquire` object for the parameter *fetcher*. + + The return value of the function is undefined. If an error occured, + an exception of type :class:`FetchFailedException` or + :class:`FetchCancelledException` is raised. + + .. versionadded:: 0.8.0 + """ + if progress is not None and fetcher is not None: + raise ValueError("Takes a progress or a an Acquire object") + if progress is None: + progress = apt.progress.text.AcquireProgress() + if fetcher is None: + fetcher = apt_pkg.Acquire(progress) + + + return self._fetch_archives(fetcher, + apt_pkg.PackageManager(self._depcache)) + def is_virtual_package(self, pkgname): """Return whether the package is a virtual package.""" try: @@ -339,6 +372,10 @@ class Cache(object): raise_on_error=True, sources_list=None): """Run the equivalent of apt-get update. + You probably want to call open() afterwards, in order to utilise the + new cache. Otherwise, the old cache will be used which can lead to + strange bugs. + The first parameter *fetch_progress* may be set to an instance of apt.progress.FetchProgress, the default is apt.progress.FetchProgress() . @@ -548,6 +585,7 @@ class ProblemResolver(object): def __init__(self, cache): self._resolver = apt_pkg.ProblemResolver(cache._depcache) + self._cache = cache def clear(self, package): """Reset the package to the default state.""" @@ -567,11 +605,15 @@ class ProblemResolver(object): def resolve(self): """Resolve dependencies, try to remove packages where needed.""" + self._cache.cache_pre_change() self._resolver.resolve() + self._cache.cache_post_change() def resolve_by_keep(self): """Resolve dependencies, do not try to remove packages.""" + self._cache.cache_pre_change() self._resolver.resolve_by_keep() + self._cache.cache_post_change() # ----------------------------- experimental interface diff --git a/apt/cdrom.py b/apt/cdrom.py index 01caa12f..9688de9e 100644 --- a/apt/cdrom.py +++ b/apt/cdrom.py @@ -79,9 +79,10 @@ class Cdrom(apt_pkg.Cdrom): src.append(apt_pkg.config.find_file("Dir::Etc::sourcelist")) # Check each file for fname in src: - for line in open(fname): - if not line.lstrip().startswith("#") and cd_id in line: - return True + with open(fname) as fobj: + for line in fobj: + if not line.lstrip().startswith("#") and cd_id in line: + return True return False if apt_pkg._COMPAT_0_7: diff --git a/apt/debfile.py b/apt/debfile.py index fb4312a1..d0f41def 100644 --- a/apt/debfile.py +++ b/apt/debfile.py @@ -64,7 +64,7 @@ class DebPackage(object): self._installed_conflicts = set() self._failure_string = "" self.filename = filename - self._debfile = apt_inst.DebFile(open(self.filename)) + self._debfile = apt_inst.DebFile(self.filename) control = self._debfile.control.extractdata("control") self._sections = apt_pkg.TagSection(control) self.pkgname = self._sections["Package"] diff --git a/apt/package.py b/apt/package.py index d7d5d167..14e80594 100644 --- a/apt/package.py +++ b/apt/package.py @@ -50,9 +50,9 @@ __all__ = ('BaseDependency', 'Dependency', 'Origin', 'Package', 'Record', def _file_is_same(path, size, md5): """Return ``True`` if the file is the same.""" - if (os.path.exists(path) and os.path.getsize(path) == size and - apt_pkg.md5sum(open(path)) == md5): - return True + if os.path.exists(path) and os.path.getsize(path) == size: + with open(path) as fobj: + return apt_pkg.md5sum(fobj) == md5 class FetchError(Exception): @@ -162,10 +162,23 @@ class Origin(object): class Record(Mapping): - """Represent a pkgRecord. + """Record in a Packages file + + Represent a record as stored in a Packages file. You can use this like + a dictionary mapping the field names of the record to their values:: + + >>> record = Record("Package: python-apt\\nVersion: 0.8.0\\n\\n") + >>> record["Package"] + 'python-apt' + >>> record["Version"] + '0.8.0' + + For example, to get the tasks of a package from a cache, you could do:: + + package.candidate.record["Tasks"].split() + + Of course, you can also use the :attr:`Version.tasks` property. - It can be accessed like a dictionary and can also give the original package - record if accessed as a string. """ def __init__(self, record_str): @@ -209,6 +222,9 @@ class Record(Mapping): class Version(object): """Representation of a package version. + The Version class contains all information related to a + specific package version. + .. versionadded:: 0.7.9 """ @@ -393,7 +409,11 @@ class Version(object): @property def record(self): - """Return a Record() object for this version.""" + """Return a Record() object for this version. + + Return a Record() object for this version which provides access + to the raw attributes of the candidate version + """ return Record(self._records.record) def get_dependencies(self, *types): @@ -474,6 +494,16 @@ class Version(object): """ return self._records.sha256_hash + @property + def tasks(self): + """Get the tasks of the package. + + A set of the names of the tasks this package belongs to. + + .. versionadded:: 0.8.0 + """ + return set(self.record["Task"].split()) + def _uris(self): """Return an iterator over all available urls. @@ -994,11 +1024,8 @@ class Package(object): """ path = "/var/lib/dpkg/info/%s.list" % self.name try: - file_list = open(path, "rb") - try: + with open(path, "rb") as file_list: return file_list.read().decode("utf-8").split(u"\n") - finally: - file_list.close() except EnvironmentError: return [] @@ -1104,6 +1131,7 @@ class Package(object): # Check if the download was canceled if cancel_lock and cancel_lock.isSet(): return u"" + # FIXME: python3.2: Should be closed manually changelog_file = urllib2.urlopen(uri) # do only get the lines that are new changelog = u"" diff --git a/apt/progress/old.py b/apt/progress/old.py index 4bd79f2e..364cd2ce 100644 --- a/apt/progress/old.py +++ b/apt/progress/old.py @@ -149,10 +149,11 @@ class TextFetchProgress(FetchProgress): Return True to continue or False to cancel. """ FetchProgress.pulse(self) + if self.currentCPS > 0: s = "[%2.f%%] %sB/s %s" % (self.percent, - apt_pkg.size_to_str(int(self.currentCPS)), - apt_pkg.time_to_str(int(self.eta))) + apt_pkg.size_to_str(self.currentCPS), + apt_pkg.time_to_str(long(self.eta))) else: s = "%2.f%% [Working]" % (self.percent) print "\r%s" % (s), diff --git a/apt/progress/text.py b/apt/progress/text.py index d777837c..c5eec092 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -157,11 +157,10 @@ class AcquireProgress(base.AcquireProgress, TextProgress): shown = False tval = '%i%%' % percent - end = "" if self.current_cps: - eta = int(float(self.total_bytes - self.current_bytes) / - self.current_cps) + eta = long(float(self.total_bytes - self.current_bytes) / + self.current_cps) end = " %sB/s %s" % (apt_pkg.size_to_str(self.current_cps), apt_pkg.time_to_str(eta)) diff --git a/aptsources/distinfo.py b/aptsources/distinfo.py index a69f944a..249985e7 100644 --- a/aptsources/distinfo.py +++ b/aptsources/distinfo.py @@ -176,89 +176,90 @@ class DistInfo(object): 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': - self.finish_template(template, component) - component=None - 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: - # look for parent and add back ref to it - if nanny.name == value: - template.parents.append(nanny) - nanny.children.append(template) - elif field == 'Available': - template.available = apt_pkg.string_to_bool(value) - elif field == 'Official': - template.official = apt_pkg.string_to_bool(value) - elif field == 'RepositoryType': - template.type = value - elif field == 'BaseURI' and not template.base_uri: - template.base_uri = value - elif field == 'BaseURI-%s' % self.arch: - template.base_uri = value - elif field == 'MatchURI' and not template.match_uri: - template.match_uri = value - elif field == 'MatchURI-%s' % self.arch: - template.match_uri = value - elif (field == 'MirrorsFile' or - field == 'MirrorsFile-%s' % self.arch): - # Make the path absolute. - value = os.path.isabs(value) and value or \ - os.path.abspath(os.path.join(base_dir, value)) - if value not in map_mirror_sets: - mirror_set = {} - try: - mirror_data = filter(match_mirror_line.match, - [x.strip() for x in open(value)]) - except Exception: - logging.warn("Failed to read mirror file") - mirror_data = [] - for line in mirror_data: - if line.startswith("#LOC:"): - location = match_loc.sub(r"\1", line) - continue - (proto, hostname, dir) = split_url(line) - if hostname in mirror_set: - 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)) - self.finish_template(template, component) - template=None - component=None + with open(dist_fname) as dist_file: + 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': + self.finish_template(template, component) + component=None + 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: + # look for parent and add back ref to it + if nanny.name == value: + template.parents.append(nanny) + nanny.children.append(template) + elif field == 'Available': + template.available = apt_pkg.string_to_bool(value) + elif field == 'Official': + template.official = apt_pkg.string_to_bool(value) + elif field == 'RepositoryType': + template.type = value + elif field == 'BaseURI' and not template.base_uri: + template.base_uri = value + elif field == 'BaseURI-%s' % self.arch: + template.base_uri = value + elif field == 'MatchURI' and not template.match_uri: + template.match_uri = value + elif field == 'MatchURI-%s' % self.arch: + template.match_uri = value + elif (field == 'MirrorsFile' or + field == 'MirrorsFile-%s' % self.arch): + # Make the path absolute. + value = os.path.isabs(value) and value or \ + os.path.abspath(os.path.join(base_dir, value)) + if value not in map_mirror_sets: + mirror_set = {} + try: + with open(value) as value_f: + mirror_data = filter(match_mirror_line.match, + [x.strip() for x in + value_f]) + except Exception: + print "WARNING: Failed to read mirror file" + mirror_data = [] + for line in mirror_data: + if line.startswith("#LOC:"): + location = match_loc.sub(r"\1", line) + continue + (proto, hostname, dir) = split_url(line) + if hostname in mirror_set: + 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)) + self.finish_template(template, component) + template=None + component=None def finish_template(self, template, component): " finish the current tempalte " diff --git a/aptsources/sourceslist.py b/aptsources/sourceslist.py index 04f6a5a7..b85e6947 100644 --- a/aptsources/sourceslist.py +++ b/aptsources/sourceslist.py @@ -1,4 +1,4 @@ -# aptsource.py - Provide an abstraction of the sources.list +# sourceslist.py - Provide an abstraction of the sources.list # # Copyright (c) 2004-2009 Canonical Ltd. # Copyright (c) 2004 Michiel Sikkes @@ -276,6 +276,12 @@ class SourcesList(object): yield entry raise StopIteration + def __find(self, *predicates, **attrs): + for source in self.list: + if (all(getattr(source, key) == attrs[key] for key in attrs) and + all(predicate(source) for predicate in predicates)): + yield source + def add(self, type, uri, dist, orig_comps, comment="", pos=-1, file=None, architectures=[]): """ Add a new source to the sources.list. @@ -287,39 +293,32 @@ class SourcesList(object): # create a working copy of the component list so that # we can modify it later comps = orig_comps[:] + sources = self.__find(lambda s: set(s.architectures) == architectures, + disabled=False, invalid=False, type=type, uri=uri, + dist=dist) # check if we have this source already in the sources.list - for source in self.list: - if not source.disabled and not source.invalid and \ - source.type == type and uri == source.uri and \ - source.dist == dist and \ - set(source.architectures) == architectures: - 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: + for source in sources: + 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 + + sources = self.__find(lambda s: set(s.architectures) == architectures, + invalid=False, type=type, uri=uri, dist=dist) + + for source in sources: # if there is a repo with the same (type, uri, dist) just add the # components - if not source.disabled and not source.invalid and \ - source.type == type and uri == source.uri and \ - source.dist == dist and \ - set(source.architectures) == architectures: - comps = uniq(source.comps + comps) - source.comps = comps - return source - # if there is a corresponding repo which is disabled, enable it - elif source.disabled and not source.invalid and \ - source.type == type and uri == source.uri and \ - set(source.architectures) == architectures and \ - source.dist == dist and \ - len(set(source.comps) & set(comps)) == len(comps): + if source.disabled and set(source.comps) == comps: source.disabled = False return source + elif not source.disabled: + source.comps = uniq(source.comps + comps) + return source # there isn't any matching source, so create a new line and parse it - line = type if architectures: line += " [arch=%s]" % ",".join(architectures) @@ -370,15 +369,12 @@ class SourcesList(object): 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) + with open(file, "r") as f: + for line in f: + source = SourceEntry(line, file) + self.list.append(source) except: - logging.error("could not open file '%s'" % file) - else: - f.close() + print "could not open file '%s'" % file def save(self): """ save the current sources """ @@ -390,14 +386,19 @@ class SourcesList(object): "## See sources.list(5) for more information, especialy\n" "# Remember that you can only use http, ftp or file URIs\n" "# CDROMs are managed through the apt-cdrom tool.\n") - open(path, "w").write(header) + + with open(path, "w") as f: + f.write(header) return - for source in self.list: - if source.file not in files: - files[source.file] = open(source.file, "w") - files[source.file].write(source.str()) - for f in files: - files[f].close() + + try: + for source in self.list: + if source.file not in files: + files[source.file] = open(source.file, "w") + files[source.file].write(source.str()) + finally: + for f in files: + files[f].close() def check_for_relations(self, sources_list): """get all parent and child channels in the sources list""" diff --git a/debian/changelog b/debian/changelog index 11e8819d..edd0081f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,66 @@ +python-apt (0.8.0~exp4ubuntu1) oneiric; urgency=low + + * Merged from debian/experimental, remaining changes: + - updated mirror list + - do not disable 0.7 compat API yet + + -- Michael Vogt <michael.vogt@ubuntu.com> Tue, 24 May 2011 10:08:56 +0200 + +python-apt (0.8.0~exp4) experimental; urgency=low + + * apt_pkg: Add OrderList, wanted for mancoosi (Closes: #623485) + * apt_pkg: Add subclassing fun to PackageManager, for #623485 as well + * apt.cache: Emit change signals in ProblemResolver + * apt.Cache: Add a _changes_count member for later use + + -- Julian Andres Klode <jak@debian.org> Fri, 29 Apr 2011 13:57:30 +0200 + +python-apt (0.8.0~exp3) experimental; urgency=low + + [ Stéphane Graber ] + * Update enable_component to also apply to -src entries (LP: #758732) + + [ Julian Andres Klode ] + * apt_pkg: Add apt_pkg.Version.multi_arch and friends + + -- Julian Andres Klode <jak@debian.org> Thu, 21 Apr 2011 15:33:38 +0200 + +python-apt (0.8.0~exp2) experimental; urgency=low + + * aptsources: Parse multi-arch sources.list files correctly + * aptsources: Allow insertion of new multi-arch entries + * aptsources: Various cleanup work + * all: Fix all instances of ResourceWarning about unclosed files + * tests/test_apt_cache.py: Use assertTrue() instead of assert_() + * apt_pkg: Raise error when parse_commandline gets empty argv (LP: #707416) + * apt_pkg: Fix time_to_str, time_rfc1123 to accept more correct values + (time_to_str accepts unsigned long, time_rfc1123 long long, y2k31-correct). + * apt.progress: Use long for ETA, natural type for size (LP: #377375) + * aptsources/sourceslist.py: s/aptsource.py/sourceslist.py/ (LP: #309603) + * doc/examples: Add example on how to get architecture names (LP: #194374) + * apt_pkg: Fix unsigned/long-vs-int issues (LP: #610820) + * apt.cache: Document that update() may need an open() (Closes: #622342) + * apt.cache: Add a fetch_archives() method (Closes: #622347) + * doc: Fix a minor formatting error, patch by Jakub Wilk (Closes: #608914) + * apt.package: Add 'tasks' to Version, improve doc (Closes: #619574) + * doc: Fix documentation of BaseDependency.relation (Closes: #607031) + + -- Julian Andres Klode <jak@debian.org> Tue, 12 Apr 2011 15:25:38 +0200 + +python-apt (0.8.0~exp1) experimental; urgency=low + + * Disable the old-style API, and break all packages using it + * Add an 'is_multi_arch' attribute to apt_pkg.Cache + * Add apt_pkg.Group class, wrapping pkgCache::GrpIterator + * Change apt_pkg.Cache() so that passing None for 'progress' results in + no progress output + * Support (name, arch) tuples in apt_pkg.Cache mappings, wrapping + FindPkg() with two string parameters. + * Introduce apt_pkg.Cache.groups and apt_pkg.Cache.group_count + * Fix debian/rules to work correctly with tilde in version number + + -- Julian Andres Klode <jak@debian.org> Tue, 05 Apr 2011 16:21:45 +0200 + python-apt (0.7.100.3ubuntu7) oneiric; urgency=low * data/templates/Ubuntu.info.in: diff --git a/debian/rules b/debian/rules index 5428375d..a85d1eb2 100755 --- a/debian/rules +++ b/debian/rules @@ -2,8 +2,8 @@ # Should be include-links, but that somehow fails. export DEBVER=$(shell dpkg-parsechangelog | sed -n -e 's/^Version: //p') export CFLAGS=-Wno-write-strings -DCOMPAT_0_7 -export PATH :=$(CURDIR)/utils:$(PATH) -export SHELL = env PATH=$(PATH) sh +export PATH := $(CURDIR)/utils:$(PATH) +export pyversions := $(CURDIR)/utils/pyversions %: dh --with python2,python3 $@ @@ -28,14 +28,14 @@ override_dh_installdocs: override_dh_strip: dh_strip -p python-apt --dbg-package=python-apt-dbg dh_strip -p python3-apt --dbg-package=python3-apt-dbg - + override_dh_compress: dh_compress -X.js -X_static/* -X _sources/* -X_sources/*/* -X.inv # We ignore failures on hurd, since its locking is broken override_dh_auto_test: ifeq (,$(findstring nocheck, $(DEB_BUILD_OPTIONS))) - set -e; for python in $(shell pyversions -r); do \ + set -e; for python in $(shell $(pyversions) -r); do \ $$python tests/test_all.py -q || [ "$(DEB_BUILD_ARCH_OS)" = "hurd" ]; \ done; else diff --git a/doc/examples/architecture.py b/doc/examples/architecture.py new file mode 100644 index 00000000..75afb2d1 --- /dev/null +++ b/doc/examples/architecture.py @@ -0,0 +1,12 @@ +import apt_pkg + + +def main(): + apt_pkg.init_config() + + print "Native architecture:", apt_pkg.config["APT::Architecture"] + print "All architectures:", apt_pkg.config.value_list("APT::Architectures") + + +if __name__ == '__main__': + main() diff --git a/doc/source/c++/api.rst b/doc/source/c++/api.rst index 97ab24d1..63ed1599 100644 --- a/doc/source/c++/api.rst +++ b/doc/source/c++/api.rst @@ -389,6 +389,38 @@ Description (pkgCache::DescIterator) Return the :ctype:`pkgCache::DescIterator` reference contained in the Python object *object*. + +Group (pkgCache::GrpIterator) +---------------------------------- +.. versionadded:: 0.8.0 + +.. cvar:: PyTypeObject PyGroup_Type + + The type object for :class:`apt_pkg.Group` objects. + +.. cfunction:: int PyGroup_Check(PyObject *object) + + Check that the object *object* is an :class:`apt_pkg.Group` object, or + a subclass thereof. + +.. cfunction:: int PyGroup_CheckExact(PyObject *object) + + Check that the object *object* is an :class:`apt_pkg.Group` object + and no subclass thereof. + +.. cfunction:: PyObject* PyGroup_FromCpp(pkgCache::GrpIterator &cpp, bool delete, PyObject *owner) + + Create a new :class:`apt_pkg.Group` object from the :ctype:`pkgCache::GrpIterator` + reference given by the parameter *cpp*. If the parameter *delete* is + true, *cpp* will be deleted when the reference + count of the returned object reaches 0. The parameter *owner* should be + a PyObject of the type :cdata:`PyCache_Type`. + +.. cfunction:: pkgCache::GrpIterator& PyGroup_ToCpp(PyObject *object) + + Return the :ctype:`pkgCache::GrpIterator` reference contained in the + Python object *object*. + Hashes (Hashes) ---------------------------------- .. cvar:: PyTypeObject PyHashes_Type @@ -590,6 +622,34 @@ IndexFile (pkgIndexFile) Return the :ctype:`pkgIndexFile` pointer contained in the Python object *object*. +OrderList (pkgOrderList) +--------------------------- +.. cvar:: PyTypeObject PyOrderList_Type + + The type object for :class:`apt_pkg.OrderList` objects. + +.. cfunction:: int PyOrderList_Check(PyObject *object) + + Check that the object *object* is an :class:`apt_pkg.OrderList` object, or + a subclass thereof. + +.. cfunction:: int PyOrderList_CheckExact(PyObject *object) + + Check that the object *object* is an :class:`apt_pkg.OrderList` object + and no subclass thereof. + +.. cfunction:: PyObject* PyOrderList_FromCpp(pkgOrderList *cpp, bool delete, PyObject *owner) + + Create a new :class:`apt_pkg.OrderList` object from the :ctype:`pkgOrderList` + pointer given by the parameter *cpp*. If the parameter *delete* is + true, the object pointed to by *cpp* will be deleted when the reference + count of the returned object reaches 0. The owner must be a + :class:`apt_pkg.DepCache` object. + +.. cfunction:: pkgOrderList* PyOrderList_ToCpp(PyObject *object) + + Return the :ctype:`pkgOrderList` pointer contained in the Python object + *object*. PackageManager (pkgPackageManager) ---------------------------------- diff --git a/doc/source/library/apt.package.rst b/doc/source/library/apt.package.rst index 4b143b8a..01a26973 100644 --- a/doc/source/library/apt.package.rst +++ b/doc/source/library/apt.package.rst @@ -34,7 +34,7 @@ Dependency Information .. attribute:: relation - The relation (>>,>=,==,<<,<=,) + The relation (>,>=,==,<,<=,) .. attribute:: version @@ -90,6 +90,35 @@ Origin Information it provides a GPG-signed Release file and the GPG-key used is in the keyring used by apt (see apt-key). + + +The Record class +----------------- +.. autoclass:: Record + :members: + + .. note:: + .. versionchanged:: 0.7.100 + This class is a subclass of :class:`collections.Mapping` when used + in Python 2.6 or newer. + + .. describe:: record[name] + + Return the value of the field with the name *name*. + + .. describe:: name in record + + Return whether a field *name* exists in record. + + .. describe:: len(record) + + The number of fields in the record + + .. describe:: str(record) + + Display the record as a string + + Examples --------- .. code-block:: python diff --git a/doc/source/library/apt_pkg.rst b/doc/source/library/apt_pkg.rst index 426cb97e..81f2d408 100644 --- a/doc/source/library/apt_pkg.rst +++ b/doc/source/library/apt_pkg.rst @@ -40,17 +40,43 @@ Working with the cache The constructor takes an optional argument which must be a subclass of :class:`apt.progress.base.OpProgress`. This object will then be used to display information during the cache opening process (or possible creation - of the cache). + of the cache). It may also be ``None``, in which case no progress will + be emitted. If not given, progress will be printed to standard output. + + .. note:: + + The cache supports colon-seperated name:architecture pairs. For + normal architectures, they are equal to a (name, architecture) + tuple. For the the "any" architecture behavior is different, as + "name:any" is equivalent to ("name:any", "any"). This is done so + that "name:any" matches all packages with that name which have + Multi-Arch: allowed set. .. describe:: cache[pkgname] Return the :class:`Package()` object for the package name given by - *pkgname*. + *pkgname*. If *pkgname* includes a colon, the part after the colon + is used as the architecture. + + .. describe:: cache[name, architecture] + + Return the :class:`Package()` object for the package with the given + name and architecture. + + .. versionadded: 0.8.0 .. describe:: pkgname in cache Check whether a package with the name given by *pkgname* exists in - the cache. + the cache for the native architecture. If *pkgname* includes a + colon, the part after the colon is used as the architecture. + + .. describe:: (name, architecture) in cache + + Check whether a package with the given name and architecture exists + in the cache. + + .. versionadded: 0.8.0 .. method:: update(progress, sources [, pulse_interval]) -> bool @@ -73,6 +99,44 @@ Working with the cache A list of all :class:`PackageFile` objects stored in the cache. + .. attribute:: group_count + + The number of groups in the cache. + + .. versionadded: 0.8.0 + + .. attribute:: groups + + A sequence of :class:`Group` objects, implemented as a + :class:`GroupList` object. + + .. versionadded: 0.8.0 + + .. class:: GroupList + + A simple sequence-like object which only provides a length and + an implementation of ``__getitem__`` for accessing groups at + a certain index. Apart from being iterable, it can be used in + the following ways: + + .. versionadded: 0.8.0 + + .. describe:: list[index] + + Get the :class:`Group` object for the group at the position + given by *index* in the GroupList *list*. + + .. describe:: len(list) + + Return the length of the GroupList object *list*. + + + .. attribute:: is_multi_arch + + An attribute determining whether the cache supports multi-arch. + + .. versionadded: 0.8.0 + .. attribute:: package_count The total number of packages available in the cache. This value is @@ -358,6 +422,158 @@ Installing with :class:`PackageManager` A constant for checking whether the the result of the call to :meth:`do_install` is 'incomplete'. + + All instances of this class also support the following methods: + + .. note:: + + This methods are provided mainly for subclassing purposes + and should not be used in most programs. This class is a + subclass of an internal :class:`_PackageManager` which does + not provide that methods. As the public C++ API creates such + an object without those methods, you should not rely on those + methods to be available unless you used the constructor of + :class:`PackageManager` to create the object. + + .. method:: configure(pkg: Package) -> bool + + Notify the package manager that the :class:`Package` given + by *pkg* is to be configured. Must return a ``True`` value + or ``None`` to continue, or a value which is ``False`` if + evaluated as boolean to abort. + + .. versionadded:: 0.8.0 + + .. method:: install(pkg: Package, filename: str) -> bool + + Notify the package manager that the :class:`Package` given + by *pkg* is to be installed from the .deb located at + *filename*. Must return a ``True`` value or ``None`` to + continue, or a value which is ``False`` if evaluated as + boolean to abort. + + + .. versionadded:: 0.8.0 + + .. method:: remove(pkg: Package, purge: bool) -> bool + + Notify the package manager that the :class:`Package` given + by *pkg* is to be removed. If *purge* is ``True``, the package + shall be purged. Must return a ``True`` value or ``None`` to + continue, or a value which is ``False`` if evaluated as boolean + to abort. + + + .. versionadded:: 0.8.0 + + .. method:: go(status_fd: int) -> bool + + Start dpkg, writing status information to the file descriptor + given by *status_fd*. Must return a ``True`` value or ``None`` to + continue, or a value which is ``False`` if evaluated as boolean + to abort. + + .. versionadded:: 0.8.0 + + .. method:: reset() + + Reset the package manager for a new round. + + .. versionadded:: 0.8.0 + + +Installation ordering with :class:`OrderList` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. class:: OrderList(depcache: DepCache) + + Represent a :ctype:`pkgOrderList`, used for installation + ordering. This class provides several methods and attributes, + is complicated and should not be used by normal programs. + + .. versionadded:: 0.8.0 + + This class is a sequence and supports the following operations: + + .. describe:: list[index] + + Get the package at the given index in the list. Negative + index is supported. + + .. describe:: len(list) + + The length of the list. + + It also supports the append() method from :class:`list`: + + .. method:: append(pkg: Package) + + Append a new package to the end of the list. Please note that + you may not append a package twice, as only as much packages + as in the cache can be added. + + The class also defines several specific attributes and methods, + to be described hereinafter. + + .. method:: score(pkg: Package) + + Return the score of the package. Packages are basically + ordered by descending score. + + This class allows flags to be set on packages. Those flags are: + + .. attribute:: FLAG_ADDED + .. attribute:: FLAG_ADD_PENDING + .. attribute:: FLAG_IMMEDIATE + .. attribute:: FLAG_LOOP + .. attribute:: FLAG_UNPACKED + .. attribute:: FLAG_CONFIGURED + .. attribute:: FLAG_REMOVED + .. attribute:: FLAG_STATES_MASK + + Same as ``FLAG_UNPACKED | FLAG_CONFIGURED | FLAG_REMOVED`` + + .. attribute:: FLAG_IN_LIST + .. attribute:: FLAG_AFTER + + The methods to work with those flags are: + + .. method:: flag(pkg: Package, flag: int[, unset_flags: int]) + + Flag a package. Sets the flags given in *flag* and unsets + any flags given in *unset_flags*. + + .. method:: is_flag(pkg: Package, flag: int) + + Check whether the flags in *flag* are set for the package. + + .. method:: wipe_flags(flags: int) + + Remove the flags in *flags* from all packages. + + .. method:: is_missing(pkg: Package) + + Check if the package is missing (not really usable right now) + + .. method:: is_now(pkg: Package) + + Check if the package is flagged for any state but removal. + + The following methods for ordering are provided: + + .. method:: order_critical() + + Order the packages for critical unpacking; that is, only + respect pre-dependencies. + + .. method:: order_unpack() + + Order the packages for unpacking, repecting Pre-Depends and + Conflicts. + + .. method:: order_configure() + + Order the packages for configuration, respecting Depends. Improve performance with :class:`ActionGroup` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -432,6 +648,47 @@ Resolving Dependencies with :class:`ProblemResolver` Try to resolve the problems without installing or removing packages. +:class:`Group` of packages with the same name +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. class:: Group(cache: Cache, name: str) + + .. versionadded:: 0.8.0 + + A collection of packages in which all packages have the same name. Groups + are used in multi-arch environments, where two or more packages have the + same name, but different architectures. + + Group objects provide the following parts for sequential access: + + .. describe:: group[index] + + Get the package at the given **index** in the group. + + .. note:: + Groups are internally implemented using a linked list. The object + keeps a pointer to the current object and the first object, so + access to the first element, or accesses in order have a + complexity of O(1). Random-access complexity is ranges from + O(1) to O(n). + + Group objects also provide special methods to find single packages: + + .. method:: find_package(architecture: str) -> Package + + Find a package with the groups name and the architecture given + in the argument *architecture*. If no such package exists, return + ``None``. + + .. method:: find_preferred_package(prefer_nonvirtual: bool = True) -> Package + + Find the preferred package. This is the package of the native + architecture (specified in ``APT::Architecture``) if available, + or the package from the first foreign architecture. If no package + could be found, return ``None`` + + If **prefer_nonvirtual** is ``True``, the preferred package + will be a non-virtual package, if one exists. + :class:`Package` information ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -653,6 +910,49 @@ Example: .. attribute:: installed_size The size of the package (in kilobytes), when unpacked on the disk. + + .. attribute:: multi_arch + + The multi-arch state of the package. Can be one of the following + attributes. + + .. attribute:: MULTI_ARCH_NONE + + No multi-arch + + .. attribute:: MULTI_ARCH_ALL + + An ``Architecture: all`` package + + + .. attribute:: MULTI_ARCH_FOREIGN + + Can satisfy dependencies of foreign-architecture + packages + + .. attribute:: MULTI_ARCH_ALL_FOREIGN + + :attr:`MULTI_ARCH_FOREIGN` for ``Architecture: all`` + packages. + + .. attribute:: MULTI_ARCH_SAME + + Multiple versions from different architectures may be + installed in parallel, but may only satisfy dependencies + of packages from the same architecture + + .. attribute:: MULTI_ARCH_ALLOWED + + Installation in parallel and satisfying ``pkg:any`` + style dependencies is allowed. + + .. attribute:: MULTI_ARCH_ALL_ALLOWED + + :attr:`MULTI_ARCH_ALLOWED` for ``Architecture: all`` + packages. + + + .. attribute:: parent_pkg diff --git a/doc/source/tutorials/apt-cdrom.rst b/doc/source/tutorials/apt-cdrom.rst index 0561e082..5dd88743 100644 --- a/doc/source/tutorials/apt-cdrom.rst +++ b/doc/source/tutorials/apt-cdrom.rst @@ -98,7 +98,7 @@ it is a boolean argument. Afterwards you could use location of the mount pint. ``('c',"config-file","","ConfigFile")`` shows how to include configuration files. This option takes a parameter which points to a configuration file which will be added to the configuration space. -('o',"option","","ArbItem") is yet another type of option, which allows users +``('o',"option","","ArbItem")`` is yet another type of option, which allows users to set configuration options on the commandline. Now we have to check whether help or version is specified, and print a message diff --git a/doc/source/whatsnew/0.8.0.rst b/doc/source/whatsnew/0.8.0.rst new file mode 100644 index 00000000..2eeb135e --- /dev/null +++ b/doc/source/whatsnew/0.8.0.rst @@ -0,0 +1,38 @@ +What's New In python-apt 0.8 +============================ +Python-apt 0.8 is a new major release of the python bindings for the APT +package management libraries. + + +Removal of old API +------------------ +The old API that was deprecated in 0.7.100 is no longer available. Applications +that have not yet updated to the new API should do so. + +Multi-arch support +------------------ +This version of python-apt introduces multi-arch support: + + * A new class, :class:`apt_pkg.Group` has been added. + * :class:`apt_pkg.Cache` can now be indexed by ``(name, architecture)`` + tuples + +Features for mancoosi +---------------------- +Several new features related to ordering have been added on request +of the mancoosi project: + + * A new class :class:`apt_pkg.OrderList` has been added + * The :class:`apt_pkg.PackageManager` class now provides new methods + for registering install/remove/configure actions which can be + subclassed to check ordering. + +Other changes +------------- +This release of python-apt also features several other, smaller changes: + + * apt_pkg.Cache() now takes None for the progress parameter, preventing + progress reporting. + +There have been various other changes, see the changelog for a complete list +of changes. diff --git a/pre-build.sh b/pre-build.sh index 026a491e..a150272d 100755 --- a/pre-build.sh +++ b/pre-build.sh @@ -7,5 +7,5 @@ if [ -n "$https_proxy" ]; then fi utils/get_ubuntu_mirrors_from_lp.py > data/templates/Ubuntu.mirrors -echo "updating Debian mirror list" -utils/get_debian_mirrors.py > data/templates/Debian.mirrors +#echo "updating Debian mirror list" +#utils/get_debian_mirrors.py > data/templates/Debian.mirrors diff --git a/python/acquire-item.cc b/python/acquire-item.cc index 895d4a21..5e7423ab 100644 --- a/python/acquire-item.cc +++ b/python/acquire-item.cc @@ -65,13 +65,13 @@ static PyObject *acquireitem_get_error_text(PyObject *self, void *closure) static PyObject *acquireitem_get_filesize(PyObject *self, void *closure) { pkgAcquire::Item *item = acquireitem_tocpp(self); - return item ? Py_BuildValue("K", item->FileSize) : 0; + return item ? MkPyNumber(item->FileSize) : 0; } static PyObject *acquireitem_get_id(PyObject *self, void *closure) { pkgAcquire::Item *item = acquireitem_tocpp(self); - return item ? Py_BuildValue("k", item->ID) : 0; + return item ? MkPyNumber(item->ID) : 0; } static PyObject *acquireitem_get_mode(PyObject *self, void *closure) @@ -95,13 +95,13 @@ static PyObject *acquireitem_get_local(PyObject *self, void *closure) static PyObject *acquireitem_get_partialsize(PyObject *self, void *closure) { pkgAcquire::Item *item = acquireitem_tocpp(self); - return item ? Py_BuildValue("K", item->PartialSize) : 0; + return item ? MkPyNumber(item->PartialSize) : 0; } static PyObject *acquireitem_get_status(PyObject *self, void *closure) { pkgAcquire::Item *item = acquireitem_tocpp(self); - return item ? Py_BuildValue("i", item->Status) : 0; + return item ? MkPyNumber(item->Status) : 0; } static int acquireitem_set_id(PyObject *self, PyObject *value, void *closure) @@ -110,7 +110,7 @@ static int acquireitem_set_id(PyObject *self, PyObject *value, void *closure) if (Itm == 0) return -1; if (PyLong_Check(value)) { - Itm->ID = PyLong_AsLong(value); + Itm->ID = PyLong_AsUnsignedLong(value); } else if (PyInt_Check(value)) { Itm->ID = PyInt_AsLong(value); diff --git a/python/acquire.cc b/python/acquire.cc index ab90bbdd..6169ff40 100644 --- a/python/acquire.cc +++ b/python/acquire.cc @@ -51,17 +51,17 @@ static PyObject *acquireworker_get_status(PyObject *self, void *closure) static PyObject *acquireworker_get_current_size(PyObject *self, void *closure) { - return Py_BuildValue("k",GetCpp<pkgAcquire::Worker*>(self)->CurrentSize); + return MkPyNumber(GetCpp<pkgAcquire::Worker*>(self)->CurrentSize); } static PyObject *acquireworker_get_total_size(PyObject *self, void *closure) { - return Py_BuildValue("k",GetCpp<pkgAcquire::Worker*>(self)->TotalSize); + return MkPyNumber(GetCpp<pkgAcquire::Worker*>(self)->TotalSize); } static PyObject *acquireworker_get_resumepoint(PyObject *self, void *closure) { - return Py_BuildValue("k",GetCpp<pkgAcquire::Worker*>(self)->ResumePoint); + return MkPyNumber(GetCpp<pkgAcquire::Worker*>(self)->ResumePoint); } static PyGetSetDef acquireworker_getset[] = { @@ -225,7 +225,7 @@ static PyObject *PkgAcquireRun(PyObject *Self,PyObject *Args) pkgAcquire::RunResult run = fetcher->Run(pulseInterval); - return HandleErrors(Py_BuildValue("i",run)); + return HandleErrors(MkPyNumber(run)); } @@ -259,15 +259,15 @@ static PyMethodDef PkgAcquireMethods[] = { #define fetcher (GetCpp<pkgAcquire*>(Self)) static PyObject *PkgAcquireGetTotalNeeded(PyObject *Self,void*) { - return Py_BuildValue("L", fetcher->TotalNeeded()); + return MkPyNumber(fetcher->TotalNeeded()); } static PyObject *PkgAcquireGetFetchNeeded(PyObject *Self,void*) { - return Py_BuildValue("L", fetcher->FetchNeeded()); + return MkPyNumber(fetcher->FetchNeeded()); } static PyObject *PkgAcquireGetPartialPresent(PyObject *Self,void*) { - return Py_BuildValue("L", fetcher->PartialPresent()); + return MkPyNumber(fetcher->PartialPresent()); } #undef fetcher diff --git a/python/apt_pkgmodule.cc b/python/apt_pkgmodule.cc index d1ac33e0..e8490b4e 100644 --- a/python/apt_pkgmodule.cc +++ b/python/apt_pkgmodule.cc @@ -24,6 +24,7 @@ #include <apt-pkg/sha256.h> #include <apt-pkg/init.h> #include <apt-pkg/pkgsystem.h> +#include <apt-pkg/orderlist.h> #include <sys/stat.h> #include <libintl.h> @@ -83,7 +84,7 @@ static PyObject *VersionCompare(PyObject *Self,PyObject *Args) return 0; } - return Py_BuildValue("i",_system->VS->DoCmpVersion(A,A+LenA,B,B+LenB)); + return MkPyNumber(_system->VS->DoCmpVersion(A,A+LenA,B,B+LenB)); } static char *doc_CheckDep = @@ -459,7 +460,7 @@ static PyObject *GetLock(PyObject *Self,PyObject *Args) int fd = GetLock(file, errors); - return HandleErrors(Py_BuildValue("i", fd)); + return HandleErrors(MkPyNumber(fd)); } static char *doc_PkgSystemLock = @@ -732,6 +733,12 @@ static struct _PyAptPkgAPIStruct API = { &PyVersion_Type, // version_type &PyVersion_FromCpp, // version_tocpp &PyVersion_ToCpp, // version_tocpp + &PyGroup_Type, // group_type + &PyGroup_FromCpp, // group_fromcpp + &PyGroup_ToCpp, // group_tocpp + &PyOrderList_Type, // orderlist_type + &PyOrderList_FromCpp, // orderlist_fromcpp + &PyOrderList_ToCpp // orderlist_tocpp }; @@ -811,6 +818,8 @@ extern "C" void initapt_pkg() ADDTYPE(Module,"DependencyList",&PyDependencyList_Type); // NO __new__(), internal ADDTYPE(Module,"Package",&PyPackage_Type); // NO __new__() ADDTYPE(Module,"Version",&PyVersion_Type); // NO __new__() + ADDTYPE(Module,"Group", &PyGroup_Type); + ADDTYPE(Module,"GroupList", &PyGroupList_Type); /* ============================ cdrom.cc ============================ */ ADDTYPE(Module,"Cdrom",&PyCdrom_Type); /* ========================= configuration.cc ========================= */ @@ -824,7 +833,8 @@ extern "C" void initapt_pkg() /* ========================= metaindex.cc ========================= */ ADDTYPE(Module,"MetaIndex",&PyMetaIndex_Type); // NO __new__() /* ========================= pkgmanager.cc ========================= */ - ADDTYPE(Module,"PackageManager",&PyPackageManager_Type); + ADDTYPE(Module,"_PackageManager",&PyPackageManager_Type); + ADDTYPE(Module,"PackageManager",&PyPackageManager2_Type); /* ========================= pkgrecords.cc ========================= */ ADDTYPE(Module,"PackageRecords",&PyPackageRecords_Type); /* ========================= pkgsrcrecords.cc ========================= */ @@ -838,6 +848,7 @@ extern "C" void initapt_pkg() ADDTYPE(Module,"AcquireItemDesc",&PyAcquireItemDesc_Type); ADDTYPE(Module,"SystemLock",&PySystemLock_Type); ADDTYPE(Module,"FileLock",&PyFileLock_Type); + ADDTYPE(Module,"OrderList",&PyOrderList_Type); // Tag file constants PyModule_AddObject(Module,"REWRITE_PACKAGE_ORDER", CharCharToList(TFRewritePackageOrder)); @@ -845,86 +856,110 @@ extern "C" void initapt_pkg() PyModule_AddObject(Module,"REWRITE_SOURCE_ORDER", CharCharToList(TFRewriteSourceOrder)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_ADDED", MkPyNumber(pkgOrderList::Added)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_ADD_PENDIG", MkPyNumber(pkgOrderList::AddPending)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_IMMEDIATE", MkPyNumber(pkgOrderList::Immediate)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_LOOP", MkPyNumber(pkgOrderList::Loop)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_UNPACKED", MkPyNumber(pkgOrderList::UnPacked)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_CONFIGURED", MkPyNumber(pkgOrderList::Configured)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_REMOVED", MkPyNumber(pkgOrderList::Removed)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_IN_LIST", MkPyNumber(pkgOrderList::InList)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_AFTER", MkPyNumber(pkgOrderList::After)); + PyDict_SetItemString(PyOrderList_Type.tp_dict, "FLAG_STATES_MASK", MkPyNumber(pkgOrderList::States)); // Acquire constants. // some constants PyDict_SetItemString(PyAcquire_Type.tp_dict, "RESULT_CANCELLED", - Py_BuildValue("i", pkgAcquire::Cancelled)); + MkPyNumber(pkgAcquire::Cancelled)); PyDict_SetItemString(PyAcquire_Type.tp_dict, "RESULT_CONTINUE", - Py_BuildValue("i", pkgAcquire::Continue)); + MkPyNumber(pkgAcquire::Continue)); PyDict_SetItemString(PyAcquire_Type.tp_dict, "RESULT_FAILED", - Py_BuildValue("i", pkgAcquire::Failed)); + MkPyNumber(pkgAcquire::Failed)); #ifdef COMPAT_0_7 PyDict_SetItemString(PyAcquire_Type.tp_dict, "ResultCancelled", - Py_BuildValue("i", pkgAcquire::Cancelled)); + MkPyNumber(pkgAcquire::Cancelled)); PyDict_SetItemString(PyAcquire_Type.tp_dict, "ResultContinue", - Py_BuildValue("i", pkgAcquire::Continue)); + MkPyNumber(pkgAcquire::Continue)); PyDict_SetItemString(PyAcquire_Type.tp_dict, "ResultFailed", - Py_BuildValue("i", pkgAcquire::Failed)); + MkPyNumber(pkgAcquire::Failed)); #endif // Dependency constants PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_DEPENDS", - Py_BuildValue("i", pkgCache::Dep::Depends)); + MkPyNumber(pkgCache::Dep::Depends)); PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_PREDEPENDS", - Py_BuildValue("i", pkgCache::Dep::PreDepends)); + MkPyNumber(pkgCache::Dep::PreDepends)); PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_SUGGESTS", - Py_BuildValue("i", pkgCache::Dep::Suggests)); + MkPyNumber(pkgCache::Dep::Suggests)); PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_RECOMMENDS", - Py_BuildValue("i", pkgCache::Dep::Suggests)); + MkPyNumber(pkgCache::Dep::Suggests)); PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_CONFLICTS", - Py_BuildValue("i", pkgCache::Dep::Conflicts)); + MkPyNumber(pkgCache::Dep::Conflicts)); PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_REPLACES", - Py_BuildValue("i", pkgCache::Dep::Replaces)); + MkPyNumber(pkgCache::Dep::Replaces)); PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_OBSOLETES", - Py_BuildValue("i", pkgCache::Dep::Obsoletes)); + MkPyNumber(pkgCache::Dep::Obsoletes)); PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_DPKG_BREAKS", - Py_BuildValue("i", pkgCache::Dep::DpkgBreaks)); + MkPyNumber(pkgCache::Dep::DpkgBreaks)); PyDict_SetItemString(PyDependency_Type.tp_dict, "TYPE_ENHANCES", - Py_BuildValue("i", pkgCache::Dep::Enhances)); + MkPyNumber(pkgCache::Dep::Enhances)); // PackageManager constants PyDict_SetItemString(PyPackageManager_Type.tp_dict, "RESULT_COMPLETED", - Py_BuildValue("i", pkgPackageManager::Completed)); + MkPyNumber(pkgPackageManager::Completed)); PyDict_SetItemString(PyPackageManager_Type.tp_dict, "RESULT_FAILED", - Py_BuildValue("i", pkgPackageManager::Failed)); + MkPyNumber(pkgPackageManager::Failed)); PyDict_SetItemString(PyPackageManager_Type.tp_dict, "RESULT_INCOMPLETE", - Py_BuildValue("i", pkgPackageManager::Incomplete)); + MkPyNumber(pkgPackageManager::Incomplete)); #ifdef COMPAT_0_7 PyDict_SetItemString(PyPackageManager_Type.tp_dict, "ResultCompleted", - Py_BuildValue("i", pkgPackageManager::Completed)); + MkPyNumber(pkgPackageManager::Completed)); PyDict_SetItemString(PyPackageManager_Type.tp_dict, "ResultFailed", - Py_BuildValue("i", pkgPackageManager::Failed)); + MkPyNumber(pkgPackageManager::Failed)); PyDict_SetItemString(PyPackageManager_Type.tp_dict, "ResultIncomplete", - Py_BuildValue("i", pkgPackageManager::Incomplete)); + MkPyNumber(pkgPackageManager::Incomplete)); #endif + PyDict_SetItemString(PyVersion_Type.tp_dict, "MULTI_ARCH_NONE", + MkPyNumber(pkgCache::Version::None)); + PyDict_SetItemString(PyVersion_Type.tp_dict, "MULTI_ARCH_ALL", + MkPyNumber(pkgCache::Version::All)); + PyDict_SetItemString(PyVersion_Type.tp_dict, "MULTI_ARCH_FOREIGN", + MkPyNumber(pkgCache::Version::Foreign)); + PyDict_SetItemString(PyVersion_Type.tp_dict, "MULTI_ARCH_SAME", + MkPyNumber(pkgCache::Version::Same)); + PyDict_SetItemString(PyVersion_Type.tp_dict, "MULTI_ARCH_ALLOWED", + MkPyNumber(pkgCache::Version::Allowed)); + PyDict_SetItemString(PyVersion_Type.tp_dict, "MULTI_ARCH_ALL_FOREIGN", + MkPyNumber(pkgCache::Version::AllForeign)); + PyDict_SetItemString(PyVersion_Type.tp_dict, "MULTI_ARCH_ALL_ALLOWED", + MkPyNumber(pkgCache::Version::AllAllowed)); // AcquireItem Constants. PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_IDLE", - Py_BuildValue("i", pkgAcquire::Item::StatIdle)); + MkPyNumber(pkgAcquire::Item::StatIdle)); PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_FETCHING", - Py_BuildValue("i", pkgAcquire::Item::StatFetching)); + MkPyNumber(pkgAcquire::Item::StatFetching)); PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_DONE", - Py_BuildValue("i", pkgAcquire::Item::StatDone)); + MkPyNumber(pkgAcquire::Item::StatDone)); PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_TRANSIENT_NETWORK_ERROR", - Py_BuildValue("i", pkgAcquire::Item::StatTransientNetworkError)); + MkPyNumber(pkgAcquire::Item::StatTransientNetworkError)); PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_ERROR", - Py_BuildValue("i", pkgAcquire::Item::StatError)); + MkPyNumber(pkgAcquire::Item::StatError)); PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_AUTH_ERROR", - Py_BuildValue("i", pkgAcquire::Item::StatAuthError)); + MkPyNumber(pkgAcquire::Item::StatAuthError)); #ifdef COMPAT_0_7 PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "StatIdle", - Py_BuildValue("i", pkgAcquire::Item::StatIdle)); + MkPyNumber(pkgAcquire::Item::StatIdle)); PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "StatFetching", - Py_BuildValue("i", pkgAcquire::Item::StatFetching)); + MkPyNumber(pkgAcquire::Item::StatFetching)); PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "StatDone", - Py_BuildValue("i", pkgAcquire::Item::StatDone)); + MkPyNumber(pkgAcquire::Item::StatDone)); PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "StatError", - Py_BuildValue("i", pkgAcquire::Item::StatError)); + MkPyNumber(pkgAcquire::Item::StatError)); PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "StatAuthError", - Py_BuildValue("i", pkgAcquire::Item::StatAuthError)); + MkPyNumber(pkgAcquire::Item::StatAuthError)); #endif #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 1 @@ -964,6 +999,7 @@ extern "C" void initapt_pkg() PyModule_AddIntConstant(Module,"INSTSTATE_HOLD",pkgCache::State::Hold); PyModule_AddIntConstant(Module,"INSTSTATE_HOLD_REINSTREQ",pkgCache::State::HoldReInstReq); + // DEPRECATED API #ifdef COMPAT_0_7 PyModule_AddObject(Module,"RewritePackageOrder", diff --git a/python/apt_pkgmodule.h b/python/apt_pkgmodule.h index da647c3f..b3534a30 100644 --- a/python/apt_pkgmodule.h +++ b/python/apt_pkgmodule.h @@ -70,6 +70,8 @@ extern PyTypeObject PyCache_Type; extern PyTypeObject PyCacheFile_Type; extern PyTypeObject PyPackageList_Type; extern PyTypeObject PyDescription_Type; +extern PyTypeObject PyGroup_Type; +extern PyTypeObject PyGroupList_Type; /* internal */ extern PyTypeObject PyPackage_Type; extern PyTypeObject PyPackageFile_Type; extern PyTypeObject PyDependency_Type; @@ -100,6 +102,7 @@ PyObject *GetPkgAcqFile(PyObject *Self, PyObject *Args, PyObject *kwds); // packagemanager extern PyTypeObject PyPackageManager_Type; +extern PyTypeObject PyPackageManager2_Type; PyObject *GetPkgManager(PyObject *Self,PyObject *Args); @@ -132,6 +135,7 @@ extern PyTypeObject PyAcquireItemDesc_Type; extern PyTypeObject PyAcquireWorker_Type; extern PyTypeObject PySystemLock_Type; extern PyTypeObject PyFileLock_Type; +extern PyTypeObject PyOrderList_Type; // Functions to be exported in the public API. @@ -149,6 +153,7 @@ extern PyTypeObject PyFileLock_Type; # define PyDependency_ToCpp GetCpp<pkgCache::DepIterator> # define PyDependencyList_ToCpp GetCpp<RDepListStruct> // TODO # define PyDescription_ToCpp GetCpp<pkgCache::DescIterator> +# define PyGroup_ToCpp GetCpp<pkgCache::GrpIterator> # define PyHashes_ToCpp GetCpp<Hashes> # define PyHashString_ToCpp GetCpp<HashString*> # define PyIndexRecords_ToCpp GetCpp<indexRecords*> @@ -156,6 +161,7 @@ extern PyTypeObject PyFileLock_Type; # define PyPackage_ToCpp GetCpp<pkgCache::PkgIterator> # define PyPackageFile_ToCpp GetCpp<pkgCache::PkgFileIterator> # define PyIndexFile_ToCpp GetCpp<pkgIndexFile*> +# define PyOrderList_ToCpp GetCpp<pkgOrderList*> # define PyPackageList_ToCpp GetCpp<PkgListStruct> // TODO # define PyPackageManager_ToCpp GetCpp<pkgPackageManager*> # define PyPackageRecords_ToCpp GetCpp<PkgRecordsStruct> // TODO @@ -186,7 +192,9 @@ PyObject* PyHashString_FromCpp(HashString* const &obj, bool Delete, PyObject *Ow PyObject* PyIndexRecords_FromCpp(indexRecords* const &obj, bool Delete, PyObject *Owner); PyObject* PyMetaIndex_FromCpp(metaIndex* const &obj, bool Delete, PyObject *Owner); PyObject* PyPackage_FromCpp(pkgCache::PkgIterator const &obj, bool Delete, PyObject *Owner); +PyObject* PyGroup_FromCpp(pkgCache::GrpIterator const &obj, bool Delete, PyObject *Owner); PyObject* PyIndexFile_FromCpp(pkgIndexFile* const &obj, bool Delete, PyObject *Owner); +PyObject* PyOrderList_FromCpp(pkgOrderList* const &obj, bool Delete, PyObject *Owner); PyObject* PyPackageFile_FromCpp(pkgCache::PkgFileIterator const &obj, bool Delete, PyObject *Owner); //PyObject* PyPackageList_FromCpp(PkgListStruct const &obj, bool Delete, PyObject *Owner); PyObject* PyPackageManager_FromCpp(pkgPackageManager* const &obj, bool Delete, PyObject *Owner); diff --git a/python/arfile.cc b/python/arfile.cc index 5377ca8d..c3aa74d1 100644 --- a/python/arfile.cc +++ b/python/arfile.cc @@ -39,32 +39,32 @@ static PyObject *armember_get_name(PyObject *self, void *closure) static PyObject *armember_get_mtime(PyObject *self, void *closure) { - return Py_BuildValue("k", GetCpp<ARArchive::Member*>(self)->MTime); + return MkPyNumber(GetCpp<ARArchive::Member*>(self)->MTime); } static PyObject *armember_get_uid(PyObject *self, void *closure) { - return Py_BuildValue("k", GetCpp<ARArchive::Member*>(self)->UID); + return MkPyNumber(GetCpp<ARArchive::Member*>(self)->UID); } static PyObject *armember_get_gid(PyObject *self, void *closure) { - return Py_BuildValue("k", GetCpp<ARArchive::Member*>(self)->GID); + return MkPyNumber(GetCpp<ARArchive::Member*>(self)->GID); } static PyObject *armember_get_mode(PyObject *self, void *closure) { - return Py_BuildValue("k", GetCpp<ARArchive::Member*>(self)->Mode); + return MkPyNumber(GetCpp<ARArchive::Member*>(self)->Mode); } static PyObject *armember_get_size(PyObject *self, void *closure) { - return Py_BuildValue("k", GetCpp<ARArchive::Member*>(self)->Size); + return MkPyNumber(GetCpp<ARArchive::Member*>(self)->Size); } static PyObject *armember_get_start(PyObject *self, void *closure) { - return Py_BuildValue("k", GetCpp<ARArchive::Member*>(self)->Start); + return MkPyNumber(GetCpp<ARArchive::Member*>(self)->Start); } static PyObject *armember_repr(PyObject *self) diff --git a/python/cache.cc b/python/cache.cc index 190d4f27..b263d320 100644 --- a/python/cache.cc +++ b/python/cache.cc @@ -39,13 +39,57 @@ const char *UntranslatedDepTypes[] = }; /*}}}*/ -struct PkgListStruct + +template<typename T> struct IterListStruct { - pkgCache::PkgIterator Iter; + T Iter; unsigned long LastIndex; - PkgListStruct(pkgCache::PkgIterator const &I) : Iter(I), LastIndex(0) {} - PkgListStruct() {abort();}; // G++ Bug.. + IterListStruct(T const &I) : Iter(I), LastIndex(0) {} + IterListStruct() {}; + + bool move(unsigned long Index) { + if (Index < 0 || (unsigned)Index >= Count()) + { + PyErr_SetNone(PyExc_IndexError); + return false; + } + + if ((unsigned)Index < LastIndex) + { + LastIndex = 0; + Iter = Begin(); + } + + while ((unsigned)Index > LastIndex) + { + LastIndex++; + Iter++; + if (Iter.end() == true) + { + PyErr_SetNone(PyExc_IndexError); + return false; + } + } + return true; + } + + virtual unsigned Count() = 0; + virtual T Begin() = 0; + +}; + +struct PkgListStruct : public IterListStruct<pkgCache::PkgIterator> { + unsigned Count() { return Iter.Cache()->HeaderP->PackageCount; } + pkgCache::PkgIterator Begin() { return Iter.Cache()->PkgBegin(); } + + PkgListStruct(pkgCache::PkgIterator const &I) { Iter = I; } +}; + +struct GrpListStruct : public IterListStruct<pkgCache::GrpIterator> { + unsigned Count() { return Iter.Cache()->HeaderP->GroupCount; } + pkgCache::GrpIterator Begin() { return Iter.Cache()->GrpBegin(); } + GrpListStruct(pkgCache::GrpIterator const &I) { Iter = I; } }; struct RDepListStruct @@ -175,6 +219,16 @@ static PyMethodDef PkgCacheMethods[] = {} }; +static PyObject *PkgCacheGetGroupCount(PyObject *Self, void*) { + pkgCache *Cache = GetCpp<pkgCache *>(Self); + return MkPyNumber(Cache->HeaderP->GroupCount); +} + +static PyObject *PkgCacheGetGroups(PyObject *Self, void*) { + pkgCache *Cache = GetCpp<pkgCache *>(Self); + return CppPyObject_NEW<GrpListStruct>(Self,&PyGroupList_Type,Cache->GrpBegin()); +} + static PyObject *PkgCacheGetPackages(PyObject *Self, void*) { pkgCache *Cache = GetCpp<pkgCache *>(Self); return CppPyObject_NEW<PkgListStruct>(Self,&PyPackageList_Type,Cache->PkgBegin()); @@ -182,31 +236,31 @@ static PyObject *PkgCacheGetPackages(PyObject *Self, void*) { static PyObject *PkgCacheGetPackageCount(PyObject *Self, void*) { pkgCache *Cache = GetCpp<pkgCache *>(Self); - return Py_BuildValue("i",Cache->HeaderP->PackageCount); + return MkPyNumber((int)Cache->HeaderP->PackageCount); } static PyObject *PkgCacheGetVersionCount(PyObject *Self, void*) { pkgCache *Cache = GetCpp<pkgCache *>(Self); - return Py_BuildValue("i",Cache->HeaderP->VersionCount); + return MkPyNumber(Cache->HeaderP->VersionCount); } static PyObject *PkgCacheGetDependsCount(PyObject *Self, void*) { pkgCache *Cache = GetCpp<pkgCache *>(Self); - return Py_BuildValue("i",Cache->HeaderP->DependsCount); + return MkPyNumber(Cache->HeaderP->DependsCount); } static PyObject *PkgCacheGetPackageFileCount(PyObject *Self, void*) { pkgCache *Cache = GetCpp<pkgCache *>(Self); - return Py_BuildValue("i",Cache->HeaderP->PackageFileCount); + return MkPyNumber(Cache->HeaderP->PackageFileCount); } static PyObject *PkgCacheGetVerFileCount(PyObject *Self, void*) { pkgCache *Cache = GetCpp<pkgCache *>(Self); - return Py_BuildValue("i",Cache->HeaderP->VerFileCount); + return MkPyNumber(Cache->HeaderP->VerFileCount); } static PyObject *PkgCacheGetProvidesCount(PyObject *Self, void*) { pkgCache *Cache = GetCpp<pkgCache *>(Self); - return Py_BuildValue("i",Cache->HeaderP->ProvidesCount); + return MkPyNumber(Cache->HeaderP->ProvidesCount); } static PyObject *PkgCacheGetFileList(PyObject *Self, void*) { @@ -222,11 +276,21 @@ static PyObject *PkgCacheGetFileList(PyObject *Self, void*) { return List; } +static PyObject *PkgCacheGetIsMultiArch(PyObject *Self, void*) { + pkgCache *Cache = GetCpp<pkgCache *>(Self); + PyBool_FromLong(Cache->MultiArchCache()); +} + static PyGetSetDef PkgCacheGetSet[] = { {"depends_count",PkgCacheGetDependsCount,0, "The number of apt_pkg.Dependency objects stored in the cache."}, {"file_list",PkgCacheGetFileList,0, "A list of apt_pkg.PackageFile objects stored in the cache."}, + {"group_count",PkgCacheGetGroupCount,0, + "The number of apt_pkg.Group objects stored in the cache."}, + {"groups", PkgCacheGetGroups, 0, "A list of Group objects in the cache"}, + {"is_multi_arch", PkgCacheGetIsMultiArch, 0, + "Whether the cache supports multi-arch."}, {"package_count",PkgCacheGetPackageCount,0, "The number of apt_pkg.Package objects stored in the cache."}, {"package_file_count",PkgCacheGetPackageFileCount,0, @@ -242,24 +306,37 @@ static PyGetSetDef PkgCacheGetSet[] = { {} }; +// Helper to call FindPkg(name) or FindPkg(name, architecture) +static pkgCache::PkgIterator CacheFindPkg(PyObject *self, PyObject *arg) +{ + const char *name; + const char *architecture; + pkgCache *cache = GetCpp<pkgCache *>(self); + name = PyObject_AsString(arg); -// Map access, operator [] -static PyObject *CacheMapOp(PyObject *Self,PyObject *Arg) -{ - pkgCache *Cache = GetCpp<pkgCache *>(Self); + if (name != NULL) + return cache->FindPkg(name); - // Get the name of the package, unicode and normal strings. - const char *Name = PyObject_AsString(Arg); - if (Name == NULL) - return 0; + PyErr_Clear(); + if (PyArg_ParseTuple(arg, "ss", &name, &architecture) == 0) { + PyErr_Clear(); + PyErr_Format(PyExc_TypeError, "Expected a string or a pair of strings"); + return pkgCache::PkgIterator(); + } + + return cache->FindPkg(name, architecture); +} - // Search for the package - pkgCache::PkgIterator Pkg = Cache->FindPkg(Name); +// Map access, operator [] +static PyObject *CacheMapOp(PyObject *Self,PyObject *Arg) +{ + pkgCache::PkgIterator Pkg = CacheFindPkg(Self, Arg); if (Pkg.end() == true) { - PyErr_SetString(PyExc_KeyError,Name); + if (!PyErr_Occurred()) + PyErr_SetObject(PyExc_KeyError,Arg); return 0; } @@ -269,11 +346,9 @@ static PyObject *CacheMapOp(PyObject *Self,PyObject *Arg) // Check whether the cache contains a package with a given name. static int CacheContains(PyObject *Self,PyObject *Arg) { - // Get the name of the package, unicode and normal strings. - const char *Name = PyObject_AsString(Arg); - if (Name == NULL) - return 0; - return (GetCpp<pkgCache *>(Self)->FindPkg(Name).end() == false); + bool res = (CacheFindPkg(Self, Arg).end() == false); + PyErr_Clear(); + return res; } static PyObject *PkgCacheNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) @@ -292,7 +367,11 @@ static PyObject *PkgCacheNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) pkgCacheFile *Cache = new pkgCacheFile(); - if(pyCallbackInst != 0) { + if (pyCallbackInst == Py_None) { + OpProgress Prog; + if (Cache->Open(Prog,false) == false) + return HandleErrors(); + } else if(pyCallbackInst != 0) { // sanity check for the progress object, see #497049 if (PyObject_HasAttrString(pyCallbackInst, "done") != true) { PyErr_SetString(PyExc_ValueError, @@ -342,9 +421,11 @@ static char *doc_PkgCache = "Cache([progress]) -> Cache() object.\n\n" "apt.progress.base.OpProgress() object (or similar) which reports\n" "progress information while the cache is being opened. If this\n" "parameter is not supplied, the progress will be reported in simple,\n" - "human-readable text to standard output.\n\n" + "human-readable text to standard output. If it is None, no output\n" + "will be made.\n\n" "The cache can be used like a mapping from package names to Package\n" - "objects (although only getting items is supported)."; + "objects (although only getting items is supported). Instead of a name,\n" + "a tuple of a name and an architecture may be used."; static PySequenceMethods CacheSeq = {0,0,0,0,0,0,0,CacheContains,0,0}; static PyMappingMethods CacheMap = {CacheMapLen,CacheMapOp,0}; PyTypeObject PyCache_Type = @@ -418,7 +499,7 @@ PyTypeObject PyCacheFile_Type = 0, // tp_as_buffer Py_TPFLAGS_DEFAULT, // tp_flags }; - /*}}}*/ + // Package List Class /*{{{*/ // --------------------------------------------------------------------- static Py_ssize_t PkgListLen(PyObject *Self) @@ -429,29 +510,9 @@ static Py_ssize_t PkgListLen(PyObject *Self) static PyObject *PkgListItem(PyObject *iSelf,Py_ssize_t Index) { PkgListStruct &Self = GetCpp<PkgListStruct>(iSelf); - if (Index < 0 || (unsigned)Index >= Self.Iter.Cache()->HeaderP->PackageCount) - { - PyErr_SetNone(PyExc_IndexError); - return 0; - } - - if ((unsigned)Index < Self.LastIndex) - { - Self.LastIndex = 0; - Self.Iter = Self.Iter.Cache()->PkgBegin(); - } - - while ((unsigned)Index > Self.LastIndex) - { - Self.LastIndex++; - Self.Iter++; - if (Self.Iter.end() == true) - { - PyErr_SetNone(PyExc_IndexError); - return 0; - } - } + if (!Self.move(Index)) + return 0; return CppPyObject_NEW<pkgCache::PkgIterator>(GetOwner<PkgListStruct>(iSelf),&PyPackage_Type, Self.Iter); } @@ -501,6 +562,68 @@ PyTypeObject PyPackageList_Type = CppClear<PkgListStruct>, // tp_clear }; +/* The same for groups */ +static Py_ssize_t GrpListLen(PyObject *Self) +{ + return GetCpp<GrpListStruct>(Self).Iter.Cache()->HeaderP->GroupCount; +} + +static PyObject *GrpListItem(PyObject *iSelf,Py_ssize_t Index) +{ + GrpListStruct &Self = GetCpp<GrpListStruct>(iSelf); + + if (!Self.move(Index)) + return 0; + return CppPyObject_NEW<pkgCache::GrpIterator>(GetOwner<GrpListStruct>(iSelf),&PyGroup_Type, + Self.Iter); +} + +static PySequenceMethods GrpListSeq = +{ + GrpListLen, + 0, // concat + 0, // repeat + GrpListItem, + 0, // slice + 0, // assign item + 0 // assign slice +}; + +static const char *grouplist_doc = + "A GroupList is an internally used structure to represent\n" + "the 'groups' attribute of apt_pkg.Cache objects in a more\n" + "efficient manner by creating Group objects only when they\n" + "are accessed."; + +PyTypeObject PyGroupList_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.GroupList", // tp_name + sizeof(CppPyObject<GrpListStruct>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<GrpListStruct>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &GrpListSeq, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, // tp_flags + grouplist_doc, // tp_doc + CppTraverse<GrpListStruct>, // tp_traverse + CppClear<GrpListStruct>, // tp_clear +}; + + #define Owner (GetOwner<pkgCache::PkgIterator>(Self)) #define MkGet(PyFunc,Ret) static PyObject *PyFunc(PyObject *Self,void*) \ { \ @@ -514,10 +637,10 @@ MkGet(PackageGetSection,Safe_FromString(Pkg.Section())) MkGet(PackageGetRevDependsList,CppPyObject_NEW<RDepListStruct>(Owner, &PyDependencyList_Type, Pkg.RevDependsList())) MkGet(PackageGetProvidesList,CreateProvides(Owner,Pkg.ProvidesList())) -MkGet(PackageGetSelectedState,Py_BuildValue("i",Pkg->SelectedState)) -MkGet(PackageGetInstState,Py_BuildValue("i",Pkg->InstState)) -MkGet(PackageGetCurrentState,Py_BuildValue("i",Pkg->CurrentState)) -MkGet(PackageGetID,Py_BuildValue("i",Pkg->ID)) +MkGet(PackageGetSelectedState,MkPyNumber(Pkg->SelectedState)) +MkGet(PackageGetInstState,MkPyNumber(Pkg->InstState)) +MkGet(PackageGetCurrentState,MkPyNumber(Pkg->CurrentState)) +MkGet(PackageGetID,MkPyNumber(Pkg->ID)) # MkGet(PackageGetAuto,PyBool_FromLong((Pkg->Flags & pkgCache::Flag::Auto) != 0)) MkGet(PackageGetEssential,PyBool_FromLong((Pkg->Flags & pkgCache::Flag::Essential) != 0)) @@ -714,7 +837,7 @@ static PyObject *DescriptionGetFileList(PyObject *Self,void*) PyObject *DescFile; PyObject *Obj; DescFile = CppPyObject_NEW<pkgCache::PkgFileIterator>(Owner,&PyPackageFile_Type,I.File()); - Obj = Py_BuildValue("Nl",DescFile,I.Index()); + Obj = Py_BuildValue("NN",DescFile,MkPyNumber(I.Index())); PyList_Append(List,Obj); Py_DECREF(Obj); } @@ -869,7 +992,7 @@ static PyObject *VersionGetFileList(PyObject *Self, void*) { PyObject *PkgFile; PyObject *Obj; PkgFile = CppPyObject_NEW<pkgCache::PkgFileIterator>(Owner,&PyPackageFile_Type,I.File()); - Obj = Py_BuildValue("Nl",PkgFile,I.Index()); + Obj = Py_BuildValue("NN",PkgFile,MkPyNumber(I.Index())); PyList_Append(List,Obj); Py_DECREF(Obj); } @@ -896,19 +1019,19 @@ static PyObject *VersionGetProvidesList(PyObject *Self, void*) { return CreateProvides(Owner,Version_GetVer(Self).ProvidesList()); } static PyObject *VersionGetSize(PyObject *Self, void*) { - return Py_BuildValue("i", Version_GetVer(Self)->Size); + return MkPyNumber(Version_GetVer(Self)->Size); } static PyObject *VersionGetInstalledSize(PyObject *Self, void*) { - return Py_BuildValue("i", Version_GetVer(Self)->InstalledSize); + return MkPyNumber(Version_GetVer(Self)->InstalledSize); } static PyObject *VersionGetHash(PyObject *Self, void*) { - return Py_BuildValue("i", Version_GetVer(Self)->Hash); + return MkPyNumber(Version_GetVer(Self)->Hash); } static PyObject *VersionGetID(PyObject *Self, void*) { - return Py_BuildValue("i", Version_GetVer(Self)->ID); + return MkPyNumber(Version_GetVer(Self)->ID); } static PyObject *VersionGetPriority(PyObject *Self, void*) { - return Py_BuildValue("i",Version_GetVer(Self)->Priority); + return MkPyNumber(Version_GetVer(Self)->Priority); } static PyObject *VersionGetPriorityStr(PyObject *Self, void*) { return Safe_FromString(Version_GetVer(Self).PriorityType()); @@ -924,6 +1047,11 @@ static PyObject *VersionGetTranslatedDescription(PyObject *Self, void*) { Ver.TranslatedDescription()); } +static PyObject *VersionGetMultiArch(PyObject *Self, void*) +{ + return MkPyNumber(Version_GetVer(Self)->MultiArch); +} + #if 0 // FIXME: enable once pkgSourceList is stored somewhere static PyObject *VersionGetIsTrusted(PyObject *Self, void*) { else if (strcmp("IsTrusted", Name) == 0) @@ -999,6 +1127,9 @@ static PyGetSetDef VersionGetSet[] = { "The numeric ID of the package."}, {"installed_size",VersionGetInstalledSize,0, "The installed size of this package version."}, + {"multi_arch",VersionGetMultiArch,0, + "Multi-arch state of this package, as an integer. See\n" + "the various MULTI_ARCH_* members."}, {"parent_pkg",VersionGetParentPkg,0, "The parent package of this version."}, {"priority",VersionGetPriority,0, @@ -1118,7 +1249,7 @@ static PyObject *PackageFile_GetIndexType(PyObject *Self,void*) static PyObject *PackageFile_GetSize(PyObject *Self,void*) { pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); - return Py_BuildValue("i",File->Size); + return MkPyNumber(File->Size); } static PyObject *PackageFile_GetNotSource(PyObject *Self,void*) @@ -1135,7 +1266,7 @@ static PyObject *PackageFile_GetNotAutomatic(PyObject *Self,void*) static PyObject *PackageFile_GetID(PyObject *Self,void*) { pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); - return Py_BuildValue("i",File->ID); + return MkPyNumber(File->ID); } #define S(s) (s == NULL ? "" : s) @@ -1344,13 +1475,13 @@ static PyObject *DependencyGetDepTypeUntranslated(PyObject *Self,void*) static PyObject *DependencyGetDepTypeEnum(PyObject *Self,void*) { pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); - return Py_BuildValue("i", Dep->Type); + return MkPyNumber(Dep->Type); } static PyObject *DependencyGetID(PyObject *Self,void*) { pkgCache::DepIterator &Dep = GetCpp<pkgCache::DepIterator>(Self); - return Py_BuildValue("i",Dep->ID); + return MkPyNumber(Dep->ID); } static PyGetSetDef DependencyGetSet[] = { diff --git a/python/cachegroup.cc b/python/cachegroup.cc new file mode 100644 index 00000000..4fc6c378 --- /dev/null +++ b/python/cachegroup.cc @@ -0,0 +1,188 @@ +/* + * cachegroup.cc - Wrapper around pkgCache::GrpIterator + * + * Copyright 2011 Julian Andres Klode <jak@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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#include <Python.h> +#include "apt_pkgmodule.h" +#include "generic.h" +#include <apt-pkg/pkgcache.h> + +struct PyGroup : CppPyObject<pkgCache::GrpIterator> { + pkgCache::PkgIterator current; + int nextIndex; +}; + +static PyObject *group_new(PyTypeObject *type,PyObject *args, + PyObject *kwds) +{ + PyObject *pyCache; + char *name; + char *kwlist[] = {"cache", "name", NULL}; + if (PyArg_ParseTupleAndKeywords(args, kwds, "O!s", kwlist, + &PyCache_Type, &pyCache, + &name) == 0) + return 0; + + pkgCache *cache = GetCpp<pkgCache *>(pyCache); + + pkgCache::GrpIterator grp = cache->FindGrp(name); + + if (!grp.end()) { + return PyGroup_FromCpp(grp, true, pyCache); + } else { + PyErr_SetString(PyExc_KeyError, name); + return NULL; + } +} + +static const char group_find_package_doc[] = + "find_package(architecture: str) -> Package\n\n" + "Return a package for the given architecture, or None if none exists"; +static PyObject *group_find_package(PyObject *self,PyObject *args) +{ + pkgCache::GrpIterator grp = GetCpp<pkgCache::GrpIterator>(self); + PyObject *owner = GetOwner<pkgCache::GrpIterator>(self); + + char *architecture; + if (PyArg_ParseTuple(args, "s", &architecture) == 0) + return 0; + + pkgCache::PkgIterator pkg = grp.FindPkg(architecture); + + if (pkg.end()) { + Py_RETURN_NONE; + } else { + return PyPackage_FromCpp(pkg, true, owner ? owner : self); + } +} + +static const char group_find_preferred_package_doc[] = + "find_preferred_package(prefer_non_virtual: bool = True) -> Package\n\n" + "Return a package for the best architecture, either the native one\n" + "or the first found one. If none exists, return None. If non_virtual\n" + "is True, prefer non-virtual packages over virtual ones."; +static PyObject *group_find_preferred_package(PyObject *self,PyObject *args, + PyObject *kwds) +{ + pkgCache::GrpIterator grp = GetCpp<pkgCache::GrpIterator>(self); + PyObject *owner = GetOwner<pkgCache::GrpIterator>(self); + char nonvirtual = 1; + char *kwlist[] = {"prefer_non_virtual", NULL}; + if (PyArg_ParseTupleAndKeywords(args, kwds, "|b", kwlist, &nonvirtual) == 0) + return 0; + pkgCache::PkgIterator pkg = grp.FindPreferredPkg(nonvirtual); + + if (pkg.end()) { + Py_RETURN_NONE; + } else { + return PyPackage_FromCpp(pkg, true, owner); + } +} + +static PyMethodDef group_methods[] = { + {"find_package",group_find_package,METH_VARARGS,group_find_package_doc}, + {"find_preferred_package",(PyCFunction) group_find_preferred_package, + METH_VARARGS|METH_KEYWORDS,group_find_preferred_package_doc}, + {} +}; + +static PyObject *group_seq_item(PyObject *pySelf,Py_ssize_t index) +{ + PyGroup *self = static_cast<PyGroup *>(pySelf); + pkgCache::GrpIterator grp = GetCpp<pkgCache::GrpIterator>(self); + PyObject *owner = GetOwner<pkgCache::GrpIterator>(self); + + if (self->nextIndex > index || self->nextIndex == 0) { + self->nextIndex = 1; + new (&self->current) pkgCache::PkgIterator(grp.PackageList()); + } + + if (self->nextIndex != index + 1) { + while (self->nextIndex <= index && !self->current.end()) { + self->current = grp.NextPkg(self->current); + self->nextIndex++; + } + } + + if (self->current.end()) + return PyErr_Format(PyExc_IndexError, "Out of range: %zd", index); + + return PyPackage_FromCpp(self->current, true, owner); +} + + +static PySequenceMethods group_as_sequence = +{ + 0, + 0, // concat + 0, // repeat + group_seq_item, + 0, // slice + 0, // assign item + 0 // assign slice +}; + + +static const char group_doc[] = "Group(cache, name)\n\n" + "Group of packages with the same name.\n\n" + "Provides access to all packages sharing a name. Can be used this\n" + "like a list, or by using the special find_*() methods. If you use\n" + "it as a sequence, make sure to access it linearly, as this uses a\n" + "linked list internally."; +PyTypeObject PyGroup_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.Group", // tp_name + sizeof(PyGroup), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgCache::GrpIterator>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &group_as_sequence, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + group_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + group_methods, // tp_methods + 0, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + group_new, // tp_new +}; diff --git a/python/configuration.cc b/python/configuration.cc index 93e92efa..9000f71f 100644 --- a/python/configuration.cc +++ b/python/configuration.cc @@ -92,7 +92,7 @@ static PyObject *CnfFindI(PyObject *Self,PyObject *Args) int Default = 0; if (PyArg_ParseTuple(Args,"s|i",&Name,&Default) == 0) return 0; - return Py_BuildValue("i",GetSelf(Self).FindI(Name,Default)); + return MkPyNumber(GetSelf(Self).FindI(Name,Default)); } static const char *doc_FindB = @@ -438,6 +438,10 @@ PyObject *ParseCommandLine(PyObject *Self,PyObject *Args) return 0; } + if (PySequence_Length(Pargv) < 1) { + PyErr_SetString(PyExc_ValueError,"argv is an empty sequence"); + return 0; + } // Convert the option list int Length = PySequence_Length(POList); CommandLine::Args *OList = new CommandLine::Args[Length+1]; diff --git a/python/depcache.cc b/python/depcache.cc index 12c13a73..e6113429 100644 --- a/python/depcache.cc +++ b/python/depcache.cc @@ -668,22 +668,22 @@ static PyMethodDef PkgDepCacheMethods[] = #define depcache (GetCpp<pkgDepCache *>(Self)) static PyObject *PkgDepCacheGetKeepCount(PyObject *Self,void*) { - return Py_BuildValue("l", depcache->KeepCount()); + return MkPyNumber(depcache->KeepCount()); } static PyObject *PkgDepCacheGetInstCount(PyObject *Self,void*) { - return Py_BuildValue("l", depcache->InstCount()); + return MkPyNumber(depcache->InstCount()); } static PyObject *PkgDepCacheGetDelCount(PyObject *Self,void*) { - return Py_BuildValue("l", depcache->DelCount()); + return MkPyNumber(depcache->DelCount()); } static PyObject *PkgDepCacheGetBrokenCount(PyObject *Self,void*) { - return Py_BuildValue("l", depcache->BrokenCount()); + return MkPyNumber(depcache->BrokenCount()); } static PyObject *PkgDepCacheGetUsrSize(PyObject *Self,void*) { - return Py_BuildValue("L", depcache->UsrSize()); + return MkPyNumber(depcache->UsrSize()); } static PyObject *PkgDepCacheGetDebSize(PyObject *Self,void*) { - return Py_BuildValue("L", depcache->DebSize()); + return MkPyNumber(depcache->DebSize()); } #undef depcache diff --git a/python/generic.h b/python/generic.h index ce9e5091..f9680ca5 100644 --- a/python/generic.h +++ b/python/generic.h @@ -57,6 +57,7 @@ typedef int Py_ssize_t; #define PyString_Type PyUnicode_Type #define PyInt_Check PyLong_Check #define PyInt_AsLong PyLong_AsLong +#define PyInt_FromLong PyLong_FromLong // Force 0.7 compatibility to be off in Python 3 builds #undef COMPAT_0_7 #else @@ -231,6 +232,21 @@ PyObject *HandleErrors(PyObject *Res = 0); const char **ListToCharChar(PyObject *List,bool NullTerm = false); PyObject *CharCharToList(const char **List,unsigned long Size = 0); +/* Happy number conversion, thanks to overloading */ +inline PyObject *MkPyNumber(unsigned long long o) { return PyLong_FromUnsignedLongLong(o); } +inline PyObject *MkPyNumber(unsigned long o) { return PyLong_FromUnsignedLong(o); } +inline PyObject *MkPyNumber(unsigned int o) { return PyLong_FromUnsignedLong(o); } +inline PyObject *MkPyNumber(unsigned short o) { return PyInt_FromLong(o); } +inline PyObject *MkPyNumber(unsigned char o) { return PyInt_FromLong(o); } + +inline PyObject *MkPyNumber(long long o) { return PyLong_FromLongLong(o); } +inline PyObject *MkPyNumber(long o) { return PyInt_FromLong(o); } +inline PyObject *MkPyNumber(int o) { return PyInt_FromLong(o); } +inline PyObject *MkPyNumber(short o) { return PyInt_FromLong(o); } +inline PyObject *MkPyNumber(char o) { return PyInt_FromLong(o); } + +inline PyObject *MkPyNumber(double o) { return PyFloat_FromDouble(o); } + # ifdef COMPAT_0_7 PyObject *_PyAptObject_getattro(PyObject *self, PyObject *attr); # else diff --git a/python/indexfile.cc b/python/indexfile.cc index 037be210..bf0df516 100644 --- a/python/indexfile.cc +++ b/python/indexfile.cc @@ -47,7 +47,7 @@ static PyObject *IndexFileGetHasPackages(PyObject *Self,void*) { return PyBool_FromLong((File->HasPackages())); } static PyObject *IndexFileGetSize(PyObject *Self,void*) { - return Py_BuildValue("i",(File->Size())); + return MkPyNumber((File->Size())); } static PyObject *IndexFileGetIsTrusted(PyObject *Self,void*) { return PyBool_FromLong((File->IsTrusted())); diff --git a/python/indexrecords.cc b/python/indexrecords.cc index d6a3263c..c7623cfd 100644 --- a/python/indexrecords.cc +++ b/python/indexrecords.cc @@ -63,7 +63,7 @@ static PyObject *indexrecords_lookup(PyObject *self,PyObject *args) // Copy the HashString(), to prevent crashes and to not require the // indexRecords object to exist. PyObject *py_hash = PyHashString_FromCpp(new HashString(result->Hash), true, NULL); - PyObject *value = Py_BuildValue("(Oi)",py_hash,result->Size); + PyObject *value = Py_BuildValue("(ON)",py_hash,MkPyNumber(result->Size)); Py_DECREF(py_hash); return value; } diff --git a/python/orderlist.cc b/python/orderlist.cc new file mode 100644 index 00000000..9fbed5f2 --- /dev/null +++ b/python/orderlist.cc @@ -0,0 +1,317 @@ +/* + * orderlist.cc - Wrapper around pkgOrderList + * + * Copyright 2011 Julian Andres Klode <jak@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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <Python.h> +#include "apt_pkgmodule.h" +#include "generic.h" +#include <apt-pkg/orderlist.h> + +struct PyOrderList : CppPyObject<pkgOrderList*> { + pkgCache::PkgIterator current; + int nextIndex; +}; + +static PyObject *order_list_new(PyTypeObject *type,PyObject *args, + PyObject *kwds) +{ + PyObject *pyDepCache = NULL; + char *kwlist[] = {"depcache", NULL}; + if (PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist, + &PyDepCache_Type, &pyDepCache) + == 0) + return 0; + + pkgDepCache *depCache = PyDepCache_ToCpp(pyDepCache); + return PyOrderList_FromCpp(new pkgOrderList(depCache), true, + pyDepCache); +} + +static const char order_list_append_doc[] = + "append(pkg: Package)\n\n" + "Append a package to the end of the list."; +static PyObject *order_list_append(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + PyObject *pyPackage = NULL; + if (PyArg_ParseTuple(args, "O!", &PyPackage_Type, &pyPackage) == 0) + return 0; + + list->push_back(PyPackage_ToCpp(pyPackage)); + Py_RETURN_NONE; +} + +static const char order_list_score_doc[] = + "score(pkg: Package) -> int\n\n" + "Return the score of the package."; +static PyObject *order_list_score(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + PyObject *pyPackage = NULL; + if (PyArg_ParseTuple(args, "O!", &PyPackage_Type, &pyPackage) == 0) + return 0; + + return MkPyNumber(list->Score(PyPackage_ToCpp(pyPackage))); +} + +static const char order_list_order_critical_doc[] = + "order_critical()\n\n" + "Order by PreDepends only (critical unpack order)."; +static PyObject *order_list_order_critical(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + if (PyArg_ParseTuple(args, "") == 0) + return 0; + + list->OrderCritical(); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static const char order_list_order_unpack_doc[] = + "order_unpack()\n\n" + "Order the packages for unpacking (see Debian Policy)."; +static PyObject *order_list_order_unpack(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + if (PyArg_ParseTuple(args, "") == 0) + return 0; + + list->OrderUnpack(); + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static const char order_list_order_configure_doc[] = + "order_configure()\n\n" + "Order the packages for configuration (see Debian Policy)."; +static PyObject *order_list_order_configure(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + if (PyArg_ParseTuple(args, "") == 0) + return 0; + + list->OrderConfigure(); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static bool valid_flags(unsigned int flags) { + return (flags & ~pkgOrderList::Added + & ~pkgOrderList::AddPending + & ~pkgOrderList::Immediate + & ~pkgOrderList::Loop + & ~pkgOrderList::UnPacked + & ~pkgOrderList::Configured + & ~pkgOrderList::Removed + & ~pkgOrderList::InList + & ~pkgOrderList::After + & ~pkgOrderList::States) == 0; +} + +static const char order_list_flag_doc[] = + "flag(pkg: Package, flag: int[, unset_flags: int])\n\n" + "Flag the package, set flags in 'flag' and remove flags in\n" + "'unset_flags'."; +static PyObject *order_list_flag(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + + PyObject *pyPkg = NULL; + unsigned int flags = 0; + unsigned int unset_flags = 0; + if (PyArg_ParseTuple(args, "O!I|I", &PyPackage_Type, &pyPkg, + &flags, &unset_flags) == 0) + return 0; + + if (!valid_flags(flags)) + return PyErr_Format(PyExc_ValueError, "flags (%u) is" + " not a valid combination of flags.", + flags); + if (!valid_flags(unset_flags)) + return PyErr_Format(PyExc_ValueError, "unset_flags (%u) is" + " not a valid combination of flags.", + unset_flags); + + list->Flag(PyPackage_ToCpp(pyPkg), flags, unset_flags); + + Py_RETURN_NONE; +} + +static const char order_list_is_flag_doc[] = + "is_flag(pkg: Package, flag: int)\n\n" + "Check if the flag(s) are set."; +static PyObject *order_list_is_flag(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + PyObject *pyPkg = NULL; + unsigned int flags = 0; + if (PyArg_ParseTuple(args, "O!I", &PyPackage_Type, &pyPkg, + &flags) == 0) + return 0; + + if (!valid_flags(flags)) + return PyErr_Format(PyExc_ValueError, "flags (%u) is" + " not a valid combination of flags.", + flags); + + return PyBool_FromLong(list->IsFlag(PyPackage_ToCpp(pyPkg), flags)); +} + +static const char order_list_wipe_flags_doc[] = + "wipe_flags(flags: int)\n\n" + "Remove the flags in 'flags' from all packages in this list"; +static PyObject *order_list_wipe_flags(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + unsigned int flags = 0; + if (PyArg_ParseTuple(args, "I", &flags) == 0) + return 0; + + if (!valid_flags(flags)) + return PyErr_Format(PyExc_ValueError, "flags (%u) is" + " not a valid combination of flags.", + flags); + + list->WipeFlags(flags); + Py_RETURN_NONE; +} + +static const char order_list_is_now_doc[] = + "is_now(pkg: Package)\n\n" + "Check if the package is flagged for any state but removal."; +static PyObject *order_list_is_now(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + PyObject *pyPkg = NULL; + if (PyArg_ParseTuple(args, "O!", &PyPackage_Type, &pyPkg) == 0) + return 0; + + return PyBool_FromLong(list->IsNow(PyPackage_ToCpp(pyPkg))); +} + +static const char order_list_is_missing_doc[] = + "is_now(pkg: Package)\n\n" + "Check if the package is marked for install."; +static PyObject *order_list_is_missing(PyObject *self,PyObject *args) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + PyObject *pyPkg = NULL; + if (PyArg_ParseTuple(args, "O!", &PyPackage_Type, &pyPkg) == 0) + return 0; + + return PyBool_FromLong(list->IsMissing(PyPackage_ToCpp(pyPkg))); +} + + +#define METHOD(name) {#name, order_list_##name, METH_VARARGS,\ + order_list_##name##_doc} + +static PyMethodDef order_list_methods[] = { + METHOD(append), + METHOD(score), + METHOD(order_critical), + METHOD(order_unpack), + METHOD(order_configure), + METHOD(flag), + METHOD(is_flag), + METHOD(is_now), + METHOD(is_missing), + METHOD(wipe_flags), + {} +}; + +static PyObject *order_list_seq_item(PyObject *self,Py_ssize_t index) +{ + pkgOrderList *list = GetCpp<pkgOrderList*>(self); + PyObject *owner = GetOwner<pkgOrderList*>(self); + PyObject *pycache = GetOwner<pkgOrderList*>(owner); + pkgCache *cache = PyCache_ToCpp(pycache); + + if (index < 0 || index >= list->size()) + return PyErr_Format(PyExc_IndexError, "Out of range: %zd", index); + + return PyPackage_FromCpp(pkgCache::PkgIterator(*cache, + *(list->begin() + index)), + true, owner); +} + +Py_ssize_t order_list_seq_length(PyObject *self) +{ + return GetCpp<pkgOrderList*>(self)->size(); +} + +static PySequenceMethods order_list_as_sequence = +{ + order_list_seq_length, // sq_length + 0, // sq_concat + 0, // sq_repeat + order_list_seq_item, // sq_item + 0, // sq_ass_item + 0, // sq_contains + 0, // sq_inplace_concat + 0 // sq_inplace_repeat +}; + +static const char order_list_doc[] = "OrderList(depcache: DepCache)\n\n" + "Sequence type for packages with special ordering methods."; +PyTypeObject PyOrderList_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.OrderList", // tp_name + sizeof(CppPyObject<pkgOrderList*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<pkgOrderList*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &order_list_as_sequence, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + order_list_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + order_list_methods, // tp_methods + 0, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + order_list_new, // tp_new +}; diff --git a/python/pkgmanager.cc b/python/pkgmanager.cc index 95e8c27e..b7bed658 100644 --- a/python/pkgmanager.cc +++ b/python/pkgmanager.cc @@ -17,36 +17,10 @@ #include <apt-pkg/acquire.h> #include <apt-pkg/init.h> #include <apt-pkg/configuration.h> +#include <apt-pkg/dpkgpm.h> #include <iostream> -static PyObject *PkgManagerNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) -{ - PyObject *Owner; - char *kwlist[] = {"depcache",0}; - if (PyArg_ParseTupleAndKeywords(Args,kwds,"O!",kwlist,&PyDepCache_Type, - &Owner) == 0) - return 0; - - pkgPackageManager *pm = _system->CreatePM(GetCpp<pkgDepCache*>(Owner)); - - CppPyObject<pkgPackageManager*> *PkgManagerObj = - CppPyObject_NEW<pkgPackageManager*>(NULL, type,pm); - - return PkgManagerObj; -} - -#ifdef COMPAT_0_7 -PyObject *GetPkgManager(PyObject *Self,PyObject *Args) -{ - PyErr_WarnEx(PyExc_DeprecationWarning, "apt_pkg.GetPackageManager() is " - "deprecated. Please see apt_pkg.PackageManager() for the " - "replacement.", 1); - return PkgManagerNew(&PyPackageManager_Type,Args,0); -} -#endif - - static PyObject *PkgManagerGetArchives(PyObject *Self,PyObject *Args) { pkgPackageManager *pm = GetCpp<pkgPackageManager*>(Self); @@ -79,7 +53,7 @@ static PyObject *PkgManagerDoInstall(PyObject *Self,PyObject *Args) pkgPackageManager::OrderResult res = pm->DoInstall(status_fd); - return HandleErrors(Py_BuildValue("i",res)); + return HandleErrors(MkPyNumber(res)); } static PyObject *PkgManagerFixMissing(PyObject *Self,PyObject *Args) @@ -114,17 +88,16 @@ static PyMethodDef PkgManagerMethods[] = {} }; - static const char *packagemanager_doc = - "PackageManager(depcache: apt_pkg.DepCache)\n\n" - "PackageManager objects allow the fetching of packages marked for\n" - "installation and the installation of those packages. The parameter\n" - "'depcache' specifies an apt_pkg.DepCache object where information\n" - "about the package selections is retrieved from."; + "_PackageManager objects allow the fetching of packages marked for\n" + "installation and the installation of those packages.\n" + "This is an abstract base class that cannot be subclassed\n" + "in Python. The only subclass is apt_pkg.PackageManager. This\n" + "class is an implementation-detail and not part of the API."; PyTypeObject PyPackageManager_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - "apt_pkg.PackageManager", // tp_name + "apt_pkg._PackageManager", // tp_name sizeof(CppPyObject<pkgPackageManager*>), // tp_basicsize 0, // tp_itemsize // Methods @@ -143,8 +116,7 @@ PyTypeObject PyPackageManager_Type = _PyAptObject_getattro, // tp_getattro 0, // tp_setattro 0, // tp_as_buffer - (Py_TPFLAGS_DEFAULT | // tp_flags - Py_TPFLAGS_BASETYPE), + Py_TPFLAGS_DEFAULT, // tp_flag, packagemanager_doc, // tp_doc 0, // tp_traverse 0, // tp_clear @@ -162,9 +134,240 @@ PyTypeObject PyPackageManager_Type = 0, // tp_dictoffset 0, // tp_init 0, // tp_alloc - PkgManagerNew, // tp_new + 0, // tp_new +}; + + +struct CppPyRef { + PyObject *o; + CppPyRef(const CppPyRef &o) { Py_XINCREF(o); this->o = o; } + CppPyRef(PyObject *o) : o(o) {} + ~CppPyRef() { Py_XDECREF(o); } + operator PyObject *() const { return o; } + PyObject *operator->() const { return o; } }; +class PyPkgManager : public pkgDPkgPM { + bool res(CppPyRef result) { + if (result == NULL) { + std::cerr << "Error in function: " << std::endl; + PyErr_Print(); + PyErr_Clear(); + return false; + } + return (result != NULL && + (result == Py_None || PyObject_IsTrue(result) == 1)); + } + + + PyObject *GetPyPkg(const PkgIterator &Pkg) { + PyObject *depcache = NULL; + PyObject *cache = NULL; + + depcache = GetOwner<PyPkgManager*>(pyinst); + if (depcache != NULL && PyDepCache_Check(depcache)) + cache = GetOwner<pkgDepCache*>(depcache); + + return PyPackage_FromCpp(Pkg, true, cache); + } + + /* Call through to Python */ + virtual bool Install(PkgIterator Pkg,string File) { + return res(PyObject_CallMethod(pyinst, "install", "(NN)", + GetPyPkg(Pkg), + CppPyString(File))); + } + virtual bool Configure(PkgIterator Pkg) { + return res(PyObject_CallMethod(pyinst, "configure", "(N)", + GetPyPkg(Pkg))); + } + virtual bool Remove(PkgIterator Pkg,bool Purge = false) { + return res(PyObject_CallMethod(pyinst, "remove", "(NN)", + GetPyPkg(Pkg), + PyBool_FromLong(Purge))); + } + virtual bool Go(int StatusFd=-1) { + return res(PyObject_CallMethod(pyinst, "go", "(i)", + StatusFd)); + } + virtual void Reset() { + CppPyRef(PyObject_CallMethod(pyinst, "reset", NULL)); + } + +public: + /* Those call the protected functions from the parent class */ + bool callInstall(PkgIterator Pkg,string File) { return pkgDPkgPM::Install(Pkg, File); } + bool callRemove(PkgIterator Pkg, bool Purge) { return pkgDPkgPM::Remove(Pkg, Purge); } + bool callGo(int StatusFd=-1) { return pkgDPkgPM::Go(StatusFd); } + void callReset() { return pkgDPkgPM::Reset(); } + bool callConfigure(PkgIterator Pkg) { return pkgDPkgPM::Configure(Pkg); } + pkgOrderList *getOrderList() { return pkgPackageManager::List; } + + PyPkgManager(pkgDepCache *Cache) : pkgDPkgPM(Cache) {}; + PyObject *pyinst; +}; + +static PyObject *PkgManagerNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) +{ + PyObject *Owner; + char *kwlist[] = {"depcache",0}; + if (PyArg_ParseTupleAndKeywords(Args,kwds,"O!",kwlist,&PyDepCache_Type, + &Owner) == 0) + return 0; + + PyPkgManager *pm = new PyPkgManager(GetCpp<pkgDepCache*>(Owner)); + + CppPyObject<PyPkgManager*> *PkgManagerObj = + CppPyObject_NEW<PyPkgManager*>(NULL, type,pm); + + pm->pyinst = PkgManagerObj; + + return PkgManagerObj; +} + +#ifdef COMPAT_0_7 +PyObject *GetPkgManager(PyObject *Self,PyObject *Args) +{ + PyErr_WarnEx(PyExc_DeprecationWarning, "apt_pkg.GetPackageManager() is " + "deprecated. Please see apt_pkg.PackageManager() for the " + "replacement.", 1); + return PkgManagerNew(&PyPackageManager2_Type,Args,0); +} +#endif + +static PyObject *PkgManagerInstall(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); + PyObject *pkg; + const char *file; + + if (PyArg_ParseTuple(Args, "O!s", &PyPackage_Type,&pkg, &file) == 0) + return 0; + + return HandleErrors(PyBool_FromLong(pm->callInstall(PyPackage_ToCpp(pkg), file))); +} + + +static PyObject *PkgManagerConfigure(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); + PyObject *pkg; + + if (PyArg_ParseTuple(Args, "O!", &PyPackage_Type,&pkg) == 0) + return 0; + + return HandleErrors(PyBool_FromLong(pm->callConfigure(PyPackage_ToCpp(pkg)))); +} + +static PyObject *PkgManagerRemove(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); + PyObject *pkg; + char purge; + + if (PyArg_ParseTuple(Args, "O!b", &PyPackage_Type,&pkg, &purge) == 0) + return 0; + + return HandleErrors(PyBool_FromLong(pm->callRemove(PyPackage_ToCpp(pkg), purge))); +} + +static PyObject *PkgManagerGo(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); + int fd; + + if (PyArg_ParseTuple(Args, "i", &fd) == 0) + return 0; + + return HandleErrors(PyBool_FromLong(pm->callGo(fd))); +} + +static PyObject *PkgManagerReset(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); + + pm->callReset(); + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static PyMethodDef PkgManager2Methods[] = +{ + {"install",PkgManagerInstall,METH_VARARGS, + "install(pkg: Package, filename: str) -> bool \n\n" + "Add a install action. Can be overriden in subclasses.\n\n" + "New in version 0.8.0."}, + {"configure",PkgManagerConfigure,METH_VARARGS, + "configure(pkg: Package) -> bool \n\n" + "Add a configure action. Can be overriden in subclasses.\n\n" + "New in version 0.8.0."}, + {"remove",PkgManagerRemove,METH_VARARGS, + "remove(pkg: Package, purge: bool) -> bool \n\n" + "Add a removal action. Can be overriden in subclasses.\n\n" + "New in version 0.8.0."}, + {"go",PkgManagerGo,METH_VARARGS, + "go(status_fd: int) -> bool \n\n" + "Start dpkg. Can be overriden in subclasses.\n\n" + "New in version 0.8.0."}, + {"reset",PkgManagerReset,METH_VARARGS, + "reset()\n\n" + "Reset the package manager for a new round.\n" + "Can be overriden in subclasses.\n\n" + "New in version 0.8.0."}, + {} +}; + +static const char *packagemanager2_doc = + "PackageManager(depcache: apt_pkg.DepCache)\n\n" + "PackageManager objects allow the fetching of packages marked for\n" + "installation and the installation of those packages. The parameter\n" + "'depcache' specifies an apt_pkg.DepCache object where information\n" + "about the package selections is retrieved from.\n\n" + "Methods in this class can be overriden in sub classes\n" + "to implement behavior different from APT's dpkg implementation."; +PyTypeObject PyPackageManager2_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.PackageManager", // tp_name + sizeof(CppPyObject<PyPkgManager*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr<PyPkgManager*>, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE), + packagemanager2_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + PkgManager2Methods, // tp_methods + 0, // tp_members + 0, // tp_getset + &PyPackageManager_Type, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + PkgManagerNew, // tp_new +}; /*}}}*/ diff --git a/python/pkgsrcrecords.cc b/python/pkgsrcrecords.cc index aad3ef7e..4c889129 100644 --- a/python/pkgsrcrecords.cc +++ b/python/pkgsrcrecords.cc @@ -147,9 +147,9 @@ static PyObject *PkgSrcRecordsGetFiles(PyObject *Self,void*) { PyObject *v; for(unsigned int i=0;i<f.size();i++) { - v = Py_BuildValue("(siss)", + v = Py_BuildValue("(sNss)", f[i].MD5Hash.c_str(), - f[i].Size, + MkPyNumber(f[i].Size), f[i].Path.c_str(), f[i].Type.c_str()); PyList_Append(List, v); @@ -218,8 +218,10 @@ static PyObject *PkgSrcRecordsGetBuildDepends_old(PyObject *Self,void*) { PyObject *v; for(unsigned int i=0;i<bd.size();i++) { - v = Py_BuildValue("(ssii)", bd[i].Package.c_str(), - bd[i].Version.c_str(), bd[i].Op, bd[i].Type); + v = Py_BuildValue("(ssNN)", bd[i].Package.c_str(), + bd[i].Version.c_str(), + MkPyNumber(bd[i].Op), + MkPyNumber(bd[i].Type)); PyList_Append(List, v); Py_DECREF(v); } diff --git a/python/policy.cc b/python/policy.cc index 7eccb30c..b11e4dde 100644 --- a/python/policy.cc +++ b/python/policy.cc @@ -45,7 +45,7 @@ PyObject *policy_get_priority(PyObject *self, PyObject *arg) { pkgPolicy *policy = GetCpp<pkgPolicy *>(self); if (PyObject_TypeCheck(arg, &PyPackage_Type)) { pkgCache::PkgIterator pkg = GetCpp<pkgCache::PkgIterator>(arg); - return Py_BuildValue("i", policy->GetPriority(pkg)); + return MkPyNumber(policy->GetPriority(pkg)); } else { PyErr_SetString(PyExc_TypeError,"Argument must be of Package()."); return 0; diff --git a/python/progress.cc b/python/progress.cc index 5700a1b6..bd3c2ad6 100644 --- a/python/progress.cc +++ b/python/progress.cc @@ -92,12 +92,12 @@ void PyOpProgress::Update() setattr(callbackInst, "op", "s", Op.c_str()); setattr(callbackInst, "subop", "s", SubOp.c_str()); setattr(callbackInst, "major_change", "b", MajorChange); - setattr(callbackInst, "percent", "f", Percent); + setattr(callbackInst, "percent", "N", MkPyNumber(Percent)); #ifdef COMPAT_0_7 setattr(callbackInst, "Op", "s", Op.c_str()); setattr(callbackInst, "subOp", "s", SubOp.c_str()); setattr(callbackInst, "majorChange", "b", MajorChange); - PyObject *arglist = Py_BuildValue("(f)", Percent); + PyObject *arglist = Py_BuildValue("(N)", MkPyNumber(Percent)); RunSimpleCallback("update", arglist); #else RunSimpleCallback("update"); @@ -156,19 +156,19 @@ void PyFetchProgress::UpdateStatus(pkgAcquire::ItemDesc &Itm, int status) // Added object file size and object partial size to // parameters that are passed to updateStatus. // -- Stephan - PyObject *arglist = Py_BuildValue("(sssikk)", Itm.URI.c_str(), + PyObject *arglist = Py_BuildValue("(sssNNN)", Itm.URI.c_str(), Itm.Description.c_str(), Itm.ShortDesc.c_str(), - status, - Itm.Owner->FileSize, - Itm.Owner->PartialSize); + MkPyNumber(status), + MkPyNumber(Itm.Owner->FileSize), + MkPyNumber(Itm.Owner->PartialSize)); RunSimpleCallback("update_status_full", arglist); // legacy version of the interface - arglist = Py_BuildValue("(sssi)", Itm.URI.c_str(), Itm.Description.c_str(), - Itm.ShortDesc.c_str(), status); + arglist = Py_BuildValue("(sssN)", Itm.URI.c_str(), Itm.Description.c_str(), + Itm.ShortDesc.c_str(), MkPyNumber(status)); if(PyObject_HasAttrString(callbackInst, "updateStatus")) RunSimpleCallback("updateStatus", arglist); @@ -240,11 +240,11 @@ void PyFetchProgress::Start() pkgAcquireStatus::Start(); #ifdef COMPAT_0_7 - setattr(callbackInst, "currentCPS", "d", 0); - setattr(callbackInst, "currentBytes", "d", 0); - setattr(callbackInst, "currentItems", "k", 0); - setattr(callbackInst, "totalItems", "k", 0); - setattr(callbackInst, "totalBytes", "d", 0); + setattr(callbackInst, "currentCPS", "N", MkPyNumber(0)); + setattr(callbackInst, "currentBytes", "N", MkPyNumber(0)); + setattr(callbackInst, "currentItems", "N", MkPyNumber(0)); + setattr(callbackInst, "totalItems", "N", MkPyNumber(0)); + setattr(callbackInst, "totalBytes", "N", MkPyNumber(0)); #endif RunSimpleCallback("start"); @@ -280,14 +280,14 @@ bool PyFetchProgress::Pulse(pkgAcquire * Owner) return false; } - setattr(callbackInst, "last_bytes", "d", LastBytes); - setattr(callbackInst, "current_cps", "d", CurrentCPS); - setattr(callbackInst, "current_bytes", "d", CurrentBytes); - setattr(callbackInst, "total_bytes", "d", TotalBytes); - setattr(callbackInst, "fetched_bytes", "d", FetchedBytes); - setattr(callbackInst, "elapsed_time", "k", ElapsedTime); - setattr(callbackInst, "current_items", "k", CurrentItems); - setattr(callbackInst, "total_items", "k", TotalItems); + setattr(callbackInst, "last_bytes", "N", MkPyNumber(LastBytes)); + setattr(callbackInst, "current_cps", "N", MkPyNumber(CurrentCPS)); + setattr(callbackInst, "current_bytes", "N", MkPyNumber(CurrentBytes)); + setattr(callbackInst, "total_bytes", "N", MkPyNumber(TotalBytes)); + setattr(callbackInst, "fetched_bytes", "N", MkPyNumber(FetchedBytes)); + setattr(callbackInst, "elapsed_time", "N", MkPyNumber(ElapsedTime)); + setattr(callbackInst, "current_items", "N", MkPyNumber(CurrentItems)); + setattr(callbackInst, "total_items", "N", MkPyNumber(TotalItems)); // New style if (!PyObject_HasAttrString(callbackInst, "updateStatus")) { @@ -313,12 +313,12 @@ bool PyFetchProgress::Pulse(pkgAcquire * Owner) return true; } #ifdef COMPAT_0_7 - setattr(callbackInst, "currentCPS", "d", CurrentCPS); - setattr(callbackInst, "currentBytes", "d", CurrentBytes); - setattr(callbackInst, "totalBytes", "d", TotalBytes); - setattr(callbackInst, "fetchedBytes", "d", FetchedBytes); - setattr(callbackInst, "currentItems", "k", CurrentItems); - setattr(callbackInst, "totalItems", "k", TotalItems); + setattr(callbackInst, "currentCPS", "N", MkPyNumber(CurrentCPS)); + setattr(callbackInst, "currentBytes", "N", MkPyNumber(CurrentBytes)); + setattr(callbackInst, "totalBytes", "N", MkPyNumber(TotalBytes)); + setattr(callbackInst, "fetchedBytes", "N", MkPyNumber(FetchedBytes)); + setattr(callbackInst, "currentItems", "N", MkPyNumber(CurrentItems)); + setattr(callbackInst, "totalItems", "N", MkPyNumber(TotalItems)); // Go through the list of items and add active items to the // activeItems vector. map<pkgAcquire::Worker *, pkgAcquire::ItemDesc *> activeItemMap; @@ -351,11 +351,11 @@ bool PyFetchProgress::Pulse(pkgAcquire * Owner) pkgAcquire::Worker *worker = iter->first; pkgAcquire::ItemDesc *itm = iter->second; - PyObject *itmTuple = Py_BuildValue("(ssskk)", itm->URI.c_str(), + PyObject *itmTuple = Py_BuildValue("(sssNN)", itm->URI.c_str(), itm->Description.c_str(), itm->ShortDesc.c_str(), - worker->TotalSize, - worker->CurrentSize); + MkPyNumber(worker->TotalSize), + MkPyNumber(worker->CurrentSize)); PyTuple_SetItem(itemsTuple, tuplePos, itmTuple); } diff --git a/python/python-apt-helpers.cc b/python/python-apt-helpers.cc index 7a0f20c4..079b93cf 100644 --- a/python/python-apt-helpers.cc +++ b/python/python-apt-helpers.cc @@ -52,7 +52,9 @@ NEW_FROM(PyHashString_FromCpp,&PyHashString_Type,HashString*) NEW_FROM(PyIndexRecords_FromCpp,&PyIndexRecords_Type,indexRecords*) NEW_FROM(PyMetaIndex_FromCpp,&PyMetaIndex_Type,metaIndex*) NEW_FROM(PyPackage_FromCpp,&PyPackage_Type,pkgCache::PkgIterator) +NEW_FROM(PyGroup_FromCpp,&PyGroup_Type,pkgCache::GrpIterator) NEW_FROM(PyIndexFile_FromCpp,&PyIndexFile_Type,pkgIndexFile*) +NEW_FROM(PyOrderList_FromCpp,&PyOrderList_Type,pkgOrderList*) NEW_FROM(PyPackageFile_FromCpp,&PyPackageFile_Type,pkgCache::PkgFileIterator) //NEW_FROM(PyPackageList_FromCpp,&PyPackageList_Type,PkgListStruct) NEW_FROM(PyPackageManager_FromCpp,&PyPackageManager_Type,pkgPackageManager*) diff --git a/python/python-apt.h b/python/python-apt.h index b9fc9212..6f2a02df 100644 --- a/python/python-apt.h +++ b/python/python-apt.h @@ -167,6 +167,13 @@ struct _PyAptPkgAPIStruct { PyObject* (*version_fromcpp)(pkgCache::VerIterator const &obj, bool Delete, PyObject *Owner); pkgCache::VerIterator& (*version_tocpp)(PyObject *self); + PyTypeObject *group_type; + PyObject* (*group_fromcpp)(pkgCache::GrpIterator const &obj, bool Delete, PyObject *Owner); + pkgCache::GrpIterator& (*group_tocpp)(PyObject *self); + + PyTypeObject *orderlist_type; + PyObject* (*orderlist_fromcpp)(pkgOrderList* const &obj, bool Delete, PyObject *Owner); + pkgOrderList*& (*orderlist_tocpp)(PyObject *self); }; // Checking macros. @@ -184,6 +191,7 @@ struct _PyAptPkgAPIStruct { # define PyDependency_Check(op) PyObject_TypeCheck(op, &PyDependency_Type) # define PyDependencyList_Check(op) PyObject_TypeCheck(op, &PyDependencyList_Type) # define PyDescription_Check(op) PyObject_TypeCheck(op, &PyDescription_Type) +# define PyGroup_Check(op) PyObject_TypeCheck(op, &PyGroup_Type) # define PyHashes_Check(op) PyObject_TypeCheck(op, &PyHashes_Type) # define PyHashString_Check(op) PyObject_TypeCheck(op, &PyHashString_Type) # define PyIndexRecords_Check(op) PyObject_TypeCheck(op, &PyIndexRecords_Type) @@ -217,12 +225,14 @@ struct _PyAptPkgAPIStruct { # define PyDependencyList_CheckExact(op) (op->op_type == &PyDependencyList_Type) # define PyDescription_CheckExact(op) (op->op_type == &PyDescription_Type) # define PyHashes_CheckExact(op) (op->op_type == &PyHashes_Type) +# define PyGroup_CheckExact(op) (op->op_type == &PyGroup_Type) # define PyHashString_CheckExact(op) (op->op_type == &PyHashString_Type) # define PyIndexRecords_CheckExact(op) (op->op_type == &PyIndexRecords_Type) # define PyMetaIndex_CheckExact(op) (op->op_type == &PyMetaIndex_Type) # define PyPackage_CheckExact(op) (op->op_type == &PyPackage_Type) # define PyPackageFile_CheckExact(op) (op->op_type == &PyPackageFile_Type) # define PyIndexFile_CheckExact(op) (op->op_type == &PyIndexFile_Type) +# define PyOrderList_CheckExact(op) (op->op_type == &PyOrderList_Type) # define PyPackageList_CheckExact(op) (op->op_type == &PyPackageList_Type) # define PyPackageManager_CheckExact(op) (op->op_type == &PyPackageManager_Type) # define PyPackageRecords_CheckExact(op) (op->op_type == &PyPackageRecords_Type) @@ -260,6 +270,7 @@ static int import_apt_pkg(void) { # define PyDependency_Type *(_PyAptPkg_API->dependency_type) # define PyDependencyList_Type *(_PyAptPkg_API->dependencylist_type) # define PyDescription_Type *(_PyAptPkg_API->description_type) +# define PyGroup_Type *(_PyAptPkg_API->group_type) # define PyHashes_Type *(_PyAptPkg_API->hashes_type) # define PyHashString_Type *(_PyAptPkg_API->hashstring_type) # define PyIndexRecords_Type *(_PyAptPkg_API->indexrecords_type) @@ -267,6 +278,7 @@ static int import_apt_pkg(void) { # define PyPackage_Type *(_PyAptPkg_API->package_type) # define PyPackageFile_Type *(_PyAptPkg_API->packagefile_type) # define PyIndexFile_Type *(_PyAptPkg_API->packageindexfile_type) +# define PyOrderList_Type *(_PyAptPkg_API->orderlist_type) # define PyPackageList_Type *(_PyAptPkg_API->packagelist_type) # define PyPackageManager_Type *(_PyAptPkg_API->packagemanager_type) # define PyPackageRecords_Type *(_PyAptPkg_API->packagerecords_type) @@ -292,6 +304,7 @@ static int import_apt_pkg(void) { # define PyDependency_ToCpp _PyAptPkg_API->dependency_tocpp # define PyDependencyList_ToCpp _PyAptPkg_API->dependencylist_tocpp // NULL # define PyDescription_ToCpp _PyAptPkg_API->description_tocpp +# define PyGroup_ToCpp _PyAptPkg_API->group_tocpp # define PyHashes_ToCpp _PyAptPkg_API->hashes_tocpp # define PyHashString_ToCpp _PyAptPkg_API->hashstring_tocpp # define PyIndexRecords_ToCpp _PyAptPkg_API->indexrecords_tocpp @@ -299,6 +312,7 @@ static int import_apt_pkg(void) { # define PyPackage_ToCpp _PyAptPkg_API->package_tocpp # define PyPackageFile_ToCpp _PyAptPkg_API->packagefile_tocpp # define PyIndexFile_ToCpp _PyAptPkg_API->packageindexfile_tocpp +# define PyOrderList_ToCpp _PyAptPkg_API->orderlist_tocpp // NULL # define PyPackageList_ToCpp _PyAptPkg_API->packagelist_tocpp // NULL # define PyPackageManager_ToCpp _PyAptPkg_API->packagemanager_tocpp # define PyPackageRecords_ToCpp _PyAptPkg_API->packagerecords_tocpp @@ -324,6 +338,7 @@ static int import_apt_pkg(void) { # define PyDependency_FromCpp _PyAptPkg_API->dependency_fromcpp # define PyDependencyList_FromCpp _PyAptPkg_API->dependencylist_fromcpp // NULL # define PyDescription_FromCpp _PyAptPkg_API->description_fromcpp +# define PyGroup_FromCpp _PyAptPkg_API->group_fromcpp # define PyHashes_FromCpp _PyAptPkg_API->hashes_fromcpp # define PyHashString_FromCpp _PyAptPkg_API->hashstring_fromcpp # define PyIndexRecords_FromCpp _PyAptPkg_API->indexrecords_fromcpp @@ -331,6 +346,7 @@ static int import_apt_pkg(void) { # define PyPackage_FromCpp _PyAptPkg_API->package_fromcpp # define PyPackageFile_FromCpp _PyAptPkg_API->packagefile_fromcpp # define PyIndexFile_FromCpp _PyAptPkg_API->packageindexfile_fromcpp +# define PyOrderList_FromCpp _PyAptPkg_API->orderlist_fromcpp // NULL # define PyPackageList_FromCpp _PyAptPkg_API->packagelist_fromcpp // NULL # define PyPackageManager_FromCpp _PyAptPkg_API->packagemanager_fromcpp # define PyPackageRecords_FromCpp _PyAptPkg_API->packagerecords_fromcpp diff --git a/python/string.cc b/python/string.cc index 6a1ce4e2..7abe2d17 100644 --- a/python/string.cc +++ b/python/string.cc @@ -28,11 +28,11 @@ PyObject *Python(PyObject *Self,PyObject *Args) \ return CppPyString(CFunc(Str)); \ } -#define MkInt(Python,CFunc) \ +#define MkInt(Python,CFunc, ctype, pytype) \ PyObject *Python(PyObject *Self,PyObject *Args) \ { \ - int Val = 0; \ - if (PyArg_ParseTuple(Args,"i",&Val) == 0) \ + ctype Val = 0; \ + if (PyArg_ParseTuple(Args,pytype,&Val) == 0) \ return 0; \ return CppPyString(CFunc(Val)); \ } @@ -56,8 +56,8 @@ PyObject *StrBase64Encode(PyObject *Self,PyObject *Args) { MkStr(StrURItoFileName,URItoFileName); //MkFloat(StrSizeToStr,SizeToStr); -MkInt(StrTimeToStr,TimeToStr); -MkInt(StrTimeRFC1123,TimeRFC1123); +MkInt(StrTimeToStr,TimeToStr, unsigned long, "k"); +MkInt(StrTimeRFC1123,TimeRFC1123, long long, "L"); /*}}}*/ // Other String functions /*{{{*/ @@ -91,7 +91,7 @@ PyObject *StrStringToBool(PyObject *Self,PyObject *Args) char *Str = 0; if (PyArg_ParseTuple(Args,"s",&Str) == 0) return 0; - return Py_BuildValue("i",StringToBool(Str)); + return MkPyNumber(StringToBool(Str)); } PyObject *StrStrToTime(PyObject *Self,PyObject *Args) @@ -107,7 +107,7 @@ PyObject *StrStrToTime(PyObject *Self,PyObject *Args) return Py_None; } - return Py_BuildValue("i",Result); + return MkPyNumber(Result); } PyObject *StrCheckDomainList(PyObject *Self,PyObject *Args) diff --git a/python/tag.cc b/python/tag.cc index 44cd06af..94554400 100644 --- a/python/tag.cc +++ b/python/tag.cc @@ -247,7 +247,7 @@ static PyObject *TagSecBytes(PyObject *Self,PyObject *Args) if (PyArg_ParseTuple(Args,"") == 0) return 0; - return Py_BuildValue("i",GetCpp<pkgTagSection>(Self).size()); + return MkPyNumber(GetCpp<pkgTagSection>(Self).size()); } static PyObject *TagSecStr(PyObject *Self) @@ -319,7 +319,8 @@ static PyObject *TagFileOffset(PyObject *Self,PyObject *Args) { if (PyArg_ParseTuple(Args,"") == 0) return 0; - return Py_BuildValue("i",((TagFileData *)Self)->Object.Offset()); + return MkPyNumber(((TagFileData *)Self)->Object.Offset()); + } static char *doc_Jump = diff --git a/python/tarfile.cc b/python/tarfile.cc index 215d3a8c..cdfe0a7c 100644 --- a/python/tarfile.cc +++ b/python/tarfile.cc @@ -189,35 +189,35 @@ static PyObject *tarmember_get_linkname(PyObject *self, void *closure) static PyObject *tarmember_get_mode(PyObject *self, void *closure) { - return Py_BuildValue("k", GetCpp<pkgDirStream::Item>(self).Mode); + return MkPyNumber(GetCpp<pkgDirStream::Item>(self).Mode); } static PyObject *tarmember_get_uid(PyObject *self, void *closure) { - return Py_BuildValue("k", GetCpp<pkgDirStream::Item>(self).UID); + return MkPyNumber(GetCpp<pkgDirStream::Item>(self).UID); } static PyObject *tarmember_get_gid(PyObject *self, void *closure) { - return Py_BuildValue("k", GetCpp<pkgDirStream::Item>(self).GID); + return MkPyNumber(GetCpp<pkgDirStream::Item>(self).GID); } static PyObject *tarmember_get_size(PyObject *self, void *closure) { - return Py_BuildValue("k", GetCpp<pkgDirStream::Item>(self).Size); + return MkPyNumber(GetCpp<pkgDirStream::Item>(self).Size); } static PyObject *tarmember_get_mtime(PyObject *self, void *closure) { - return Py_BuildValue("k", GetCpp<pkgDirStream::Item>(self).MTime); + return MkPyNumber(GetCpp<pkgDirStream::Item>(self).MTime); } static PyObject *tarmember_get_major(PyObject *self, void *closure) { - return Py_BuildValue("k", GetCpp<pkgDirStream::Item>(self).Major); + return MkPyNumber(GetCpp<pkgDirStream::Item>(self).Major); } static PyObject *tarmember_get_minor(PyObject *self, void *closure) { - return Py_BuildValue("k", GetCpp<pkgDirStream::Item>(self).Minor); + return MkPyNumber(GetCpp<pkgDirStream::Item>(self).Minor); } static PyObject *tarmember_repr(PyObject *self) @@ -33,7 +33,8 @@ files = ['apt_pkgmodule.cc', 'acquire.cc', 'cache.cc', 'cdrom.cc', 'hashstring.cc', 'indexfile.cc', 'indexrecords.cc', 'metaindex.cc', 'pkgmanager.cc', 'pkgrecords.cc', 'pkgsrcrecords.cc', 'policy.cc', 'progress.cc', 'sourcelist.cc', 'string.cc', 'tag.cc', - 'lock.cc', 'acquire-item.cc', 'python-apt-helpers.cc'] + 'lock.cc', 'acquire-item.cc', 'python-apt-helpers.cc', + 'cachegroup.cc', 'orderlist.cc'] files = sorted(['python/' + fname for fname in files], key=lambda s: s[:-3]) apt_pkg = Extension("apt_pkg", files, libraries=["apt-pkg"]) diff --git a/tests/test_apt_cache.py b/tests/test_apt_cache.py index cccfc9c8..aaa9f601 100644 --- a/tests/test_apt_cache.py +++ b/tests/test_apt_cache.py @@ -48,9 +48,9 @@ class TestAptCache(unittest.TestCase): # tons of seek operations r = pkg.candidate.record self.assertEqual(r['Package'], pkg.shortname) - self.assert_('Version' in r) - self.assert_(len(r['Description']) > 0) - self.assert_(str(r).startswith('Package: %s\n' % pkg.shortname)) + self.assertTrue('Version' in r) + self.assertTrue(len(r['Description']) > 0) + self.assertTrue(str(r).startswith('Package: %s\n' % pkg.shortname)) def test_get_provided_packages(self): cache = apt.Cache() @@ -70,7 +70,7 @@ class TestAptCache(unittest.TestCase): def test_low_level_pkg_provides(self): # low level cache provides list of the pkg - cache = apt_pkg.Cache() + cache = apt_pkg.Cache(progress=None) l = cache["mail-transport-agent"].provides_list # arbitrary number, just needs to be higher enough self.assertTrue(len(l), 5) @@ -89,17 +89,17 @@ class TestAptCache(unittest.TestCase): tmpdir = tempfile.mkdtemp() dpkg_dir = os.path.join(tmpdir,"var","lib","dpkg") os.makedirs(os.path.join(dpkg_dir,"updates")) - open(os.path.join(dpkg_dir,"status"), "w") + open(os.path.join(dpkg_dir,"status"), "w").close() apt_pkg.config.set("Dir::State::status", os.path.join(dpkg_dir,"status")) cache = apt.Cache() # test empty self.assertFalse(cache.dpkg_journal_dirty) # that is ok, only [0-9] are dpkg jounral entries - open(os.path.join(dpkg_dir,"updates","xxx"), "w") + open(os.path.join(dpkg_dir,"updates","xxx"), "w").close() self.assertFalse(cache.dpkg_journal_dirty) # that is a dirty journal - open(os.path.join(dpkg_dir,"updates","000"), "w") + open(os.path.join(dpkg_dir,"updates","000"), "w").close() self.assertTrue(cache.dpkg_journal_dirty) # reset config value apt_pkg.config.set("Dir::State::status", old_status) @@ -121,20 +121,19 @@ class TestAptCache(unittest.TestCase): apt_pkg.config.set("dir::etc::sourceparts", "xxx") # main sources.list sources_list = base_sources - f=open(sources_list, "w") - repo = os.path.abspath("./data/test-repo2") - f.write("deb copy:%s /\n" % repo) - f.close() + with open(sources_list, "w") as f: + repo = os.path.abspath("./data/test-repo2") + f.write("deb copy:%s /\n" % repo) # test single sources.list fetching sources_list = os.path.join(rootdir, "test.list") - f=open(sources_list, "w") - repo_dir = os.path.abspath("./data/test-repo") - f.write("deb copy:%s /\n" % repo_dir) - f.close() + with open(sources_list, "w") as f: + repo_dir = os.path.abspath("./data/test-repo") + f.write("deb copy:%s /\n" % repo_dir) + self.assertTrue(os.path.exists(sources_list)) # write marker to ensure listcleaner is not run - open("./data/tmp/var/lib/apt/lists/marker", "w") + open("./data/tmp/var/lib/apt/lists/marker", "w").close() # update a single sources.list cache = apt.Cache() diff --git a/tests/test_cache_invocation.py b/tests/test_cache_invocation.py index 6f4014de..a89ef557 100644 --- a/tests/test_cache_invocation.py +++ b/tests/test_cache_invocation.py @@ -14,7 +14,7 @@ class TestCache(unittest.TestCase): def test_wrong_invocation(self): """cache_invocation: Test wrong invocation.""" - apt_cache = apt_pkg.Cache(apt.progress.base.OpProgress()) + apt_cache = apt_pkg.Cache(progress=None) self.assertRaises(ValueError, apt_pkg.Cache, apt_cache) self.assertRaises(ValueError, apt_pkg.Cache, @@ -23,7 +23,7 @@ class TestCache(unittest.TestCase): def test_proper_invocation(self): """cache_invocation: Test correct invocation.""" - apt_cache = apt_pkg.Cache(apt.progress.base.OpProgress()) + apt_cache = apt_pkg.Cache(progress=None) apt_depcache = apt_pkg.DepCache(apt_cache) if __name__ == "__main__": diff --git a/tests/test_configuration.py b/tests/test_configuration.py new file mode 100644 index 00000000..80509cff --- /dev/null +++ b/tests/test_configuration.py @@ -0,0 +1,30 @@ +#!/usr/bin/python +# +# Copyright (C) 2011 Julian Andres Klode <jak@debian.org> +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +"""Unit tests for verifying the correctness of apt_pkg.Configuration""" +import unittest + +import apt_pkg + + +class TestConfiguration(unittest.TestCase): + """Test various configuration things""" + + def setUp(self): + """Prepare the tests, create reference values...""" + apt_pkg.init_config() + + def test_lp707416(self): + """configuration: Test empty arguments (LP: #707416)""" + self.assertRaises(ValueError, apt_pkg.parse_commandline, + apt_pkg.config,[], []) + self.assertRaises(SystemError, apt_pkg.parse_commandline, + apt_pkg.config,[], ["cmd", "--arg0"]) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_group.py b/tests/test_group.py new file mode 100644 index 00000000..3c3a5b7a --- /dev/null +++ b/tests/test_group.py @@ -0,0 +1,32 @@ +import unittest + +import apt_pkg + + +class TestGroup(unittest.TestCase): + + def setUp(self): + apt_pkg.init() + self.cache = apt_pkg.Cache(progress=None) + + def test_pkgingroup(self): + """Check that each package belongs to the corresponding group""" + for pkg in self.cache.packages: + group = apt_pkg.Group(self.cache, pkg.name) + assert any(pkg.id == p.id for p in group) + + def test_iteration(self): + """Check that iteration works correctly.""" + for pkg in self.cache.packages: + group = apt_pkg.Group(self.cache, pkg.name) + + list(group) == list(group) + + + def test_cache_groups(self): + """group: Iterate over all groups""" + assert len(list(self.cache.groups)) == self.cache.group_count + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_hashes.py b/tests/test_hashes.py index e0aabe09..660373cb 100644 --- a/tests/test_hashes.py +++ b/tests/test_hashes.py @@ -82,11 +82,16 @@ class TestHashString(unittest.TestCase): def setUp(self): """Prepare the test by reading the file.""" - self.hashes = apt_pkg.Hashes(open(apt_pkg.__file__)) + self.file = open(apt_pkg.__file__) + self.hashes = apt_pkg.Hashes(self.file) self.md5 = apt_pkg.HashString("MD5Sum", self.hashes.md5) self.sha1 = apt_pkg.HashString("SHA1", self.hashes.sha1) self.sha256 = apt_pkg.HashString("SHA256", self.hashes.sha256) + def tearDown(self): + """Cleanup, Close the file object used for the tests.""" + self.file.close() + def test_md5(self): """hashes: Test apt_pkg.HashString().md5""" self.assertEqual("MD5Sum:%s" % self.hashes.md5, str(self.md5)) diff --git a/tests/test_progress.py b/tests/test_progress.py index ffab5bc0..73853dfa 100644 --- a/tests/test_progress.py +++ b/tests/test_progress.py @@ -34,7 +34,8 @@ class TestProgress(unittest.TestCase): apt_pkg.config.set("Dir::state::lists", "./tmp") # create artifical line deb_line = "deb file:%s/data/fake-packages/ /\n" % basedir - open("fetch_sources.list","w").write(deb_line) + with open("fetch_sources.list","w") as fobj: + fobj.write(deb_line) apt_pkg.config.set("Dir::Etc::sourcelist", "fetch_sources.list") def test_acquire_progress(self): |
