mirror of
https://github.com/ARM-software/workload-automation.git
synced 2025-09-02 11:22:41 +01:00
Initial commit of open source Workload Automation.
This commit is contained in:
16
wlauto/commands/__init__.py
Normal file
16
wlauto/commands/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# Copyright 2014-2015 ARM Limited
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
|
300
wlauto/commands/create.py
Normal file
300
wlauto/commands/create.py
Normal file
@@ -0,0 +1,300 @@
|
||||
# Copyright 2013-2015 ARM Limited
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
|
||||
import os
|
||||
import stat
|
||||
import string
|
||||
import textwrap
|
||||
import argparse
|
||||
import shutil
|
||||
import getpass
|
||||
|
||||
from wlauto import ExtensionLoader, Command, settings
|
||||
from wlauto.exceptions import CommandError
|
||||
from wlauto.utils.cli import init_argument_parser
|
||||
from wlauto.utils.misc import (capitalize, check_output,
|
||||
ensure_file_directory_exists as _f, ensure_directory_exists as _d)
|
||||
from wlauto.utils.types import identifier
|
||||
from wlauto.utils.doc import format_body
|
||||
|
||||
|
||||
__all__ = ['create_workload']
|
||||
|
||||
|
||||
TEMPLATES_DIR = os.path.join(os.path.dirname(__file__), 'templates')
|
||||
|
||||
UIAUTO_BUILD_SCRIPT = """#!/bin/bash
|
||||
|
||||
class_dir=bin/classes/com/arm/wlauto/uiauto
|
||||
base_class=`python -c "import os, wlauto; print os.path.join(os.path.dirname(wlauto.__file__), 'common', 'android', 'BaseUiAutomation.class')"`
|
||||
mkdir -p $$class_dir
|
||||
cp $$base_class $$class_dir
|
||||
|
||||
ant build
|
||||
|
||||
if [[ -f bin/${package_name}.jar ]]; then
|
||||
cp bin/${package_name}.jar ..
|
||||
fi
|
||||
"""
|
||||
|
||||
|
||||
class CreateSubcommand(object):
|
||||
|
||||
name = None
|
||||
help = None
|
||||
usage = None
|
||||
description = None
|
||||
epilog = None
|
||||
formatter_class = None
|
||||
|
||||
def __init__(self, logger, subparsers):
|
||||
self.logger = logger
|
||||
self.group = subparsers
|
||||
parser_params = dict(help=(self.help or self.description), usage=self.usage,
|
||||
description=format_body(textwrap.dedent(self.description), 80),
|
||||
epilog=self.epilog)
|
||||
if self.formatter_class:
|
||||
parser_params['formatter_class'] = self.formatter_class
|
||||
self.parser = subparsers.add_parser(self.name, **parser_params)
|
||||
init_argument_parser(self.parser) # propagate top-level options
|
||||
self.initialize()
|
||||
|
||||
def initialize(self):
|
||||
pass
|
||||
|
||||
|
||||
class CreateWorkloadSubcommand(CreateSubcommand):
|
||||
|
||||
name = 'workload'
|
||||
description = '''Create a new workload. By default, a basic workload template will be
|
||||
used but you can use options to specify a different template.'''
|
||||
|
||||
def initialize(self):
|
||||
self.parser.add_argument('name', metavar='NAME',
|
||||
help='Name of the workload to be created')
|
||||
self.parser.add_argument('-p', '--path', metavar='PATH', default=None,
|
||||
help='The location at which the workload will be created. If not specified, ' +
|
||||
'this defaults to "~/.workload_automation/workloads".')
|
||||
self.parser.add_argument('-f', '--force', action='store_true',
|
||||
help='Create the new workload even if a workload with the specified ' +
|
||||
'name already exists.')
|
||||
|
||||
template_group = self.parser.add_mutually_exclusive_group()
|
||||
template_group.add_argument('-A', '--android-benchmark', action='store_true',
|
||||
help='Use android benchmark template. This template allows you to specify ' +
|
||||
' an APK file that will be installed and run on the device. You should ' +
|
||||
' place the APK file into the workload\'s directory at the same level ' +
|
||||
'as the __init__.py.')
|
||||
template_group.add_argument('-U', '--ui-automation', action='store_true',
|
||||
help='Use UI automation template. This template generates a UI automation ' +
|
||||
'Android project as well as the Python class. This a more general ' +
|
||||
'version of the android benchmark template that makes no assumptions ' +
|
||||
'about the nature of your workload, apart from the fact that you need ' +
|
||||
'UI automation. If you need to install an APK, start an app on device, ' +
|
||||
'etc., you will need to do that explicitly in your code.')
|
||||
template_group.add_argument('-B', '--android-uiauto-benchmark', action='store_true',
|
||||
help='Use android uiauto benchmark template. This generates a UI automation ' +
|
||||
'project as well as a Python class. This template should be used ' +
|
||||
'if you have a APK file that needs to be run on the device. You ' +
|
||||
'should place the APK file into the workload\'s directory at the ' +
|
||||
'same level as the __init__.py.')
|
||||
|
||||
def execute(self, args): # pylint: disable=R0201
|
||||
where = args.path or 'local'
|
||||
check_name = not args.force
|
||||
|
||||
if args.android_benchmark:
|
||||
kind = 'android'
|
||||
elif args.ui_automation:
|
||||
kind = 'uiauto'
|
||||
elif args.android_uiauto_benchmark:
|
||||
kind = 'android_uiauto'
|
||||
else:
|
||||
kind = 'basic'
|
||||
|
||||
try:
|
||||
create_workload(args.name, kind, where, check_name)
|
||||
except CommandError, e:
|
||||
print "ERROR:", e
|
||||
|
||||
|
||||
class CreatePackageSubcommand(CreateSubcommand):
|
||||
|
||||
name = 'package'
|
||||
description = '''Create a new empty Python package for WA extensions. On installation,
|
||||
this package will "advertise" itself to WA so that Extensions with in it will
|
||||
be loaded by WA when it runs.'''
|
||||
|
||||
def initialize(self):
|
||||
self.parser.add_argument('name', metavar='NAME',
|
||||
help='Name of the package to be created')
|
||||
self.parser.add_argument('-p', '--path', metavar='PATH', default=None,
|
||||
help='The location at which the new pacakge will be created. If not specified, ' +
|
||||
'current working directory will be used.')
|
||||
self.parser.add_argument('-f', '--force', action='store_true',
|
||||
help='Create the new package even if a file or directory with the same name '
|
||||
'already exists at the specified location.')
|
||||
|
||||
def execute(self, args): # pylint: disable=R0201
|
||||
package_dir = args.path or os.path.abspath('.')
|
||||
template_path = os.path.join(TEMPLATES_DIR, 'setup.template')
|
||||
self.create_extensions_package(package_dir, args.name, template_path, args.force)
|
||||
|
||||
def create_extensions_package(self, location, name, setup_template_path, overwrite=False):
|
||||
package_path = os.path.join(location, name)
|
||||
if os.path.exists(package_path):
|
||||
if overwrite:
|
||||
self.logger.info('overwriting existing "{}"'.format(package_path))
|
||||
shutil.rmtree(package_path)
|
||||
else:
|
||||
raise CommandError('Location "{}" already exists.'.format(package_path))
|
||||
actual_package_path = os.path.join(package_path, name)
|
||||
os.makedirs(actual_package_path)
|
||||
setup_text = render_template(setup_template_path, {'package_name': name, 'user': getpass.getuser()})
|
||||
with open(os.path.join(package_path, 'setup.py'), 'w') as wfh:
|
||||
wfh.write(setup_text)
|
||||
touch(os.path.join(actual_package_path, '__init__.py'))
|
||||
|
||||
|
||||
class CreateCommand(Command):
|
||||
|
||||
name = 'create'
|
||||
description = '''Used to create various WA-related objects (see positional arguments list for what
|
||||
objects may be created).\n\nUse "wa create <object> -h" for object-specific arguments.'''
|
||||
formatter_class = argparse.RawDescriptionHelpFormatter
|
||||
subcmd_classes = [CreateWorkloadSubcommand, CreatePackageSubcommand]
|
||||
|
||||
def initialize(self):
|
||||
subparsers = self.parser.add_subparsers(dest='what')
|
||||
self.subcommands = [] # pylint: disable=W0201
|
||||
for subcmd_cls in self.subcmd_classes:
|
||||
subcmd = subcmd_cls(self.logger, subparsers)
|
||||
self.subcommands.append(subcmd)
|
||||
|
||||
def execute(self, args):
|
||||
for subcmd in self.subcommands:
|
||||
if subcmd.name == args.what:
|
||||
subcmd.execute(args)
|
||||
break
|
||||
else:
|
||||
raise CommandError('Not a valid create parameter: {}'.format(args.name))
|
||||
|
||||
|
||||
def create_workload(name, kind='basic', where='local', check_name=True, **kwargs):
|
||||
if check_name:
|
||||
extloader = ExtensionLoader(packages=settings.extension_packages, paths=settings.extension_paths)
|
||||
if name in [wl.name for wl in extloader.list_workloads()]:
|
||||
raise CommandError('Workload with name "{}" already exists.'.format(name))
|
||||
|
||||
class_name = get_class_name(name)
|
||||
if where == 'local':
|
||||
workload_dir = _d(os.path.join(settings.environment_root, 'workloads', name))
|
||||
else:
|
||||
workload_dir = _d(os.path.join(where, name))
|
||||
|
||||
if kind == 'basic':
|
||||
create_basic_workload(workload_dir, name, class_name, **kwargs)
|
||||
elif kind == 'uiauto':
|
||||
create_uiautomator_workload(workload_dir, name, class_name, **kwargs)
|
||||
elif kind == 'android':
|
||||
create_android_benchmark(workload_dir, name, class_name, **kwargs)
|
||||
elif kind == 'android_uiauto':
|
||||
create_android_uiauto_benchmark(workload_dir, name, class_name, **kwargs)
|
||||
else:
|
||||
raise CommandError('Unknown workload type: {}'.format(kind))
|
||||
|
||||
print 'Workload created in {}'.format(workload_dir)
|
||||
|
||||
|
||||
def create_basic_workload(path, name, class_name):
|
||||
source_file = os.path.join(path, '__init__.py')
|
||||
with open(source_file, 'w') as wfh:
|
||||
wfh.write(render_template('basic_workload', {'name': name, 'class_name': class_name}))
|
||||
|
||||
|
||||
def create_uiautomator_workload(path, name, class_name):
|
||||
uiauto_path = _d(os.path.join(path, 'uiauto'))
|
||||
create_uiauto_project(uiauto_path, name)
|
||||
source_file = os.path.join(path, '__init__.py')
|
||||
with open(source_file, 'w') as wfh:
|
||||
wfh.write(render_template('uiauto_workload', {'name': name, 'class_name': class_name}))
|
||||
|
||||
|
||||
def create_android_benchmark(path, name, class_name):
|
||||
source_file = os.path.join(path, '__init__.py')
|
||||
with open(source_file, 'w') as wfh:
|
||||
wfh.write(render_template('android_benchmark', {'name': name, 'class_name': class_name}))
|
||||
|
||||
|
||||
def create_android_uiauto_benchmark(path, name, class_name):
|
||||
uiauto_path = _d(os.path.join(path, 'uiauto'))
|
||||
create_uiauto_project(uiauto_path, name)
|
||||
source_file = os.path.join(path, '__init__.py')
|
||||
with open(source_file, 'w') as wfh:
|
||||
wfh.write(render_template('android_uiauto_benchmark', {'name': name, 'class_name': class_name}))
|
||||
|
||||
|
||||
def create_uiauto_project(path, name, target='1'):
|
||||
sdk_path = get_sdk_path()
|
||||
android_path = os.path.join(sdk_path, 'tools', 'android')
|
||||
package_name = 'com.arm.wlauto.uiauto.' + name.lower()
|
||||
|
||||
# ${ANDROID_HOME}/tools/android create uitest-project -n com.arm.wlauto.uiauto.linpack -t 1 -p ../test2
|
||||
command = '{} create uitest-project --name {} --target {} --path {}'.format(android_path,
|
||||
package_name,
|
||||
target,
|
||||
path)
|
||||
check_output(command, shell=True)
|
||||
|
||||
build_script = os.path.join(path, 'build.sh')
|
||||
with open(build_script, 'w') as wfh:
|
||||
template = string.Template(UIAUTO_BUILD_SCRIPT)
|
||||
wfh.write(template.substitute({'package_name': package_name}))
|
||||
os.chmod(build_script, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
|
||||
|
||||
source_file = _f(os.path.join(path, 'src',
|
||||
os.sep.join(package_name.split('.')[:-1]),
|
||||
'UiAutomation.java'))
|
||||
with open(source_file, 'w') as wfh:
|
||||
wfh.write(render_template('UiAutomation.java', {'name': name, 'package_name': package_name}))
|
||||
|
||||
|
||||
# Utility functions
|
||||
|
||||
def get_sdk_path():
|
||||
sdk_path = os.getenv('ANDROID_HOME')
|
||||
if not sdk_path:
|
||||
raise CommandError('Please set ANDROID_HOME environment variable to point to ' +
|
||||
'the locaton of Android SDK')
|
||||
return sdk_path
|
||||
|
||||
|
||||
def get_class_name(name, postfix=''):
|
||||
name = identifier(name)
|
||||
return ''.join(map(capitalize, name.split('_'))) + postfix
|
||||
|
||||
|
||||
def render_template(name, params):
|
||||
filepath = os.path.join(TEMPLATES_DIR, name)
|
||||
with open(filepath) as fh:
|
||||
text = fh.read()
|
||||
template = string.Template(text)
|
||||
return template.substitute(params)
|
||||
|
||||
|
||||
def touch(path):
|
||||
with open(path, 'w') as wfh: # pylint: disable=unused-variable
|
||||
pass
|
59
wlauto/commands/list.py
Normal file
59
wlauto/commands/list.py
Normal file
@@ -0,0 +1,59 @@
|
||||
# Copyright 2014-2015 ARM Limited
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
|
||||
from wlauto import ExtensionLoader, Command, settings
|
||||
from wlauto.utils.formatter import DescriptionListFormatter
|
||||
from wlauto.utils.doc import get_summary
|
||||
|
||||
|
||||
class ListCommand(Command):
|
||||
|
||||
name = 'list'
|
||||
description = 'List available WA extensions with a short description of each.'
|
||||
|
||||
def initialize(self):
|
||||
extension_types = ['{}s'.format(ext.name) for ext in settings.extensions]
|
||||
self.parser.add_argument('kind', metavar='KIND',
|
||||
help=('Specify the kind of extension to list. Must be '
|
||||
'one of: {}'.format(', '.join(extension_types))),
|
||||
choices=extension_types)
|
||||
self.parser.add_argument('-n', '--name', help='Filter results by the name specified')
|
||||
|
||||
def execute(self, args):
|
||||
filters = {}
|
||||
if args.name:
|
||||
filters['name'] = args.name
|
||||
|
||||
ext_loader = ExtensionLoader(packages=settings.extension_packages, paths=settings.extension_paths)
|
||||
results = ext_loader.list_extensions(args.kind[:-1])
|
||||
if filters:
|
||||
filtered_results = []
|
||||
for result in results:
|
||||
passed = True
|
||||
for k, v in filters.iteritems():
|
||||
if getattr(result, k) != v:
|
||||
passed = False
|
||||
break
|
||||
if passed:
|
||||
filtered_results.append(result)
|
||||
else: # no filters specified
|
||||
filtered_results = results
|
||||
|
||||
if filtered_results:
|
||||
output = DescriptionListFormatter()
|
||||
for result in sorted(filtered_results, key=lambda x: x.name):
|
||||
output.add_item(get_summary(result), result.name)
|
||||
print output.format_data()
|
87
wlauto/commands/run.py
Normal file
87
wlauto/commands/run.py
Normal file
@@ -0,0 +1,87 @@
|
||||
# Copyright 2014-2015 ARM Limited
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
import wlauto
|
||||
from wlauto import Command, settings
|
||||
from wlauto.core.agenda import Agenda
|
||||
from wlauto.core.execution import Executor
|
||||
from wlauto.utils.log import add_log_file
|
||||
|
||||
|
||||
class RunCommand(Command):
|
||||
|
||||
name = 'run'
|
||||
description = 'Execute automated workloads on a remote device and process the resulting output.'
|
||||
|
||||
def initialize(self):
|
||||
self.parser.add_argument('agenda', metavar='AGENDA',
|
||||
help='Agenda for this workload automation run. This defines which workloads will ' +
|
||||
'be executed, how many times, with which tunables, etc. ' +
|
||||
'See example agendas in {} '.format(os.path.dirname(wlauto.__file__)) +
|
||||
'for an example of how this file should be structured.')
|
||||
self.parser.add_argument('-d', '--output-directory', metavar='DIR', default=None,
|
||||
help='Specify a directory where the output will be generated. If the directory' +
|
||||
'already exists, the script will abort unless -f option (see below) is used,' +
|
||||
'in which case the contents of the directory will be overwritten. If this option' +
|
||||
'is not specified, then {} will be used instead.'.format(settings.output_directory))
|
||||
self.parser.add_argument('-f', '--force', action='store_true',
|
||||
help='Overwrite output directory if it exists. By default, the script will abort in this' +
|
||||
'situation to prevent accidental data loss.')
|
||||
self.parser.add_argument('-i', '--id', action='append', dest='only_run_ids', metavar='ID',
|
||||
help='Specify a workload spec ID from an agenda to run. If this is specified, only that particular ' +
|
||||
'spec will be run, and other workloads in the agenda will be ignored. This option may be used to ' +
|
||||
'specify multiple IDs.')
|
||||
|
||||
def execute(self, args): # NOQA
|
||||
self.set_up_output_directory(args)
|
||||
add_log_file(settings.log_file)
|
||||
|
||||
if os.path.isfile(args.agenda):
|
||||
agenda = Agenda(args.agenda)
|
||||
settings.agenda = args.agenda
|
||||
shutil.copy(args.agenda, settings.meta_directory)
|
||||
else:
|
||||
self.logger.debug('{} is not a file; assuming workload name.'.format(args.agenda))
|
||||
agenda = Agenda()
|
||||
agenda.add_workload_entry(args.agenda)
|
||||
|
||||
file_name = 'config_{}.py'
|
||||
for file_number, path in enumerate(settings.get_config_paths(), 1):
|
||||
shutil.copy(path, os.path.join(settings.meta_directory, file_name.format(file_number)))
|
||||
|
||||
executor = Executor()
|
||||
executor.execute(agenda, selectors={'ids': args.only_run_ids})
|
||||
|
||||
def set_up_output_directory(self, args):
|
||||
if args.output_directory:
|
||||
settings.output_directory = args.output_directory
|
||||
self.logger.debug('Using output directory: {}'.format(settings.output_directory))
|
||||
if os.path.exists(settings.output_directory):
|
||||
if args.force:
|
||||
self.logger.info('Removing existing output directory.')
|
||||
shutil.rmtree(settings.output_directory)
|
||||
else:
|
||||
self.logger.error('Output directory {} exists.'.format(settings.output_directory))
|
||||
self.logger.error('Please specify another location, or use -f option to overwrite.\n')
|
||||
sys.exit(1)
|
||||
|
||||
self.logger.info('Creating output directory.')
|
||||
os.makedirs(settings.output_directory)
|
||||
os.makedirs(settings.meta_directory)
|
101
wlauto/commands/show.py
Normal file
101
wlauto/commands/show.py
Normal file
@@ -0,0 +1,101 @@
|
||||
# Copyright 2014-2015 ARM Limited
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
from cStringIO import StringIO
|
||||
|
||||
from terminalsize import get_terminal_size # pylint: disable=import-error
|
||||
from wlauto import Command, ExtensionLoader, settings
|
||||
from wlauto.utils.doc import (get_summary, get_description, get_type_name, format_column, format_body,
|
||||
format_paragraph, indent, strip_inlined_text)
|
||||
from wlauto.utils.misc import get_pager
|
||||
|
||||
|
||||
class ShowCommand(Command):
|
||||
|
||||
name = 'show'
|
||||
|
||||
description = """
|
||||
Display documentation for the specified extension (workload, instrument, etc.).
|
||||
"""
|
||||
|
||||
def initialize(self):
|
||||
self.parser.add_argument('name', metavar='EXTENSION',
|
||||
help='''The name of the extension for which information will
|
||||
be shown.''')
|
||||
|
||||
def execute(self, args):
|
||||
ext_loader = ExtensionLoader(packages=settings.extension_packages, paths=settings.extension_paths)
|
||||
extension = ext_loader.get_extension_class(args.name)
|
||||
out = StringIO()
|
||||
term_width, term_height = get_terminal_size()
|
||||
format_extension(extension, out, term_width)
|
||||
text = out.getvalue()
|
||||
pager = get_pager()
|
||||
if len(text.split('\n')) > term_height and pager:
|
||||
sp = subprocess.Popen(pager, stdin=subprocess.PIPE)
|
||||
sp.communicate(text)
|
||||
else:
|
||||
sys.stdout.write(text)
|
||||
|
||||
|
||||
def format_extension(extension, out, width):
|
||||
format_extension_name(extension, out)
|
||||
out.write('\n')
|
||||
format_extension_summary(extension, out, width)
|
||||
out.write('\n')
|
||||
if extension.parameters:
|
||||
format_extension_parameters(extension, out, width)
|
||||
out.write('\n')
|
||||
format_extension_description(extension, out, width)
|
||||
|
||||
|
||||
def format_extension_name(extension, out):
|
||||
out.write('\n{}\n'.format(extension.name))
|
||||
|
||||
|
||||
def format_extension_summary(extension, out, width):
|
||||
out.write('{}\n'.format(format_body(strip_inlined_text(get_summary(extension)), width)))
|
||||
|
||||
|
||||
def format_extension_description(extension, out, width):
|
||||
# skip the initial paragraph of multi-paragraph description, as already
|
||||
# listed above.
|
||||
description = get_description(extension).split('\n\n', 1)[-1]
|
||||
out.write('{}\n'.format(format_body(strip_inlined_text(description), width)))
|
||||
|
||||
|
||||
def format_extension_parameters(extension, out, width, shift=4):
|
||||
out.write('parameters:\n\n')
|
||||
param_texts = []
|
||||
for param in extension.parameters:
|
||||
description = format_paragraph(strip_inlined_text(param.description or ''), width - shift)
|
||||
param_text = '{}'.format(param.name)
|
||||
if param.mandatory:
|
||||
param_text += " (MANDATORY)"
|
||||
param_text += '\n{}\n'.format(description)
|
||||
param_text += indent('type: {}\n'.format(get_type_name(param.kind)))
|
||||
if param.allowed_values:
|
||||
param_text += indent('allowed values: {}\n'.format(', '.join(map(str, param.allowed_values))))
|
||||
elif param.constraint:
|
||||
param_text += indent('constraint: {}\n'.format(get_type_name(param.constraint)))
|
||||
if param.default:
|
||||
param_text += indent('default: {}\n'.format(param.default))
|
||||
param_texts.append(indent(param_text, shift))
|
||||
|
||||
out.write(format_column('\n'.join(param_texts), width))
|
||||
|
25
wlauto/commands/templates/UiAutomation.java
Normal file
25
wlauto/commands/templates/UiAutomation.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package ${package_name};
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
// Import the uiautomator libraries
|
||||
import com.android.uiautomator.core.UiObject;
|
||||
import com.android.uiautomator.core.UiObjectNotFoundException;
|
||||
import com.android.uiautomator.core.UiScrollable;
|
||||
import com.android.uiautomator.core.UiSelector;
|
||||
import com.android.uiautomator.testrunner.UiAutomatorTestCase;
|
||||
|
||||
import com.arm.wlauto.uiauto.BaseUiAutomation;
|
||||
|
||||
public class UiAutomation extends BaseUiAutomation {
|
||||
|
||||
public static String TAG = "${name}";
|
||||
|
||||
public void runUiAutomation() throws Exception {
|
||||
// UI Automation code goes here
|
||||
}
|
||||
|
||||
}
|
27
wlauto/commands/templates/android_benchmark
Normal file
27
wlauto/commands/templates/android_benchmark
Normal file
@@ -0,0 +1,27 @@
|
||||
from wlauto import AndroidBenchmark, Parameter
|
||||
|
||||
|
||||
class ${class_name}(AndroidBenchmark):
|
||||
|
||||
name = '${name}'
|
||||
# NOTE: Please do not leave these comments in the code.
|
||||
#
|
||||
# Replace with the package for the app in the APK file.
|
||||
package = 'com.foo.bar'
|
||||
# Replace with the full path to the activity to run.
|
||||
activity = '.RunBuzz'
|
||||
description = "This is an placeholder description"
|
||||
|
||||
parameters = [
|
||||
# Workload parameters go here e.g.
|
||||
Parameter('Example parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
|
||||
description='This is an example parameter')
|
||||
]
|
||||
|
||||
def run(self, context):
|
||||
pass
|
||||
|
||||
def update_result(self, context):
|
||||
super(${class_name}, self).update_result(context)
|
||||
# process results and add them using
|
||||
# context.result.add_metric
|
24
wlauto/commands/templates/android_uiauto_benchmark
Normal file
24
wlauto/commands/templates/android_uiauto_benchmark
Normal file
@@ -0,0 +1,24 @@
|
||||
from wlauto import AndroidUiAutoBenchmark, Parameter
|
||||
|
||||
|
||||
class ${class_name}(AndroidUiAutoBenchmark):
|
||||
|
||||
name = '${name}'
|
||||
# NOTE: Please do not leave these comments in the code.
|
||||
#
|
||||
# Replace with the package for the app in the APK file.
|
||||
package = 'com.foo.bar'
|
||||
# Replace with the full path to the activity to run.
|
||||
activity = '.RunBuzz'
|
||||
description = "This is an placeholder description"
|
||||
|
||||
parameters = [
|
||||
# Workload parameters go here e.g.
|
||||
Parameter('Example parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
|
||||
description='This is an example parameter')
|
||||
]
|
||||
|
||||
def update_result(self, context):
|
||||
super(${class_name}, self).update_result(context)
|
||||
# process results and add them using
|
||||
# context.result.add_metric
|
28
wlauto/commands/templates/basic_workload
Normal file
28
wlauto/commands/templates/basic_workload
Normal file
@@ -0,0 +1,28 @@
|
||||
from wlauto import Workload, Parameter
|
||||
|
||||
|
||||
class ${class_name}(Workload):
|
||||
|
||||
name = '${name}'
|
||||
description = "This is an placeholder description"
|
||||
|
||||
parameters = [
|
||||
# Workload parameters go here e.g.
|
||||
Parameter('Example parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
|
||||
description='This is an example parameter')
|
||||
]
|
||||
|
||||
def setup(self, context):
|
||||
pass
|
||||
|
||||
def run(self, context):
|
||||
pass
|
||||
|
||||
def update_result(self, context):
|
||||
pass
|
||||
|
||||
def teardown(self, context):
|
||||
pass
|
||||
|
||||
def validate(self):
|
||||
pass
|
102
wlauto/commands/templates/setup.template
Normal file
102
wlauto/commands/templates/setup.template
Normal file
@@ -0,0 +1,102 @@
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
from multiprocessing import Process
|
||||
|
||||
try:
|
||||
from setuptools.command.install import install as orig_install
|
||||
from setuptools import setup
|
||||
except ImportError:
|
||||
from distutils.command.install import install as orig_install
|
||||
from distutils.core import setup
|
||||
|
||||
try:
|
||||
import pwd
|
||||
except ImportError:
|
||||
pwd = None
|
||||
|
||||
warnings.filterwarnings('ignore', "Unknown distribution option: 'install_requires'")
|
||||
|
||||
try:
|
||||
os.remove('MANIFEST')
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
packages = []
|
||||
data_files = {}
|
||||
source_dir = os.path.dirname(__file__)
|
||||
for root, dirs, files in os.walk('$package_name'):
|
||||
rel_dir = os.path.relpath(root, source_dir)
|
||||
data = []
|
||||
if '__init__.py' in files:
|
||||
for f in files:
|
||||
if os.path.splitext(f)[1] not in ['.py', '.pyc', '.pyo']:
|
||||
data.append(f)
|
||||
package_name = rel_dir.replace(os.sep, '.')
|
||||
package_dir = root
|
||||
packages.append(package_name)
|
||||
data_files[package_name] = data
|
||||
else:
|
||||
# use previous package name
|
||||
filepaths = [os.path.join(root, f) for f in files]
|
||||
data_files[package_name].extend([os.path.relpath(f, package_dir) for f in filepaths])
|
||||
|
||||
params = dict(
|
||||
name='$package_name',
|
||||
version='0.0.1',
|
||||
packages=packages,
|
||||
package_data=data_files,
|
||||
url='N/A',
|
||||
maintainer='$user',
|
||||
maintainer_email='$user@example.com',
|
||||
install_requires=[
|
||||
'wlauto',
|
||||
],
|
||||
# https://pypi.python.org/pypi?%3Aaction=list_classifiers
|
||||
classifiers=[
|
||||
'Development Status :: 3 - Alpha',
|
||||
'Environment :: Console',
|
||||
'License :: Other/Proprietary License',
|
||||
'Operating System :: Unix',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def update_wa_packages():
|
||||
sudo_user = os.getenv('SUDO_USER')
|
||||
if sudo_user:
|
||||
user_entry = pwd.getpwnam(sudo_user)
|
||||
os.setgid(user_entry.pw_gid)
|
||||
os.setuid(user_entry.pw_uid)
|
||||
env_root = os.getenv('WA_USER_DIRECTORY', os.path.join(os.path.expanduser('~'), '.workload_automation'))
|
||||
if not os.path.isdir(env_root):
|
||||
os.makedirs(env_root)
|
||||
wa_packages_file = os.path.join(env_root, 'packages')
|
||||
if os.path.isfile(wa_packages_file):
|
||||
with open(wa_packages_file, 'r') as wfh:
|
||||
package_list = wfh.read().split()
|
||||
if params['name'] not in package_list:
|
||||
package_list.append(params['name'])
|
||||
else: # no existing package file
|
||||
package_list = [params['name']]
|
||||
with open(wa_packages_file, 'w') as wfh:
|
||||
wfh.write('\n'.join(package_list))
|
||||
|
||||
|
||||
class install(orig_install):
|
||||
|
||||
def run(self):
|
||||
orig_install.run(self)
|
||||
# Must be done in a separate process because will drop privileges if
|
||||
# sudo, and won't be able to reacquire them.
|
||||
p = Process(target=update_wa_packages)
|
||||
p.start()
|
||||
p.join()
|
||||
|
||||
|
||||
params['cmdclass'] = {'install': install}
|
||||
|
||||
|
||||
setup(**params)
|
35
wlauto/commands/templates/uiauto_workload
Normal file
35
wlauto/commands/templates/uiauto_workload
Normal file
@@ -0,0 +1,35 @@
|
||||
from wlauto import UiAutomatorWorkload, Parameter
|
||||
|
||||
|
||||
class ${class_name}(UiAutomatorWorkload):
|
||||
|
||||
name = '${name}'
|
||||
description = "This is an placeholder description"
|
||||
|
||||
parameters = [
|
||||
# Workload parameters go here e.g.
|
||||
Parameter('Example parameter', kind=int, allowed_values=[1,2,3], default=1, override=True, mandatory=False,
|
||||
description='This is an example parameter')
|
||||
]
|
||||
|
||||
def setup(self, context):
|
||||
super(${class_name}, self).setup(context)
|
||||
# Perform any necessary setup before starting the UI automation
|
||||
# e.g. copy files to the device, start apps, reset logs, etc.
|
||||
|
||||
|
||||
def update_result(self, context):
|
||||
pass
|
||||
# Process workload execution artifacts to extract metrics
|
||||
# and add them to the run result using
|
||||
# context.result.add_metric()
|
||||
|
||||
def teardown(self, context):
|
||||
super(${class_name}, self).teardown(context)
|
||||
# Preform any necessary cleanup
|
||||
|
||||
def validate(self):
|
||||
pass
|
||||
# Validate inter-parameter assumptions etc
|
||||
|
||||
|
Reference in New Issue
Block a user