[yocto] [[PATCH][yocto-autobuilder]] bin/forcebuild.py: Add a script to support force a build

Aníbal Limón anibal.limon at linux.intel.com
Wed Feb 8 07:10:37 PST 2017



On 02/08/2017 08:12 AM, Lock, Joshua G wrote:
> On Wed, 2017-02-01 at 14:14 -0600, Aníbal Limón wrote:
>> I know we have the remote_kick.py [1] script but i don't know if is
>> currently on use also this new script support list the options in
>> builders and specify custom ones via cmdline.
> 
> I don't use remote_kick.py, I'm loathe to carry two scripts with a
> similar purpose. Any idea how they differ?

The remote_kick script has a fixed set of parameters like builder
(nigthly), buildbot url (localhost:8010) and forces the same build.

The new forcebuild script you can specify buildbot server url, user,
password, builder and options (WEB inputs).

Cheers,
	alimon

> 
> Thanks,
> 
> Joshua
> 
>> Cheers,
>> 	alimon
>>
>> [1]
>> http://git.yoctoproject.org/cgit/cgit.cgi/yocto-autobuilder/tree/bin/
>> remote_kick.py
>>
>> On 02/01/2017 02:12 PM, Aníbal Limón wrote:
>>> The script supports to list avaialable builders and his options,
>>> also can force a build if the builder is IDLE or not.
>>>
>>> Also supports specify options via cmdline using python dictionaries
>>> as string.
>>>
>>> Signed-off-by: Aníbal Limón <anibal.limon at linux.intel.com>
>>> ---
>>>  bin/forcebuild.py | 183
>>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>  1 file changed, 183 insertions(+)
>>>  create mode 100755 bin/forcebuild.py
>>>
>>> diff --git a/bin/forcebuild.py b/bin/forcebuild.py
>>> new file mode 100755
>>> index 0000000..5fe61a0
>>> --- /dev/null
>>> +++ b/bin/forcebuild.py
>>> @@ -0,0 +1,183 @@
>>> +#!/usr/bin/env python
>>> +
>>> +# YoctoAutobuilder force build script
>>> +#
>>> +# Copyright (C) 2017 Intel Corporation
>>> +#
>>> +# This program is free software; you can redistribute it and/or
>>> modify
>>> +# it under the terms of the GNU General Public License version 2
>>> as
>>> +# published by the Free Software Foundation.
>>> +#
>>> +# 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.
>>> +
>>> +import urllib2
>>> +import urllib
>>> +import cookielib
>>> +import uuid
>>> +import sys
>>> +import argparse
>>> +import json
>>> +from bs4 import BeautifulSoup
>>> +
>>> +class YoctoAutobuilderAPI(object):
>>> +    def __init__(self, server):
>>> +        self.server = server
>>> +        self.opener = urllib2.build_opener(
>>> +                urllib2.HTTPCookieProcessor(cookielib.CookieJar())
>>> )
>>> +
>>> +    def login(self, user, passwd):
>>> +        data = urllib.urlencode(dict(username=user,
>>> +                                     passwd=passwd))
>>> +        url = self.server + "/login"
>>> +        request = urllib2.Request(url, data)
>>> +        result = self.opener.open(request).read()
>>> +        if result.find("The username or password you entered were
>>> not correct") > 0:
>>> +            print("Invalid username or password")
>>> +            return 1
>>> +        return 0
>>> +
>>> +    def _get_builders(self):
>>> +        url = "%s/json/builders/?as_text=1" % (self.server)
>>> +        request = urllib2.Request(url)
>>> +        json_raw_data = self.opener.open(request)
>>> +
>>> +        return json.load(json_raw_data)
>>> +
>>> +    def list_builders(self):
>>> +        builders = self._get_builders()
>>> +
>>> +        if builders:
>>> +            print('Available builders:\n')
>>> +            for builder in builders:
>>> +                print(builder)
>>> +            return 0
>>> +        else:
>>> +            print('No available builders in this server.')
>>> +            return 1
>>> +
>>> +    def _get_options_by_builder(self, builder):
>>> +        options = {}
>>> +
>>> +        url = "%s/builders/%s" % (self.server, builder)
>>> +        request = urllib2.Request(url)
>>> +        html = self.opener.open(request).read()
>>> +
>>> +        inputs = BeautifulSoup(html, 'lxml').find_all('input')
>>> +        for input in inputs:
>>> +            type = input.attrs['type']
>>> +            if  type == 'submit':
>>> +                continue
>>> +
>>> +            options[input.attrs['name']] = input.attrs['value']
>>> +
>>> +        selects = BeautifulSoup(html, 'lxml').find_all('select')
>>> +        for select in selects:
>>> +            value = select.find_all('option',
>>> selected=True)[0].getText()
>>> +            options[select.attrs['name']] = value
>>> +
>>> +        return options
>>> +
>>> +    def list_options(self, builder):
>>> +        builders = self._get_builders()
>>> +        if not builder in builders:
>>> +            print('Builder %s specified isn\'t available' %
>>> builder)
>>> +            return 1
>>> +
>>> +        opts = self._get_options_by_builder(builder)
>>> +        print('Available options in builder %s:\n' % (builder))
>>> +        for name in opts:
>>> +            value = opts[name]
>>> +            print('Name: %s, Default value: %s' % (name, value))
>>> +
>>> +    def force_build(self, builder, opts, idle_check=False):
>>> +        builders = self._get_builders()
>>> +        if not builder in builders:
>>> +            print('Builder specified isn\'t available')
>>> +            return 1
>>> +
>>> +        state = builders[builder]['state']
>>> +        if idle_check and not state == 'idle':
>>> +            print('Builder %s specified isn\'t IDLE, current state
>>> %s' \
>>> +                    % (builder, state))
>>> +            return 1
>>> +
>>> +        opts = eval(opts) # FIXME: transform string argument into
>>> dictionary, security?
>>> +        current_opts = self._get_options_by_builder(builder)
>>> +        for opt in opts:
>>> +            if not opt in current_opts:
>>> +                print('Option %s isn\'t supported by builder %s' %
>>> \
>>> +                        (opt, builder))
>>> +                return 1
>>> +            else:
>>> +                current_opts[opt] = opts[opt]
>>> +
>>> +        url_params = urllib.urlencode(current_opts)
>>> +        url = "%s/builders/%s/force" % (self.server, builder)
>>> +        request = urllib2.Request(url, url_params)
>>> +        result = self.opener.open(request)
>>> +        if 'Forced build' in result.read():
>>> +            return 0
>>> +        else:
>>> +            print("Failed to force build")
>>> +            return 1
>>> +
>>> +def main():
>>> +    parser = argparse.ArgumentParser(description="Yocto
>>> Autobuilder force build script",
>>> +            add_help=False)
>>> +    parser.add_argument('-s', '--server', help='Server URL',
>>> +            action='store', required=True)
>>> +
>>> +    parser.add_argument('-u', '--username', action='store',
>>> required=True)
>>> +    parser.add_argument('-p', '--password', action='store',
>>> required=True)
>>> +
>>> +    group = parser.add_mutually_exclusive_group()
>>> +    group.add_argument('--list-builders', help='List available
>>> builders',
>>> +            action='store_true')
>>> +    group.add_argument('--list-options', help='List options by
>>> builder',
>>> +            action='store', metavar='BUILDER')
>>> +    group.add_argument('--force-build', help='Force build by
>>> builder',
>>> +            action='store', metavar='BUILDER')
>>> +    group.add_argument('--force-build-idle', help='Force build by
>>> builder if is idle',
>>> +            action='store', metavar='BUILDER')
>>> +
>>> +    parser.add_argument('-o', '--options', help='Custom options by
>>> operation',
>>> +            action='store')
>>> +
>>> +    parser.add_argument('-d', '--debug', help='Enable debug
>>> output',
>>> +            action='store_true')
>>> +    parser.add_argument('-q', '--quiet', help='Print only errors',
>>> +            action='store_true')
>>> +
>>> +    parser.add_argument('-h', '--help', action='help',
>>> default=argparse.SUPPRESS,
>>> +                        help='show this help message and exit')
>>> +
>>> +    args = parser.parse_args()
>>> +
>>> +    api = YoctoAutobuilderAPI(args.server)
>>> +    if api.login(args.username, args.password):
>>> +        return 1
>>> +
>>> +    if args.list_builders:
>>> +        return api.list_builders()
>>> +    elif args.list_options:
>>> +        return api.list_options(args.list_options)
>>> +    elif args.force_build:
>>> +        return api.force_build(args.force_build, args.options)
>>> +    elif args.force_build_idle:
>>> +        return api.force_build(args.force_build_idle,
>>> args.options, idle_check=True)
>>> +
>>> +if __name__ == '__main__':
>>> +    try:
>>> +        ret = main()
>>> +    except Exception:
>>> +        ret = 1
>>> +        import traceback
>>> +        traceback.print_exc()
>>> +    sys.exit(ret)
>>>
>>

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <http://lists.yoctoproject.org/pipermail/yocto/attachments/20170208/a9686a5c/attachment.pgp>


More information about the yocto mailing list