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

2511.1.15 by Michael Terry
auto-pep8'd more warnings
1
# MetaRelease.py
2511.1.10 by Michael Terry
pep8-ify Core/
2
# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 4; coding: utf-8 -*-
2511.1.15 by Michael Terry
auto-pep8'd more warnings
3
#
52 by Michael Vogt
* added a bunch of missing copyright notices in the files
4
#  Copyright (c) 2004,2005 Canonical
2511.1.15 by Michael Terry
auto-pep8'd more warnings
5
#
52 by Michael Vogt
* added a bunch of missing copyright notices in the files
6
#  Author: Michael Vogt <michael.vogt@ubuntu.com>
2511.1.15 by Michael Terry
auto-pep8'd more warnings
7
#
8
#  This program is free software; you can redistribute it and/or
9
#  modify it under the terms of the GNU General Public License as
52 by Michael Vogt
* added a bunch of missing copyright notices in the files
10
#  published by the Free Software Foundation; either version 2 of the
11
#  License, or (at your option) any later version.
2511.1.15 by Michael Terry
auto-pep8'd more warnings
12
#
52 by Michael Vogt
* added a bunch of missing copyright notices in the files
13
#  This program is distributed in the hope that it will be useful,
14
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
#  GNU General Public License for more details.
2511.1.15 by Michael Terry
auto-pep8'd more warnings
17
#
52 by Michael Vogt
* added a bunch of missing copyright notices in the files
18
#  You should have received a copy of the GNU General Public License
19
#  along with this program; if not, write to the Free Software
20
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21
#  USA
22
2647.1.1 by Anders Kaseorg
MetaReleaseCore: Cache get_ubuntu_flavor() more carefully
23
import apt
1512 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
24
import apt_pkg
2826.1.1 by Łukasz 'sil2100' Zemczak
Ignore Prompt=lts for non-LTS series. This way if a user is on a non-LTS and has Prompt=lts, he/she will be upgraded to the next supported series until finally reaching an LTS.
25
import distro_info
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
26
2973 by Benjamin Drung
Drop imports only needed for Python 2
27
import configparser
28
from http.client import BadStatusLine
1660 by Michael Vogt
UpdateManager/Core/MetaRelease.py: better debugging
29
import logging
2406 by Colin Watson
Use email.utils.parsedate (with a DST handling correction) rather than
30
import email.utils
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
31
import os
2530 by Michael Terry
Don't throw exception on socket timeout when downloading metarelease
32
import socket
1512 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
33
import sys
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
34
import time
2407 by Colin Watson
Use the threading module instead of thread (renamed to _thread in Python
35
import threading
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
36
2973 by Benjamin Drung
Drop imports only needed for Python 2
37
from urllib.parse import quote
38
from urllib.request import Request, urlopen
39
from urllib.error import HTTPError, URLError
1512 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
40
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
41
from .utils import (
42
    get_lang,
43
    get_dist,
44
    get_dist_version,
45
    get_ubuntu_flavor,
46
    get_ubuntu_flavor_name,
47
)
2511.1.10 by Michael Terry
pep8-ify Core/
48
1243 by Michael Vogt
improve logic that detects what mirror is in use by
49
2680 by Michael Vogt
make meta-release parser stricter to avoid storing the data that e.g. intercepting proxies send
50
class MetaReleaseParseError(Exception):
51
    pass
52
53
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
54
class Dist(object):
308 by Michael Vogt
* show version not codename when in the upgrade button
55
    def __init__(self, name, version, date, supported):
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
56
        self.name = name
308 by Michael Vogt
* show version not codename when in the upgrade button
57
        self.version = version
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
58
        self.date = date
59
        self.supported = supported
17 by Michael Vogt
* release notes information added
60
        self.releaseNotesURI = None
1674 by Michael Vogt
* rename update-manager-support-status to ubuntu-support-status
61
        self.releaseNotesHtmlUri = None
18 by Michael Vogt
* dist-upgade tool can fetch the update tarball now
62
        self.upgradeTool = None
179.1.21 by Michael Vogt
* UpdateManager/MetaRelease.py, DistUpgradeFetcher:
63
        self.upgradeToolSig = None
1824 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
64
        # the server may report that the upgrade is broken currently
65
        self.upgrade_broken = None
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
66
2511.1.10 by Michael Terry
pep8-ify Core/
67
450 by Michael Vogt
* UpdateManager/MetaReleaseGObject.py:
68
class MetaReleaseCore(object):
771 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
69
    """
2642 by Brian Murray
ubuntu-support-status: free up file descriptors when using apt.Cache
70
    A MetaReleaseCore object abstracts the list of released
2511.1.15 by Michael Terry
auto-pep8'd more warnings
71
    distributions.
771 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
72
    """
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
73
1251 by Michael Vogt
improve the debug output via the "DEBUG_UPDATE_MANAGER"
74
    DEBUG = "DEBUG_UPDATE_MANAGER" in os.environ
824 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
75
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
76
    # some constants
771 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
77
    CONF = "/etc/update-manager/release-upgrades"
992 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
78
    CONF_METARELEASE = "/etc/update-manager/meta-release"
771 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
79
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
80
    def __init__(
81
        self,
82
        useDevelopmentRelease=False,
83
        useProposed=False,
84
        debug=False,
85
        forceLTS=False,
86
        forceDownload=False,
87
        cache=None,
88
    ):
2933 by Brian Murray
If --debug is used on the command line pass it along to the metarelease
89
        if debug:
90
            self.DEBUG = True
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
91
        self._debug(
92
            "MetaRelease.__init__() useDevel=%s useProposed=%s"
93
            % (useDevelopmentRelease, useProposed)
94
        )
2170 by Michael Vogt
when downloading the html release notes, ensure to send a
95
        # force download instead of sending if-modified-since
96
        self.forceDownload = forceDownload
2711 by Brian Murray
UpdateManager/Core/MetaRelease.py: When not running in development mode,
97
        self.useDevelopmentRelease = useDevelopmentRelease
795 by Michael Vogt
- when no updates are available, display the information when the
98
        # information about the available dists
2647.1.2 by Anders Kaseorg
MetaReleaseCore: replace downloading flag with downloaded Event
99
        self.downloaded = threading.Event()
2428.4.5 by Michael Terry
move meta release checking into main UpdateManager class; use dialog panes for those interactions rather than popup dialogs
100
        self.upgradable_to = None
795 by Michael Vogt
- when no updates are available, display the information when the
101
        self.new_dist = None
2647.1.1 by Anders Kaseorg
MetaReleaseCore: Cache get_ubuntu_flavor() more carefully
102
        if cache is None:
103
            cache = apt.Cache()
104
        self.flavor = get_ubuntu_flavor(cache=cache)
105
        self.flavor_name = get_ubuntu_flavor_name(cache=cache)
1252 by Michael Vogt
tests/test_dist_upgrade_fetcher_core.py,
106
        self.current_dist_name = get_dist()
2428.4.5 by Michael Terry
move meta release checking into main UpdateManager class; use dialog panes for those interactions rather than popup dialogs
107
        self.current_dist_version = get_dist_version()
795 by Michael Vogt
- when no updates are available, display the information when the
108
        self.no_longer_supported = None
2847 by Brian Murray
UpdateManager/Core/MetaRelease.py: set prompt in MetaReleaseCore so that
109
        self.prompt = None
992 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
110
1097 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
111
        # default (if the conf file is missing)
2806.1.1 by Julian Andres Klode
Use HTTPS for changelogs.ubuntu.com (LP: #1744318)
112
        base_uri = "https://changelogs.ubuntu.com/"
2511.1.10 by Michael Terry
pep8-ify Core/
113
        self.METARELEASE_URI = base_uri + "meta-release"
114
        self.METARELEASE_URI_LTS = base_uri + "meta-release-lts"
1097 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
115
        self.METARELEASE_URI_UNSTABLE_POSTFIX = "-development"
2919 by Brian Murray
* UpdateManager/Core/MetaRelease.py: use -proposed in the variable which
116
        self.METARELEASE_URI_PROPOSED_POSTFIX = "-proposed"
1097 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
117
992 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
118
        # check the meta-release config first
2400 by Colin Watson
Use Python 3 renaming of ConfigParser if available.
119
        parser = configparser.ConfigParser()
992 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
120
        if os.path.exists(self.CONF_METARELEASE):
1512 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
121
            try:
122
                parser.read(self.CONF_METARELEASE)
2400 by Colin Watson
Use Python 3 renaming of ConfigParser if available.
123
            except configparser.Error as e:
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
124
                sys.stderr.write(
125
                    "ERROR: failed to read '%s':\n%s"
126
                    % (self.CONF_METARELEASE, e)
127
                )
1512 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
128
                return
992 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
129
            # make changing the metarelease file and the location
130
            # for the files easy
131
            if parser.has_section("METARELEASE"):
132
                sec = "METARELEASE"
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
133
                for k in [
134
                    "URI",
135
                    "URI_LTS",
136
                    "URI_UNSTABLE_POSTFIX",
137
                    "URI_PROPOSED_POSTFIX",
138
                ]:
992 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
139
                    if parser.has_option(sec, k):
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
140
                        self._debug(
141
                            "%s: %s "
142
                            % (self.CONF_METARELEASE, parser.get(sec, k))
143
                        )
992 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
144
                        setattr(self, "%s_%s" % (sec, k), parser.get(sec, k))
145
771 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
146
        # check the config file first to figure if we want lts upgrades only
2400 by Colin Watson
Use Python 3 renaming of ConfigParser if available.
147
        parser = configparser.ConfigParser()
771 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
148
        if os.path.exists(self.CONF):
1512 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
149
            try:
150
                parser.read(self.CONF)
2400 by Colin Watson
Use Python 3 renaming of ConfigParser if available.
151
            except configparser.Error as e:
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
152
                sys.stderr.write(
153
                    "ERROR: failed to read '%s':\n%s" % (self.CONF, e)
154
                )
1512 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
155
                return
992 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
156
            # now check which specific url to use
2511.1.10 by Michael Terry
pep8-ify Core/
157
            if parser.has_option("DEFAULT", "Prompt"):
2826.1.3 by Łukasz 'sil2100' Zemczak
Stop using 'type' as a variable name. It's a bad python variable name.
158
                prompt = parser.get("DEFAULT", "Prompt").lower()
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
159
                if prompt == "never" or prompt == "no":
160
                    self.prompt = "never"
771 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
161
                    # nothing to do for this object
795 by Michael Vogt
- when no updates are available, display the information when the
162
                    # FIXME: what about no longer supported?
2647.1.2 by Anders Kaseorg
MetaReleaseCore: replace downloading flag with downloaded Event
163
                    self.downloaded.set()
771 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
164
                    return
2826.1.3 by Łukasz 'sil2100' Zemczak
Stop using 'type' as a variable name. It's a bad python variable name.
165
                elif prompt == "lts":
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
166
                    self.prompt = "lts"
2826.1.1 by Łukasz 'sil2100' Zemczak
Ignore Prompt=lts for non-LTS series. This way if a user is on a non-LTS and has Prompt=lts, he/she will be upgraded to the next supported series until finally reaching an LTS.
167
                    # the Prompt=lts setting only makes sense when running on
2826.1.2 by Łukasz 'sil2100' Zemczak
Small correction in a comment.
168
                    # a LTS, otherwise it would result in users not receiving
2826.1.1 by Łukasz 'sil2100' Zemczak
Ignore Prompt=lts for non-LTS series. This way if a user is on a non-LTS and has Prompt=lts, he/she will be upgraded to the next supported series until finally reaching an LTS.
169
                    # any distro upgrades
170
                    di = distro_info.UbuntuDistroInfo()
171
                    if di.is_lts(self.current_dist_name):
172
                        self.METARELEASE_URI = self.METARELEASE_URI_LTS
173
                    else:
174
                        self._debug("Prompt=lts for non-LTS, ignoring")
2847 by Brian Murray
UpdateManager/Core/MetaRelease.py: set prompt in MetaReleaseCore so that
175
                else:
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
176
                    self.prompt = "normal"
905 by Michael Vogt
* DistUpgrade/DistUpgradeController.py:
177
        # needed for the _tryUpgradeSelf() code in DistUpgradeController
178
        if forceLTS:
179
            self.METARELEASE_URI = self.METARELEASE_URI_LTS
771 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
180
        # devel and proposed "just" change the postfix
452 by Michael Vogt
* DistUpgrade/DistUpgradeFetcherSelf.py:
181
        if useDevelopmentRelease:
771 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
182
            self.METARELEASE_URI += self.METARELEASE_URI_UNSTABLE_POSTFIX
446 by Michael Vogt
* DistUpgrade/Changelog: updated
183
        elif useProposed:
771 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
184
            self.METARELEASE_URI += self.METARELEASE_URI_PROPOSED_POSTFIX
528 by Michael Vogt
* Use .update-manager-core dir
185
992 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
186
        self._debug("metarelease-uri: %s" % self.METARELEASE_URI)
729 by Michael Vogt
* UpdateManager/Core/MetaReleaseCore.py,
187
        self.metarelease_information = None
1177 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
188
        if not self._buildMetaReleaseFile():
189
            self._debug("_buildMetaReleaseFile failed")
190
            return
729 by Michael Vogt
* UpdateManager/Core/MetaReleaseCore.py,
191
        # we start the download thread here and we have a timeout
2407 by Colin Watson
Use the threading module instead of thread (renamed to _thread in Python
192
        threading.Thread(target=self.download).start()
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
193
        # threading.Thread(target=self.check).start()
729 by Michael Vogt
* UpdateManager/Core/MetaReleaseCore.py,
194
195
    def _buildMetaReleaseFile(self):
690 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
196
        # build the metarelease_file name
2511.1.10 by Michael Terry
pep8-ify Core/
197
        self.METARELEASE_FILE = os.path.join(
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
198
            "/var/lib/update-manager/", os.path.basename(self.METARELEASE_URI)
199
        )
528 by Michael Vogt
* Use .update-manager-core dir
200
        # check if we can write to the global location, if not,
201
        # write to homedir
202
        try:
2607 by Colin Watson
MetaReleaseCore: Plug some open file object leaks.
203
            open(self.METARELEASE_FILE, "a").close()
2853 by Brian Murray
debian/tests/control: really use pyflakes3 instead of pyflakes,
204
        except IOError:
1609 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
205
            cache_dir = os.getenv(
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
206
                "XDG_CACHE_HOME", os.path.expanduser("~/.cache")
207
            )
2592 by Colin Watson
Create parent directory of ~/.cache too.
208
            # Take special care when creating this directory; ~/.cache needs
209
            # to be created with mode 0700, but the other directories do
210
            # not.
211
            cache_parent_dir = os.path.split(cache_dir)[0]
212
            if not os.path.exists(cache_parent_dir):
213
                try:
214
                    os.makedirs(cache_parent_dir)
215
                except OSError as e:
216
                    sys.stderr.write("mkdir() failed: '%s'" % e)
217
                    return False
2591 by Colin Watson
MetaReleaseCore: Create ~/.cache if it does not exist.
218
            if not os.path.exists(cache_dir):
219
                try:
220
                    os.mkdir(cache_dir, 0o700)
221
                except OSError as e:
222
                    sys.stderr.write("mkdir() failed: '%s'" % e)
223
                    return False
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
224
            path = os.path.join(cache_dir, "update-manager-core")
349 by Michael Vogt
* data/update-manager.schemas.in:
225
            if not os.path.exists(path):
2404 by Colin Watson
Remove all hard tabs from Python code. Python 3 no longer tolerates
226
                try:
1177 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
227
                    os.mkdir(path)
2404 by Colin Watson
Remove all hard tabs from Python code. Python 3 no longer tolerates
228
                except OSError as e:
1177 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
229
                    sys.stderr.write("mkdir() failed: '%s'" % e)
2404 by Colin Watson
Remove all hard tabs from Python code. Python 3 no longer tolerates
230
                    return False
2511.1.10 by Michael Terry
pep8-ify Core/
231
            self.METARELEASE_FILE = os.path.join(
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
232
                path, os.path.basename(self.METARELEASE_URI)
233
            )
672 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
234
        # if it is empty, remove it to avoid I-M-S hits on empty file
235
        try:
236
            if os.path.getsize(self.METARELEASE_FILE) == 0:
237
                os.unlink(self.METARELEASE_FILE)
2853 by Brian Murray
debian/tests/control: really use pyflakes3 instead of pyflakes,
238
        except Exception:
672 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
239
            pass
729 by Michael Vogt
* UpdateManager/Core/MetaReleaseCore.py,
240
        return True
450 by Michael Vogt
* UpdateManager/MetaReleaseGObject.py:
241
242
    def dist_no_longer_supported(self, dist):
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
243
        """virtual function that is called when the distro is no longer
244
        supported
450 by Michael Vogt
* UpdateManager/MetaReleaseGObject.py:
245
        """
452 by Michael Vogt
* DistUpgrade/DistUpgradeFetcherSelf.py:
246
        self.no_longer_supported = dist
2511.1.10 by Michael Terry
pep8-ify Core/
247
450 by Michael Vogt
* UpdateManager/MetaReleaseGObject.py:
248
    def new_dist_available(self, dist):
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
249
        """virtual function that is called when a new distro release
250
        is available
450 by Michael Vogt
* UpdateManager/MetaReleaseGObject.py:
251
        """
452 by Michael Vogt
* DistUpgrade/DistUpgradeFetcherSelf.py:
252
        self.new_dist = dist
450 by Michael Vogt
* UpdateManager/MetaReleaseGObject.py:
253
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
254
    def parse(self):
824 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
255
        self._debug("MetaRelease.parse()")
1252 by Michael Vogt
tests/test_dist_upgrade_fetcher_core.py,
256
        current_dist_name = self.current_dist_name
257
        self._debug("current dist name: '%s'" % current_dist_name)
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
258
        current_dist = None
259
        dists = []
260
261
        # parse the metarelease_information file
1847 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
262
        index_tag = apt_pkg.TagFile(self.metarelease_information)
2772 by Brian Murray
UpdateManager/Core/MetaRelease.py: apt_pkg now raises its own error when trying to step through a bad meta-release file, account for that and raise a MetaReleaseParseError.
263
        try:
264
            while index_tag.step():
265
                for required_key in ("Dist", "Version", "Supported", "Date"):
266
                    if required_key not in index_tag.section:
267
                        raise MetaReleaseParseError(
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
268
                            "Required key '%s' missing" % required_key
269
                        )
2772 by Brian Murray
UpdateManager/Core/MetaRelease.py: apt_pkg now raises its own error when trying to step through a bad meta-release file, account for that and raise a MetaReleaseParseError.
270
                name = index_tag.section["Dist"]
271
                self._debug("found distro name: '%s'" % name)
272
                rawdate = index_tag.section["Date"]
273
                parseddate = list(email.utils.parsedate(rawdate))
274
                parseddate[8] = 0  # assume no DST
275
                date = time.mktime(tuple(parseddate))
276
                supported = int(index_tag.section["Supported"])
277
                version = index_tag.section["Version"]
278
                # add the information to a new date object
279
                dist = Dist(name, version, date, supported)
280
                if "ReleaseNotes" in index_tag.section:
281
                    dist.releaseNotesURI = index_tag.section["ReleaseNotes"]
282
                    lang = get_lang()
283
                    if lang:
284
                        dist.releaseNotesURI += "?lang=%s" % lang
285
                if "ReleaseNotesHtml" in index_tag.section:
286
                    dist.releaseNotesHtmlUri = index_tag.section[
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
287
                        "ReleaseNotesHtml"
288
                    ]
2772 by Brian Murray
UpdateManager/Core/MetaRelease.py: apt_pkg now raises its own error when trying to step through a bad meta-release file, account for that and raise a MetaReleaseParseError.
289
                    query = self._get_release_notes_uri_query_string(dist)
290
                    if query:
291
                        dist.releaseNotesHtmlUri += query
292
                if "UpgradeTool" in index_tag.section:
293
                    dist.upgradeTool = index_tag.section["UpgradeTool"]
294
                if "UpgradeToolSignature" in index_tag.section:
295
                    dist.upgradeToolSig = index_tag.section[
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
296
                        "UpgradeToolSignature"
297
                    ]
2772 by Brian Murray
UpdateManager/Core/MetaRelease.py: apt_pkg now raises its own error when trying to step through a bad meta-release file, account for that and raise a MetaReleaseParseError.
298
                if "UpgradeBroken" in index_tag.section:
299
                    dist.upgrade_broken = index_tag.section["UpgradeBroken"]
300
                dists.append(dist)
301
                if name == current_dist_name:
302
                    current_dist = dist
303
        except apt_pkg.Error:
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
304
            raise MetaReleaseParseError(
305
                "Unable to parse %s" % self.METARELEASE_URI
306
            )
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
307
2607 by Colin Watson
MetaReleaseCore: Plug some open file object leaks.
308
        self.metarelease_information.close()
309
        self.metarelease_information = None
310
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
311
        # first check if the current runing distro is in the meta-release
312
        # information. if not, we assume that we run on something not
313
        # supported and silently return
1148 by Michael Vogt
fix some pychecker warnings
314
        if current_dist is None:
1781 by Michael Vogt
merged from the main branch
315
            self._debug("current dist not found in meta-release file\n")
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
316
            return False
317
2511.1.15 by Michael Terry
auto-pep8'd more warnings
318
        # then see what we can upgrade to
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
319
        upgradable_to = ""
320
        for dist in dists:
1691 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
321
            if dist.date > current_dist.date:
2711 by Brian Murray
UpdateManager/Core/MetaRelease.py: When not running in development mode,
322
                # Only offer to upgrade to an unsupported release if running
323
                # with useDevelopmentRelease, this way one can upgrade from an
324
                # LTS release to the next supported non-LTS release e.g. from
325
                # 14.04 to 15.04.
326
                if not dist.supported and not self.useDevelopmentRelease:
327
                    continue
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
328
                upgradable_to = dist
824 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
329
                self._debug("new dist: %s" % upgradable_to)
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
330
                break
331
2511.1.15 by Michael Terry
auto-pep8'd more warnings
332
        # only warn if unsupported and a new dist is available (because
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
333
        # the development version is also unsupported)
334
        if upgradable_to != "" and not current_dist.supported:
2428.4.5 by Michael Terry
move meta release checking into main UpdateManager class; use dialog panes for those interactions rather than popup dialogs
335
            self.upgradable_to = upgradable_to
2076 by Michael Vogt
add tests around the distro end of life handling
336
            self.dist_no_longer_supported(current_dist)
1385 by Michael Vogt
* UpdateManager/Core/MetaRelease.py, UpdateManager/MetaReleaseGObject.py:
337
        if upgradable_to != "":
2428.4.5 by Michael Terry
move meta release checking into main UpdateManager class; use dialog panes for those interactions rather than popup dialogs
338
            self.upgradable_to = upgradable_to
450 by Michael Vogt
* UpdateManager/MetaReleaseGObject.py:
339
            self.new_dist_available(upgradable_to)
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
340
341
        # parsing done and sucessfully
342
        return True
343
344
    # the network thread that tries to fetch the meta-index file
345
    # can't touch the gui, runs as a thread
346
    def download(self):
824 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
347
        self._debug("MetaRelease.download()")
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
348
        lastmodified = 0
2403 by Colin Watson
Use Python 3 renamings of urllib, urllib2, and urlparse if available.
349
        req = Request(self.METARELEASE_URI)
590 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
350
        # make sure that we always get the latest file (#107716)
351
        req.add_header("Cache-Control", "No-Cache")
352
        req.add_header("Pragma", "no-cache")
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
353
        if os.access(self.METARELEASE_FILE, os.W_OK):
1649 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
354
            try:
355
                lastmodified = os.stat(self.METARELEASE_FILE).st_mtime
2853 by Brian Murray
debian/tests/control: really use pyflakes3 instead of pyflakes,
356
            except OSError:
1649 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
357
                pass
2170 by Michael Vogt
when downloading the html release notes, ensure to send a
358
        if lastmodified > 0 and not self.forceDownload:
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
359
            req.add_header(
360
                "If-Modified-Since", time.asctime(time.gmtime(lastmodified))
361
            )
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
362
        try:
1974 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
363
            # open
2511.1.10 by Michael Terry
pep8-ify Core/
364
            uri = urlopen(req, timeout=20)
463 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
365
            # sometime there is a root owned meta-relase file
366
            # there, try to remove it so that we get it
367
            # with proper permissions
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
368
            if os.path.exists(self.METARELEASE_FILE) and not os.access(
369
                self.METARELEASE_FILE, os.W_OK
370
            ):
463 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
371
                try:
372
                    os.unlink(self.METARELEASE_FILE)
2395 by Colin Watson
Use "except Exception as e" syntax rather than the old-style "except
373
                except OSError as e:
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
374
                    print(
375
                        "Can't unlink '%s' (%s)" % (self.METARELEASE_FILE, e)
376
                    )
2376 by Brian Murray
* DistUpgrade/Distupgrade.py:
377
            # we may get exception here on e.g. disk full
1254 by Michael Vogt
* UpdateManager/Core/MyCache.py:
378
            try:
2521 by Michael Terry
apply patch from Colin Watson to fix an encoding error when writing metarelease file
379
                f = open(self.METARELEASE_FILE, "w+")
1254 by Michael Vogt
* UpdateManager/Core/MyCache.py:
380
                for line in uri.readlines():
2521 by Michael Terry
apply patch from Colin Watson to fix an encoding error when writing metarelease file
381
                    f.write(line.decode("UTF-8"))
1254 by Michael Vogt
* UpdateManager/Core/MyCache.py:
382
                f.flush()
2511.1.10 by Michael Terry
pep8-ify Core/
383
                f.seek(0, 0)
384
                self.metarelease_information = f
2853 by Brian Murray
debian/tests/control: really use pyflakes3 instead of pyflakes,
385
            except IOError:
1254 by Michael Vogt
* UpdateManager/Core/MyCache.py:
386
                pass
14 by Michael Vogt
* move the MetaRelease code into it's own class/file
387
            uri.close()
1974 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
388
        # http error
2403 by Colin Watson
Use Python 3 renamings of urllib, urllib2, and urlparse if available.
389
        except HTTPError as e:
1974 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
390
            # mvo: only reuse local info on "not-modified"
391
            if e.code == 304 and os.path.exists(self.METARELEASE_FILE):
392
                self._debug("reading file '%s'" % self.METARELEASE_FILE)
2511.1.10 by Michael Terry
pep8-ify Core/
393
                self.metarelease_information = open(self.METARELEASE_FILE, "r")
1974 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
394
            else:
395
                self._debug("result of meta-release download: '%s'" % e)
396
        # generic network error
2530 by Michael Terry
Don't throw exception on socket timeout when downloading metarelease
397
        except (URLError, BadStatusLine, socket.timeout) as e:
1660 by Michael Vogt
UpdateManager/Core/MetaRelease.py: better debugging
398
            self._debug("result of meta-release download: '%s'" % e)
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
399
            print(
400
                "Failed to connect to %s. Check your Internet connection "
401
                "or proxy settings" % self.METARELEASE_URI
402
            )
450 by Michael Vogt
* UpdateManager/MetaReleaseGObject.py:
403
        # now check the information we have
2511.1.10 by Michael Terry
pep8-ify Core/
404
        if self.metarelease_information is not None:
824 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
405
            self._debug("have self.metarelease_information")
1781 by Michael Vogt
merged from the main branch
406
            try:
407
                self.parse()
2853 by Brian Murray
debian/tests/control: really use pyflakes3 instead of pyflakes,
408
            except Exception:
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
409
                logging.exception(
410
                    "parse failed for '%s'" % self.METARELEASE_FILE
411
                )
1781 by Michael Vogt
merged from the main branch
412
                # no use keeping a broken file around
413
                os.remove(self.METARELEASE_FILE)
1824 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
414
            # we don't want to keep a meta-release file around when it
415
            # has a "Broken" flag, this ensures we are not bitten by
416
            # I-M-S/cache issues
1828 by Michael Vogt
UpdateManager/Core/MetaRelease.py: fix crash when no new_dist is found
417
            if self.new_dist and self.new_dist.upgrade_broken:
1824 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
418
                os.remove(self.METARELEASE_FILE)
824 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
419
        else:
420
            self._debug("NO self.metarelease_information")
2647.1.2 by Anders Kaseorg
MetaReleaseCore: replace downloading flag with downloaded Event
421
        self.downloaded.set()
422
423
    @property
424
    def downloading(self):
425
        return not self.downloaded.is_set()
771 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
426
2170 by Michael Vogt
when downloading the html release notes, ensure to send a
427
    def _get_release_notes_uri_query_string(self, dist):
428
        q = "?"
429
        # get the lang
430
        lang = get_lang()
431
        if lang:
432
            q += "lang=%s&" % lang
433
        # get the os
2647.1.1 by Anders Kaseorg
MetaReleaseCore: Cache get_ubuntu_flavor() more carefully
434
        q += "os=%s&" % self.flavor
2170 by Michael Vogt
when downloading the html release notes, ensure to send a
435
        # get the version to upgrade to
436
        q += "ver=%s" % dist.version
2723 by Brian Murray
Quote URL parameters for the Release Announcement. (LP: #1561215)
437
        # the archive didn't respond well to ? being %3F
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
438
        return quote(q, "/?")
2170 by Michael Vogt
when downloading the html release notes, ensure to send a
439
824 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
440
    def _debug(self, msg):
441
        if self.DEBUG:
2511.1.10 by Michael Terry
pep8-ify Core/
442
            sys.stderr.write(msg + "\n")
824 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
443
771 by Michael Vogt
* UpdateManager/Core/MetaRelease.py:
444
445
if __name__ == "__main__":
446
    meta = MetaReleaseCore(False, False)