# Copyright 2015 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import logging import urllib from google.appengine.api import urlfetch from common.buildbot import build from common.buildbot import network class Builds(object): def __init__(self, master_name, builder_name, url): self._master_name = master_name self._builder_name = builder_name self._url = url def __getitem__(self, key): """Fetches a Build object containing build details. Args: key: A nonnegative build number. Returns: A Build object. Raises: TypeError: key is not an int. ValueError: key is negative. """ # We can't take slices because we don't have a defined length. if not isinstance(key, int): raise TypeError('build numbers must be integers, not %s' % type(key).__name__) return self.Fetch((key,)) def Fetch(self, build_numbers): """Downloads and returns build details. If a build has corrupt data, it is not included in the result. If you strictly need all the builds requested, be sure to check the result length. Args: build_numbers: An iterable of build numbers to download. Yields: Build objects, in the order requested. Some may be missing. Raises: ValueError: A build number is invalid. """ if not build_numbers: return for build_number in build_numbers: if build_number < 0: raise ValueError('Invalid build number: %d' % build_number) build_query = urllib.urlencode( [('select', build_number) for build_number in build_numbers]) url = 'json/builders/%s/builds/?%s' % ( urllib.quote(self._builder_name), build_query) url = network.BuildUrl(self._master_name, url) try: builds = network.FetchData(url).values() except (ValueError, urlfetch.ResponseTooLargeError): # The JSON decode failed, or the data was too large. # Try downloading the builds individually instead. builds = [] for build_number in build_numbers: url = 'json/builders/%s/builds/%d' % ( urllib.quote(self._builder_name), build_number) url = network.BuildUrl(self._master_name, url) try: builds.append(network.FetchData(url)) except (ValueError, urlfetch.ResponseTooLargeError): logging.warning('Unable to fetch %s build %d', self._master_name, build_number) continue for build_data in builds: if 'error' in build_data: continue yield build.Build(build_data, self._url)