summaryrefslogtreecommitdiffstats
path: root/israwhidebroken/client.py
blob: 474d438c4a774be4db431940edc5280a74c39752 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/python
# uses the fedora.client library to talk to israwhidebroken
#
# Copyright 2009, Red Hat, Inc.
#
# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Author: Will Woods <wwoods@redhat.com>

from fedora.client import BaseClient, AppError, ServerError
import os, sys

# A couple of useful helper methods
def todays_compose_id(serial=1):
    import datetime
    '''Return the default compose_id for today'''
    return int(datetime.datetime.today().strftime('%Y%m%d') + '%02u' % serial)

def treedata_from_url(url):
    import urllib2, ConfigParser
    import xml.etree.cElementTree as ElementTree
    '''Given the URL of a rawhide tree, return a dict of tree data'''
    treedata = dict()
    # this one's a gimme
    treedata['compose_id'] = todays_compose_id()
    try:
        # fetch treeinfo
        treeinfo = ConfigParser.SafeConfigParser()
        treeinfo.readfp(urllib2.urlopen(url+'/.treeinfo'))
        treedata['arch'] = treeinfo.get('general','arch')
        treedata['tree_time'] = int(float(treeinfo.get('general','timestamp')))
    except:
        pass
    try:
        # fetch repomd.xml
        repomd = urllib2.urlopen(url+'/repodata/repomd.xml')
        repomdtree = ElementTree.parse(repomd)
        ns = '{http://linux.duke.edu/metadata/repo}'
        revision = repomdtree.getroot().find(ns+'revision')
        treedata['repodata_time'] = int(revision.text)
    except:
        pass
    return treedata

# XXX TODO: if 'exc' in r: raise appropriate error?
class IRBClient(BaseClient):
    def get_tests(self):
        '''Returns a list of known tests'''
        r = self.send_request('/get_tests')
        return r.get('tests')

    def get_trees(self, *args, **kw):
        '''Get a list of trees that match all the given parameters:
        id, compose_id, arch, tree_time, repodata_time'''
        r = self.send_request('/get_trees', req_params=kw)
        return r.get('trees')

    def add_tree(self, *args, **kw):
        '''Add a new tree to israwhidebroken.
        Required arguments: arch, compose_id
        Optional: tree_time, repodata_time
        Returns the new tree.'''
        for field in ('arch', 'compose_id', 'tree_time', 'repodata_time'):
            if field not in kw:
                raise ValueError, "Missing required arg %s" % field
        if type(kw['arch']) is not str:
            raise ValueError, 'arch must be str'
        r = self.send_request('/add_tree', auth=True, req_params=kw)
        return r.get('tree')

    def update_tree(self, *args, **kw):
        '''Add a new tree, or update an existing tree.
        Required arguments: id, or arch and compose_id
        Optional: tree_time, repodata_time
        Returns the tree data.'''
        if 'id' in kw:
            treelist = self.get_trees(id=id)
        else:
            treelist = self.get_trees(arch=kw['arch'],
                                      compose_id=kw['compose_id'])
        if len(treelist) == 0:
            return self.add_tree(*args, **kw)

        kw['treeid'] = treelist[0]['id']
        r = self.send_request('/update_tree', auth=True, req_params=kw)
        return r.get('tree')

    def add_result(self, treeid, testid, result, detail_url=None):
        '''Add a test result to the database. Returns result id on success.'''
        params = {'treeid':treeid, 'testid':testid, 'result': result}
        if detail_url:
            params['detail_url'] = detail_url
        r = self.send_request('/add_result', auth=True, req_params=params)
        return r.get('id')

    def report_result(self, testid, tree_data, result, add_tree=False):
        '''Convenience method that will look up the tree using tree_data and
        then add the given result for the given testid. 

        tree_data should be a dict containing enough data to look up exactly
        one tree. Typically that means either specifying the exact treeid if
        it's already known (e.g. {'id':treeid}) or a dict with 'arch' and one or
        more of (compose_id, tree_time, repodata_time)

        If add_tree is True and tree_data does not match any known tree, a new
        tree will be added.

        Returns result id on success.'''
        treelist = self.get_trees(**tree_data)
        if not treelist:
            if not add_tree:
                print 'Could not find a matching tree'
                return None
            tree = self.add_tree(**tree_data)
            # FIXME else check for error
        elif len(treelist) > 1:
            print 'Ambiguous tree data - too many matching trees'
            return False
        else:
            tree = treelist.pop()
        return self.add_result(treeid=tree['id'], testid=testid, result=result)