diff options
Diffstat (limited to 'apt')
| -rw-r--r-- | apt/__init__.py | 16 | ||||
| -rw-r--r-- | apt/auth.py | 56 | ||||
| -rw-r--r-- | apt/cache.py | 327 | ||||
| -rw-r--r-- | apt/cdrom.py | 6 | ||||
| -rw-r--r-- | apt/debfile.py | 247 | ||||
| -rw-r--r-- | apt/deprecation.py | 106 | ||||
| -rw-r--r-- | apt/package.py | 505 | ||||
| -rw-r--r-- | apt/progress/__init__.py | 14 | ||||
| -rw-r--r-- | apt/progress/base.py | 7 | ||||
| -rw-r--r-- | apt/progress/gtk2.py | 519 | ||||
| -rw-r--r-- | apt/progress/old.py | 259 | ||||
| -rw-r--r-- | apt/progress/text.py | 26 | ||||
| -rw-r--r-- | apt/utils.py | 13 |
13 files changed, 588 insertions, 1513 deletions
diff --git a/apt/__init__.py b/apt/__init__.py index 677a625b..b8d291e3 100644 --- a/apt/__init__.py +++ b/apt/__init__.py @@ -18,20 +18,20 @@ # USA # import the core of apt_pkg """High-Level Interface for working with apt.""" +from __future__ import print_function + import apt_pkg # import some fancy classes from apt.package import Package from apt.cache import Cache, ProblemResolver +Cache # pyflakes +ProblemResolver # pyflakes from apt.cdrom import Cdrom -if apt_pkg._COMPAT_0_7: - from apt.progress.old import (OpProgress, FetchProgress, InstallProgress, - CdromProgress) - from apt_pkg import (size_to_str as SizeToStr, time_to_str as TimeToStr, - version_compare as VersionCompare) - -# init the package system -apt_pkg.init() +# init the package system, but do not re-initialize config +if "APT" not in apt_pkg.config: + apt_pkg.init_config() +apt_pkg.init_system() __all__ = ['Cache', 'Cdrom', 'Package'] diff --git a/apt/auth.py b/apt/auth.py index c1b8da2a..74fea10b 100644 --- a/apt/auth.py +++ b/apt/auth.py @@ -24,7 +24,8 @@ # USA """Handle GnuPG keys used to trust signed repositories.""" -import atexit +from __future__ import print_function + import os import os.path import shutil @@ -68,7 +69,8 @@ def _call_apt_key_script(*args, **kwargs): # configuration from the chroot to the apt-key script by using # a temporary APT_CONFIG file. The apt-key script uses apt-config # shell internally - conf = tempfile.NamedTemporaryFile(prefix="apt-key", suffix=".conf") + conf = tempfile.NamedTemporaryFile( + prefix="apt-key", suffix=".conf") conf.write(apt_pkg.config.dump().encode("UTF-8")) conf.flush() env["APT_CONFIG"] = conf.name @@ -79,17 +81,18 @@ def _call_apt_key_script(*args, **kwargs): content = kwargs.get("stdin", None) # py2 needs this encoded, py3.3 will crash if it is - if isinstance(content, unicode) and sys.version_info[:2] < (3, 3): + if sys.version_info.major < 3 and isinstance(content, unicode): content = content.encode("utf-8") output, stderr = proc.communicate(content) if proc.returncode: - raise AptKeyError("The apt-key script failed with return code %s:\n" - "%s\n" - "stdout: %s\n" - "stderr: %s" % (proc.returncode, " ".join(cmd), - output,stderr)) + raise AptKeyError( + "The apt-key script failed with return code %s:\n" + "%s\n" + "stdout: %s\n" + "stderr: %s" % ( + proc.returncode, " ".join(cmd), output, stderr)) elif stderr: sys.stderr.write(stderr) # Forward stderr @@ -98,6 +101,7 @@ def _call_apt_key_script(*args, **kwargs): if conf is not None: conf.close() + def add_key_from_file(filename): """Import a GnuPG key file to trust repositores signed by it. @@ -110,6 +114,7 @@ def add_key_from_file(filename): raise AptKeyError("Key file cannot be accessed: %s" % filename) _call_apt_key_script("add", filename) + def add_key_from_keyserver(keyid, keyserver): """Import a GnuPG key file to trust repositores signed by it. @@ -126,8 +131,9 @@ def add_key_from_keyserver(keyid, keyserver): finally: shutil.rmtree(tmp_keyring_dir) + def _add_key_from_keyserver(keyid, keyserver, tmp_keyring_dir): - if len(keyid) < 160/8: + if len(keyid) < (160 / 8): raise AptKeyError("Only long keyids (v4, 160bit) are supported") # create a temp keyring dir tmp_secret_keyring = os.path.join(tmp_keyring_dir, "secring.gpg") @@ -137,17 +143,23 @@ def _add_key_from_keyserver(keyid, keyserver, tmp_keyring_dir): "gpg", "--no-default-keyring", "--no-options", "--homedir", tmp_keyring_dir, - ] + ] # download the key to a temp keyring first res = subprocess.call(gpg_default_options + [ "--secret-keyring", tmp_secret_keyring, "--keyring", tmp_keyring, "--keyserver", keyserver, "--recv", keyid, - ]) + ]) if res != 0: raise AptKeyError("recv from '%s' failed for '%s'" % ( keyserver, keyid)) + # FIXME: + # - with gnupg 1.4.18 the downloaded key is actually checked(!), + # i.e. gnupg will not import anything that the server sends + # into the keyring, so the below checks are now redundant *if* + # gnupg 1.4.18 is used + # now export again using the long key id (to ensure that there is # really only this one key in our keyring) and not someone MITM us tmp_export_keyring = os.path.join(tmp_keyring_dir, "export-keyring.gpg") @@ -155,7 +167,7 @@ def _add_key_from_keyserver(keyid, keyserver, tmp_keyring_dir): "--keyring", tmp_keyring, "--output", tmp_export_keyring, "--export", keyid, - ]) + ]) if res != 0: raise AptKeyError("export of '%s' failed", keyid) # now verify the fingerprint, this is probably redundant as we @@ -167,10 +179,10 @@ def _add_key_from_keyserver(keyid, keyserver, tmp_keyring_dir): "--fingerprint", "--batch", "--with-colons", - ], - stdout=subprocess.PIPE, - universal_newlines=True).communicate()[0] - got_fingerprint=None + ], + stdout=subprocess.PIPE, + universal_newlines=True).communicate()[0] + got_fingerprint = None for line in output.splitlines(): if line.startswith("fpr:"): got_fingerprint = line.split(":")[9] @@ -180,12 +192,15 @@ def _add_key_from_keyserver(keyid, keyserver, tmp_keyring_dir): # what gnupg is using) signing_key_fingerprint = keyid.replace("0x", "").upper() if got_fingerprint != signing_key_fingerprint: + # make the error match what gnupg >= 1.4.18 will output when + # it checks the key itself before importing it raise AptKeyError( - "Fingerprints do not match, not importing: '%s' != '%s'" % ( - signing_key_fingerprint, got_fingerprint)) + "recv from '%s' failed for '%s'" % ( + keyserver, signing_key_fingerprint)) # finally add it add_key_from_file(tmp_export_keyring) + def add_key(content): """Import a GnuPG key to trust repositores signed by it. @@ -195,6 +210,7 @@ def add_key(content): _call_apt_key_script("adv", "--quiet", "--batch", "--import", "-", stdin=content) + def remove_key(fingerprint): """Remove a GnuPG key to no longer trust repositores signed by it. @@ -203,6 +219,7 @@ def remove_key(fingerprint): """ _call_apt_key_script("rm", fingerprint) + def export_key(fingerprint): """Return the GnuPG key in text format. @@ -211,6 +228,7 @@ def export_key(fingerprint): """ return _call_apt_key_script("export", fingerprint) + def update(): """Update the local keyring with the archive keyring and remove from the local keyring the archive keys which are no longer valid. The @@ -219,6 +237,7 @@ def update(): """ return _call_apt_key_script("update") + def net_update(): """Work similar to the update command above, but get the archive keyring from an URI instead and validate it against a master key. @@ -229,6 +248,7 @@ def net_update(): """ return _call_apt_key_script("net-update") + def list_keys(): """Returns a list of TrustedKey instances for each key which is used to trust repositories. diff --git a/apt/cache.py b/apt/cache.py index 9842cb2a..74bbe71f 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -19,15 +19,15 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA +from __future__ import print_function + import fnmatch import os +import warnings import weakref import apt_pkg from apt import Package -from apt_pkg import gettext as _ -from apt.deprecation import (AttributeDeprecatedBy, function_deprecated_by, - deprecated_args) import apt.progress.text @@ -42,6 +42,7 @@ class FetchFailedException(IOError): class LockFailedException(IOError): """Exception that is thrown when locking fails.""" + class CacheClosedException(Exception): """Exception that is thrown when the cache is used after close().""" @@ -55,14 +56,21 @@ class Cache(object): list of available packages. The cache can be used like a mapping from package names to Package - objects (although only getting items is supported). + objects (although only getting items is supported). Keyword arguments: - progress -- a OpProgress object - rootdir -- a alternative root directory. if that is given - the system sources.list and system lists/ files are - not read, only files relative to the given rootdir - memonly -- build the cache in memory only + progress -- a OpProgress object, + rootdir -- an alternative root directory. if that is given the system + sources.list and system lists/files are not read, only file relative + to the given rootdir, + memonly -- build the cache in memory only. + + + .. versionchanged:: 1.0 + + The cache now supports package names with special architecture + qualifiers such as :all and :native. It does not export them + in :meth:`keys()`, though, to keep :meth:`keys()` a unique set. """ def __init__(self, progress=None, rootdir=None, memonly=False): @@ -71,30 +79,30 @@ class Cache(object): self._records = None self._list = None self._callbacks = {} + self._callbacks2 = {} 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) + + self.connect("cache_post_open", "_inc_changes_count") + self.connect("cache_post_change", "_inc_changes_count") if memonly: # force apt to build its caches in memory apt_pkg.config.set("Dir::Cache::pkgcache", "") if rootdir: - if os.path.exists(rootdir+"/etc/apt/apt.conf"): + rootdir = os.path.abspath(rootdir) + if os.path.exists(rootdir + "/etc/apt/apt.conf"): apt_pkg.read_config_file(apt_pkg.config, - rootdir + "/etc/apt/apt.conf") - if os.path.isdir(rootdir+"/etc/apt/apt.conf.d"): + rootdir + "/etc/apt/apt.conf") + if os.path.isdir(rootdir + "/etc/apt/apt.conf.d"): apt_pkg.read_config_dir(apt_pkg.config, - rootdir + "/etc/apt/apt.conf.d") + rootdir + "/etc/apt/apt.conf.d") apt_pkg.config.set("Dir", rootdir) apt_pkg.config.set("Dir::State::status", rootdir + "/var/lib/dpkg/status") # also set dpkg to the rootdir path so that its called for the # --print-foreign-architectures call - apt_pkg.config.set("Dir::bin::dpkg", + apt_pkg.config.set("Dir::bin::dpkg", os.path.join(rootdir, "usr", "bin", "dpkg")) # create required dirs/files when run with special rootdir # automatically @@ -103,7 +111,6 @@ class Cache(object): # recognized (LP: #320665) apt_pkg.init_system() self.open(progress) - def _inc_changes_count(self): """Increase the number of changes""" @@ -116,12 +123,12 @@ class Cache(object): """ files = ["/var/lib/dpkg/status", "/etc/apt/sources.list", - ] + ] dirs = ["/var/lib/dpkg", "/etc/apt/", "/var/cache/apt/archives/partial", "/var/lib/apt/lists/partial", - ] + ] for d in dirs: if not os.path.exists(rootdir + d): #print "creating: ", rootdir + d @@ -134,7 +141,14 @@ class Cache(object): """ internal helper to run a callback """ if name in self._callbacks: for callback in self._callbacks[name]: - callback() + if callback == '_inc_changes_count': + self._inc_changes_count() + else: + callback() + + if name in self._callbacks2: + for callback, args, kwds in self._callbacks2[name]: + callback(self, *args, **kwds) def open(self, progress=None): """ Open the package cache, after that it can be used like @@ -152,28 +166,11 @@ class Cache(object): self._records = apt_pkg.PackageRecords(self._cache) self._list = apt_pkg.SourceList() self._list.read_main_list() - self._set.clear() - self._fullnameset.clear() self._sorted_set = None self._weakref.clear() self._have_multi_arch = len(apt_pkg.get_architectures()) > 1 - progress.op = _("Building data structures") - i = last = 0 - size = len(self._cache.packages) - for pkg in self._cache.packages: - if progress is not None and last+100 < i: - progress.update(i/float(size)*100) - last = i - # drop stuff with no versions (cruft) - if pkg.has_versions: - self._set.add(pkg.get_fullname(pretty=True)) - if self._have_multi_arch: - self._fullnameset.add(pkg.get_fullname(pretty=False)) - - i += 1 - progress.done() self._run_callbacks("cache_post_open") @@ -196,37 +193,58 @@ class Cache(object): try: return self._weakref[key] except KeyError: - if key in self._set or key in self._fullnameset: - key = str(key) - pkg = self._weakref[key] = Package(self, self._cache[key]) - return pkg - else: + key = str(key) + try: + rawpkg = self._cache[key] + except KeyError: + raise KeyError('The cache has no package named %r' % key) + + # It might be excluded due to not having a version or something + if not self.__is_real_pkg(rawpkg): raise KeyError('The cache has no package named %r' % key) + # Check if we already know the package using the normalized name + name = rawpkg.get_fullname(pretty=False) + try: + return self._weakref[name] + except KeyError: + pkg = Package(self, rawpkg) + self._weakref[key] = self._weakref[name] = pkg + + return pkg + def __iter__(self): # We iterate sorted over package names here. With this we read the # package lists linearly if we need to access the package records, # instead of having to do thousands of random seeks; the latter # is disastrous if we use compressed package indexes, and slower than # necessary for uncompressed indexes. - if self._sorted_set is None: - self._sorted_set = sorted(self._set) - - for pkgname in self._sorted_set: + for pkgname in self.keys(): yield self[pkgname] raise StopIteration + def __is_real_pkg(self, rawpkg): + """Check if the apt_pkg.Package provided is a real package.""" + return rawpkg.has_versions + def has_key(self, key): - return (key in self._set or key in self._fullnameset) + return key in self def __contains__(self, key): - return (key in self._set or key in self._fullnameset) + try: + return self.__is_real_pkg(self._cache[key]) + except KeyError: + return False def __len__(self): - return len(self._set) + return len(self.keys()) def keys(self): - return list(self._set) + if self._sorted_set is None: + self._sorted_set = sorted(p.get_fullname(pretty=True) + for p in self._cache.packages + if self.__is_real_pkg(p)) + return list(self._sorted_set) # We need a copy here, caller may modify def get_changes(self): """ Get the marked changes """ @@ -242,7 +260,6 @@ class Cache(object): changes.append(package) return changes - @deprecated_args def upgrade(self, dist_upgrade=False): """Upgrade all packages. @@ -258,7 +275,8 @@ class Cache(object): def required_download(self): """Get the size of the packages that are required to download.""" if self._records is None: - raise CacheClosedException("Cache object used after close() called") + raise CacheClosedException( + "Cache object used after close() called") pm = apt_pkg.PackageManager(self._depcache) fetcher = apt_pkg.Acquire() pm.get_archives(fetcher, self._list, self._records) @@ -288,16 +306,14 @@ class Cache(object): # now check the result (this is the code from apt-get.cc) failed = False - transient = False err_msg = "" for item in fetcher.items: if item.status == item.STAT_DONE: continue if item.STAT_IDLE: - transient = True continue err_msg += "Failed to fetch %s %s\n" % (item.desc_uri, - item.error_text) + item.error_text) failed = True # we raise a exception if the download failed or it was cancelt @@ -310,7 +326,8 @@ class Cache(object): def _fetch_archives(self, fetcher, pm): """ fetch the needed archives """ if self._records is None: - raise CacheClosedException("Cache object used after close() called") + raise CacheClosedException( + "Cache object used after close() called") # get lock lockfile = apt_pkg.config.find_dir("Dir::Cache::Archives") + "lock" @@ -348,7 +365,6 @@ class Cache(object): if fetcher is None: fetcher = apt_pkg.Acquire(progress) - return self._fetch_archives(fetcher, apt_pkg.PackageManager(self._depcache)) @@ -361,12 +377,12 @@ class Cache(object): else: return bool(pkg.has_provides and not pkg.has_versions) - def get_providing_packages(self, pkgname, candidate_only=True, + def get_providing_packages(self, pkgname, candidate_only=True, include_nonvirtual=False): """Return a list of all packages providing a package. - + Return a list of packages which provide the virtual package of the - specified name. + specified name. If 'candidate_only' is False, return all packages with at least one version providing the virtual package. Otherwise, @@ -377,7 +393,7 @@ class Cache(object): packages providing pkgname, even if pkgname is not itself a virtual pkg. """ - + providers = set() get_candidate_ver = self._depcache.get_candidate_ver try: @@ -398,7 +414,6 @@ class Cache(object): providers.add(package) return list(providers) - @deprecated_args def update(self, fetch_progress=None, pulse_interval=0, raise_on_error=True, sources_list=None): """Run the equivalent of apt-get update. @@ -411,7 +426,7 @@ class Cache(object): apt.progress.FetchProgress, the default is apt.progress.FetchProgress() . sources_list -- Update a alternative sources.list than the default. - Note that the sources.list.d directory is ignored in this case + Note that the sources.list.d directory is ignored in this case """ lockfile = apt_pkg.config.find_dir("Dir::State::Lists") + "lock" lock = apt_pkg.get_lock(lockfile) @@ -423,7 +438,8 @@ class Cache(object): old_sources_list = apt_pkg.config.find("Dir::Etc::sourcelist") old_sources_list_d = apt_pkg.config.find("Dir::Etc::sourceparts") old_cleanup = apt_pkg.config.find("APT::List-Cleanup") - apt_pkg.config.set("Dir::Etc::sourcelist", os.path.abspath(sources_list)) + apt_pkg.config.set("Dir::Etc::sourcelist", + os.path.abspath(sources_list)) apt_pkg.config.set("Dir::Etc::sourceparts", "xxx") apt_pkg.config.set("APT::List-Cleanup", "0") slist = apt_pkg.SourceList() @@ -450,7 +466,6 @@ class Cache(object): apt_pkg.config.set("Dir::Etc::sourceparts", old_sources_list_d) apt_pkg.config.set("APT::List-Cleanup", old_cleanup) - @deprecated_args def install_archives(self, pm, install_progress): """ The first parameter *pm* refers to an object returned by @@ -471,7 +486,6 @@ class Cache(object): install_progress.finish_update() return res - @deprecated_args def commit(self, fetch_progress=None, install_progress=None): """Apply the marked changes to the cache. @@ -531,12 +545,40 @@ class Cache(object): self._run_callbacks("cache_pre_change") def connect(self, name, callback): - """ connect to a signal, currently only used for - cache_{post,pre}_{changed,open} """ - if not name in self._callbacks: + """Connect to a signal. + + .. deprecated:: 1.0 + + Please use connect2() instead, as this function is very + likely to cause a memory leak. + """ + if callback != '_inc_changes_count': + warnings.warn("connect() likely causes a reference" + " cycle, use connect2() instead", RuntimeWarning, 2) + if name not in self._callbacks: self._callbacks[name] = [] self._callbacks[name].append(callback) + def connect2(self, name, callback, *args, **kwds): + """Connect to a signal. + + The callback will be passed the cache as an argument, and + any arguments passed to this function. Make sure that, if you + pass a method of a class as your callback, your class does not + contain a reference to the cache. + + Cyclic references to the cache can cause issues if the Cache object + is replaced by a new one, because the cache keeps a lot of objects and + tens of open file descriptors. + + currently only used for cache_{post,pre}_{changed,open}. + + .. versionadded:: 1.0 + """ + if name not in self._callbacks2: + self._callbacks2[name] = [] + self._callbacks2[name].append((callback, args, kwds)) + def actiongroup(self): """Return an `ActionGroup` object for the current cache. @@ -561,9 +603,9 @@ class Cache(object): @property def dpkg_journal_dirty(self): """Return True if the dpkg was interrupted - + All dpkg operations will fail until this is fixed, the action to - fix the system if dpkg got interrupted is to run + fix the system if dpkg got interrupted is to run 'dpkg --configure -a' as root. """ dpkg_status_dir = os.path.dirname( @@ -593,20 +635,6 @@ class Cache(object): """Return the number of packages marked as keep.""" return self._depcache.keep_count - if apt_pkg._COMPAT_0_7: - _runCallbacks = function_deprecated_by(_run_callbacks) - getChanges = function_deprecated_by(get_changes) - requiredDownload = AttributeDeprecatedBy('required_download') - additionalRequiredSpace = AttributeDeprecatedBy('required_space') - reqReinstallPkgs = AttributeDeprecatedBy('req_reinstall_pkgs') - _runFetcher = function_deprecated_by(_run_fetcher) - _fetchArchives = function_deprecated_by(_fetch_archives) - isVirtualPackage = function_deprecated_by(is_virtual_package) - getProvidingPackages = function_deprecated_by(get_providing_packages) - installArchives = function_deprecated_by(install_archives) - cachePostChange = function_deprecated_by(cache_post_change) - cachePreChange = function_deprecated_by(cache_pre_change) - class ProblemResolver(object): """Resolve problems due to dependencies and conflicts. @@ -670,6 +698,38 @@ class MarkedChangesFilter(Filter): return False +class _FilteredCacheHelper(object): + """Helper class for FilteredCache to break a reference cycle.""" + + def __init__(self, cache): + # Do not keep a reference to the cache, or you have a cycle! + + self._filtered = {} + self._filters = {} + cache.connect2("cache_post_change", self.filter_cache_post_change) + cache.connect2("cache_post_open", self.filter_cache_post_change) + + def _reapply_filter(self, cache): + " internal helper to refilter " + # Do not keep a reference to the cache, or you have a cycle! + self._filtered = {} + for pkg in cache: + for f in self._filters: + if f.apply(pkg): + self._filtered[pkg.name] = 1 + break + + def set_filter(self, filter): + """Set the current active filter.""" + self._filters = [] + self._filters.append(filter) + + def filter_cache_post_change(self, cache): + """Called internally if the cache changes, emit a signal then.""" + # Do not keep a reference to the cache, or you have a cycle! + self._reapply_filter(cache) + + class FilteredCache(object): """ A package cache that is filtered. @@ -681,99 +741,74 @@ class FilteredCache(object): self.cache = Cache(progress) else: self.cache = cache - self.cache.connect("cache_post_change", self.filter_cache_post_change) - self.cache.connect("cache_post_open", self.filter_cache_post_change) - self._filtered = {} - self._filters = [] + self._helper = _FilteredCacheHelper(self.cache) def __len__(self): - return len(self._filtered) + return len(self._helper._filtered) def __getitem__(self, key): return self.cache[key] def __iter__(self): - for pkgname in self._filtered: + for pkgname in self._helper._filtered: yield self.cache[pkgname] def keys(self): - return self._filtered.keys() + return self._helper._filtered.keys() def has_key(self, key): - return (key in self._filtered) + return key in self def __contains__(self, key): - return (key in self._filtered) - - def _reapply_filter(self): - " internal helper to refilter " - self._filtered = {} - for pkg in self.cache: - for f in self._filters: - if f.apply(pkg): - self._filtered[pkg.name] = 1 - break + try: + # Normalize package name for multi arch + return self.cache[key].name in self._helper._filtered + except KeyError: + return False def set_filter(self, filter): """Set the current active filter.""" - self._filters = [] - self._filters.append(filter) - #self._reapplyFilter() - # force a cache-change event that will result in a refiltering + self._helper.set_filter(filter) self.cache.cache_post_change() def filter_cache_post_change(self): """Called internally if the cache changes, emit a signal then.""" - #print "filterCachePostChange()" - self._reapply_filter() - - -# def connect(self, name, callback): -# self.cache.connect(name, callback) + self._helper.filter_cache_post_change(self.cache) def __getattr__(self, key): """we try to look exactly like a real cache.""" - #print "getattr: %s " % key return getattr(self.cache, key) - if apt_pkg._COMPAT_0_7: - _reapplyFilter = function_deprecated_by(_reapply_filter) - setFilter = function_deprecated_by(set_filter) - filterCachePostChange = function_deprecated_by(\ - filter_cache_post_change) - -def cache_pre_changed(): - print "cache pre changed" +def cache_pre_changed(cache): + print("cache pre changed") -def cache_post_changed(): - print "cache post changed" +def cache_post_changed(cache): + print("cache post changed") def _test(): """Internal test code.""" - print "Cache self test" + print("Cache self test") apt_pkg.init() cache = Cache(apt.progress.text.OpProgress()) - cache.connect("cache_pre_change", cache_pre_changed) - cache.connect("cache_post_change", cache_post_changed) - print ("aptitude" in cache) + cache.connect2("cache_pre_change", cache_pre_changed) + cache.connect2("cache_post_change", cache_post_changed) + print(("aptitude" in cache)) pkg = cache["aptitude"] - print pkg.name - print len(cache) + print(pkg.name) + print(len(cache)) for pkgname in cache.keys(): assert cache[pkgname].name == pkgname cache.upgrade() changes = cache.get_changes() - print len(changes) + print(len(changes)) for pkg in changes: assert pkg.name - - # see if fetching works for dirname in ["/tmp/pytest", "/tmp/pytest/partial"]: if not os.path.exists(dirname): @@ -784,28 +819,28 @@ def _test(): cache._fetch_archives(fetcher, pm) #sys.exit(1) - print "Testing filtered cache (argument is old cache)" + print("Testing filtered cache (argument is old cache)") filtered = FilteredCache(cache) - filtered.cache.connect("cache_pre_change", cache_pre_changed) - filtered.cache.connect("cache_post_change", cache_post_changed) + filtered.cache.connect2("cache_pre_change", cache_pre_changed) + filtered.cache.connect2("cache_post_change", cache_post_changed) filtered.cache.upgrade() filtered.set_filter(MarkedChangesFilter()) - print len(filtered) + print(len(filtered)) for pkgname in filtered.keys(): assert pkgname == filtered[pkg].name - print len(filtered) + print(len(filtered)) - print "Testing filtered cache (no argument)" + print("Testing filtered cache (no argument)") filtered = FilteredCache(progress=apt.progress.base.OpProgress()) - filtered.cache.connect("cache_pre_change", cache_pre_changed) - filtered.cache.connect("cache_post_change", cache_post_changed) + filtered.cache.connect2("cache_pre_change", cache_pre_changed) + filtered.cache.connect2("cache_post_change", cache_post_changed) filtered.cache.upgrade() filtered.set_filter(MarkedChangesFilter()) - print len(filtered) + print(len(filtered)) for pkgname in filtered.keys(): assert pkgname == filtered[pkgname].name - print len(filtered) + print(len(filtered)) if __name__ == '__main__': _test() diff --git a/apt/cdrom.py b/apt/cdrom.py index 9688de9e..35a0b180 100644 --- a/apt/cdrom.py +++ b/apt/cdrom.py @@ -20,10 +20,11 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA """Classes related to cdrom handling.""" +from __future__ import print_function + import glob import apt_pkg -from apt.deprecation import AttributeDeprecatedBy from apt.progress.base import CdromProgress @@ -84,6 +85,3 @@ class Cdrom(apt_pkg.Cdrom): if not line.lstrip().startswith("#") and cd_id in line: return True return False - - if apt_pkg._COMPAT_0_7: - inSourcesList = AttributeDeprecatedBy('in_sources_list') diff --git a/apt/debfile.py b/apt/debfile.py index adf9b348..3f4bca4b 100644 --- a/apt/debfile.py +++ b/apt/debfile.py @@ -17,6 +17,8 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA """Classes for working with locally available Debian packages.""" +from __future__ import print_function + import apt import apt_inst import apt_pkg @@ -25,19 +27,21 @@ import os import sys from apt_pkg import gettext as _ -from StringIO import StringIO +from io import BytesIO + class NoDebArchiveException(IOError): """Exception which is raised if a file is no Debian archive.""" + class DebPackage(object): """A Debian Package (.deb file).""" # Constants for comparing the local package file with the version # in the cache - (VERSION_NONE, - VERSION_OUTDATED, - VERSION_SAME, + (VERSION_NONE, + VERSION_OUTDATED, + VERSION_SAME, VERSION_NEWER) = range(4) debug = 0 @@ -68,7 +72,7 @@ class DebPackage(object): self._sections = apt_pkg.TagSection(control) self.pkgname = self._sections["Package"] self._check_was_run = False - + def __getitem__(self, key): return self._sections[key] @@ -91,29 +95,31 @@ class DebPackage(object): """ return the list of files in control.tar.gt """ control = [] try: - self._debfile.control.go(lambda item, data: control.append(item.name)) + self._debfile.control.go( + lambda item, data: control.append(item.name)) except SystemError: return [_("List of control files for '%s' could not be read") % self.filename] return sorted(control) - # helper that will return a pkgname with a multiarch suffix if needed - def _maybe_append_multiarch_suffix(self, pkgname, + def _maybe_append_multiarch_suffix(self, pkgname, in_conflict_checking=False): # trivial cases + if ":" in pkgname: + return pkgname if not self._multiarch: return pkgname elif self._cache.is_virtual_package(pkgname): return pkgname - elif (pkgname in self._cache and + elif (pkgname in self._cache and self._cache[pkgname].candidate and self._cache[pkgname].candidate.architecture == "all"): return pkgname # now do the real multiarch checking multiarch_pkgname = "%s:%s" % (pkgname, self._multiarch) # the upper layers will handle this - if not multiarch_pkgname in self._cache: + if multiarch_pkgname not in self._cache: return multiarch_pkgname # now check the multiarch state cand = self._cache[multiarch_pkgname].candidate._cand @@ -124,8 +130,8 @@ class DebPackage(object): return pkgname # for conflicts we need a special case here, any not multiarch enabled # package has a implicit conflict - if (in_conflict_checking and - not (cand.multi_arch & cand.MULTI_ARCH_SAME)): + if (in_conflict_checking and + not (cand.multi_arch & cand.MULTI_ARCH_SAME)): return pkgname return multiarch_pkgname @@ -146,9 +152,11 @@ class DebPackage(object): depname = self._maybe_append_multiarch_suffix(depname) # check for virtual pkgs - if not depname in self._cache: + if depname not in self._cache: if self._cache.is_virtual_package(depname): - self._dbg(3, "_is_or_group_satisfied(): %s is virtual dep" % depname) + self._dbg( + 3, "_is_or_group_satisfied(): %s is virtual dep" % + depname) for pkg in self._cache.get_providing_packages(depname): if pkg.is_installed: return True @@ -161,13 +169,15 @@ class DebPackage(object): # if no real dependency is installed, check if there is # a package installed that provides this dependency # (e.g. scrollkeeper dependecies are provided by rarian-compat) - # but only do that if there is no version required in the + # but only do that if there is no version required in the # dependency (we do not supprot versionized dependencies) if not oper: for ppkg in self._cache.get_providing_packages( depname, include_nonvirtual=True): if ppkg.is_installed: - self._dbg(3, "found installed '%s' that provides '%s'" % (ppkg.name, depname)) + self._dbg( + 3, "found installed '%s' that provides '%s'" % ( + ppkg.name, depname)) return True return False @@ -180,7 +190,7 @@ class DebPackage(object): depname = self._maybe_append_multiarch_suffix(depname) # if we don't have it in the cache, it may be virtual - if not depname in self._cache: + if depname not in self._cache: if not self._cache.is_virtual_package(depname): continue providers = self._cache.get_providing_packages(depname) @@ -210,16 +220,19 @@ class DebPackage(object): or_str += dep[0] if ver and oper: or_str += " (%s %s)" % (dep[2], dep[1]) - if dep != or_group[len(or_group)-1]: + if dep != or_group[len(or_group) - 1]: or_str += "|" - self._failure_string += _("Dependency is not satisfiable: %s\n") % or_str + self._failure_string += _( + "Dependency is not satisfiable: %s\n") % or_str return False def _check_single_pkg_conflict(self, pkgname, ver, oper): """Return True if a pkg conflicts with a real installed/marked pkg.""" # FIXME: deal with conflicts against its own provides # (e.g. Provides: ftp-server, Conflicts: ftp-server) - self._dbg(3, "_check_single_pkg_conflict() pkg='%s' ver='%s' oper='%s'" % (pkgname, ver, oper)) + self._dbg( + 3, "_check_single_pkg_conflict() pkg='%s' ver='%s' oper='%s'" % ( + pkgname, ver, oper)) pkg = self._cache[pkgname] if pkg.is_installed: pkgver = pkg.installed.version @@ -232,7 +245,7 @@ class DebPackage(object): #print "pkgver: %s " % pkgver #print "oper: %s " % oper if (apt_pkg.check_dep(pkgver, oper, ver) and not - self.replaces_real_pkg(pkgname, oper, ver)): + self.replaces_real_pkg(pkgname, oper, ver)): self._failure_string += _("Conflicts with the installed package " "'%s'") % pkg.name self._dbg(3, "conflicts with installed pkg '%s'" % pkg.name) @@ -253,7 +266,7 @@ class DebPackage(object): depname, in_conflict_checking=True) # check conflicts with virtual pkgs - if not depname in self._cache: + if depname not in self._cache: # FIXME: we have to check for virtual replaces here as # well (to pass tests/gdebi-test8.deb) if self._cache.is_virtual_package(depname): @@ -263,8 +276,8 @@ class DebPackage(object): if self.pkgname == pkg.name: self._dbg(3, "conflict on self, ignoring") continue - if self._check_single_pkg_conflict(pkg.name, ver, - oper): + if self._check_single_pkg_conflict( + pkg.name, ver, oper): self._installed_conflicts.add(pkg.name) continue if self._check_single_pkg_conflict(depname, ver, oper): @@ -276,7 +289,7 @@ class DebPackage(object): """List of package names conflicting with this package.""" key = "Conflicts" try: - return apt_pkg.parse_depends(self._sections[key]) + return apt_pkg.parse_depends(self._sections[key], False) except KeyError: return [] @@ -287,7 +300,8 @@ class DebPackage(object): # find depends for key in "Depends", "Pre-Depends": try: - depends.extend(apt_pkg.parse_depends(self._sections[key])) + depends.extend( + apt_pkg.parse_depends(self._sections[key], False)) except KeyError: pass return depends @@ -297,7 +311,7 @@ class DebPackage(object): """List of virtual packages which are provided by this package.""" key = "Provides" try: - return apt_pkg.parse_depends(self._sections[key]) + return apt_pkg.parse_depends(self._sections[key], False) except KeyError: return [] @@ -306,7 +320,7 @@ class DebPackage(object): """List of packages which are replaced by this package.""" key = "Replaces" try: - return apt_pkg.parse_depends(self._sections[key]) + return apt_pkg.parse_depends(self._sections[key], False) except KeyError: return [] @@ -347,22 +361,22 @@ class DebPackage(object): return res def check_breaks_existing_packages(self): - """ - check if installing the package would break exsisting + """ + check if installing the package would break exsisting package on the system, e.g. system has: smc depends on smc-data (= 1.4) and user tries to installs smc-data 1.6 """ # show progress information as this step may take some time size = float(len(self._cache)) - steps = max(int(size/50), 1) + steps = max(int(size / 50), 1) debver = self._sections["Version"] debarch = self._sections["Architecture"] # store what we provide so that we can later check against that - provides = [ x[0][0] for x in self.provides] + provides = [x[0][0] for x in self.provides] for (i, pkg) in enumerate(self._cache): - if i%steps == 0: - self._cache.op_progress.update(float(i)/size*100.0) + if i % steps == 0: + self._cache.op_progress.update(float(i) / size * 100.0) if not pkg.is_installed: continue # check if the exising dependencies are still satisfied @@ -371,14 +385,21 @@ class DebPackage(object): for dep_or in pkg.installed.dependencies: for dep in dep_or.or_dependencies: if dep.name == self.pkgname: - if not apt_pkg.check_dep(debver, dep.relation, dep.version): + if not apt_pkg.check_dep( + debver, dep.relation, dep.version): self._dbg(2, "would break (depends) %s" % pkg.name) - # TRANSLATORS: the first '%s' is the package that breaks, the second the dependency that makes it break, the third the relation (e.g. >=) and the latest the version for the releation - self._failure_string += _("Breaks existing package '%(pkgname)s' dependency %(depname)s (%(deprelation)s %(depversion)s)") % { - 'pkgname' : pkg.name, - 'depname' : dep.name, - 'deprelation' : dep.relation, - 'depversion' : dep.version} + # TRANSLATORS: the first '%s' is the package that + # breaks, the second the dependency that makes it + # break, the third the relation (e.g. >=) and the + # latest the version for the releation + self._failure_string += _( + "Breaks existing package '%(pkgname)s' " + "dependency %(depname)s " + "(%(deprelation)s %(depversion)s)") % { + 'pkgname': pkg.name, + 'depname': dep.name, + 'deprelation': dep.relation, + 'depversion': dep.version} self._cache.op_progress.done() return False # now check if there are conflicts against this package on @@ -386,25 +407,41 @@ class DebPackage(object): if "Conflicts" in ver.depends_list: for conflicts_ver_list in ver.depends_list["Conflicts"]: for c_or in conflicts_ver_list: - if c_or.target_pkg.name == self.pkgname and c_or.target_pkg.architecture == debarch: - if apt_pkg.check_dep(debver, c_or.comp_type, c_or.target_ver): - self._dbg(2, "would break (conflicts) %s" % pkg.name) - # TRANSLATORS: the first '%s' is the package that conflicts, the second the packagename that it conflicts with (so the name of the deb the user tries to install), the third is the relation (e.g. >=) and the last is the version for the relation - self._failure_string += _("Breaks existing package '%(pkgname)s' conflict: %(targetpkg)s (%(comptype)s %(targetver)s)") % { - 'pkgname' : pkg.name, - 'targetpkg' : c_or.target_pkg.name, - 'comptype' : c_or.comp_type, - 'targetver' : c_or.target_ver } + if (c_or.target_pkg.name == self.pkgname and + c_or.target_pkg.architecture == debarch): + if apt_pkg.check_dep( + debver, c_or.comp_type, c_or.target_ver): + self._dbg( + 2, "would break (conflicts) %s" % pkg.name) + # TRANSLATORS: the first '%s' is the package + # that conflicts, the second the packagename + # that it conflicts with (so the name of the + # deb the user tries to install), the third is + # the relation (e.g. >=) and the last is the + # version for the relation + self._failure_string += _( + "Breaks existing package '%(pkgname)s' " + "conflict: %(targetpkg)s " + "(%(comptype)s %(targetver)s)") % { + 'pkgname': pkg.name, + 'targetpkg': c_or.target_pkg.name, + 'comptype': c_or.comp_type, + 'targetver': c_or.target_ver} self._cache.op_progress.done() return False if (c_or.target_pkg.name in provides and - self.pkgname != pkg.name): - self._dbg(2, "would break (conflicts) %s" % provides) - self._failure_string += _("Breaks existing package '%(pkgname)s' that conflict: '%(targetpkg)s'. But the '%(debfile)s' provides it via: '%(provides)s'") % { - 'provides' : ",".join(provides), - 'debfile' : self.filename, - 'targetpkg' : c_or.target_pkg.name, - 'pkgname' : pkg.name } + self.pkgname != pkg.name): + self._dbg( + 2, "would break (conflicts) %s" % provides) + self._failure_string += _( + "Breaks existing package '%(pkgname)s' " + "that conflict: '%(targetpkg)s'. But the " + "'%(debfile)s' provides it via: " + "'%(provides)s'") % { + 'provides': ",".join(provides), + 'debfile': self.filename, + 'targetpkg': c_or.target_pkg.name, + 'pkgname': pkg.name} self._cache.op_progress.done() return False self._cache.op_progress.done() @@ -419,6 +456,11 @@ class DebPackage(object): """ self._dbg(3, "compare_to_version_in_cache") pkgname = self._sections["Package"] + architecture = self._sections["Architecture"] + + # Arch qualify the package name + pkgname = ":".join([pkgname, architecture]) + debver = self._sections["Version"] self._dbg(1, "debver: %s" % debver) if pkgname in self._cache: @@ -439,19 +481,19 @@ class DebPackage(object): return self.VERSION_OUTDATED return self.VERSION_NONE - def check(self): + def check(self, allow_downgrade=False): """Check if the package is installable.""" self._dbg(3, "check") self._check_was_run = True # check arch - if not "Architecture" in self._sections: + if "Architecture" not in self._sections: self._dbg(1, "ERROR: no architecture field") self._failure_string = _("No Architecture field in the package") return False arch = self._sections["Architecture"] - if arch != "all" and arch != apt_pkg.config.find("APT::Architecture"): + if arch != "all" and arch != apt_pkg.config.find("APT::Architecture"): if arch in apt_pkg.get_architectures(): self._multiarch = arch self.pkgname = "%s:%s" % (self.pkgname, self._multiarch) @@ -462,10 +504,12 @@ class DebPackage(object): return False # check version - if self.compare_to_version_in_cache() == self.VERSION_OUTDATED: + if (not allow_downgrade and + self.compare_to_version_in_cache() == self.VERSION_OUTDATED): if self._cache[self.pkgname].installed: # the deb is older than the installed - self._failure_string = _("A later version is already installed") + self._failure_string = _( + "A later version is already installed") return False # FIXME: this sort of error handling sux @@ -475,7 +519,7 @@ class DebPackage(object): if not self.check_conflicts(): return False - # check if installing it would break anything on the + # check if installing it would break anything on the # current system if not self.check_breaks_existing_packages(): return False @@ -499,19 +543,18 @@ class DebPackage(object): def satisfy_depends_str(self, dependsstr): """Satisfy the dependencies in the given string.""" - return self._satisfy_depends(apt_pkg.parse_depends(dependsstr)) + return self._satisfy_depends(apt_pkg.parse_depends(dependsstr, False)) def _satisfy_depends(self, depends): """Satisfy the dependencies.""" # turn off MarkAndSweep via a action group (if available) try: _actiongroup = apt_pkg.ActionGroup(self._cache._depcache) + _actiongroup # pyflakes except AttributeError: pass # check depends for or_group in depends: - #print "or_group: %s" % or_group - #print "or_group satified: %s" % self._is_or_group_satisfied(or_group) if not self._is_or_group_satisfied(or_group): if not self._satisfy_or_group(or_group): return False @@ -530,7 +573,8 @@ class DebPackage(object): """Return missing dependencies.""" self._dbg(1, "Installing: %s" % self._need_pkgs) if not self._check_was_run: - raise AttributeError("property only available after check() was run") + raise AttributeError( + "property only available after check() was run") return self._need_pkgs @property @@ -543,7 +587,8 @@ class DebPackage(object): remove = [] unauthenticated = [] if not self._check_was_run: - raise AttributeError("property only available after check() was run") + raise AttributeError( + "property only available after check() was run") for pkg in self._cache: if pkg.marked_install or pkg.marked_upgrade: install.append(pkg.name) @@ -562,7 +607,7 @@ class DebPackage(object): def to_hex(in_data): hex = "" for (i, c) in enumerate(in_data): - if i%80 == 0: + if i % 80 == 0: hex += "\n" hex += "%2.2x " % ord(c) return hex @@ -585,20 +630,20 @@ class DebPackage(object): else: s += chr(b) return s - + def _get_content(self, part, name, auto_decompress=True, auto_hex=True): if name.startswith("./"): name = name[2:] data = part.extractdata(name) # check for zip content if name.endswith(".gz") and auto_decompress: - io = StringIO(data) + io = BytesIO(data) gz = gzip.GzipFile(fileobj=io) - data = _("Automatically decompressed:\n\n") + data = _("Automatically decompressed:\n\n").encode("utf-8") data += gz.read() # auto-convert to hex try: - data = unicode(data, "utf-8") + data = data.decode("utf-8") except Exception: new_data = _("Automatically converted to printable ascii:\n") new_data += self.to_strish(data) @@ -622,7 +667,7 @@ class DebPackage(object): def _dbg(self, level, msg): """Write debugging output to sys.stderr.""" if level <= self.debug: - print >> sys.stderr, msg + print(msg, file=sys.stderr) def install(self, install_progress=None): """Install the package.""" @@ -640,6 +685,7 @@ class DebPackage(object): install_progress.finishUpdate() return res + class DscSrcPackage(DebPackage): """A locally available source package.""" @@ -664,28 +710,42 @@ class DscSrcPackage(DebPackage): """Return the dependencies of the package""" return self._conflicts + @property + def filelist(self): + """Return the list of files associated with this dsc file""" + # Files stanza looks like (hash, size, filename, ...) + return self._sections['Files'].split()[2::3] + def open(self, file): """Open the package.""" depends_tags = ["Build-Depends", "Build-Depends-Indep"] conflicts_tags = ["Build-Conflicts", "Build-Conflicts-Indep"] - fobj = open(file) + fd = apt_pkg.open_maybe_clear_signed_file(file) + fobj = os.fdopen(fd) tagfile = apt_pkg.TagFile(fobj) try: for sec in tagfile: + # we only care about the stanza with the "Format:" tag, the + # rest is gpg signature noise. we should probably have + # bindings for apts OpenMaybeClearsignedFile() + if "Format" not in sec: + continue for tag in depends_tags: - if not tag in sec: + if tag not in sec: continue self._depends.extend(apt_pkg.parse_src_depends(sec[tag])) for tag in conflicts_tags: - if not tag in sec: + if tag not in sec: continue self._conflicts.extend(apt_pkg.parse_src_depends(sec[tag])) if 'Source' in sec: self.pkgname = sec['Source'] if 'Binary' in sec: - self.binaries = sec['Binary'].split(', ') - if 'Version' in sec: - self._sections['Version'] = sec['Version'] + self.binaries = [b.strip() for b in + sec['Binary'].split(',')] + for tag in sec.keys(): + if tag in sec: + self._sections[tag] = sec[tag] finally: del tagfile fobj.close() @@ -695,7 +755,7 @@ class DscSrcPackage(DebPackage): " ".join(self.binaries)) self._sections["Description"] = s self._check_was_run = False - + def check(self): """Check if the package is installable..""" if not self.check_conflicts(): @@ -709,6 +769,7 @@ class DscSrcPackage(DebPackage): # after _satisfy_depends() should probably be done return self._satisfy_depends(self.depends) + def _test(): """Test function""" from apt.cache import Cache @@ -717,25 +778,25 @@ def _test(): cache = Cache() vp = "www-browser" - print "%s virtual: %s" % (vp, cache.is_virtual_package(vp)) + print("%s virtual: %s" % (vp, cache.is_virtual_package(vp))) providers = cache.get_providing_packages(vp) - print "Providers for %s :" % vp + print("Providers for %s :" % vp) for pkg in providers: - print " %s" % pkg.name + print(" %s" % pkg.name) d = DebPackage(sys.argv[1], cache) - print "Deb: %s" % d.pkgname + print("Deb: %s" % d.pkgname) if not d.check(): - print "can't be satified" - print d._failure_string - print "missing deps: %s" % d.missing_deps - print d.required_changes + print("can't be satified") + print(d._failure_string) + print("missing deps: %s" % d.missing_deps) + print(d.required_changes) - print d.filelist + print(d.filelist) - print "Installing ..." + print("Installing ...") ret = d.install(InstallProgress()) - print ret + print(ret) #s = DscSrcPackage(cache, "../tests/3ddesktop_0.2.9-6.dsc") #s.check_dep() @@ -744,7 +805,7 @@ def _test(): s = DscSrcPackage(cache=cache) d = "libc6 (>= 2.3.2), libaio (>= 0.3.96) | libaio1 (>= 0.3.96)" - print s._satisfy_depends(apt_pkg.parse_depends(d)) + print(s._satisfy_depends(apt_pkg.parse_depends(d, False))) if __name__ == "__main__": _test() diff --git a/apt/deprecation.py b/apt/deprecation.py deleted file mode 100644 index 0f39ad63..00000000 --- a/apt/deprecation.py +++ /dev/null @@ -1,106 +0,0 @@ -# deprecation.py - Module providing classes and functions for deprecation. -# -# Copyright (c) 2009 Julian Andres Klode <jak@debian.org> -# Copyright (c) 2009 Ben Finney <ben+debian@benfinney.id.au> -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -"""Classes and functions for deprecating features. - -This is used for internal purposes only and not part of the official API. Do -not use it for anything outside the apt package. -""" -import re -import operator -import warnings - -import apt_pkg - -__all__ = [] - - -class AttributeDeprecatedBy(object): - """Property acting as a proxy for a new attribute. - - When accessed, the property issues a DeprecationWarning and (on get) calls - attrgetter() for the attribute 'attribute' on the current object or (on - set) uses setattr to set the value of the wrapped attribute. - """ - - def __init__(self, attribute): - """Initialize the property.""" - self.attribute = attribute - self.__doc__ = 'Deprecated, please use \'%s\' instead' % attribute - self.getter = operator.attrgetter(attribute) - - def __get__(self, obj, type_=None): - """Issue a DeprecationWarning and return the requested value.""" - if obj is None: - return getattr(type_, self.attribute, self) - warnings.warn(self.__doc__, DeprecationWarning, stacklevel=2) - return self.getter(obj or type_) - - def __set__(self, obj, value): - """Issue a DeprecationWarning and set the requested value.""" - warnings.warn(self.__doc__, DeprecationWarning, stacklevel=2) - setattr(obj, self.attribute, value) - - -def function_deprecated_by(func, convert_names=True): - """Return a function that warns it is deprecated by another function. - - Returns a new function that warns it is deprecated by function 'func', - then acts as a pass-through wrapper for 'func'. - - This function also converts all keyword argument names from mixedCase to - lowercase_with_underscores, but only if 'convert_names' is True (default). - """ - warning = 'Deprecated, please use \'%s()\' instead' % func.__name__ - - def deprecated_function(*args, **kwds): - """Wrapper around a deprecated function.""" - warnings.warn(warning, DeprecationWarning, stacklevel=2) - if convert_names: - for key in kwds.keys(): - kwds[re.sub('([A-Z])', '_\\1', key).lower()] = kwds.pop(key) - return func(*args, **kwds) - return deprecated_function - - -def deprecated_args(func): - """A function with deprecated arguments. - - Similar to function_deprecated_by() but warns on every deprecated argument - instead of function calls. - """ - if not apt_pkg._COMPAT_0_7: - return func - - def deprecated_function(*args, **kwds): - """Wrapper around a function with deprecated arguments.""" - for key in kwds.keys(): - new_key = re.sub('([A-Z])', '_\\1', key).lower() - if new_key != key: - warnings.warn("Deprecated parameter %r" % key) - kwds[new_key] = kwds.pop(key) - return func(*args, **kwds) - - # Wrap the function completely (same as functools.wraps) - # pylint: disable-msg=W0622 - deprecated_function.__name__ = func.__name__ - deprecated_function.__doc__ = func.__doc__ - deprecated_function.__module__ = func.__module__ - deprecated_function.__dict__.update(func.__dict__) - return deprecated_function diff --git a/apt/package.py b/apt/package.py index dbaab320..57c89b35 100644 --- a/apt/package.py +++ b/apt/package.py @@ -19,34 +19,35 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA """Functionality related to packages.""" -import httplib +from __future__ import print_function + + import os import sys import re import socket import subprocess -import urllib2 -import warnings -try: - from collections import Mapping, Sequence -except ImportError: - # (for Python < 2.6) pylint: disable-msg=C0103 - Sequence = Mapping = object try: - from collections import Sequence + from http.client import BadStatusLine + from urllib.error import HTTPError + from urllib.request import urlopen except ImportError: - Sequence = object + from httplib import BadStatusLine + from urllib2 import HTTPError, urlopen + +from collections import Mapping, Sequence import apt_pkg import apt.progress.text from apt_pkg import gettext as _ -from apt.deprecation import (function_deprecated_by, AttributeDeprecatedBy, - deprecated_args) __all__ = ('BaseDependency', 'Dependency', 'Origin', 'Package', 'Record', 'Version', 'VersionList') +if sys.version_info.major >= 3: + unicode = str + def _file_is_same(path, size, md5): """Return ``True`` if the file is the same.""" @@ -60,38 +61,77 @@ class FetchError(Exception): class BaseDependency(object): - """A single dependency. - - Attributes defined here: - name - The name of the dependency - relation - The relation (>,>=,==,<,<=,) - version - The version depended on - rawtype - The type of the dependendy (e.g. 'Recommends') - pre_depend - Boolean value whether this is a pre-dependency. - """ + """A single dependency.""" class __dstr(str): - """Helper to make > match >> and < match <<""" + """Compare helper for compatibility with old third-party code. + + Old third-party code might still compare the relation with the + previously used relations (<<,<=,==,!=,>=,>>,) instead of the curently + used ones (<,<=,=,!=,>=,>,). This compare helper lets < match to <<, + > match to >> and = match to ==. + """ def __eq__(self, other): - return str.__eq__(self, other) or str.__eq__(2 * self, other) + if str.__eq__(self, other): + return True + elif str.__eq__(self, '<'): + return str.__eq__('<<', other) + elif str.__eq__(self, '>'): + return str.__eq__('>>', other) + elif str.__eq__(self, '='): + return str.__eq__('==', other) + else: + return False def __ne__(self, other): - return str.__eq__(self, other) and str.__ne__(2 * self, other) + return not self.__eq__(other) - def __init__(self, name, rel, ver, pre, rawtype=None): - self.name = name - self.relation = len(rel) == 1 and self.__dstr(rel) or rel - self.version = ver - self.pre_depend = pre - self.rawtype = rawtype + def __init__(self, dep): + self._dep = dep # apt_pkg.Dependency - def __repr__(self): - return ('<BaseDependency: name:%r relation:%r version:%r preDepend:%r>' - % (self.name, self.relation, self.version, self.pre_depend)) + @property + def name(self): + """The name of the target package.""" + return self._dep.target_pkg.name + + @property + def relation(self): + """The relation (<, <=, !=, =, >=, >, ). + + Note that the empty string is a valid string as well, if no version + is specified. + """ + return self.__dstr(self._dep.comp_type) - if apt_pkg._COMPAT_0_7: - preDepend = AttributeDeprecatedBy('pre_depend') + @property + def version(self): + """The target version or an empty string. + + Note that the version is only an empty string in case of an unversioned + dependency. In this case the relation is also an empty string. + """ + return self._dep.target_ver + + @property + def rawtype(self): + """Type of the dependency. + + This should be one of 'Breaks', 'Conflicts', 'Depends', 'Enhances', + 'PreDepends', 'Recommends', 'Replaces', 'Suggests'. + + Additional types might be added in the future. + """ + return self._dep.dep_type_untranslated + + @property + def pre_depend(self): + """Whether this is a PreDepends.""" + return self._dep.dep_type_untranslated == 'PreDepends' + + def __repr__(self): + return ('<BaseDependency: name:%r relation:%r version:%r rawtype:%r>' + % (self.name, self.relation, self.version, self.rawtype)) class Dependency(list): @@ -99,34 +139,29 @@ class Dependency(list): Attributes defined here: or_dependencies - The possible choices + rawtype - The type of the dependencies in the Or-group """ - def __init__(self, alternatives): - super(Dependency, self).__init__() - self.extend(alternatives) + def __init__(self, base_deps, rawtype): + super(Dependency, self).__init__(base_deps) + self._rawtype = rawtype @property def or_dependencies(self): return self -class DeprecatedProperty(property): - """A property which gives DeprecationWarning on access. + @property + def rawtype(self): + """Type of the Or-group of dependency. - This is only used for providing the properties in Package, which have been - replaced by the ones in Version. - """ + This should be one of 'Breaks', 'Conflicts', 'Depends', 'Enhances', + 'PreDepends', 'Recommends', 'Replaces', 'Suggests'. - def __init__(self, fget=None, fset=None, fdel=None, doc=None): - property.__init__(self, fget, fset, fdel, doc) - self.__doc__ = (doc or fget.__doc__ or '') + Additional types might be added in the future. - def __get__(self, obj, type_=None): - if obj is not None: - warnings.warn("Accessed deprecated property %s.%s, please see the " - "Version class for alternatives." % - ((obj.__class__.__name__ or type_.__name__), - self.fget.__name__), DeprecationWarning, 2) - return property.__get__(self, obj, type_) + .. versionadded:: 1.0.0 + """ + return self._rawtype class Origin(object): @@ -356,14 +391,14 @@ class Version(object): try: if not isinstance(dsc, unicode): # Only convert where needed (i.e. Python 2.X) - dsc = unicode(dsc, "utf-8") + dsc = dsc.decode("utf-8") except UnicodeDecodeError as err: return _("Invalid unicode in description for '%s' (%s). " - "Please report.") % (self.package.name, err) + "Please report.") % (self.package.name, err) lines = iter(dsc.split("\n")) # Skip the first line, since its a duplication of the summary - lines.next() + next(lines) for raw_line in lines: if raw_line.strip() == ".": # The line is just line break @@ -417,7 +452,7 @@ class Version(object): """ priority = 0 policy = self.package._pcache._depcache.policy - for (packagefile, _) in self._cand.file_list: + for (packagefile, _unused) in self._cand.file_list: priority = max(priority, policy.get_priority(packagefile)) return priority @@ -431,7 +466,14 @@ class Version(object): return Record(self._records.record) def get_dependencies(self, *types): - """Return a list of Dependency objects for the given types.""" + """Return a list of Dependency objects for the given types. + + Multiple types can be specified. Possible types are: + 'Breaks', 'Conflicts', 'Depends', 'Enhances', 'PreDepends', + 'Recommends', 'Replaces', 'Suggests' + + Additional types might be added in the future. + """ depends_list = [] depends = self._cand.depends_list for type_ in types: @@ -439,11 +481,8 @@ class Version(object): for dep_ver_list in depends[type_]: base_deps = [] for dep_or in dep_ver_list: - base_deps.append(BaseDependency(dep_or.target_pkg.name, - dep_or.comp_type, dep_or.target_ver, - (type_ == "PreDepends"), - rawtype=type_)) - depends_list.append(Dependency(base_deps)) + base_deps.append(BaseDependency(dep_or)) + depends_list.append(Dependency(base_deps, type_)) except KeyError: pass return depends_list @@ -452,7 +491,7 @@ class Version(object): def provides(self): """ Return a list of names that this version provides.""" return [p[0] for p in self._cand.provides_list] - + @property def enhances(self): """Return the list of enhances for the package version.""" @@ -477,7 +516,7 @@ class Version(object): def origins(self): """Return a list of origins for the package version.""" origins = [] - for (packagefile, _) in self._cand.file_list: + for (packagefile, _unused) in self._cand.file_list: origins.append(Origin(self.package, packagefile)) return origins @@ -528,7 +567,7 @@ class Version(object): .. versionadded:: 0.7.10 """ - for (packagefile, _) in self._cand.file_list: + for (packagefile, _unused) in self._cand.file_list: indexfile = self.package._pcache._list.find_index(packagefile) if indexfile: yield indexfile.archive_uri(self._records.filename) @@ -548,7 +587,7 @@ class Version(object): .. versionadded:: 0.7.10 """ try: - return iter(self._uris()).next() + return next(iter(self._uris())) except StopIteration: return None @@ -567,7 +606,7 @@ class Version(object): base = os.path.basename(self._records.filename) destfile = os.path.join(destdir, base) if _file_is_same(destfile, self.size, self._records.md5_hash): - print('Ignoring already existing file: %s' % destfile) + print(('Ignoring already existing file: %s' % destfile)) return os.path.abspath(destfile) acq = apt_pkg.Acquire(progress or apt.progress.text.AcquireProgress()) acqfile = apt_pkg.AcquireFile(acq, self.uri, self._records.md5_hash, @@ -616,7 +655,7 @@ class Version(object): if type_ == 'dsc': dsc = destfile if _file_is_same(destfile, size, md5): - print('Ignoring already existing file: %s' % destfile) + print(('Ignoring already existing file: %s' % destfile)) continue files.append(apt_pkg.AcquireFile(acq, src.index.archive_uri(path), md5, size, base, destfile=destfile)) @@ -625,7 +664,7 @@ class Version(object): for item in acq.items: if item.status != item.STAT_DONE: raise FetchError("The item %r could not be fetched: %s" % - (item.destfile, item.error_text)) + (item.destfile, item.error_text)) if unpack: outdir = src.package + '-' + apt_pkg.upstream_version(src.version) @@ -657,8 +696,8 @@ class VersionList(Sequence): """ def __init__(self, package, slice_=None): - self._package = package # apt.package.Package() - self._versions = package._pkg.version_list # [apt_pkg.Version(), ...] + self._package = package # apt.package.Package() + self._versions = package._pkg.version_list # [apt_pkg.Version(), ...] if slice_: self._versions = self._versions[slice_] @@ -683,7 +722,7 @@ class VersionList(Sequence): return (Version(self._package, ver) for ver in self._versions) def __contains__(self, item): - if isinstance(item, Version): # Sequence interface + if isinstance(item, Version): # Sequence interface item = item.version # Dictionary interface. for ver in self._versions: @@ -726,8 +765,8 @@ class Package(object): self._changelog = "" # Cached changelog def __repr__(self): - return '<Package: name:%r architecture=%r id:%r>' % (self._pkg.name, - self._pkg.architecture, self._pkg.id) + return '<Package: name:%r architecture=%r id:%r>' % ( + self._pkg.name, self._pkg.architecture, self._pkg.id) def __lt__(self, other): return self.name < other.name @@ -769,6 +808,7 @@ class Package(object): as :attr:`shortname` .. versionchanged:: 0.7.100.3 + As part of multi-arch, this field now may include architecture information. """ @@ -806,36 +846,6 @@ class Package(object): """Return True if the package is an essential part of the system.""" return self._pkg.essential - @DeprecatedProperty - def installedVersion(self): #pylint: disable-msg=C0103 - """Return the installed version as string. - - .. deprecated:: 0.7.9""" - return getattr(self.installed, 'version', None) - - @DeprecatedProperty - def candidateVersion(self): #pylint: disable-msg=C0103 - """Return the candidate version as string. - - .. deprecated:: 0.7.9""" - return getattr(self.candidate, "version", None) - - @DeprecatedProperty - def candidateDependencies(self): #pylint: disable-msg=C0103 - """Return a list of candidate dependencies. - - .. deprecated:: 0.7.9 - """ - return getattr(self.candidate, "dependencies", None) - - @DeprecatedProperty - def installedDependencies(self): #pylint: disable-msg=C0103 - """Return a list of installed dependencies. - - .. deprecated:: 0.7.9 - """ - return getattr(self.installed, 'dependencies', []) - def architecture(self): """Return the Architecture of the package. @@ -846,107 +856,11 @@ class Package(object): """ return self._pkg.architecture - @DeprecatedProperty - def candidateDownloadable(self): #pylint: disable-msg=C0103 - """Return ``True`` if the candidate is downloadable. - - .. deprecated:: 0.7.9 - """ - return getattr(self.candidate, "downloadable", None) - - @DeprecatedProperty - def installedDownloadable(self): #pylint: disable-msg=C0103 - """Return ``True`` if the installed version is downloadable. - - .. deprecated:: 0.7.9 - """ - return getattr(self.installed, 'downloadable', False) - - @DeprecatedProperty - def sourcePackageName(self): #pylint: disable-msg=C0103 - """Return the source package name as string. - - .. deprecated:: 0.7.9 - """ - try: - return self.candidate._records.source_pkg or self._pkg.name - except AttributeError: - try: - return self.installed._records.source_pkg or self._pkg.name - except AttributeError: - return self._pkg.name - - @DeprecatedProperty - def homepage(self): - """Return the homepage field as string. - - .. deprecated:: 0.7.9 - """ - return getattr(self.candidate, "homepage", None) - @property def section(self): """Return the section of the package.""" return self._pkg.section - @DeprecatedProperty - def priority(self): - """Return the priority (of the candidate version). - - .. deprecated:: 0.7.9 - """ - return getattr(self.candidate, "priority", None) - - @DeprecatedProperty - def installedPriority(self): #pylint: disable-msg=C0103 - """Return the priority (of the installed version). - - .. deprecated:: 0.7.9 - """ - return getattr(self.installed, 'priority', None) - - @DeprecatedProperty - def summary(self): - """Return the short description (one line summary). - - .. deprecated:: 0.7.9 - """ - return getattr(self.candidate, "summary", None) - - @DeprecatedProperty - def description(self): - """Return the formatted long description. - - Return the formatted long description according to the Debian policy - (Chapter 5.6.13). - See http://www.debian.org/doc/debian-policy/ch-controlfields.html - for more information. - - .. deprecated:: 0.7.9 - """ - return getattr(self.candidate, "description", None) - - @DeprecatedProperty - def rawDescription(self): #pylint: disable-msg=C0103 - """return the long description (raw). - - .. deprecated:: 0.7.9""" - return getattr(self.candidate, "raw_description", None) - - @DeprecatedProperty - def candidateRecord(self): #pylint: disable-msg=C0103 - """Return the Record of the candidate version of the package. - - .. deprecated:: 0.7.9""" - return getattr(self.candidate, "record", None) - - @DeprecatedProperty - def installedRecord(self): #pylint: disable-msg=C0103 - """Return the Record of the candidate version of the package. - - .. deprecated:: 0.7.9""" - return getattr(self.installed, 'record', '') - # depcache states @property @@ -1007,39 +921,6 @@ class Package(object): return self._pcache._depcache.is_auto_installed(self._pkg) # sizes - @DeprecatedProperty - def packageSize(self): #pylint: disable-msg=C0103 - """Return the size of the candidate deb package. - - .. deprecated:: 0.7.9 - """ - return getattr(self.candidate, "size", None) - - @DeprecatedProperty - def installedPackageSize(self): #pylint: disable-msg=C0103 - """Return the size of the installed deb package. - - .. deprecated:: 0.7.9 - """ - return getattr(self.installed, 'size', 0) - - @DeprecatedProperty - def candidateInstalledSize(self): #pylint: disable-msg=C0103 - """Return the size of the candidate installed package. - - .. deprecated:: 0.7.9 - """ - return getattr(self.candidate, "installed_size", None) - - @DeprecatedProperty - def installedSize(self): #pylint: disable-msg=C0103 - """Return the size of the currently installed package. - - - .. deprecated:: 0.7.9 - """ - return getattr(self.installed, 'installed_size', 0) - @property def installed_files(self): """Return a list of files installed by the package. @@ -1047,7 +928,7 @@ class Package(object): Return a list of unicode names of the files which have been installed by this package """ - for name in self.shortname, self.fullname: + for name in self.name, self.fullname: path = "/var/lib/dpkg/info/%s.list" % name try: with open(path, "rb") as file_list: @@ -1100,10 +981,10 @@ class Package(object): src_section = "main" # use the section of the candidate as a starting point section = self.candidate.section - + # get the source version src_ver = self.candidate.source_version - + try: # try to get the source version of the pkg, this differs # for some (e.g. libnspr4 on ubuntu) @@ -1160,7 +1041,7 @@ class Package(object): if cancel_lock and cancel_lock.isSet(): return u"" # FIXME: python3.2: Should be closed manually - changelog_file = urllib2.urlopen(uri) + changelog_file = urlopen(uri) # do only get the lines that are new changelog = u"" regexp = "^%s \((.*)\)(.*)$" % (re.escape(src_pkg)) @@ -1189,7 +1070,7 @@ class Package(object): changelog_ver = changelog_ver.split(":", 1)[1] if (installed and apt_pkg.version_compare( - changelog_ver, installed) <= 0): + changelog_ver, installed) <= 0): break # EOF (shouldn't really happen) changelog += line @@ -1201,29 +1082,25 @@ class Package(object): changelog = changelog.decode("utf-8") self._changelog = changelog - except urllib2.HTTPError: - res = _("The list of changes is not available yet.\n\n" - "Please use http://launchpad.net/ubuntu/+source/%s/" - "%s/+changelog\n" - "until the changes become available or try again " - "later.") % (src_pkg, src_ver) + except HTTPError: + if self.candidate.origins[0].origin == "Ubuntu": + res = _("The list of changes is not available yet.\n\n" + "Please use " + "http://launchpad.net/ubuntu/+source/%s/" + "%s/+changelog\n" + "until the changes become available or try again " + "later.") % (src_pkg, src_ver) + else: + res = _("The list of changes is not available") return res if isinstance(res, unicode) else res.decode("utf-8") - except (IOError, httplib.BadStatusLine): + except (IOError, BadStatusLine): res = _("Failed to download the list of changes. \nPlease " - "check your Internet connection.") + "check your Internet connection.") return res if isinstance(res, unicode) else res.decode("utf-8") finally: socket.setdefaulttimeout(timeout) return self._changelog - @DeprecatedProperty - def candidateOrigin(self): #pylint: disable-msg=C0103 - """Return a list of `Origin()` objects for the candidate version. - - .. deprecated:: 0.7.9 - """ - return getattr(self.candidate, "origins", None) - @property def versions(self): """Return a VersionList() object for all available versions. @@ -1242,6 +1119,11 @@ class Package(object): """Return True if the installed package is broken.""" return self._pcache._depcache.is_now_broken(self._pkg) + @property + def has_config_files(self): + """Checks whether the package is is the config-files state.""" + return self. _pkg.current_state == apt_pkg.CURSTATE_CONFIG_FILES + # depcache actions def mark_keep(self): @@ -1250,7 +1132,6 @@ class Package(object): self._pcache._depcache.mark_keep(self._pkg) self._pcache.cache_post_change() - @deprecated_args def mark_delete(self, auto_fix=True, purge=False): """Mark a package for deletion. @@ -1272,7 +1153,6 @@ class Package(object): fix.resolve() self._pcache.cache_post_change() - @deprecated_args def mark_install(self, auto_fix=True, auto_inst=True, from_user=True): """Mark a package for install. @@ -1297,11 +1177,12 @@ class Package(object): fixer.resolve(True) self._pcache.cache_post_change() - def mark_upgrade(self): + def mark_upgrade(self, from_user=True): """Mark a package for upgrade.""" if self.is_upgradable: - from_user = not self._pcache._depcache.is_auto_installed(self._pkg) + auto = self.is_auto_installed self.mark_install(from_user=from_user) + self.mark_auto(auto) else: # FIXME: we may want to throw a exception here sys.stderr.write(("MarkUpgrade() called on a non-upgrable pkg: " @@ -1328,103 +1209,61 @@ class Package(object): self._pcache._depcache.commit(fprogress, iprogress) - if not apt_pkg._COMPAT_0_7: - del installedVersion - del candidateVersion - del candidateDependencies - del installedDependencies - del architecture - del candidateDownloadable - del installedDownloadable - del sourcePackageName - del homepage - del priority - del installedPriority - del summary - del description - del rawDescription - del candidateRecord - del installedRecord - del packageSize - del installedPackageSize - del candidateInstalledSize - del installedSize - del candidateOrigin - else: - markedInstalled = AttributeDeprecatedBy('marked_installed') - markedInstall = AttributeDeprecatedBy('marked_install') - markedUpgrade = AttributeDeprecatedBy('marked_upgrade') - markedDelete = AttributeDeprecatedBy('marked_delete') - markedKeep = AttributeDeprecatedBy('marked_keep') - markedDowngrade = AttributeDeprecatedBy('marked_downgrade') - markedReinstall = AttributeDeprecatedBy('marked_reinstall') - isInstalled = AttributeDeprecatedBy('is_installed') - isUpgradable = AttributeDeprecatedBy('is_upgradable') - isAutoRemovable = AttributeDeprecatedBy('is_auto_removable') - installedFiles = AttributeDeprecatedBy('installed_files') - getChangelog = function_deprecated_by(get_changelog) - markDelete = function_deprecated_by(mark_delete) - markInstall = function_deprecated_by(mark_install) - markKeep = function_deprecated_by(mark_keep) - markUpgrade = function_deprecated_by(mark_upgrade) - - def _test(): """Self-test.""" - print "Self-test for the Package modul" + print("Self-test for the Package modul") import random apt_pkg.init() progress = apt.progress.text.OpProgress() cache = apt.Cache(progress) pkg = cache["apt-utils"] - print "Name: %s " % pkg.name - print "ID: %s " % pkg.id - print "Priority (Candidate): %s " % pkg.candidate.priority - print "Priority (Installed): %s " % pkg.installed.priority - print "Installed: %s " % pkg.installed.version - print "Candidate: %s " % pkg.candidate.version - print "CandidateDownloadable: %s" % pkg.candidate.downloadable - print "CandidateOrigins: %s" % pkg.candidate.origins - print "SourcePkg: %s " % pkg.candidate.source_name - print "Section: %s " % pkg.section - print "Summary: %s" % pkg.candidate.summary - print "Description (formatted) :\n%s" % pkg.candidate.description - print "Description (unformatted):\n%s" % pkg.candidate.raw_description - print "InstalledSize: %s " % pkg.candidate.installed_size - print "PackageSize: %s " % pkg.candidate.size - print "Dependencies: %s" % pkg.installed.dependencies - print "Recommends: %s" % pkg.installed.recommends + print("Name: %s " % pkg.name) + print("ID: %s " % pkg.id) + print("Priority (Candidate): %s " % pkg.candidate.priority) + print("Priority (Installed): %s " % pkg.installed.priority) + print("Installed: %s " % pkg.installed.version) + print("Candidate: %s " % pkg.candidate.version) + print("CandidateDownloadable: %s" % pkg.candidate.downloadable) + print("CandidateOrigins: %s" % pkg.candidate.origins) + print("SourcePkg: %s " % pkg.candidate.source_name) + print("Section: %s " % pkg.section) + print("Summary: %s" % pkg.candidate.summary) + print("Description (formatted) :\n%s" % pkg.candidate.description) + print("Description (unformatted):\n%s" % pkg.candidate.raw_description) + print("InstalledSize: %s " % pkg.candidate.installed_size) + print("PackageSize: %s " % pkg.candidate.size) + print("Dependencies: %s" % pkg.installed.dependencies) + print("Recommends: %s" % pkg.installed.recommends) for dep in pkg.candidate.dependencies: - print ",".join("%s (%s) (%s) (%s)" % (o.name, o.version, o.relation, - o.pre_depend) for o in dep.or_dependencies) - print "arch: %s" % pkg.candidate.architecture - print "homepage: %s" % pkg.candidate.homepage - print "rec: ", pkg.candidate.record - + print(",".join("%s (%s) (%s) (%s)" % (o.name, o.version, o.relation, + o.pre_depend) for o in dep.or_dependencies)) + print("arch: %s" % pkg.candidate.architecture) + print("homepage: %s" % pkg.candidate.homepage) + print("rec: ", pkg.candidate.record) - print cache["2vcard"].get_changelog() + print(cache["2vcard"].get_changelog()) for i in True, False: - print "Running install on random upgradable pkgs with AutoFix: %s " % i + print("Running install on random upgradable pkgs with AutoFix: ", i) for pkg in cache: if pkg.is_upgradable: if random.randint(0, 1) == 1: pkg.mark_install(i) - print "Broken: %s " % cache._depcache.broken_count - print "InstCount: %s " % cache._depcache.inst_count + print("Broken: %s " % cache._depcache.broken_count) + print("InstCount: %s " % cache._depcache.inst_count) - print + print() # get a new cache for i in True, False: - print "Randomly remove some packages with AutoFix: %s" % i + print("Randomly remove some packages with AutoFix: %s" % i) cache = apt.Cache(progress) for name in cache.keys(): if random.randint(0, 1) == 1: try: cache[name].mark_delete(i) except SystemError: - print "Error trying to remove: %s " % name - print "Broken: %s " % cache._depcache.broken_count - print "DelCount: %s " % cache._depcache.del_count + print("Error trying to remove: %s " % name) + print("Broken: %s " % cache._depcache.broken_count) + print("DelCount: %s " % cache._depcache.del_count) # self-test if __name__ == "__main__": diff --git a/apt/progress/__init__.py b/apt/progress/__init__.py index 10c11021..1ae94d06 100644 --- a/apt/progress/__init__.py +++ b/apt/progress/__init__.py @@ -19,17 +19,11 @@ """Progress reporting. This package provides progress reporting for the python-apt package. The module -'base' provides classes with no output, the module 'gtk2' provides classes for -GTK+ applications, and the module 'text' provides classes for terminals, etc. +'base' provides classes with no output, and the module 'text' provides classes +for terminals, etc. """ -import apt_pkg - -__all__ = [] +from __future__ import print_function -if apt_pkg._COMPAT_0_7: - from apt.progress.old import (CdromProgress, DpkgInstallProgress, - DumbInstallProgress, FetchProgress, - InstallProgress, OpProgress, - OpTextProgress, TextFetchProgress) +__all__ = [] diff --git a/apt/progress/base.py b/apt/progress/base.py index 2c80ae29..95eca9ec 100644 --- a/apt/progress/base.py +++ b/apt/progress/base.py @@ -22,6 +22,8 @@ Custom progress classes should inherit from these classes. They can also be used as dummy progress classes which simply do nothing. """ +from __future__ import print_function + import errno import fcntl import os @@ -217,7 +219,7 @@ class InstallProgress(object): except IOError as err: # resource temporarly unavailable is ignored if err.errno != errno.EAGAIN and err.errno != errno.EWOULDBLOCK: - print err.strerror + print(err.strerror) return pkgname = status = status_str = percent = base = "" @@ -269,7 +271,8 @@ class InstallProgress(object): try: select.select([self.status_stream], [], [], self.select_timeout) - except select.error as (errno_, _errstr): + except select.error as error: + (errno_, _errstr) = error.args if errno_ != errno.EINTR: raise diff --git a/apt/progress/gtk2.py b/apt/progress/gtk2.py deleted file mode 100644 index c2635ca0..00000000 --- a/apt/progress/gtk2.py +++ /dev/null @@ -1,519 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2004-2009 Canonical -# -# Authors: Michael Vogt <michael.vogt@ubuntu.com> -# Sebastian Heinlein <glatzor@ubuntu.com> -# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -"""GObject-powered progress classes and a GTK+ status widget.""" - -import pygtk -pygtk.require('2.0') -import gtk -try: - import glib -except ImportError: - import gobject as glib -import gobject -import pango -import time -import vte - -import apt_pkg -from apt_pkg import gettext as _ -from apt.deprecation import function_deprecated_by, AttributeDeprecatedBy -from apt.progress import base - -if apt_pkg._COMPAT_0_7: - from apt.progress import old - - -__all__ = ['GAcquireProgress', 'GInstallProgress', 'GOpProgress', - 'GtkAptProgress'] - - -def mksig(params=(), run=gobject.SIGNAL_RUN_FIRST, rettype=gobject.TYPE_NONE): - """Simplified Create a gobject signal. - - This allows us to write signals easier, because we just need to define the - type of the parameters (in most cases). - - ``params`` is a tuple which defines the types of the arguments. - """ - return (run, rettype, params) - - -class GOpProgress(gobject.GObject, base.OpProgress): - """Operation progress with GObject signals. - - Signals: - - * status-changed(str: operation, int: percent) - * status-started() - Not Implemented yet - * status-finished() - - """ - - __gsignals__ = {"status-changed": mksig((str, int)), - "status-started": mksig(), - "status-finished": mksig()} - - def __init__(self): - base.OpProgress.__init__(self) - gobject.GObject.__init__(self) - self._context = glib.main_context_default() - - def update(self, percent=None): - """Called to update the percentage done""" - base.OpProgress.update(self, percent) - self.emit("status-changed", self.op, self.percent) - while self._context.pending(): - self._context.iteration() - - def done(self): - """Called when all operation have finished.""" - base.OpProgress.done(self) - self.emit("status-finished") - - if apt_pkg._COMPAT_0_7: - subOp = AttributeDeprecatedBy('subop') - Op = AttributeDeprecatedBy('op') - - -class GInstallProgress(gobject.GObject, base.InstallProgress): - """Installation progress with GObject signals. - - Signals: - - * status-changed(str: status, int: percent) - * status-started() - * status-finished() - * status-timeout() - * status-error() - * status-conffile() - - """ - # Seconds until a maintainer script will be regarded as hanging - INSTALL_TIMEOUT = 5 * 60 - - __gsignals__ = {"status-changed": mksig((str, int)), - "status-started": mksig(), - "status-timeout": mksig(), - "status-error": mksig(), - "status-conffile": mksig(), - "status-finished": mksig()} - - def __init__(self, term): - base.InstallProgress.__init__(self) - gobject.GObject.__init__(self) - self.finished = False - self.apt_status = -1 - self.time_last_update = time.time() - self.term = term - self.term.connect("child-exited", self.child_exited) - self.env = ["VTE_PTY_KEEP_FD=%s" % self.writefd, - "DEBIAN_FRONTEND=gnome", - "APT_LISTCHANGES_FRONTEND=gtk"] - self._context = glib.main_context_default() - - def child_exited(self, term): - """Called when a child process exits""" - self.apt_status = term.get_child_exit_status() - self.finished = True - - def error(self, pkg, errormsg): - """Called when an error happens. - - Emits: status-error() - """ - self.emit("status-error") - - def conffile(self, current, new): - """Called during conffile. - - Emits: status-conffile() - """ - self.emit("status-conffile") - - def start_update(self): - """Called when the update starts. - - Emits: status-started() - """ - self.emit("status-started") - - def run(self, obj): - """Run.""" - self.finished = False - return base.InstallProgress.run(self, obj) - - def finish_update(self): - """Called when the update finished. - - Emits: status-finished() - """ - self.emit("status-finished") - - def processing(self, pkg, stage): - """Called when entering a new stage in dpkg.""" - # We have no percentage or alike, send -1 to let the bar pulse. - self.emit("status-changed", ("Installing %s...") % pkg, -1) - - def status_change(self, pkg, percent, status): - """Called when the status changed. - - Emits: status-changed(status, percent) - """ - self.time_last_update = time.time() - self.emit("status-changed", status, percent) - - def update_interface(self): - """Called periodically to update the interface. - - Emits: status-timeout() [When a timeout happens] - """ - base.InstallProgress.update_interface(self) - while self._context.pending(): - self._context.iteration() - if self.time_last_update + self.INSTALL_TIMEOUT < time.time(): - self.emit("status-timeout") - - def fork(self): - """Fork the process.""" - return self.term.forkpty(envv=self.env) - - def wait_child(self): - """Wait for the child process to exit.""" - while not self.finished: - self.update_interface() - time.sleep(0.02) - return self.apt_status - - if apt_pkg._COMPAT_0_7: - updateInterface = function_deprecated_by(update_interface) - startUpdate = function_deprecated_by(start_update) - finishUpdate = function_deprecated_by(finish_update) - statusChange = function_deprecated_by(status_change) - waitChild = function_deprecated_by(wait_child) - childExited = function_deprecated_by(child_exited) - - -GDpkgInstallProgress = GInstallProgress - - -class GAcquireProgress(gobject.GObject, base.AcquireProgress): - """A Fetch Progress with GObject signals. - - Signals: - - * status-changed(str: description, int: percent) - * status-started() - * status-finished() - - DEPRECATED. - """ - - __gsignals__ = {"status-changed": mksig((str, int)), - "status-started": mksig(), - "status-finished": mksig()} - - def __init__(self): - base.AcquireProgress.__init__(self) - gobject.GObject.__init__(self) - self._continue = True - self._context = glib.main_context_default() - - def start(self): - base.AcquireProgress.start(self) - self.emit("status-started") - - def stop(self): - base.AcquireProgress.stop(self) - self.emit("status-finished") - - def cancel(self): - self._continue = False - - def pulse(self, owner): - base.AcquireProgress.pulse(self, owner) - current_item = self.current_items + 1 - if current_item > self.total_items: - current_item = self.total_items - if self.current_cps > 0: - text = (_("Downloading file %(current)li of %(total)li with " - "%(speed)s/s") % \ - {"current": current_item, - "total": self.total_items, - "speed": apt_pkg.size_to_str(self.current_cps)}) - else: - text = (_("Downloading file %(current)li of %(total)li") % \ - {"current": current_item, - "total": self.total_items}) - - percent = (((self.current_bytes + self.current_items) * 100.0) / - float(self.total_bytes + self.total_items)) - self.emit("status-changed", text, percent) - while self._context.pending(): - self._context.iteration() - return self._continue - -if apt_pkg._COMPAT_0_7: - - class GFetchProgress(gobject.GObject, old.FetchProgress): - """A Fetch Progress with GObject signals. - - Signals: - - * status-changed(str: description, int: percent) - * status-started() - * status-finished() - - DEPRECATED. - """ - - __gsignals__ = {"status-changed": mksig((str, int)), - "status-started": mksig(), - "status-finished": mksig()} - - def __init__(self): - old.FetchProgress.__init__(self) - gobject.GObject.__init__(self) - self._continue = True - self._context = glib.main_context_default() - - def start(self): - self.emit("status-started") - - def stop(self): - self.emit("status-finished") - - def cancel(self): - self._continue = False - - def pulse(self): - old.FetchProgress.pulse(self) - current_item = self.currentItems + 1 - if current_item > self.totalItems: - current_item = self.totalItems - if self.current_cps > 0: - text = (_("Downloading file %(current)li of %(total)li with " - "%(speed)s/s") % \ - {"current": current_item, - "total": self.totalItems, - "speed": apt_pkg.size_to_str(self.currentCPS)}) - else: - text = (_("Downloading file %(current)li of %(total)li") % \ - {"current": current_item, - "total": self.totalItems}) - self.emit("status-changed", text, self.percent) - while self._context.pending(): - self._context.iteration() - return self._continue - - -class GtkAptProgress(gtk.VBox): - """Graphical progress for installation/fetch/operations. - - This widget provides a progress bar, a terminal and a status bar for - showing the progress of package manipulation tasks. - """ - - def __init__(self): - gtk.VBox.__init__(self) - self.set_spacing(6) - # Setup some child widgets - self._expander = gtk.Expander(_("Details")) - self._terminal = vte.Terminal() - #self._terminal.set_font_from_string("monospace 10") - self._expander.add(self._terminal) - self._progressbar = gtk.ProgressBar() - # Setup the always italic status label - self._label = gtk.Label() - attr_list = pango.AttrList() - attr_list.insert(pango.AttrStyle(pango.STYLE_ITALIC, 0, -1)) - self._label.set_attributes(attr_list) - self._label.set_ellipsize(pango.ELLIPSIZE_END) - self._label.set_alignment(0, 0) - # add child widgets - self.pack_start(self._progressbar, False) - self.pack_start(self._label, False) - self.pack_start(self._expander, False) - # Setup the internal progress handlers - self._progress_open = GOpProgress() - self._progress_open.connect("status-changed", self._on_status_changed) - self._progress_open.connect("status-started", self._on_status_started) - self._progress_open.connect("status-finished", - self._on_status_finished) - self._progress_acquire = GAcquireProgress() - self._progress_acquire.connect("status-changed", - self._on_status_changed) - self._progress_acquire.connect("status-started", - self._on_status_started) - self._progress_acquire.connect("status-finished", - self._on_status_finished) - - self._progress_fetch = None - self._progress_install = GInstallProgress(self._terminal) - self._progress_install.connect("status-changed", - self._on_status_changed) - self._progress_install.connect("status-started", - self._on_status_started) - self._progress_install.connect("status-finished", - self._on_status_finished) - self._progress_install.connect("status-timeout", - self._on_status_timeout) - self._progress_install.connect("status-error", - self._on_status_timeout) - self._progress_install.connect("status-conffile", - self._on_status_timeout) - - def clear(self): - """Reset all status information.""" - self._label.set_label("") - self._progressbar.set_fraction(0) - self._expander.set_expanded(False) - - @property - def open(self): - """Return the cache opening progress handler.""" - return self._progress_open - - @property - def install(self): - """Return the install progress handler.""" - return self._progress_install - - @property - def dpkg_install(self): - """Return the install progress handler for dpkg.""" - return self._progress_install - - if apt_pkg._COMPAT_0_7: - - @property - def fetch(self): - """Return the fetch progress handler.""" - if self._progress_fetch is None: - self._progress_fetch = GFetchProgress() - self._progress_fetch.connect("status-changed", - self._on_status_changed) - self._progress_fetch.connect("status-started", - self._on_status_started) - self._progress_fetch.connect("status-finished", - self._on_status_finished) - return self._progress_fetch - - @property - def acquire(self): - """Return the acquire progress handler.""" - return self._progress_acquire - - def _on_status_started(self, progress): - """Called when something starts.""" - self._on_status_changed(progress, _("Starting..."), 0) - while gtk.events_pending(): - gtk.main_iteration() - - def _on_status_finished(self, progress): - """Called when something finished.""" - self._on_status_changed(progress, _("Complete"), 100) - while gtk.events_pending(): - gtk.main_iteration() - - def _on_status_changed(self, progress, status, percent): - """Called when the status changed.""" - self._label.set_text(status) - if percent is None or percent == -1: - self._progressbar.pulse() - else: - self._progressbar.set_fraction(percent/100.0) - while gtk.events_pending(): - gtk.main_iteration() - - def _on_status_timeout(self, progress): - """Called when timeout happens.""" - self._expander.set_expanded(True) - while gtk.events_pending(): - gtk.main_iteration() - - def cancel_download(self): - """Cancel a currently running download.""" - self._progress_fetch.cancel() - - def show_terminal(self, expanded=False): - """Show the expander for the terminal. - - Show an expander with a terminal widget which provides a way - to interact with dpkg - """ - self._expander.show() - self._terminal.show() - self._expander.set_expanded(expanded) - while gtk.events_pending(): - gtk.main_iteration() - - def hide_terminal(self): - """Hide the expander with the terminal widget.""" - self._expander.hide() - while gtk.events_pending(): - gtk.main_iteration() - - def show(self): - """Show the Box""" - gtk.HBox.show(self) - self._label.show() - self._progressbar.show() - while gtk.events_pending(): - gtk.main_iteration() - - -def _test(): - """Test function""" - import sys - - import apt - from apt.debfile import DebPackage - - win = gtk.Window() - apt_progress = GtkAptProgress() - win.set_title("GtkAptProgress Demo") - win.add(apt_progress) - apt_progress.show() - win.show() - cache = apt.cache.Cache(apt_progress.open) - pkg = cache["xterm"] - if pkg.is_installed: - pkg.mark_delete() - else: - pkg.mark_install() - apt_progress.show_terminal(True) - try: - cache.commit(apt_progress.acquire, apt_progress.install) - except Exception as exc: - print >> sys.stderr, "Exception happened:", exc - if len(sys.argv) > 1: - deb = DebPackage(sys.argv[1], cache) - deb.install(apt_progress.dpkg_install) - win.connect("destroy", gtk.main_quit) - gtk.main() - - -if __name__ == "__main__": - _test() - -# vim: ts=4 et sts=4 diff --git a/apt/progress/old.py b/apt/progress/old.py deleted file mode 100644 index 364cd2ce..00000000 --- a/apt/progress/old.py +++ /dev/null @@ -1,259 +0,0 @@ -# progress.py - progress reporting classes -# -# Copyright (c) 2005-2009 Canonical -# -# Author: Michael Vogt <michael.vogt@ubuntu.com> -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# pylint: disable-msg = C0103 -"""Deprecated progress reporting classes. - -This module provides classes for compatibility with python-apt 0.7. They are -completely deprecated and should not be used anymore. -""" - - -import os -import sys - -import apt_pkg -from apt.deprecation import AttributeDeprecatedBy, function_deprecated_by -import warnings -from apt.progress import base, text - -__all__ = [] - - -class OpProgress(base.OpProgress): - """Abstract class to implement reporting on cache opening.""" - - def __init__(self): - base.OpProgress.__init__(self) - warnings.warn("apt.progress.OpProgress is deprecated.", - DeprecationWarning, stacklevel=2) - - subOp = AttributeDeprecatedBy('subop') - Op = AttributeDeprecatedBy('op') - - -class OpTextProgress(OpProgress, text.OpProgress): - """A simple text based cache open reporting class.""" - - def __init__(self): - text.OpProgress.__init__(self) - warnings.warn("apt.progress.OpTextProgress is deprecated.", - DeprecationWarning, stacklevel=2) - - -class FetchProgress(object): - """Report the download/fetching progress.""" - - # download status constants - (dlDone, dlQueued, dlFailed, dlHit, dlIgnored) = range(5) - dlStatusStr = {dlDone: "Done", dlQueued: "Queued", dlFailed: "Failed", - dlHit: "Hit", dlIgnored: "Ignored"} - - def __init__(self): - self.eta = 0.0 - self.percent = 0.0 - # Make checking easier - self.currentBytes = 0 - self.currentItems = 0 - self.totalBytes = 0 - self.totalItems = 0 - self.currentCPS = 0 - warnings.warn("apt.progress.FetchProgress is deprecated.", - DeprecationWarning, stacklevel=2) - - def start(self): - """Called when the fetching starts.""" - - def stop(self): - """Called when all files have been fetched.""" - - def updateStatus(self, uri, descr, short_descr, status): - """Called when the status of an item changes. - - This happens eg. when the downloads fails or is completed. - """ - - def update_status_full(self, uri, descr, short_descr, status, file_size, - partial_size): - """Called when the status of an item changes. - - This happens eg. when the downloads fails or is completed. This - version include information on current filesize and partial size - """ - - def pulse(self): - """Called periodically to update the user interface. - - Return True to continue or False to cancel. - """ - self.percent = (((self.currentBytes + self.currentItems) * 100.0) / - float(self.totalBytes + self.totalItems)) - if self.currentCPS > 0: - self.eta = ((self.totalBytes - self.currentBytes) / - float(self.currentCPS)) - return True - - def pulse_items(self, items): - """Called periodically to update the user interface. - This function includes details about the items being fetched - Return True to continue or False to cancel. - - """ - self.percent = (((self.currentBytes + self.currentItems) * 100.0) / - float(self.totalBytes + self.totalItems)) - if self.currentCPS > 0: - self.eta = ((self.totalBytes - self.currentBytes) / - float(self.currentCPS)) - return True - - def mediaChange(self, medium, drive): - """react to media change events.""" - - -class TextFetchProgress(FetchProgress): - """ Ready to use progress object for terminal windows """ - - def __init__(self): - FetchProgress.__init__(self) - self.items = {} - - def updateStatus(self, uri, descr, short_descr, status): - """Called when the status of an item changes. - - This happens eg. when the downloads fails or is completed. - """ - if status != self.dlQueued: - print "\r%s %s" % (self.dlStatusStr[status], descr) - self.items[uri] = status - - def pulse(self): - """Called periodically to update the user interface. - - 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(self.currentCPS), - apt_pkg.time_to_str(long(self.eta))) - else: - s = "%2.f%% [Working]" % (self.percent) - print "\r%s" % (s), - sys.stdout.flush() - return True - - def stop(self): - """Called when all files have been fetched.""" - print "\rDone downloading " - - def mediaChange(self, medium, drive): - """react to media change events.""" - print ("Media change: please insert the disc labeled " - "'%s' in the drive '%s' and press enter") % (medium, drive) - - return raw_input() not in ('c', 'C') - - -class CdromProgress(object): - """Report the cdrom add progress.""" - - def __init__(self): - warnings.warn("apt.progress.CdromProgress is deprecated.", - DeprecationWarning, stacklevel=2) - - def askCdromName(self): - """Ask for a cdrom name""" - - def changeCdrom(self): - """Change cdrom""" - - def update(self, text, current): - """Update.""" - - -class DumbInstallProgress(base.InstallProgress): - """Report the install progress.""" - - def __init__(self): - base.InstallProgress.__init__(self) - warnings.warn("apt.progress.*InstallProgress are deprecated.", - DeprecationWarning, stacklevel=2) - - def updateInterface(self): - # *_stream were not available in the old progress reporting classes, - # create the attributes if they do not exist yet; as they are used - # in base.InstallProgress.update_interface(). - if hasattr(self, "writefd") and not hasattr(self, "write_stream"): - self.write_stream = os.fdopen(self.writefd, "w") - if hasattr(self, "statusfd") and not hasattr(self, "status_stream"): - self.status_stream = os.fdopen(self.statusfd, "r") - return base.InstallProgress.update_interface(self) - - def update_interface(self): - return self.updateInterface() - - def startUpdate(self): - return base.InstallProgress.start_update(self) - - def start_update(self): - return self.startUpdate() - - def finishUpdate(self): - return base.InstallProgress.finish_update(self) - - def finish_update(self): - return self.finishUpdate() - - -class InstallProgress(DumbInstallProgress, base.InstallProgress): - """An InstallProgress that is pretty useful. - - It supports the attributes 'percent' 'status' and callbacks for the dpkg - errors and conffiles and status changes. - """ - - selectTimeout = AttributeDeprecatedBy('select_timeout') - - def statusChange(self, pkg, percent, status): - return base.InstallProgress.status_change(self, pkg, percent, status) - - def status_change(self, pkg, percent, status): - return self.statusChange(pkg, percent, status) - - def waitChild(self): - return base.InstallProgress.wait_child(self) - - def wait_child(self): - return self.waitChild() - - -class DpkgInstallProgress(InstallProgress): - """Progress handler for a local Debian package installation.""" - - debfile = "" - debname = "" - - def run(self, debfile): - """Start installing the given Debian package.""" - # Deprecated stuff - self.debfile = debfile - self.debname = os.path.basename(debfile).split("_")[0] - return base.InstallProgress.run(self, debfile) diff --git a/apt/progress/text.py b/apt/progress/text.py index c5eec092..d1f87539 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -15,6 +15,8 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA """Progress reporting for text interfaces.""" +from __future__ import print_function + import os import sys @@ -23,6 +25,11 @@ from apt.progress import base __all__ = ['AcquireProgress', 'CdromProgress', 'OpProgress'] +if sys.version_info.major < 3: + input = raw_input +else: + long = int + def _(msg): """Translate the message, also try apt if translation is missing.""" @@ -47,7 +54,7 @@ class TextProgress(object): # Fill remaining stuff with whitespace if self._width > len(msg): self._file.write((self._width - len(msg)) * ' ') - elif maximize: # Needed for OpProgress. + elif maximize: # Needed for OpProgress. self._width = max(self._width, len(msg)) if newline: self._file.write("\n") @@ -91,7 +98,7 @@ class AcquireProgress(base.AcquireProgress, TextProgress): base.AcquireProgress.__init__(self) self._signal = None self._width = 80 - self._id = 1 + self._id = long(1) def start(self): """Start an Acquire progress. @@ -104,7 +111,7 @@ class AcquireProgress(base.AcquireProgress, TextProgress): self._signal = signal.signal(signal.SIGWINCH, self._winch) # Get the window size. self._winch() - self._id = 1L + self._id = long(1) def _winch(self, *dummy): """Signal handler for window resize signals.""" @@ -114,7 +121,7 @@ class AcquireProgress(base.AcquireProgress, TextProgress): import struct buf = fcntl.ioctl(self._file, termios.TIOCGWINSZ, 8 * ' ') dummy, col, dummy, dummy = struct.unpack('hhhh', buf) - self._width = col - 1 # 1 for the cursor + self._width = col - 1 # 1 for the cursor def ims_hit(self, item): """Called when an item is update (e.g. not modified on the server).""" @@ -188,8 +195,9 @@ class AcquireProgress(base.AcquireProgress, TextProgress): # Add the total size and percent if worker.total_size and not worker.current_item.owner.complete: - val += "/%sB %i%%" % (apt_pkg.size_to_str(worker.total_size), - worker.current_size*100.0/worker.total_size) + val += "/%sB %i%%" % ( + apt_pkg.size_to_str(worker.total_size), + worker.current_size * 100.0 / worker.total_size) val += ']' @@ -214,7 +222,7 @@ class AcquireProgress(base.AcquireProgress, TextProgress): self._write(_("Media change: please insert the disc labeled\n" " '%s'\n" "in the drive '%s' and press enter\n") % (medium, drive)) - return raw_input() not in ('c', 'C') + return input() not in ('c', 'C') def stop(self): """Invoked when the Acquire process stops running.""" @@ -239,7 +247,7 @@ class CdromProgress(base.CdromProgress, TextProgress): self._write(_("Please provide a name for this Disc, such as " "'Debian 2.1r1 Disk 1'"), False) try: - return raw_input(":") + return input(":") except KeyboardInterrupt: return @@ -255,6 +263,6 @@ class CdromProgress(base.CdromProgress, TextProgress): self._write(_("Please insert a Disc in the drive and press enter"), False) try: - return (raw_input() == '') + return (input() == '') except KeyboardInterrupt: return False diff --git a/apt/utils.py b/apt/utils.py index 08140258..948aac92 100644 --- a/apt/utils.py +++ b/apt/utils.py @@ -16,6 +16,7 @@ # 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 +from __future__ import print_function import os.path @@ -32,7 +33,7 @@ def get_maintenance_end_date(release_date, m_months): years = m_months // 12 months = m_months % 12 support_end_year = (release_date.year + years + - (release_date.month + months)//12) + (release_date.month + months) // 12) support_end_month = (release_date.month + months) % 12 # special case: this happens when e.g. doing 2010-06 + 18 months if support_end_month == 0: @@ -49,7 +50,7 @@ def get_release_date_from_release_file(path): return None tag = apt_pkg.TagFile(open(path)) section = next(tag) - if not "Date" in section: + if "Date" not in section: return None date = section["Date"] return apt_pkg.str_to_time(date) @@ -69,8 +70,8 @@ def get_release_filename_for_pkg(cache, pkgname, label, release): for ver_file, _index in aver.file_list: #print verFile if (ver_file.origin == label and - ver_file.label == label and - ver_file.archive == release): + ver_file.label == label and + ver_file.archive == release): ver = aver if not ver: return None @@ -78,8 +79,8 @@ def get_release_filename_for_pkg(cache, pkgname, label, release): for metaindex in cache._list.list: for m in metaindex.index_files: if (indexfile and - indexfile.describe == m.describe and - indexfile.is_trusted): + indexfile.describe == m.describe and + indexfile.is_trusted): dirname = apt_pkg.config.find_dir("Dir::State::lists") name = (apt_pkg.uri_to_filename(metaindex.uri) + "dists_%s_Release" % metaindex.dist) |
