~ubuntu-core-dev/update-manager/main

« back to all changes in this revision

Viewing changes to UpdateManager/UpdateManager.py

  • Committer: Michael Vogt
  • Date: 2008-12-06 00:53:28 UTC
  • Revision ID: egon@tas-20081206005328-1q63ncr3jk62k1t3
* UpdateManager/Common/MyCache.py,
  UpdateManager/Common/UpdateList.py:
  - move the cache,updatelist implementation out into  
    its own file

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
except:
34
34
    import fakegconf as gconf
35
35
import gobject
 
36
 
36
37
import warnings
37
38
warnings.filterwarnings("ignore", "apt API not stable yet", FutureWarning)
38
39
import apt
57
58
import time
58
59
import thread
59
60
import xml.sax.saxutils
60
 
from Common.HelpViewer import HelpViewer
61
61
 
62
62
import dbus
63
63
import dbus.service
64
64
import dbus.glib
65
65
 
 
66
import GtkProgress
 
67
 
66
68
from gettext import gettext as _
67
69
from gettext import ngettext
68
70
 
69
71
from Common.utils import *
70
72
from Common.SimpleGladeApp import SimpleGladeApp
 
73
from Common.UpdateList import UpdateList
 
74
from Common.HelpViewer import HelpViewer
 
75
from Common.MyCache import MyCache
 
76
 
71
77
from DistUpgradeFetcher import DistUpgradeFetcherGtk
72
78
from ChangelogViewer import ChangelogViewer
73
 
import GtkProgress
74
79
 
75
80
from Core.MetaRelease import Dist
76
81
from MetaReleaseGObject import MetaRelease
86
91
# actions for "invoke_manager"
87
92
(INSTALL, UPDATE) = range(2)
88
93
 
89
 
SYNAPTIC_PINFILE = "/var/lib/synaptic/preferences"
90
 
 
91
 
CHANGELOGS_URI="http://changelogs.ubuntu.com/changelogs/pool/%s/%s/%s/%s_%s/changelog"
92
 
 
93
 
 
94
 
class MyCache(apt.Cache):
95
 
    def __init__(self, progress, rootdir=None):
96
 
        apt.Cache.__init__(self, progress, rootdir)
97
 
        # raise if we have packages in reqreinst state
98
 
        # and let the caller deal with that (runs partial upgrade)
99
 
        assert len(self.reqReinstallPkgs) == 0
100
 
        # init the regular cache
101
 
        self._initDepCache()
102
 
        self.all_changes = {}
103
 
        # on broken packages, try to fix via saveDistUpgrade()
104
 
        if self._depcache.BrokenCount > 0:
105
 
            self.saveDistUpgrade()
106
 
        assert (self._depcache.BrokenCount == 0 and 
107
 
                self._depcache.DelCount == 0)
108
 
 
109
 
    def _initDepCache(self):
110
 
        #apt_pkg.Config.Set("Debug::pkgPolicy","1")
111
 
        #self.depcache = apt_pkg.GetDepCache(self.cache)
112
 
        #self._depcache = apt_pkg.GetDepCache(self._cache)
113
 
        self._depcache.ReadPinFile()
114
 
        if os.path.exists(SYNAPTIC_PINFILE):
115
 
            self._depcache.ReadPinFile(SYNAPTIC_PINFILE)
116
 
        self._depcache.Init()
117
 
    def clear(self):
118
 
        self._initDepCache()
119
 
    @property
120
 
    def requiredDownload(self):
121
 
        """ get the size of the packages that are required to download """
122
 
        pm = apt_pkg.GetPackageManager(self._depcache)
123
 
        fetcher = apt_pkg.GetAcquire()
124
 
        pm.GetArchives(fetcher, self._list, self._records)
125
 
        return fetcher.FetchNeeded
126
 
    @property
127
 
    def installCount(self):
128
 
        return self._depcache.InstCount
129
 
    def saveDistUpgrade(self):
130
 
        """ this functions mimics a upgrade but will never remove anything """
131
 
        self._depcache.Upgrade(True)
132
 
        wouldDelete = self._depcache.DelCount
133
 
        if self._depcache.DelCount > 0:
134
 
            self.clear()
135
 
        assert self._depcache.BrokenCount == 0 and self._depcache.DelCount == 0
136
 
        self._depcache.Upgrade()
137
 
        return wouldDelete
138
 
    def matchPackageOrigin(self, pkg, matcher):
