~vorlon/ubuntu-archive-tools/sru-release-esm

358 by Colin Watson
add coding: line where necessary
1
# -*- coding: utf-8 -*-
2
359 by Colin Watson
Use Python 3-style print functions.
3
# Copyright (C) 2011, 2012  Canonical Ltd.
355 by Colin Watson
Apply GPLv3 to anything not already licensed; ok slangasek, broder, laney, kitterman, geser
4
# Author: Stéphane Graber <stgraber@ubuntu.com>
5
6
# This program is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; version 3 of the License.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
311.1.1 by Stéphane Graber
Add a new isotracker_xmlrpc python module with similar API as the old isotracker module
18
# To use this module, you need a ini configuration file at ~/.isotracker.conf
19
# example:
20
#  [general]
665.2.3 by Stéphane Graber
Rename isotracker_xmlrpc.py to isotracker.py, move the code to a new ISOTracker class and make it use QATracker instead of doing raw RPC
21
#  url=http://iso.qa.ubuntu.com/xmlrpc.php
317 by Colin Watson
isotracker_xmlrpc: avoid exposing passwords in tracebacks
22
#  username=stgraber
23
#  password=blablabla
311.1.1 by Stéphane Graber
Add a new isotracker_xmlrpc python module with similar API as the old isotracker module
24
#  default_milestone=Precise Daily
665.2.16 by Stéphane Graber
Add an example of using a different target to isotracker.py
25
#
26
#  [localized]
27
#  url=http://localized-iso.qa.ubuntu.com/xmlrpc.php
28
#  password=differentpassword
311.1.1 by Stéphane Graber
Add a new isotracker_xmlrpc python module with similar API as the old isotracker module
29
359 by Colin Watson
Use Python 3-style print functions.
30
from __future__ import print_function
375 by Stéphane Graber
Deal with python3
31
try:
421 by Colin Watson
isotracker_xmlrpc.py: prefer Python 3 configparser name
32
    import configparser
375 by Stéphane Graber
Deal with python3
33
except ImportError:
421 by Colin Watson
isotracker_xmlrpc.py: prefer Python 3 configparser name
34
    import ConfigParser as configparser
375 by Stéphane Graber
Deal with python3
35
665.2.3 by Stéphane Graber
Rename isotracker_xmlrpc.py to isotracker.py, move the code to a new ISOTracker class and make it use QATracker instead of doing raw RPC
36
from qatracker import QATracker, QATrackerMilestone, QATrackerProduct
316 by Colin Watson
isotracker_xmlrpc: PEP-8
37
import os
857.1.1 by Michael Vogt
do not sys.exit() inside the ISOTracker.__init__() but raise a exception instead
38
39
class NoConfigurationError(Exception):
40
    pass
311.1.1 by Stéphane Graber
Add a new isotracker_xmlrpc python module with similar API as the old isotracker module
41
665.2.3 by Stéphane Graber
Rename isotracker_xmlrpc.py to isotracker.py, move the code to a new ISOTracker class and make it use QATracker instead of doing raw RPC
42
43
class ISOTracker:
665.2.11 by Stéphane Graber
Remove the 'series' from isotracker.py and instead replace by a new parameter to the ISOTracker class called 'target' which identifies the section in the isotracker.conf file.
44
    def __init__(self, target=None):
45
        # Store the alternative target (configuration section)
46
        self.target = target
47
665.2.3 by Stéphane Graber
Rename isotracker_xmlrpc.py to isotracker.py, move the code to a new ISOTracker class and make it use QATracker instead of doing raw RPC
48
        # Read configuration
49
        configfile = os.path.expanduser('~/.isotracker.conf')
50
        if not os.path.exists(configfile):
857.1.1 by Michael Vogt
do not sys.exit() inside the ISOTracker.__init__() but raise a exception instead
51
            raise NoConfigurationError(
52
                "Missing configuration file at: %s" % configfile)
665.2.3 by Stéphane Graber
Rename isotracker_xmlrpc.py to isotracker.py, move the code to a new ISOTracker class and make it use QATracker instead of doing raw RPC
53
54
        # Load the config
55
        self.config = configparser.ConfigParser()
56
        self.config.read([configfile])
57
58
        # Connect to the tracker
59
        url = self.config.get('general', 'url')
60
        username = self.config.get('general', 'username')
61
        password = self.config.get('general', 'password')
665.2.11 by Stéphane Graber
Remove the 'series' from isotracker.py and instead replace by a new parameter to the ISOTracker class called 'target' which identifies the section in the isotracker.conf file.
62
63
        # Override with custom URL and credentials for the target
665.2.17 by Stéphane Graber
Show a message when the specified target doesn't exist.
64
        if self.target:
65
            if self.config.has_section(self.target):
66
                if self.config.has_option(self.target, 'url'):
67
                    url = self.config.get(self.target, 'url')
68
                if self.config.has_option(self.target, 'username'):
69
                    username = self.config.get(self.target, 'username')
70
                if self.config.has_option(self.target, 'password'):
71
                    password = self.config.get(self.target, 'password')
72
            else:
73
                print("Couldn't find a '%s' target, using the default." %
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
74
                      self.target)
665.2.11 by Stéphane Graber
Remove the 'series' from isotracker.py and instead replace by a new parameter to the ISOTracker class called 'target' which identifies the section in the isotracker.conf file.
75
715 by Stéphane Graber
Make the QATracker instance available to ISOTracker users.
76
        self.qatracker = QATracker(url, username, password)
665.2.3 by Stéphane Graber
Rename isotracker_xmlrpc.py to isotracker.py, move the code to a new ISOTracker class and make it use QATracker instead of doing raw RPC
77
78
        # Get the required list of products and milestones
