#!/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 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=kw['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)