139
 
        """ match 'pkg' origin against 'matcher', take versions between
140
 
            installedVersion and candidateVersion into account too
141
 
            Useful if installed pkg A v1.0 is available in both
142
 
            -updates (as v1.2) and -security (v1.1). we want to display
143
 
            it as a security update then
144
 
        """
145
 
        inst_ver = pkg._pkg.CurrentVer
146
 
        cand_ver = self._depcache.GetCandidateVer(pkg._pkg)
147
 
        # init with empty match
148
 
        update_origin = matcher[(None,None)]
149
 
        for ver in pkg._pkg.VersionList:
150
 
            # discard is < than installed ver
151
 
            if (inst_ver and
152
 
                apt_pkg.VersionCompare(ver.VerStr, inst_ver.VerStr) <= 0):
153
 
                #print "skipping '%s' " % ver.VerStr
154
 
                continue
155
 
            # check if we have a match
156
 
            for(verFileIter,index) in ver.FileList:
157
 
                if matcher.has_key((verFileIter.Archive, verFileIter.Origin)):
158
 
                    indexfile = pkg._list.FindIndex(verFileIter)
159
 
                    if indexfile: # and indexfile.IsTrusted:
160
 
                        match = matcher[verFileIter.Archive, verFileIter.Origin]
161
 
                        if match.importance > update_origin.importance:
162
 
                            update_origin = match
163
 
        return update_origin
164
 
        
165
 
    def get_changelog(self, name, lock):
166
 
        # don't touch the gui in this function, it needs to be thread-safe
167
 
        pkg = self[name]
168
 
 
169
 
        # get the src package name
170
 
        srcpkg = pkg.sourcePackageName
171
 
 
172
 
        # assume "main" section 
173
 
        src_section = "main"
174
 
        # use the section of the candidate as a starting point
175
 
        section = pkg._depcache.GetCandidateVer(pkg._pkg).Section
176
 
 
177
 
        # get the source version, start with the binaries version
178
 
        binver = pkg.candidateVersion
179
 
        srcver = pkg.candidateVersion
180
 
        #print "bin: %s" % binver
181
 
 
182
 
        l = section.split("/")
183
 
        if len(l) > 1:
184
 
            src_section = l[0]
185
 
 
186
 
        # lib is handled special
187
 
        prefix = srcpkg[0]
188
 
        if srcpkg.startswith("lib"):
189
 
            prefix = "lib" + srcpkg[3]
190
 
 
191
 
        # stip epoch, but save epoch for later when displaying the
192
 
        # launchpad changelog
193
 
        srcver_epoch = srcver
194
 
        l = string.split(srcver,":")
195
 
        if len(l) > 1:
196
 
            srcver = "".join(l[1:])
197
 
 
198
 
        try:
199
 
            uri = CHANGELOGS_URI % (src_section,prefix,srcpkg,srcpkg, srcver)
200
 
            # print "Trying: %s " % uri
201
 
            changelog = urllib2.urlopen(uri)
202
 
            #print changelog.read()
203
 
            # do only get the lines that are new
204
 
            alllines = ""
205
 
            regexp = "^%s \((.*)\)(.*)$" % (re.escape(srcpkg))
206
 
 
207
 
            i=0
208
 
            while True:
209
 
                line = changelog.readline()
210
 
                if line == "":
211
 
                    break
212
 
                match = re.match(regexp,line)
213
 
                if match:
214
 
                    # strip epoch from installed version
215
 
                    # and from changelog too
216
 
                    installed = pkg.installedVersion
217
 
                    if installed and ":" in installed:
218
 
                        installed = installed.split(":",1)[1]
219
 
                    changelogver = match.group(1)
220
 
                    if changelogver and ":" in changelogver:
221
 
                        changelogver = changelogver.split(":",1)[1]
222
 
                    # we test for "==" here to ensure that the version
223
 
                    # is actually really in the changelog - if not
224
 
                    # just display it all, this catches cases like:
225
 
                    # gcc-defaults with "binver=4.3.1" and srcver=1.76
226
 
                    if (installed and 
227
 
                        apt_pkg.VersionCompare(changelogver,installed)==0):
228
 
                        break
229
 
                alllines = alllines + line
230
 
 
231
 
            # Print an error if we failed to extract a changelog
232
 
            if len(alllines) == 0:
233
 
                alllines = _("The changelog does not contain any relevant changes.\n\n"
234
 
                             "Please use http://launchpad.net/ubuntu/+source/%s/%s/+changelog\n"
235
 
                             "until the changes become available or try again "
236
 
                             "later.") % (srcpkg, srcver_epoch),
