Skip to content

Commit

Permalink
Merge pull request FPGAwars#120 from Jesus89/develop
Browse files Browse the repository at this point in the history
Add config commands. Configure native binaries. Closes  FPGAwars#118
  • Loading branch information
Jesus89 authored Oct 18, 2016
2 parents 42ecd30 + 29178db commit 5365443
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 62 deletions.
2 changes: 1 addition & 1 deletion apio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def cli(ctx):
# Update help structure
if ctx.invoked_subcommand is None:
env_help = []
env_commands = ['boards', 'drivers', 'examples', 'init',
env_commands = ['boards', 'config', 'drivers', 'examples', 'init',
'install', 'system', 'uninstall', 'upgrade']

help = ctx.get_help()
Expand Down
32 changes: 32 additions & 0 deletions apio/commands/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# -- This file is part of the Apio project
# -- (C) 2016 FPGAwars
# -- Author Jesús Arroyo
# -- Licence GPLv2

import click

from apio.profile import Profile


@click.command('config')
@click.pass_context
@click.option('-l', '--list', is_flag=True,
help='List all configuration parameters.')
@click.option('-e', '--exe', type=click.Choice(['apio', 'native']),
help='Configure executables: `apio` selects apio packages, ' +
'`native` selects system binaries.')
def cli(ctx, list, exe):
"""Apio configuration."""

if list: # pragma: no cover
profile = Profile()
exe_mode = profile.get_config_exe()
click.secho('Executable mode: ' + exe_mode, fg='yellow')
elif exe: # pragma: no cover
profile = Profile()
profile.add_config(exe)
profile.save()
click.secho('Executable mode updated: ' + exe, fg='green')
else:
click.secho(ctx.get_help())
4 changes: 2 additions & 2 deletions apio/commands/examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
@click.option('-f', '--files', type=unicode, metavar='NAME',
help='Copy the selected example files.')
@click.option('--project-dir', type=unicode, metavar='PATH',
help='Set the target directory for the examples')
help='Set the target directory for the examples.')
@click.option('-n', '--sayno', is_flag=True,
help='Automatically answer NO to all the questions')
help='Automatically answer NO to all the questions.')
def cli(ctx, list, dir, files, project_dir, sayno):
"""Manage verilog examples.\n
Install with `apio install examples`"""
Expand Down
8 changes: 4 additions & 4 deletions apio/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def install(self):
else:
if dlpath:
remove(dlpath)
self.profile.add(self.package, self.version)
self.profile.add_package(self.package, self.version)
self.profile.save()
click.secho(
"""Package \'{}\' has been """
Expand Down Expand Up @@ -161,7 +161,7 @@ def uninstall(self):
else:
click.secho('Package \'{0}\' is not installed'.format(
self.package), fg='red')
self.profile.remove(self.package)
self.profile.remove_package(self.package)
self.profile.save()

def _get_architecture(self):
Expand Down Expand Up @@ -202,15 +202,15 @@ def _get_latest_version(self, name, organization, tag_name):
return version

def _download(self, url):
if self.profile.check_version(self.package, self.version) or \
if self.profile.check_package_version(self.package, self.version) or \
self.forced_install:
fd = FileDownloader(url, self.packages_dir)
click.secho('Download ' + basename(fd.get_filepath()))
fd.start()
return fd.get_filepath()
else:
click.secho('Already installed. Version {0}'.format(
self.profile.get_version(self.package)), fg='yellow')
self.profile.get_package_version(self.package)), fg='yellow')
return None

def _unpack(self, pkgpath, pkgdir):
Expand Down
77 changes: 45 additions & 32 deletions apio/managers/scons.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
from apio.resources import Resources
from apio.managers.system import System
from apio.managers.project import Project
from apio.profile import Profile


class SCons(object):

def __init__(self):
self.profile = Profile()
self.resources = Resources()

def clean(self):
Expand Down Expand Up @@ -158,42 +160,51 @@ def run(self, command, variables=[], board=None):
scons_dir = os.path.join(packages_dir, 'tool-scons', 'script')
sconstruct_name = 'SConstruct'

# Give the priority to the packages installed by apio
os.environ['PATH'] = os.pathsep.join(
[iverilog_dir, icestorm_dir, os.environ['PATH']])

