# Copyright (C) 2006, 2009 Canonical Ltd. # Written by Michael Vogt and # Colin Watson . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Update the installer from the network. import sys import os import syslog import apt import apt_pkg from ubiquity import misc MAGIC_MARKER = "/var/run/ubiquity.updated" # Make sure that ubiquity is last, otherwise apt may try to install another # frontend. UBIQUITY_PKGS = ["ubiquity-casper", "ubiquity-frontend-debconf", "ubiquity-frontend-gtk", "ubiquity-frontend-kde", "ubiquity-ubuntu-artwork", "ubiquity"] class CacheProgressDebconfProgressAdapter(apt.progress.OpProgress): def __init__(self, frontend): self.frontend = frontend self.frontend.debconf_progress_start( 0, 100, self.frontend.get_string('reading_package_information')) def update(self, percent): self.frontend.debconf_progress_set(percent) self.frontend.refresh() def really_done(self): # Unfortunately the process of opening a Cache calls done() twice, # so we have to take care of this manually. self.frontend.debconf_progress_stop() class FetchProgressDebconfProgressAdapter(apt.progress.FetchProgress): def __init__(self, frontend): apt.progress.FetchProgress.__init__(self) self.frontend = frontend def pulse(self): apt.progress.FetchProgress.pulse(self) if self.currentCPS > 0: info = self.frontend.get_string('apt_progress_cps') info = info.replace( '${SPEED}', apt_pkg.size_to_str(self.currentCPS)) else: info = self.frontend.get_string('apt_progress') info = info.replace('${INDEX}', str(self.currentItems)) info = info.replace('${TOTAL}', str(self.totalItems)) self.frontend.debconf_progress_info(info) self.frontend.debconf_progress_set(self.percent) self.frontend.refresh() return True def stop(self): self.frontend.debconf_progress_stop() def start(self): self.frontend.debconf_progress_start( 0, 100, self.frontend.get_string('updating_package_information')) class InstallProgressDebconfProgressAdapter(apt.progress.InstallProgress): def __init__(self, frontend): apt.progress.InstallProgress.__init__(self) self.frontend = frontend def statusChange(self, unused_pkg, percent, unused_status): self.frontend.debconf_progress_set(percent) def startUpdate(self): self.frontend.debconf_progress_start( 0, 100, self.frontend.get_string('installing_update')) def finishUpdate(self): self.frontend.debconf_progress_stop() def updateInterface(self): apt.progress.InstallProgress.updateInterface(self) self.frontend.refresh() @misc.raise_privileges def update(frontend): frontend.debconf_progress_start( 0, 3, frontend.get_string('checking_for_installer_updates')) # check if we have updates cache_progress = CacheProgressDebconfProgressAdapter(frontend) cache = apt.Cache(cache_progress) cache_progress.really_done() fetchprogress = FetchProgressDebconfProgressAdapter(frontend) try: cache.update(fetchprogress) cache_progress = CacheProgressDebconfProgressAdapter(frontend) cache = apt.Cache(cache_progress) cache_progress.really_done() updates = filter( lambda pkg: pkg in cache and cache[pkg].is_upgradable, UBIQUITY_PKGS) except IOError, e: print "ERROR: cache.update() returned: '%s'" % e updates = [] if not updates: frontend.debconf_progress_stop() return False # We have something to upgrade. Shut down debconf-communicator for # the duration, otherwise we'll have locking problems. if frontend.dbfilter is not None and frontend.dbfilter.db is not None: frontend.stop_debconf() frontend.dbfilter.db = None stopped_debconf = True else: stopped_debconf = False try: # install the updates os.environ['DPKG_UNTRANSLATED_MESSAGES'] = '1' fixer = apt.ProblemResolver(cache) for pkg in updates: cache[pkg].mark_install(auto_fix=False) fixer.clear(cache[pkg]) fixer.protect(cache[pkg]) fixer.resolve() try: # dpkg will talk to stdout. We'd rather have this in the debug # log file. old_stdout = os.dup(1) os.dup2(2, 1) cache.commit(FetchProgressDebconfProgressAdapter(frontend), InstallProgressDebconfProgressAdapter(frontend)) except (SystemError, IOError), e: syslog.syslog(syslog.LOG_ERR, "Error installing the update: '%s'" % e) title = frontend.get_string('error_updating_installer') if frontend.locale is None: extended_locale = 'extended:c' else: extended_locale = 'extended:%s' % frontend.locale msg = frontend.get_string('error_updating_installer', extended_locale) msg = msg.replace('${ERROR}', str(e)) frontend.error_dialog(title, msg) frontend.debconf_progress_stop() return True finally: os.dup2(old_stdout, 1) os.close(old_stdout) # all went well, write marker and restart self # FIXME: we probably want some sort of in-between-restart-splash # or at least a dialog here open(MAGIC_MARKER, "w").write("1") os.execv(sys.argv[0], sys.argv) return False finally: if stopped_debconf: frontend.start_debconf() frontend.dbfilter.db = frontend.db def already_updated(): return os.path.exists(MAGIC_MARKER)