237
 
            # only write if we where not canceld
238
 
            if lock.locked():
239
 
                self.all_changes[name] = [alllines, srcpkg]
240
 
        except urllib2.HTTPError, e:
241
 
            if lock.locked():
242
 
                self.all_changes[name] = [
243
 
                    _("The list of changes is not available yet.\n\n"
244
 
                      "Please use http://launchpad.net/ubuntu/+source/%s/%s/+changelog\n"
245
 
                      "until the changes become available or try again "
246
 
                      "later.") % (srcpkg, srcver_epoch),
247
 
                    srcpkg]
248
 
        except (IOError, httplib.BadStatusLine, socket.error), e:
249
 
            print "caught exception: ", e
250
 
            if lock.locked():
251
 
                self.all_changes[name] = [_("Failed to download the list "
252
 
                                            "of changes. \nPlease "
253
 
                                            "check your Internet "
254
 
                                            "connection."), srcpkg]
255
 
        if lock.locked():
256
 
            lock.release()
257
 
 
258
 
class UpdateList:
259
 
  class UpdateOrigin:
260
 
    def __init__(self, desc, importance):
261
 
      self.packages = []
262
 
      self.importance = importance
263
 
      self.description = desc
264
 
 
265
 
  def __init__(self, parent):
266
 
    # a map of packages under their origin
267
 
    try:
268
 
        pipe = os.popen("lsb_release -c -s")
269
 
        dist = pipe.read().strip()
270
 
        del pipe
271
 
    except Exception, e:
272
 
        print "Error in lsb_release: %s" % e
273
 
        parent.error(_("Failed to detect distribution"),
274
 
                     _("A error '%s' occurred while checking what system "
275
 
                       "you are using.") % e)
276
 
        sys.exit(1)
277
 
    self.distUpgradeWouldDelete = 0
278
 
    self.pkgs = {}
279
 
    self.num_updates = 0
280
 
    self.matcher = self.initMatcher(dist)
281
 
    
282
 
  def initMatcher(self, dist):
283
 
      # (origin, archive, description, importance)
284
 
      matcher_templates = [
285
 
          ("%s-security" % dist, "Ubuntu", _("Important security updates"),10),
286
 
          ("%s-updates" % dist, "Ubuntu", _("Recommended updates"), 9),
287
 
          ("%s-proposed" % dist, "Ubuntu", _("Proposed updates"), 8),
288
 
          ("%s-backports" % dist, "Ubuntu", _("Backports"), 7),
289
 
          (dist, "Ubuntu", _("Distribution updates"), 6)
290
 
      ]
291
 
      matcher = {}
292
 
      for (origin, archive, desc, importance) in matcher_templates:
293
 
          matcher[(origin, archive)] = self.UpdateOrigin(desc, importance)
294
 
      matcher[(None,None)] = self.UpdateOrigin(_("Other updates"), -1)
295
 
      return matcher
296
 
 
297
 
  def update(self, cache):
298
 
    self.held_back = []
299
 
 
300
 
    # do the upgrade
301
 
    self.distUpgradeWouldDelete = cache.saveDistUpgrade()
302
 
 
303
 
    dselect_upgrade_origin = self.UpdateOrigin(_("Previous selected"), 1)
304
 
 
305
 
    # sort by origin
306
 
    for pkg in cache:
307
 
      if pkg.isUpgradable or pkg.markedInstall:
308
 
        if pkg.candidateOrigin == None:
309
 
            # can happen for e.g. locked packages
310
 
            # FIXME: do something more sensible here (but what?)
311
 
            print "WARNING: upgradable but no canidateOrigin?!?: ", pkg.name
312
 
            continue
313
 
        # check where the package belongs
314
 
        origin_node = cache.matchPackageOrigin(pkg, self.matcher)
315
 
        if not self.pkgs.has_key(origin_node):
316
 
          self.pkgs[origin_node] = []
317
 
        self.pkgs[origin_node].append(pkg)
318
 
        self.num_updates = self.num_updates + 1
319
 
      if pkg.isUpgradable and not (pkg.markedUpgrade or pkg.markedInstall):
320
 
          self.held_back.append(pkg.name)
321
 
    for l in self.pkgs.keys():
322
 
      self.pkgs[l].sort(lambda x,y: cmp(x.name,y.name))
323
 
    self.keepcount = cache._depcache.KeepCount
324
 
 
325
94
 
326
95
class UpdateManagerDbusControler(dbus.service.Object):
327
96
    """ this is a helper to provide the UpdateManagerIFace """