# Add environment variables
os.environ['IVL'] = os.path.join(
packages_dir, 'toolchain-iverilog', 'lib', 'ivl')
os.environ['VLIB'] = os.path.join(
packages_dir, 'toolchain-iverilog', 'vlib', 'system.v')

# -- Check for the SConstruct file
if not isfile(join(util.get_project_dir(), sconstruct_name)):
click.secho('Using default SConstruct file')
variables += ['-f', join(
dirname(__file__), '..', 'resources', sconstruct_name)]

# -- Check for the scons tools
if not isdir(scons_dir):
click.secho('Error: scons toolchain is not installed', fg='red')
click.secho('Please run:\n'
' apio install scons', fg='yellow')
if self.profile.check_exe_apio():

# Give the priority to the packages installed by apio
os.environ['PATH'] = os.pathsep.join(
[iverilog_dir, icestorm_dir, os.environ['PATH']])

# Add environment variables
os.environ['IVL'] = os.path.join(
packages_dir, 'toolchain-iverilog', 'lib', 'ivl')
os.environ['VLIB'] = os.path.join(
packages_dir, 'toolchain-iverilog', 'vlib', 'system.v')

# -- Check for the scons tools
if not isdir(scons_dir):
click.secho(
'Error: scons toolchain is not installed', fg='red')
click.secho('Please run:\n'
' apio install scons', fg='yellow')

# -- Check for the icestorm tools
if not isdir(icestorm_dir):
click.secho('Error: icestorm toolchain is not installed', fg='red')
click.secho('Please run:\n'
' apio install icestorm', fg='yellow')
# -- Check for the icestorm tools
if not isdir(icestorm_dir):
click.secho(
'Error: icestorm toolchain is not installed', fg='red')
click.secho('Please run:\n'
' apio install icestorm', fg='yellow')

# -- Check for the iverilog tools
if not isdir(iverilog_dir):
click.secho('Error: iverilog toolchain is not installed', fg='red')
click.secho('Please run:\n'
' apio install iverilog', fg='yellow')
# -- Check for the iverilog tools
if not isdir(iverilog_dir):
click.secho(
'Error: iverilog toolchain is not installed', fg='red')
click.secho('Please run:\n'
' apio install iverilog', fg='yellow')

# -- Execute scons
if isdir(scons_dir) and isdir(icestorm_dir) and isdir(iverilog_dir):
if not self.profile.check_exe_apio() or \
(isdir(scons_dir) and
isdir(icestorm_dir) and
isdir(iverilog_dir)):

terminal_width, _ = click.get_terminal_size()
start_time = time.time()

Expand All @@ -211,13 +222,15 @@ def run(self, command, variables=[], board=None):

click.secho("Executing: scons -Q {0} {1}".format(
command, ' '.join(variables)))

if self.profile.check_exe_apio():
scons = [os.path.normpath(sys.executable),
os.path.join(scons_dir, 'scons')]
else:
scons = ['scons']

result = util.exec_command(
[
os.path.normpath(sys.executable),
os.path.join(scons_dir, 'scons'),
'-Q',
command
] + variables,
scons + ['-Q', command] + variables,
stdout=util.AsyncPipe(self._on_run_out),
stderr=util.AsyncPipe(self._on_run_err)
)
Expand Down
38 changes: 29 additions & 9 deletions apio/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,38 +13,58 @@
class Profile(object):

def __init__(self):
self.config = {}
self.packages = {}
self._profile_path = join(get_home_dir(), 'profile.json')
self.load()

def check_package(self, name):
return (name in self.packages.keys())

def check_version(self, name, version):
return not ((name in self.packages.keys()) and
(self.packages[name]['version'] >= version))
def check_package_version(self, name, version):
return not (self.check_package(name) and
(self.get_package_version(name) >= version))

def add(self, name, version):
def check_exe_apio(self):
return self.get_config_exe() == 'apio'

def add_package(self, name, version):
self.packages[name] = {'version': version}

def remove(self, name):
def add_config(self, exe):
self.config = {'exe': exe}

def remove_package(self, name):
if name in self.packages.keys():
del self.packages[name]

def get_version(self, name):
def get_package_version(self, name):
return self.packages[name]['version']

def get_config_exe(self):
if 'exe' in self.config.keys():
return self.config['exe']
else:
return 'apio'

