From d8f014ff86144623b7963ca717ddee3782876a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Arroyo=20Torrens?= Date: Sun, 24 Apr 2016 23:13:33 +0200 Subject: [PATCH 1/4] Added colors to install commands --- apio/__init__.py | 10 ++++------ apio/installer.py | 18 ++++++++++++------ apio/packages/driver.py | 21 +++++++++++++-------- apio/packages/piofpga.py | 9 +++++++-- 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/apio/__init__.py b/apio/__init__.py index cc3700349..3f0aa6d3e 100644 --- a/apio/__init__.py +++ b/apio/__init__.py @@ -42,7 +42,8 @@ def boards(): @cli.command('debug') def debug(): """Show system information.""" - print('Platform: ' + get_systype()) + click.secho('Platform: ', nl=False) + click.secho(get_systype(), fg='green') @cli.command('scons') @@ -76,8 +77,8 @@ def examples(ctx, list, dir, files): elif files: Examples().copy_example_files(files) else: - print(ctx.get_help()) - print(Examples().examples_of_use_cad()) + click.secho(ctx.get_help()) + click.secho(Examples().examples_of_use_cad()) # System # @@ -143,9 +144,6 @@ def install_icestorm(): def intall_pio_fpga(): """Install platformio-fpga support.""" PiofpgaInstaller().install() - print("> Now execute the following command:") - print("") - print("pio platforms install lattice_ice40") # Uninstall # diff --git a/apio/installer.py b/apio/installer.py index c21475656..a24dc75c3 100644 --- a/apio/installer.py +++ b/apio/installer.py @@ -1,5 +1,6 @@ # Installer class +import click import shutil from os import makedirs, remove @@ -22,7 +23,8 @@ def __init__(self): def install(self): if self.package is not None: - print('Install ' + self.package) + click.secho('Install ', nl=False) + click.secho(self.package, fg='cyan') if not isdir(self.packages_dir): makedirs(self.packages_dir) assert isdir(self.packages_dir) @@ -35,7 +37,8 @@ def install(self): shutil.rmtree(package_dir) self._unpack(dlpath, self.packages_dir) except Exception: - print('Package {0} is not found'.format(self._get_package_name())) + click.secho('Package {0} is not found'.format( + self._get_package_name(), fg='red')) finally: if dlpath: remove(dlpath) @@ -45,10 +48,12 @@ def install(self): def uninstall(self): if self.package is not None: if isdir(join(self.packages_dir, self.package)): - print('Uninstall package {0}'.format(self.package)) + click.secho('Uninstall package ', nl=False) + click.secho(self.package, fg='cyan') shutil.rmtree(join(self.packages_dir, self.package)) else: - print('Package {0} is not installed'.format(self.package)) + click.secho('Package {0} is not installed'.format( + self.package), fg='yellow') self.profile.remove(self.package) self.profile.save() @@ -64,12 +69,13 @@ def _get_package_name(self): def _download(self, url, sha1=None): fd = FileDownloader(url, self.packages_dir) if self.profile.check_version(self.package, basename(fd.get_filepath())): - print('Download ' + basename(fd.get_filepath())) + click.secho('Download ' + basename(fd.get_filepath())) fd.start() fd.verify(sha1) return fd.get_filepath() else: - print('Package {0} is already the newest version'.format(self.package)) + click.secho('Package {0} is already the newest version'.format( + self.package), fg='green') return None def _unpack(self, pkgpath, pkgdir): diff --git a/apio/packages/driver.py b/apio/packages/driver.py index a52217555..05eedb634 100644 --- a/apio/packages/driver.py +++ b/apio/packages/driver.py @@ -1,5 +1,6 @@ # Rules icestick class +import click import subprocess from os.path import join, dirname, isfile @@ -31,31 +32,35 @@ def uninstall(self): self._uninstall_windows() def _install_linux(self): - print('Install icestick.rules') + click.secho('Install ', nl=False) + click.secho('icestick.rules', fg='cyan') if not isfile(self.rules_system_path): - subprocess.call(['sudo', 'cp', self.rules_local_path, self.rules_system_path]) + subprocess.call(['sudo', 'cp', + self.rules_local_path, self.rules_system_path]) subprocess.call(['sudo', 'service', 'udev', 'restart']) else: - print('Package icestick.rules is already the newest version') + click.secho('Package icestick.rules is already the newest version', + fg='green') def _uninstall_linux(self): if isfile(self.rules_system_path): - print('Uninstall package icestick.rules') + click.secho('Uninstall package ', nl=False) + click.secho('icestick.rules', fg='cyan') subprocess.call(['sudo', 'rm', self.rules_system_path]) else: - print('Package icestick.rules is not installed') + click.secho('Package icestick.rules is not installed', fg='yellow') def _install_darwin(self): # TODO: return if brew is not installed subprocess.call(['brew', 'install', 'libftdi0']) - print('Configure FTDI drivers for FPGA') + click.secho('Configure FTDI drivers for FPGA') subprocess.call(['sudo', 'kextunload', '-b', 'com.FTDI.driver.FTDIUSBSerialDriver']) subprocess.call(['sudo', 'kextunload', '-b', 'com.apple.driver.AppleUSBFTDI']) def _uninstall_darwin(self): - print('Revert FTDI drivers\' configuration') + click.secho('Revert FTDI drivers\' configuration') subprocess.call(['sudo', 'kextload', '-b', 'com.FTDI.driver.FTDIUSBSerialDriver']) subprocess.call(['sudo', 'kextload', '-b', @@ -64,7 +69,7 @@ def _uninstall_darwin(self): def _install_windows(self): import webbrowser url = 'https://github.com/FPGAwars/apio/wiki/Installation#windows' - print('Follow the next instructions: ' + url) + click.secho('Follow the next instructions: ' + url) webbrowser.open(url) def _uninstall_windows(self): diff --git a/apio/packages/piofpga.py b/apio/packages/piofpga.py index 5671c7e48..018e8095a 100644 --- a/apio/packages/piofpga.py +++ b/apio/packages/piofpga.py @@ -1,4 +1,5 @@ import os +import click import shutil import glob @@ -11,7 +12,7 @@ class PiofpgaInstaller(object): """Support for FPGA in platformio(pio) plug-in installer""" def install(self): - print("Installing FPGA support for platformio...") + click.secho("Installing FPGA support for platformio...") pio_dir = os.path.join(dirname(__file__), 'platformio') # -- Source dirs @@ -38,6 +39,10 @@ def install(self): if not self._is_pyc(f): shutil.copy(f, join(platform_dest_dir, name + '-builder.py')) + click.secho("\nNow execute the following command:") + click.secho("") + click.secho(" pio platforms install lattice_ice40", fg='green') + def _copy_files(self, src, dest): """Copy files from src to dest folder. Files .pyc are not copied""" @@ -50,7 +55,7 @@ def _copy_files(self, src, dest): if not self._is_pyc(f): shutil.copy(f, dest) else: - print("Ignorig {}".format(f)) + click.secho("Ignorig {}".format(f), fg='yellow') else: # -- dest directory does not exist shutil.copytree(src, dest) From af39fac68c1d0eee18b0e08ae922320331cb429d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Arroyo=20Torrens?= Date: Tue, 26 Apr 2016 15:20:31 +0200 Subject: [PATCH 2/4] Improved install/uninstall echo --- apio/__init__.py | 10 +++------- apio/installer.py | 25 +++++++++++++++++-------- apio/packages/driver.py | 22 +++++++++++++++------- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/apio/__init__.py b/apio/__init__.py index 3f0aa6d3e..69a1a78fb 100644 --- a/apio/__init__.py +++ b/apio/__init__.py @@ -14,11 +14,6 @@ from .packages.system import SystemInstaller from .packages.piofpga import PiofpgaInstaller -try: - input = raw_input -except NameError: - pass - try: unicode = str except NameError: @@ -185,10 +180,11 @@ def uninstall_icestorm(): def _uninstall(*functions): - key = input('Are you sure? [Y/N]: ') - if key == 'y' or key == 'Y': + if click.confirm('Do you want to continue?'): for count, function in enumerate(functions): function() + else: + click.secho('Abort!', fg='red') # Synthesize # diff --git a/apio/installer.py b/apio/installer.py index a24dc75c3..503700de9 100644 --- a/apio/installer.py +++ b/apio/installer.py @@ -23,8 +23,9 @@ def __init__(self): def install(self): if self.package is not None: - click.secho('Install ', nl=False) - click.secho(self.package, fg='cyan') + click.secho('Installing ', nl=False) + click.secho(self.package, fg='cyan', nl=False) + click.secho(' package:') if not isdir(self.packages_dir): makedirs(self.packages_dir) assert isdir(self.packages_dir) @@ -44,16 +45,25 @@ def install(self): remove(dlpath) self.profile.packages[self.package] = basename(dlpath) self.profile.save() + click.secho( + 'Package \'{0}\' has been successfully installed!'.format( + self.package + ), fg='green') def uninstall(self): if self.package is not None: if isdir(join(self.packages_dir, self.package)): - click.secho('Uninstall package ', nl=False) - click.secho(self.package, fg='cyan') + click.secho('Uninstalling ', nl=False) + click.secho(self.package, fg='cyan', nl=False) + click.secho(' package') shutil.rmtree(join(self.packages_dir, self.package)) + click.secho( + 'Package \'{0}\' has been successfully uninstalled!'.format( + self.package + ), fg='green') else: - click.secho('Package {0} is not installed'.format( - self.package), fg='yellow') + click.secho('Package \'{0}\' is not installed'.format( + self.package), fg='red') self.profile.remove(self.package) self.profile.save() @@ -74,8 +84,7 @@ def _download(self, url, sha1=None): fd.verify(sha1) return fd.get_filepath() else: - click.secho('Package {0} is already the newest version'.format( - self.package), fg='green') + click.secho('Already installed', fg='yellow') return None def _unpack(self, pkgpath, pkgdir): diff --git a/apio/packages/driver.py b/apio/packages/driver.py index 05eedb634..9e79f3ac4 100644 --- a/apio/packages/driver.py +++ b/apio/packages/driver.py @@ -32,23 +32,31 @@ def uninstall(self): self._uninstall_windows() def _install_linux(self): - click.secho('Install ', nl=False) - click.secho('icestick.rules', fg='cyan') + click.secho('Installing ', nl=False) + click.secho('icestick.rules', fg='cyan', nl=False) + click.secho(' package:') if not isfile(self.rules_system_path): subprocess.call(['sudo', 'cp', self.rules_local_path, self.rules_system_path]) subprocess.call(['sudo', 'service', 'udev', 'restart']) + click.secho( + 'Package \'icestick.rules\' has been successfully installed!', + fg='green') else: - click.secho('Package icestick.rules is already the newest version', - fg='green') + click.secho('Already installed', fg='yellow') + def _uninstall_linux(self): if isfile(self.rules_system_path): - click.secho('Uninstall package ', nl=False) - click.secho('icestick.rules', fg='cyan') + click.secho('Uninstalling ', nl=False) + click.secho('icestick.rules', fg='cyan', nl=False) + click.secho(' package:') subprocess.call(['sudo', 'rm', self.rules_system_path]) + click.secho( + 'Package \'icestick.rules\' has been successfully uninstalled!', + fg='green') else: - click.secho('Package icestick.rules is not installed', fg='yellow') + click.secho('Package \'icestick.rules\' is not installed', fg='red') def _install_darwin(self): # TODO: return if brew is not installed From d95fd83c4e4336b38eac05a49de05ef43fc4ae10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Arroyo=20Torrens?= Date: Tue, 26 Apr 2016 15:46:49 +0200 Subject: [PATCH 3/4] Add colors to examples command --- apio/examples.py | 58 +++++++++++++++++++++++++----------------- examples/Makefile/info | 2 +- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/apio/examples.py b/apio/examples.py index 2dd37d456..68b2e1e9a 100644 --- a/apio/examples.py +++ b/apio/examples.py @@ -7,20 +7,15 @@ from os.path import join, isdir, isfile, dirname, basename -try: - input = raw_input -except NameError: - pass - # -- Error messages EXAMPLE_NOT_FOUND_MSG = """ -Sorry, this example does not exist -Use "apio examples -l" for listing all the available examples""" +Warning: this example does not exist +Use `apio examples -l` for listing all the available examples""" EXAMPLE_OF_USE_CAD = """ Example of use: - apio examples -f leds + apio examples -f leds Copy the leds example files to the current directory""" EXAMPLE_DIR_FILE = """ @@ -35,7 +30,7 @@ def __init__(self): def list_examples(self): examples = sorted(os.listdir(self.examples_dir)) - click.echo('') + click.secho('') for example in examples: example_dir = join(self.examples_dir, example) info_path = join(example_dir, 'info') @@ -43,9 +38,12 @@ def list_examples(self): if isfile(info_path): with open(info_path, 'r') as info_file: info = info_file.read().replace('\n', '') - click.echo(' > ' + example + ' ' + info) - click.echo(EXAMPLE_DIR_FILE) - click.echo(EXAMPLE_OF_USE_CAD) + click.secho(' ' + example, fg='blue', bold=True) + click.secho('-' * click.get_terminal_size()[0]) + click.secho(' ' + info) + click.secho('') + click.secho(EXAMPLE_DIR_FILE, fg='green') + click.secho(EXAMPLE_OF_USE_CAD, fg='green') return def copy_example_dir(self, example): @@ -54,17 +52,19 @@ def copy_example_dir(self, example): if isdir(local_example_path): if isdir(example_path): - click.echo('Warning: ' + example + ' directory already exists') - key = input('Do you want to replace it? [Y/N]: ') - if key == 'y' or key == 'Y': + click.secho( + 'Warning: ' + example + ' directory already exists', + fg='yellow') + if click.confirm('Do you want to replace it?'): shutil.rmtree(example_path) self._copy_dir(example, local_example_path, example_path) elif isfile(example_path): - click.echo('Warning: ' + example + ' is already a file') + click.secho( + 'Warning: ' + example + ' is already a file', fg='yellow') else: self._copy_dir(example, local_example_path, example_path) else: - click.echo(EXAMPLE_NOT_FOUND_MSG) + click.secho(EXAMPLE_NOT_FOUND_MSG, fg='yellow') def copy_example_files(self, example): example_path = os.getcwd() @@ -73,27 +73,37 @@ def copy_example_files(self, example): if isdir(local_example_path): self._copy_files(example, local_example_path, example_path) else: - click.echo(EXAMPLE_NOT_FOUND_MSG) + click.secho(EXAMPLE_NOT_FOUND_MSG, fg='yellow') def _copy_files(self, example, src_path, dest_path): - click.echo(' Copying ' + example + ' example') + click.secho('Copying ' + example + ' example files ...') example_files = glob.glob(join(src_path, '*')) for f in example_files: filename = basename(f) if filename != 'info': if isfile(join(dest_path, filename)): - click.echo('Warning: ' + filename + ' file already exists') - key = input('Do you want to replace it? [Y/N]: ') - if key == 'y' or key == 'Y': + click.secho( + 'Warning: ' + filename + ' file already exists', + fg='yellow') + if click.confirm('Do you want to replace it?'): shutil.copy(f, dest_path) elif isdir(join(dest_path, filename)): - click.echo('Warning: ' + filename + ' is already a directory') + click.secho( + 'Warning: ' + filename + ' is already a directory', + fg='yellow') + return else: shutil.copy(f, dest_path) + click.secho( + 'Example files \'' + example + '\' have been successfully created!', + fg='green') def _copy_dir(self, example, src_path, dest_path): - click.echo(' Creating ' + example + ' directory') + click.secho('Creating ' + example + ' directory ...') shutil.copytree(src_path, dest_path) + click.secho( + 'Example \'' + example + '\' has been successfully created!', + fg='green') def examples_of_use_cad(self): return EXAMPLE_OF_USE_CAD diff --git a/examples/Makefile/info b/examples/Makefile/info index cdde11787..daaf52960 100644 --- a/examples/Makefile/info +++ b/examples/Makefile/info @@ -1 +1 @@ - Generic Makefile for building projects (legacy) +Generic Makefile for building projects (legacy) From 7e86db955868ef148b852d6d8c868ce23f16b382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Arroyo=20Torrens?= Date: Tue, 26 Apr 2016 20:35:09 +0200 Subject: [PATCH 4/4] Add colors to execute commands --- apio/execute.py | 74 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/apio/execute.py b/apio/execute.py index a6d56e47d..76f5bd897 100644 --- a/apio/execute.py +++ b/apio/execute.py @@ -2,8 +2,10 @@ import os import sys +import time import click import platform +import datetime from os.path import join, dirname, isdir, isfile, expanduser from .project import Project @@ -39,8 +41,9 @@ def _run(self, command): stderr=util.AsyncPipe(self._on_run_out) ) else: - print('System tools are not installed. Please run:\n\n' - ' apio install system\n') + click.secho('Error: system tools are not installed', fg='red') + click.secho('Please run:\n' + ' apio install system', fg='yellow') def _on_run_out(self, line): click.secho(line) @@ -57,21 +60,24 @@ def run(self, variables=[]): sconstruct_name = 'SConstruct' # Give the priority to the packages installed by apio - os.environ['PATH'] = os.pathsep.join([icestorm_dir, os.environ['PATH']]) + os.environ['PATH'] = os.pathsep.join( + [icestorm_dir, os.environ['PATH']]) # -- Check for the icestorm tools if not isdir(icestorm_dir): - print('Icestorm toolchain is not installed. Please run:\n\n' - ' apio install icestorm\n') + click.secho('Error: icestorm toolchain is not installed', fg='red') + click.secho('Please run:\n' + ' apio install icestorm', fg='yellow') # -- Check for the scons if not isdir(scons_dir): - print('Scons toolchain is not installed. Please run:\n\n' - ' apio install scons\n') + click.secho('Error: scons toolchain is not installed', fg='red') + click.secho('Please run:\n' + ' apio install scons', fg='yellow') # -- Check for the SConstruct file if not isfile(join(os.getcwd(), sconstruct_name)): - click.secho('Using default SConstruct file\n') + click.secho('Using default SConstruct file', fg='yellow') variables += ['-f', join(dirname(__file__), sconstruct_name)] # -- Check for the project configuration file @@ -80,16 +86,18 @@ def run(self, variables=[]): board_flag = "board={}".format(p.board) variables.append(board_flag) - # if isfile('apio.ini'): - # print("APIO ini file") - # p.read() - # else: - # print("WRNING: APIO.INI file not found") - # -- Execute scons if isdir(scons_dir) and isdir(icestorm_dir): - print("Executing: scons -Q {}".format(variables)) - util.exec_command( + terminal_width, _ = click.get_terminal_size() + start_time = time.time() + + click.echo("[%s] Processing %s" % ( + datetime.datetime.now().strftime("%c"), + click.style(p.board, fg="cyan", bold=True))) + click.secho("-" * terminal_width, bold=True) + + click.secho("Executing: scons -Q {}".format(' '.join(variables))) + result = util.exec_command( [ os.path.normpath(sys.executable), os.path.join(scons_dir, 'scons'), @@ -99,11 +107,26 @@ def run(self, variables=[]): stderr=util.AsyncPipe(self._on_run_err) ) + # -- Print result + is_error = result['returncode'] != 0 + summary_text = " Took %.2f seconds " % (time.time() - start_time) + half_line = "=" * ((terminal_width - len(summary_text) - 10) / 2) + click.echo("%s [%s]%s%s" % ( + half_line, + (click.style(" ERROR ", fg="red", bold=True) + if is_error else click.style("SUCCESS", fg="green", bold=True)), + summary_text, + half_line + ), err=is_error) + def _on_run_out(self, line): - click.secho(line) + fg = 'green' if 'is up to date' in line else None + click.secho(line, fg=fg) def _on_run_err(self, line): - click.secho(line) + time.sleep(0.01) # Delay + fg = 'red' if 'error' in line.lower() else 'yellow' + click.secho(line, fg=fg) def create_sconstruct(self): sconstruct_name = 'SConstruct' @@ -111,18 +134,21 @@ def create_sconstruct(self): local_sconstruct_path = join(dirname(__file__), sconstruct_name) if isfile(sconstruct_path): - click.echo('Warning: ' + sconstruct_name + ' file already exists') - key = input('Do you want to replace it? [Y/N]: ') - if key == 'y' or key == 'Y': + click.secho('Warning: ' + sconstruct_name + ' file already exists', + fg='yellow') + if click.confirm('Do you want to replace it?'): self._copy_file(sconstruct_name, sconstruct_path, local_sconstruct_path) else: self._copy_file(sconstruct_name, sconstruct_path, local_sconstruct_path) - def _copy_file(self, sconstruct_name, sconstruct_path, - local_sconstruct_path): - click.echo('Creating ' + sconstruct_name + ' file') + def _copy_file(self, sconstruct_name, + sconstruct_path, local_sconstruct_path): + click.secho('Creating ' + sconstruct_name + ' file ...') with open(sconstruct_path, 'w') as sconstruct: with open(local_sconstruct_path, 'r') as local_sconstruct: sconstruct.write(local_sconstruct.read()) + click.secho( + 'File \'' + sconstruct_name + '\' has been successfully created!', + fg='green')