blob: 542c76ae041a8f42b64d3eccaa3c813b3fe35333 [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2019 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
import json
import os
import re
import subprocess
class Host(object):
"""Represents a local system with a build of Fuchsia.
This class abstracts the details of various repository, tool, and build
paths, as well as details about the host architecture and platform.
Attributes:
fuchsia: The root directory of the Fuchsia repository
ssh_config: Location of the SSH configuration used to connect to device.
"""
# Convenience file descriptor for silencing subprocess output
DEVNULL = open(os.devnull, 'w')
class ConfigError(RuntimeError):
"""Indicates the host is not configured for building Fuchsia."""
pass
@classmethod
def join(cls, *segments):
fuchsia = os.getenv('FUCHSIA_DIR')
if not fuchsia:
raise Host.ConfigError('Unable to find FUCHSIA_DIR; have you `fx set`?')
return os.path.join(fuchsia, *segments)
def __init__(self):
build_dir = None
with open(Host.join('.config'), 'r') as f:
for line in f.readlines():
m = re.search(r'^FUCHSIA_BUILD_DIR=\'(\S*)\'$', line)
if m:
build_dir = Host.join(m.group(1))
if not build_dir:
raise Host.ConfigError(
'Unable to determine FUCHSIA_BUILD_DIR from .config')
self.ssh_config = os.path.join(build_dir, 'ssh-keys', 'ssh_config')
self._ids = os.path.join(build_dir, 'ids.txt')
if os.uname()[0] == 'Darwin':
self._platform = 'mac-x64'
else:
self._platform = 'linux-x64'
self.fuzzers = []
try:
with open(os.path.join(build_dir, 'fuzzers.json')) as f:
fuzz_specs = json.load(f)
for fuzz_spec in fuzz_specs:
pkg = fuzz_spec['fuzz_package']
for tgt in fuzz_spec['fuzz_targets']:
self.fuzzers.append((pkg, tgt))
except IOError as e:
if e.errno != errno.ENOENT:
raise
def zircon_tool(self, cmd, logfile=None):
"""Executes a tool found in the ZIROCN_BUILD_DIR."""
cmd = [Host.join('out', 'build-zircon', 'tools', cmd[0])] + cmd[1:]
if logfile:
subprocess.Popen(cmd, stdout=logfile, stderr=subprocess.STDOUT)
else:
return subprocess.check_output(cmd, stderr=Host.DEVNULL).strip()
def symbolize(self, log_in, log_out):
"""Symbolizes backtraces in a log file using the current build."""
executable = Host.join('zircon', 'prebuilt', 'downloads', 'symbolize')
symbolizer = Host.join('buildtools', self._platform, 'clang', 'bin',
'llvm-symbolizer')
subprocess.check_call([
executable, '-ids-rel', '-ids', self._ids, '-llvm-symbolizer',
symbolizer
],
stdin=log_in,
stdout=log_out)
def notify_user(self, title, body):
"""Displays a message to the user in a platform-specific way"""
if self._platform == 'mac-x64':
subprocess.call([
'osascript', '-e',
'display notification "' + body + '" with title "' + title + '"'
])
elif subprocess.call(['which', 'notify-send'],
stdout=Host.DEVNULL,
stderr=Host.DEVNULL) == 0:
subprocess.call(['notify-send', title, body],
stdout=Host.DEVNULL,
stderr=Host.DEVNULL)
else:
subprocess.call(['wall', title + '; ' + body],
stdout=Host.DEVNULL,
stderr=Host.DEVNULL)