def load(self):
self.packages = {}
data = {}
if isfile(self._profile_path):
with open(self._profile_path, 'r') as profile:
try:
self.packages = json.load(profile)
data = json.load(profile)
if 'config' in data.keys():
self.config = data['config']
if 'packages' in data.keys():
self.packages = data['packages']
else:
self.packages = data # Backward compatibility
except:
pass
profile.close()

def save(self):
with open(self._profile_path, 'w') as profile:
json.dump(self.packages, profile)
data = {'config': self.config, 'packages': self.packages}
json.dump(data, profile)
profile.close()
2 changes: 1 addition & 1 deletion apio/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def list_packages(self, installed=True, notinstalled=True):
'description': self.packages[package]['description']
}
if self.profile.check_package(package):
data['version'] = self.profile.get_version(package)
data['version'] = self.profile.get_package_version(package)
installed_packages += [data]
else:
notinstalled_packages += [data]
Expand Down
12 changes: 7 additions & 5 deletions apio/resources/SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ if 'build' in COMMAND_LINE_TARGETS or \
print("DEVICE: {}".format(DEVICE))

# -- Resources paths
IVL_PATH = os.environ['IVL']
VLIB_PATH = os.environ['VLIB']
IVL_PATH = os.environ['IVL'] if 'IVL' in os.environ else ''
VLIB_PATH = os.environ['VLIB'] if 'VLIB' in os.environ else ''

isWindows = 'Windows' == system()
VVP_PATH = '' if isWindows else '-M {0}'.format(IVL_PATH)
IVER_PATH = '' if isWindows else '-B {0}'.format(IVL_PATH)
VVP_PATH = '' if isWindows or not IVL_PATH else '-M {0}'.format(IVL_PATH)
IVER_PATH = '' if isWindows or not IVL_PATH else '-B {0}'.format(IVL_PATH)

# -- Target name
TARGET = 'hardware'
Expand All @@ -91,6 +91,7 @@ except IndexError:
testbench = None

SIMULNAME = ''
TARGET_SIM = ''

# clean
if len(COMMAND_LINE_TARGETS) == 0:
Expand All @@ -107,7 +108,8 @@ elif 'sim' in COMMAND_LINE_TARGETS:
SIMULNAME, ext = os.path.splitext(testbench)

# -- Target sim name
TARGET_SIM = SIMULNAME
if SIMULNAME:
TARGET_SIM = SIMULNAME # .replace('\\', '\\\\')

# -------- Get the synthesis files. They are ALL the files except the
# -------- testbench
Expand Down
13 changes: 6 additions & 7 deletions apio/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ def __str__(self): # pragma: no cover
return Exception.__str__(self)


class AbortedByUser(ApioException):

MESSAGE = "Aborted by user"


class AsyncPipe(Thread): # pragma: no cover

def __init__(self, outcallback=None):
Expand Down Expand Up @@ -128,12 +123,16 @@ def exec_command(*args, **kwargs): # pragma: no cover
default.update(kwargs)
kwargs = default

p = subprocess.Popen(*args, **kwargs)
try:
p = subprocess.Popen(*args, **kwargs)
result['out'], result['err'] = p.communicate()
result['returncode'] = p.returncode
except KeyboardInterrupt:
raise AbortedByUser()
click.secho('Aborted by user', fg='red')
exit(1)
except Exception as e:
click.secho(str(e), fg='red')
exit(1)
finally:
for s in ("stdout", "stderr"):
if isinstance(kwargs[s], AsyncPipe):
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

setup(
name='apio',
version='0.1.7.4',
version='0.1.7.5',
description='Experimental micro-ecosystem for open FPGAs',
author='Jesús Arroyo Torrens',
author_email='[email protected]',
Expand Down
16 changes: 16 additions & 0 deletions test/env_commands/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from apio.commands.config import cli as cmd_config


def test_config(clirunner, validate_cliresult):
result = clirunner.invoke(cmd_config)
validate_cliresult(result)


def test_config_list(clirunner, validate_cliresult):
result = clirunner.invoke(cmd_config, ['--list'])
validate_cliresult(result)


def test_config_exe(clirunner, validate_cliresult):
result = clirunner.invoke(cmd_config, ['--exe', 'native'])
validate_cliresult(result)

0 comments on commit 5365443

Please sign in to comment.