| #!/usr/bin/env python3.8 |
| # 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 |