715 by Stéphane Graber
Make the QATracker instance available to ISOTracker users.
79
        self.tracker_products = self.qatracker.get_products()
80
        self.tracker_milestones = self.qatracker.get_milestones()
665.2.3 by Stéphane Graber
Rename isotracker_xmlrpc.py to isotracker.py, move the code to a new ISOTracker class and make it use QATracker instead of doing raw RPC
81
665.2.11 by Stéphane Graber
Remove the 'series' from isotracker.py and instead replace by a new parameter to the ISOTracker class called 'target' which identifies the section in the isotracker.conf file.
82
    def default_milestone(self):
665.2.3 by Stéphane Graber
Rename isotracker_xmlrpc.py to isotracker.py, move the code to a new ISOTracker class and make it use QATracker instead of doing raw RPC
83
        """
84
            Get the default milestone from the configuration file.
85
        """
86
87
        milestone_name = None
88
665.2.11 by Stéphane Graber
Remove the 'series' from isotracker.py and instead replace by a new parameter to the ISOTracker class called 'target' which identifies the section in the isotracker.conf file.
89
        if self.target:
665.2.3 by Stéphane Graber
Rename isotracker_xmlrpc.py to isotracker.py, move the code to a new ISOTracker class and make it use QATracker instead of doing raw RPC
90
            # Series-specific default milestone
91
            try:
665.2.11 by Stéphane Graber
Remove the 'series' from isotracker.py and instead replace by a new parameter to the ISOTracker class called 'target' which identifies the section in the isotracker.conf file.
92
                milestone_name = self.config.get(self.target,
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
93
                                                 'default_milestone')
665.2.11 by Stéphane Graber
Remove the 'series' from isotracker.py and instead replace by a new parameter to the ISOTracker class called 'target' which identifies the section in the isotracker.conf file.
94
            except (KeyError, configparser.NoSectionError,
95
                    configparser.NoOptionError):
665.2.3 by Stéphane Graber
Rename isotracker_xmlrpc.py to isotracker.py, move the code to a new ISOTracker class and make it use QATracker instead of doing raw RPC
96
                pass
665.2.11 by Stéphane Graber
Remove the 'series' from isotracker.py and instead replace by a new parameter to the ISOTracker class called 'target' which identifies the section in the isotracker.conf file.
97
98
        if not milestone_name:
665.2.3 by Stéphane Graber
Rename isotracker_xmlrpc.py to isotracker.py, move the code to a new ISOTracker class and make it use QATracker instead of doing raw RPC
99
            # Generic default milestone
100
            try:
101
                milestone_name = self.config.get('general',
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
102
                                                 'default_milestone')
665.2.11 by Stéphane Graber
Remove the 'series' from isotracker.py and instead replace by a new parameter to the ISOTracker class called 'target' which identifies the section in the isotracker.conf file.
103
            except (KeyError, configparser.NoSectionError,
104
                    configparser.NoOptionError):
665.2.3 by Stéphane Graber
Rename isotracker_xmlrpc.py to isotracker.py, move the code to a new ISOTracker class and make it use QATracker instead of doing raw RPC
105
                pass
106
107
        if not milestone_name:
108
            raise KeyError("No default milestone selected")
109
        else:
110
            return self.get_milestone_by_name(milestone_name)
111
112
    def get_product_by_name(self, product):
113
        """
114
            Get a QATrackerProduct from the product's name.
115
        """
116
117
        for entry in self.tracker_products:
118
            if entry.title.lower() == product.lower():
119
                return entry
120
        else:
121
            raise KeyError("Product '%s' not found" % product)
122
123
    def get_milestone_by_name(self, milestone):
124
        """
125
            Get a QATrackerMilestone from the milestone's name.
126
        """
127
128
        for entry in self.tracker_milestones:
129
            if entry.title.lower() == milestone.lower():
130
                return entry
131
        else:
132
            raise KeyError("Milestone '%s' not found" % milestone)
133
134
    def get_builds(self, milestone=None,
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
135
                   status=['Active', 'Re-building', 'Ready']):
665.2.3 by Stéphane Graber
Rename isotracker_xmlrpc.py to isotracker.py, move the code to a new ISOTracker class and make it use QATracker instead of doing raw RPC
136
        """
137
            Get a list of QATrackerBuild for the given milestone and status.
138
        """
139
140
        if not milestone:
141
            milestone = self.default_milestone()
142
        elif not isinstance(milestone, QATrackerMilestone):
143
            milestone = self.get_milestone_by_name(milestone)
144
145
        return milestone.get_builds(status)
146
147
    def post_build(self, product, version, milestone=None, note="",
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
148
                   notify=True):
665.2.3 by Stéphane Graber
Rename isotracker_xmlrpc.py to isotracker.py, move the code to a new ISOTracker class and make it use QATracker instead of doing raw RPC
149
        """
150
            Post a new build to the given milestone.
151
        """
152
153
        if not isinstance(product, QATrackerProduct):
154
            product = self.get_product_by_name(product)
155
156
        notefile = os.path.expanduser('~/.isotracker.note')
157
        if note == "" and os.path.exists(notefile):
158
            with open(notefile, 'r') as notefd:
159
                note = notefd.read()
160
161
        if not milestone:
162
            milestone = self.default_milestone()
163
        elif not isinstance(milestone, QATrackerMilestone):
164
            milestone = self.get_milestone_by_name(milestone)
165
166
        if milestone.add_build(product, version, note, notify):
167
            print("Build successfully added to the tracker")
168
        else:
169
            print("Failed to add build to the tracker")