| #!/usr/bin/env python2.7 | |
| # Copyright 2020 The Fuchsia 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 errno | |
| from args import ArgParser | |
| from host import Host | |
| from buildenv import BuildEnv | |
| from device import Device | |
| from fuzzer import Fuzzer | |
| class Factory(object): | |
| """Facility for creating associated objects. | |
| The factory can create Hosts, BuildEnvs, Devices, and | |
| Fuzzers. More importantly, it can construct them with references to | |
| each other, i.e. a Factory-constructed Fuzzer automatically gets a | |
| reference to a Factory-constructed Device, which has a reference to a | |
| Factory-constructed BuildEnv. | |
| Attributes: | |
| host: System interface object for user interactions. | |
| buildenv: The associated BuildEnv object. | |
| device: The associated Device object. | |
| """ | |
| def __init__(self, host=None): | |
| if not host: | |
| host = Host() | |
| self._parser = None | |
| self._host = host | |
| self._buildenv = None | |
| self._device = None | |
| @property | |
| def host(self): | |
| """System interface object for user interactions.""" | |
| return self._host | |
| @property | |
| def parser(self): | |
| """The associated ArgParser object.""" | |
| if self._parser: | |
| return self._parser | |
| parser = ArgParser() | |
| parser.host = self.host | |
| parser.add_parsers() | |
| self._parser = parser | |
| return self._parser | |
| @property | |
| def buildenv(self): | |
| """The associated BuildEnv object.""" | |
| if self._buildenv: | |
| return self._buildenv | |
| buildenv = BuildEnv(self) | |
| pathname = buildenv.abspath('//.fx-build-dir') | |
| build_dir = '//' + self.host.readfile( | |
| pathname, | |
| on_error=[ | |
| 'Failed to read build directory from {}.'.format(pathname), | |
| 'Have you run "fx set ... --fuzz-with <sanitizer>"?' | |
| ]) | |
| buildenv.configure(build_dir) | |
| buildenv.read_fuzzers(buildenv.abspath(build_dir, 'fuzzers.json')) | |
| self._buildenv = buildenv | |
| return self._buildenv | |
| @property | |
| def device(self): | |
| """The associated Device object.""" | |
| if self._device: | |
| return self._device | |
| pathname = '{}.device'.format(self.buildenv.build_dir) | |
| device_name = self.host.readfile(pathname, missing_ok=True) | |
| device = Device(self, name=device_name) | |
| device.configure() | |
| self._device = device | |
| return self._device | |
| def create_fuzzer(self, args, include_tests=False): | |
| """Constructs a Fuzzer from command line arguments, showing a | |
| disambiguation menu if specified name matches more than one fuzzer.""" | |
| fuzzers = self.buildenv.fuzzers(args.name, include_tests=include_tests) | |
| if not fuzzers: | |
| self.host.error('No matching fuzzers found.', 'Try "fx fuzz list".') | |
| if len(fuzzers) > 1: | |
| choices = {} | |
| for fuzzer in fuzzers: | |
| choices[str(fuzzer)] = fuzzer | |
| self.host.echo('More than one match found.') | |
| prompt = 'Please pick one from the list' | |
| choice = self.host.choose(prompt, sorted(choices.keys())) | |
| fuzzer = choices[choice] | |
| else: | |
| fuzzer = fuzzers[0] | |
| fuzzer.update(args) | |
| return fuzzer |