#!/usr/bin/python3 # ########################################################################## # Copyright 2020 # ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> # P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ########################################################################## # ########################################################################## # Author: Pieter Donker # Purpose: run vhdl_style_fix.py on all files in the hdl dir using multiple # workers # Description: # -p: number of workers to use # -v: verbose # usage: # cd git/hdl/ # . ./init_hdl.sh # vhdl_style_fix_all_files.py -p 4 # # ########################################################################## from os import getenv, path from sys import exit, version_info from time import sleep from argparse import ArgumentParser, RawTextHelpFormatter from textwrap import dedent from subprocess import Popen, PIPE from multiprocessing import Process, Queue from queue import Empty PYTHON_VERSION = version_info[0] def run_cmd(cmd): """ run_cmd() run 'cmd' in a terminal and return response cmd: command to execute in terminal return: 'stdout' or 'Error, stderr' in case of a error """ proc = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) _stdout, _stderr = proc.communicate() if _stderr: stderr = _stderr.decode('utf - 8') if PYTHON_VERSION == 3 else _stderr print(stderr) return 'Error, {}'.format(stderr) stdout = _stdout.decode('utf - 8') if PYTHON_VERSION == 3 else _stdout return stdout class Worker(Process): """ Worker, used for file checking before giving it to vsg to fix. generated files and files with inside message 'DO NOT EDIT' are skipped. """ def __init__(self, id, control, in_data, out_data, verbose=None): Process.__init__(self) self.id = id self.control = control self.in_data = in_data self.out_data = out_data self.verbose = False if verbose is None else verbose self.stop = False def is_generated(self, filename): """ Look if 'generated' is found in the pathname. Return the skip message and return True if found, else False """ if "generated" in filename: response = f"skip {filename}: (generated file)" self.out_data.put(response) return True return False def is_do_not_edit(self, filename): """ Look if 'DO NOT EDIT' is found inside the file. Return the skip message and return True if found, else False """ with open(filename, 'r') as fd: data = fd.read() if "DO NOT EDIT" in data: response = f"skip {filename}: (DO NOT EDIT)" self.out_data.put(response) return True return False def run_fix(self, filename): """ Use vhdl_style_fix.py to fix the file """ basedir = getenv("HDL_WORK") fixtool = path.join(basedir, "tools", "vhdl_style_fix.py") cmd = f"{fixtool} {filename}" if self.verbose: cmd += " --verbose" response = run_cmd(cmd) self.out_data.put(response.strip()) def run(self): while not self.stop: try: if not self.control.empty(): control = self.control.get() if control == "stop": self.stop = True print(f"stop worker {self.id}") # get next vhd file to process filename = self.in_data.get(block=False) # look if generated is part of the full-filename, skip if found if self.is_generated(filename): continue # look if inside the file is a DO NOT EDIT message, skip if found if self.is_do_not_edit(filename): continue # fix the vhd file with vsg self.run_fix(filename) except Empty: sleep(0.001) def main(): basedir = getenv("HDL_WORK") print(f"basedir = {basedir}") # dirs in basedir to check/fix checkdirs = ["/libraries/base/", "/libraries/dsp/", "/libraries/io/", "/libraries/technology/", "/boards/", "/applications/"] # info for the workers, number of workers to use is given by cmdline arg --proc n_workers = args.proc workers = [] worker_control = [Queue() for i in range(n_workers)] process_queue = Queue() response_queue = Queue() n_files = 0 n_files_done = 0 # start the workers for id in range(n_workers): if args.verbose: print(f"start vsg worker {id}") _p = Worker(id, worker_control[id], process_queue, response_queue) workers.append(_p) _p.start() # put all vhd files in the for checkdir in checkdirs: dirname = basedir + checkdir if args.verbose: print(f"dirname = {dirname}") cmd = f'find {dirname} -name "*vhd"' response = run_cmd(cmd) for filename in response.splitlines(): process_queue.put(filename) n_files += 1 if args.verbose: print(f"put {n_files} in the worker queue") fd = open("vhdl_fix_all_response.txt", 'w') while True: if response_queue.empty(): sleep(0.001) else: response = response_queue.get() if response: fd.write(response + '\n') fd.flush() if args.verbose: print(response) n_files_done += 1 if n_files == n_files_done: if args.verbose: print("All files processed, stop workers now") for nr in range(n_workers): worker_control[nr].put("stop") sleep(0.5) for worker in workers: worker.terminate() break fd.close() return 0 if __name__ == "__main__": # Parse command line arguments parser = ArgumentParser( description="".join(dedent(""" run vhdl-style-guide on all found hdl files with settings from vsg_config.yaml: with --proc the number of vsg workers can be selected, output from this script is put in 'vsg_fix_all_response.txt' and send to stdout if --verbose is used. \n""")), formatter_class=RawTextHelpFormatter) parser.add_argument('-p', '--proc', type=int, default=4, help="number of processes to use") parser.add_argument('-v', '--verbose', action='store_true', help="verbose output") args = parser.parse_args() exit_code = main() exit(exit_code)