From f7b9092a2ac2540e8f50f52ede64141d6809e7db Mon Sep 17 00:00:00 2001 From: "Salvador E. Tropea" Date: Tue, 3 Jan 2023 10:04:44 -0300 Subject: [PATCH] Simplified the KiAuto use - Temporal video remove - Other temporals - Messages on execution error --- kibot/__init__.py | 2 +- kibot/gs.py | 32 ++++++++++++++++++++++++-- kibot/kiplot.py | 26 +++++---------------- kibot/out_any_pcb_print.py | 31 +++++++++---------------- kibot/out_any_sch_print.py | 31 ++++++++----------------- kibot/out_base.py | 46 +++++++++++++++++++++----------------- kibot/out_base_3d.py | 9 ++++++-- kibot/out_copy_files.py | 9 ++------ kibot/out_gencad.py | 24 +++++++------------- kibot/out_netlist.py | 26 +++++++-------------- kibot/out_panelize.py | 15 +++++-------- kibot/out_pcb_print.py | 21 +++++++---------- kibot/out_render_3d.py | 24 +++++--------------- kibot/out_step.py | 36 +++++------------------------ kibot/out_vrml.py | 20 +++++------------ kibot/pre_base.py | 25 +++++++++++++++++++-- kibot/pre_run_drc.py | 13 +++++------ kibot/pre_run_erc.py | 9 +++----- kibot/pre_update_xml.py | 23 +++++++------------ 19 files changed, 176 insertions(+), 246 deletions(-) diff --git a/kibot/__init__.py b/kibot/__init__.py index fa77d4a2..b6b2d509 100644 --- a/kibot/__init__.py +++ b/kibot/__init__.py @@ -1,5 +1,5 @@ __author__ = 'Salvador E. Tropea, John Beard' -__copyright__ = 'Copyright 2018-2022, Salvador E. Tropea/INTI/John Beard' +__copyright__ = 'Copyright 2018-2023, Salvador E. Tropea/INTI/John Beard' __credits__ = ['Salvador E. Tropea', 'John Beard'] __license__ = 'GPL v3+' __email__ = 'stropea@inti.gob.ar' diff --git a/kibot/gs.py b/kibot/gs.py index fba4257c..fb5942a0 100644 --- a/kibot/gs.py +++ b/kibot/gs.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2020-2022 Salvador E. Tropea -# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial +# Copyright (c) 2020-2023 Salvador E. Tropea +# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial # License: GPL-3.0 # Project: KiBot (formerly KiPlot) import os @@ -498,3 +498,31 @@ class GS(object): if shape == pcbnew.S_CIRCLE: return g.GetArcStart() return g.GetEnd() + + @staticmethod + def get_kiauto_video_name(cmd): + """ Compute the name for the video captured by KiAuto """ + command = os.path.basename(cmd[0])[:-3] + subcommand = next(filter(lambda x: x[0] != '-' and (not x[0].isdigit() or x[1] == 'd'), cmd[1:])) + if command == 'pcbnew': + return command+'_'+subcommand+'_screencast.ogv' + if command == 'eeschema': + return subcommand+'_'+command+'_screencast.ogv' + return command+'_screencast.ogv' + + @staticmethod + def add_extra_options(cmd): + is_gitlab_ci = 'GITLAB_CI' in os.environ + video_remove = (not GS.debug_enabled) and is_gitlab_ci + if GS.debug_enabled: + cmd.insert(1, '-'+'v'*GS.debug_level) + if GS.debug_enabled or is_gitlab_ci: + # Forcing record on GitLab CI/CD (black magic) + cmd.insert(1, '-r') + if GS.global_kiauto_time_out_scale: + cmd.insert(1, str(GS.global_kiauto_time_out_scale)) + cmd.insert(1, '--time_out_scale') + if GS.global_kiauto_wait_start: + cmd.insert(1, str(GS.global_kiauto_wait_start)) + cmd.insert(1, '--wait_start') + return cmd, video_remove diff --git a/kibot/kiplot.py b/kibot/kiplot.py index 671ae109..9074d964 100644 --- a/kibot/kiplot.py +++ b/kibot/kiplot.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2020-2022 Salvador E. Tropea -# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial +# Copyright (c) 2020-2023 Salvador E. Tropea +# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial # Copyright (c) 2018 John Beard # License: GPL-3.0 # Project: KiBot (formerly KiPlot) @@ -171,7 +171,7 @@ def run_command(command, change_to=None, just_raise=False, use_x11=False): return res.stdout.decode().rstrip() -def exec_with_retry(cmd): +def exec_with_retry(cmd, exit_with=None): cmd_str = shlex.join(cmd) logger.debug('Executing: '+cmd_str) if GS.debug_level > 2: @@ -191,26 +191,12 @@ def exec_with_retry(cmd): if 'Timed out' in err: logger.warning(W_TIMEOUT+'Time out detected, on slow machines or complex projects try:') logger.warning(W_TIMEOUT+'`kiauto_time_out_scale` and/or `kiauto_wait_start` global options') + if exit_with is not None and ret: + logger.error(cmd[0]+' returned %d', ret) + exit(exit_with) return ret -def add_extra_options(cmd): - is_gitlab_ci = 'GITLAB_CI' in os.environ - video_remove = (not GS.debug_enabled) and is_gitlab_ci - if GS.debug_enabled: - cmd.insert(1, '-'+'v'*GS.debug_level) - if GS.debug_enabled or is_gitlab_ci: - # Forcing record on GitLab CI/CD (black magic) - cmd.insert(1, '-r') - if GS.global_kiauto_time_out_scale: - cmd.insert(1, str(GS.global_kiauto_time_out_scale)) - cmd.insert(1, '--time_out_scale') - if GS.global_kiauto_wait_start: - cmd.insert(1, str(GS.global_kiauto_wait_start)) - cmd.insert(1, '--wait_start') - return cmd, video_remove - - def load_board(pcb_file=None, forced=False): if GS.board is not None and not forced: # Already loaded diff --git a/kibot/out_any_pcb_print.py b/kibot/out_any_pcb_print.py index d71a1648..2e1f8e4a 100644 --- a/kibot/out_any_pcb_print.py +++ b/kibot/out_any_pcb_print.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2020-2022 Salvador E. Tropea -# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial +# Copyright (c) 2020-2023 Salvador E. Tropea +# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial # License: GPL-3.0 # Project: KiBot (formerly KiPlot) import os -from shutil import rmtree from .pre_base import BasePreFlight from .gs import GS -from .kiplot import exec_with_retry, add_extra_options +from .kiplot import exec_with_retry from .misc import PDF_PCB_PRINT from .out_base import VariantOptions from .macros import macros, document, output_class # noqa: F401 @@ -56,14 +55,15 @@ class Any_PCB_PrintOptions(VariantOptions): def filter_components(self): if not self.will_filter_pcb_components() and self.title == '': - return GS.pcb_file, None + return GS.pcb_file self.filter_pcb_components() self.set_title(self.title) # Save the PCB to a temporal dir fname, pcb_dir = self.save_tmp_dir_board('pdf_pcb_print') self.restore_title() self.unfilter_pcb_components() - return fname, pcb_dir + self._files_to_remove.append(pcb_dir) + return fname def get_targets(self, out_dir): return [self._parent.expand_filename(out_dir, self.output)] @@ -88,26 +88,17 @@ class Any_PCB_PrintOptions(VariantOptions): cmd.extend(['--color_theme', self.color_theme]) if svg: cmd.append('--svg') - board_name, board_dir = self.filter_components() + board_name = self.filter_components() cmd.extend([board_name, os.path.dirname(output)]) - cmd, video_remove = add_extra_options(cmd) + # Add the extra options before the layers (so the output dir is the last option) + cmd = self.add_extra_options(cmd) # Add the layers cmd.extend([la.layer for la in self._layers]) if GS.ki6 and self.force_edge_cuts and not self.separated: cmd.append('Edge.Cuts') # Execute it - ret = exec_with_retry(cmd) - # Remove the temporal PCB - if board_dir: - logger.debug('Removing temporal variant dir `{}`'.format(board_dir)) - rmtree(board_dir) - if ret: - logger.error(command+' returned %d', ret) - exit(PDF_PCB_PRINT) - if video_remove: - video_name = os.path.join(self.expand_filename_pcb(GS.out_dir), 'pcbnew_export_screencast.ogv') - if os.path.isfile(video_name): - os.remove(video_name) + exec_with_retry(cmd, PDF_PCB_PRINT) + self.remove_temporals() def set_layers(self, layers): layers = Layer.solve(layers) diff --git a/kibot/out_any_sch_print.py b/kibot/out_any_sch_print.py index e2f26658..6998870e 100644 --- a/kibot/out_any_sch_print.py +++ b/kibot/out_any_sch_print.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2020-2022 Salvador E. Tropea -# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial +# Copyright (c) 2020-2023 Salvador E. Tropea +# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial # License: GPL-3.0 # Project: KiBot (formerly KiPlot) import os from tempfile import mkdtemp -from shutil import rmtree, copy2 +from shutil import copy2 from .gs import GS -from .kiplot import add_extra_options, exec_with_retry +from .kiplot import exec_with_retry from .out_base import VariantOptions from .kicad.config import KiConf from .macros import macros, document, output_class # noqa: F401 @@ -50,17 +50,15 @@ class Any_SCH_PrintOptions(VariantOptions): def run(self, name): super().run(name) - output_dir = os.path.dirname(name) - our_name = self._expand_ext+'_sch_print' command = self.ensure_tool('KiAuto') if self._comps: # Save it to a temporal dir - sch_dir = mkdtemp(prefix='tmp-kibot-'+our_name+'-') + sch_dir = mkdtemp(prefix='tmp-kibot-'+self._expand_ext+'_sch_print-') copy_project(sch_dir) fname = GS.sch.save_variant(sch_dir) sch_file = os.path.join(sch_dir, fname) + self._files_to_remove.append(sch_dir) else: - sch_dir = None sch_file = GS.sch_file cmd = [command, 'export', '--file_format', self._expand_ext, '-o', name] if self.monochrome: @@ -69,17 +67,6 @@ class Any_SCH_PrintOptions(VariantOptions): cmd.append('--no_frame') if self.all_pages: cmd.append('--all_pages') - cmd.extend([sch_file, output_dir]) - cmd, video_remove = add_extra_options(cmd) - ret = exec_with_retry(cmd) - if ret: - logger.error(command+' returned %d', ret) - exit(self._exit_error) - # Remove the temporal dir if needed - if sch_dir: - logger.debug('Removing temporal variant dir `{}`'.format(sch_dir)) - rmtree(sch_dir) - if video_remove: - video_name = os.path.join(output_dir, 'export_eeschema_screencast.ogv') - if os.path.isfile(video_name): - os.remove(video_name) + cmd.extend([sch_file, os.path.dirname(name)]) + exec_with_retry(self.add_extra_options(cmd), self._exit_error) + self.remove_temporals() diff --git a/kibot/out_base.py b/kibot/out_base.py index cfbc6755..8f633419 100644 --- a/kibot/out_base.py +++ b/kibot/out_base.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2020-2022 Salvador E. Tropea -# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial +# Copyright (c) 2020-2023 Salvador E. Tropea +# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial # License: GPL-3.0 # Project: KiBot (formerly KiPlot) from copy import deepcopy -from glob import glob import math import os import re +from shutil import rmtree from tempfile import NamedTemporaryFile, mkdtemp from .gs import GS from .kiplot import load_sch, get_board_comps_data @@ -650,6 +650,7 @@ class VariantOptions(BaseOptions): return with NamedTemporaryFile(mode='w', suffix='.wrl', delete=False) as f: self._highlight_3D_file = f.name + self._files_to_remove.append(f.name) logger.debug('Creating temporal highlight file '+f.name) f.write(HIGHLIGHT_3D_WRL) @@ -772,12 +773,6 @@ class VariantOptions(BaseOptions): if self._sub_pcb: self._sub_pcb.revert(self.comps_hash) - def remove_highlight_3D_file(self): - # Remove the highlight 3D file if it was created - if self._highlight_3D_file: - os.remove(self._highlight_3D_file) - self._highlight_3D_file = None - def set_title(self, title, sch=False): self.old_title = None if title: @@ -848,8 +843,7 @@ class VariantOptions(BaseOptions): else: m.SetValue(data) - @staticmethod - def save_tmp_board(dir=None): + def save_tmp_board(self, dir=None): """ Save the PCB to a temporal file. Advantage: all relative paths inside the file remains valid Disadvantage: the name of the file gets altered """ @@ -860,9 +854,10 @@ class VariantOptions(BaseOptions): logger.debug('Storing modified PCB to `{}`'.format(fname)) GS.board.Save(fname) GS.copy_project(fname) + self._files_to_remove.extend(GS.get_pcb_and_pro_names(fname)) return fname - def save_tmp_board_if_variant(self, to_remove, new_title='', dir=None, do_3D=False): + def save_tmp_board_if_variant(self, new_title='', dir=None, do_3D=False): """ If we have a variant apply it and save the PCB to a file """ if not self.will_filter_pcb_components() and not new_title: return GS.pcb_file @@ -872,7 +867,6 @@ class VariantOptions(BaseOptions): fname = self.save_tmp_board() self.restore_title() self.unfilter_pcb_components(do_3D=do_3D) - to_remove.extend(GS.get_pcb_and_pro_names(fname)) logger.debug('- Modified PCB: '+fname) return fname @@ -889,13 +883,6 @@ class VariantOptions(BaseOptions): KiConf.fix_page_layout(pro_name) return fname, pcb_dir - def remove_tmp_board(self, board_name): - # Remove the temporal PCB - if board_name != GS.pcb_file: - # KiCad likes to create project files ... - for f in glob(board_name.replace('.kicad_pcb', '.*')): - os.remove(f) - def solve_kf_filters(self, components): """ Solves references to KiBot filters in the list of components to show. They are not yet expanded, just solved to filter objects """ @@ -944,8 +931,27 @@ class VariantOptions(BaseOptions): new_list += ext_list return new_list + def remove_temporals(self): + logger.debug('Removing temporal files') + for f in self._files_to_remove: + if os.path.isfile(f): + logger.debug('- File `{}`'.format(f)) + os.remove(f) + elif os.path.isdir(f): + logger.debug('- Dir `{}`'.format(f)) + rmtree(f) + self._files_to_remove = [] + self._highlight_3D_file = None + + def add_extra_options(self, cmd, dir=None): + cmd, video_remove = GS.add_extra_options(cmd) + if video_remove: + self._files_to_remove.append(os.path.join(dir or cmd[-1], GS.get_kiauto_video_name(cmd))) + return cmd + def run(self, output_dir): """ Makes the list of components available """ + self._files_to_remove = [] if not self.dnf_filter and not self.variant and not self.pre_transform: return load_sch() diff --git a/kibot/out_base_3d.py b/kibot/out_base_3d.py index 9517fe3b..e0b933c8 100644 --- a/kibot/out_base_3d.py +++ b/kibot/out_base_3d.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2020-2022 Salvador E. Tropea -# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial +# Copyright (c) 2020-2023 Salvador E. Tropea +# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial # License: GPL-3.0 # Project: KiBot (formerly KiPlot) from fnmatch import fnmatch @@ -82,6 +82,7 @@ class Base3DOptions(VariantOptions): return None if self._tmp_dir is None: self._tmp_dir = tempfile.mkdtemp() + self._files_to_remove.append(self._tmp_dir) rel_dirs.append(self._tmp_dir) logger.debug('Using `{}` as temporal dir for downloaded files'.format(self._tmp_dir)) dest = os.path.join(self._tmp_dir, fname) @@ -210,6 +211,10 @@ class Base3DOptions(VariantOptions): def get_targets(self, out_dir): return [self._parent.expand_filename(out_dir, self.output)] + def remove_temporals(self): + super().remove_temporals() + self._tmp_dir = None + class Base3D(BaseOutput): def __init__(self): diff --git a/kibot/out_copy_files.py b/kibot/out_copy_files.py index 9b58d732..68cc621e 100644 --- a/kibot/out_copy_files.py +++ b/kibot/out_copy_files.py @@ -7,7 +7,7 @@ import fnmatch import glob import os import re -from shutil import copy2, rmtree +from shutil import copy2 from sys import exit from .error import KiPlotConfigurationError from .gs import GS @@ -197,15 +197,12 @@ class Copy_FilesOptions(Base3DOptions): dest = os.path.relpath(dest, d) break else: - logger.error(fname) - logger.error(self.rel_dirs) dest = os.path.basename(fname) if mode_3d_append: dest = os.path.join(f.dest[:-1], dest) else: dest = os.path.relpath(dest, src_dir) files.append((fname_real, dest)) - return files def get_targets(self, out_dir): @@ -242,9 +239,7 @@ class Copy_FilesOptions(Base3DOptions): copy2(src, dest) copied[dest] = src # Remove the downloaded 3D models - if self._tmp_dir: - rmtree(self._tmp_dir) - self._tmp_dir = None + self.remove_temporals() @output_class diff --git a/kibot/out_gencad.py b/kibot/out_gencad.py index 9b4cf078..c00b7429 100644 --- a/kibot/out_gencad.py +++ b/kibot/out_gencad.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2022 Salvador E. Tropea -# Copyright (c) 2022 Instituto Nacional de Tecnología Industrial +# Copyright (c) 2022-2023 Salvador E. Tropea +# Copyright (c) 2022-2023 Instituto Nacional de Tecnología Industrial # License: GPL-3.0 # Project: KiBot (formerly KiPlot) """ @@ -13,7 +13,7 @@ import os from .gs import GS from .out_base import VariantOptions from .misc import FAILED_EXECUTE -from .kiplot import exec_with_retry, add_extra_options +from .kiplot import exec_with_retry from .macros import macros, document, output_class # noqa: F401 from . import log @@ -46,9 +46,8 @@ class GenCADOptions(VariantOptions): def run(self, name): command = self.ensure_tool('KiAuto') super().run(name) - to_remove = [] - board_name = self.save_tmp_board_if_variant(to_remove) - # Output file name + board_name = self.save_tmp_board_if_variant() + # Create the command line cmd = [command, 'export_gencad', '--output_name', os.path.basename(name)] if self.flip_bottom_padstacks: cmd.append('--flip_bottom_padstacks') @@ -61,17 +60,10 @@ class GenCADOptions(VariantOptions): if self.save_origin: cmd.append('--save_origin') cmd.extend([board_name, os.path.dirname(name)]) - cmd, video_remove = add_extra_options(cmd) - if video_remove: - to_remove.append(os.path.join(self.expand_filename_pcb(GS.out_dir), 'pcbnew_export_gencad_screencast.ogv')) + cmd = self.add_extra_options(cmd) # Execute it - ret = exec_with_retry(cmd) - if ret: - logger.error(command+' returned %d', ret) - exit(FAILED_EXECUTE) - for f in to_remove: - if os.path.isfile(f): - os.remove(f) + exec_with_retry(cmd, FAILED_EXECUTE) + self.remove_temporals() @output_class diff --git a/kibot/out_netlist.py b/kibot/out_netlist.py index 7e67ddcb..807ba815 100644 --- a/kibot/out_netlist.py +++ b/kibot/out_netlist.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2022 Salvador E. Tropea -# Copyright (c) 2022 Instituto Nacional de Tecnología Industrial +# Copyright (c) 2022-2023 Salvador E. Tropea +# Copyright (c) 2022-2023 Instituto Nacional de Tecnología Industrial # License: GPL-3.0 # Project: KiBot (formerly KiPlot) """ @@ -14,7 +14,7 @@ import os from .gs import GS from .out_base import VariantOptions from .misc import FAILED_EXECUTE -from .kiplot import exec_with_retry, add_extra_options +from .kiplot import exec_with_retry from .macros import macros, document, output_class # noqa: F401 from . import log @@ -50,28 +50,18 @@ class NetlistOptions(VariantOptions): def run(self, name): command = self.ensure_tool('KiAuto') super().run(name) - to_remove = [] if self.format == 'ipc': command = command.replace('eeschema_do', 'pcbnew_do') subcommand = 'ipc_netlist' - file = self.save_tmp_board_if_variant(to_remove) + file = self.save_tmp_board_if_variant() else: subcommand = 'netlist' file = GS.sch_file - output_dir = os.path.dirname(name) - # Output file name - cmd = [command, subcommand, '--output_name', name, file, output_dir] - cmd, video_remove = add_extra_options(cmd) - if video_remove: - to_remove.append(os.path.join(self.expand_filename_pcb(GS.out_dir), command[:-3]+'_'+subcommand+'_screencast.ogv')) + # Create the command line + cmd = self.add_extra_options([command, subcommand, '--output_name', name, file, os.path.dirname(name)]) # Execute it - ret = exec_with_retry(cmd) - if ret: - logger.error(command+' returned %d', ret) - exit(FAILED_EXECUTE) - for f in to_remove: - if os.path.isfile(f): - os.remove(f) + exec_with_retry(cmd, FAILED_EXECUTE) + self.remove_temporals() @output_class diff --git a/kibot/out_panelize.py b/kibot/out_panelize.py index a6264423..4ff39c2a 100644 --- a/kibot/out_panelize.py +++ b/kibot/out_panelize.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2022 Salvador E. Tropea -# Copyright (c) 2022 Instituto Nacional de Tecnología Industrial +# Copyright (c) 2022-2023 Salvador E. Tropea +# Copyright (c) 2022-2023 Instituto Nacional de Tecnología Industrial # License: GPL-3.0 # Project: KiBot (formerly KiPlot) """ @@ -692,9 +692,7 @@ class PanelizeOptions(VariantOptions): if GS.ki5 and version >= (1, 1, 0): raise KiPlotConfigurationError("Installed KiKit doesn't support KiCad 5") super().run(output) - to_remove = [] - fname = self.save_tmp_board_if_variant(to_remove, new_title=self.title, do_3D=True) - + fname = self.save_tmp_board_if_variant(new_title=self.title, do_3D=True) # Create the command cmd = [cmd_kikit, 'panelize'] # , '--dump', 'test.json' # Add all the configurations @@ -706,7 +704,7 @@ class PanelizeOptions(VariantOptions): cmd.append(cfg) else: cfg_f = self.create_config(cfg) - to_remove.append(cfg_f) + self._files_to_remove.append(cfg_f) cmd.append(cfg_f) # Add the PCB and output cmd.append(fname) @@ -715,10 +713,7 @@ class PanelizeOptions(VariantOptions): run_command(cmd) self.create_preview_file(output) finally: - # Remove temporals - for f in to_remove: - if os.path.isfile(f): - os.remove(f) + self.remove_temporals() def get_targets(self, out_dir): pcb_name = self._parent.expand_filename(out_dir, self.output) diff --git a/kibot/out_pcb_print.py b/kibot/out_pcb_print.py index dd382587..7336e223 100644 --- a/kibot/out_pcb_print.py +++ b/kibot/out_pcb_print.py @@ -46,7 +46,7 @@ from .kicad.config import KiConf from .kicad.v5_sch import SchError from .kicad.pcb import PCB from .misc import PDF_PCB_PRINT, W_PDMASKFAIL, KICAD5_SVG_SCALE, W_MISSTOOL, PCBDRAW_ERR, W_PCBDRAW -from .kiplot import exec_with_retry, add_extra_options +from .kiplot import exec_with_retry from .create_pdf import create_pdf_from_pages from .macros import macros, document, output_class # noqa: F401 from .drill_marks import DRILL_MARKS_MAP, add_drill_marks @@ -473,28 +473,23 @@ class PCB_PrintOptions(VariantOptions): # Move all the drawings away # KiCad 5 always prints Edge.Cuts, so we make it empty self.clear_layer(layer) + # Start with a fresh list of files to remove + cur_files_to_remove = self._files_to_remove + self._files_to_remove = [] # Save the PCB pcb_name, pcb_dir = self.save_tmp_dir_board('pcb_print') + self._files_to_remove.append(pcb_dir) # Restore the layer self.restore_layer() # Output file name cmd = [command, 'export', '--output_name', output, '--monochrome', '--svg', '--pads', '0', pcb_name, dir_name, layer] - cmd, video_remove = add_extra_options(cmd) # Execute it - ret = exec_with_retry(cmd) - # Remove the temporal PCB - logger.debug('Removing temporal PCB used for frame `{}`'.format(pcb_dir)) - rmtree(pcb_dir) - if ret: - logger.error(command+' returned %d', ret) - exit(PDF_PCB_PRINT) - if video_remove: - video_name = os.path.join(self.expand_filename_pcb(GS.out_dir), 'pcbnew_export_screencast.ogv') - if os.path.isfile(video_name): - os.remove(video_name) + exec_with_retry(self.add_extra_options(cmd, dir_name), PDF_PCB_PRINT) # Rotate the paper size if needed and remove the background (or it will be over the drawings) patch_svg_file(output, remove_bkg=True, is_portrait=self.paper_portrait) + self.remove_temporals() + self._files_to_remove = cur_files_to_remove def plot_pads(self, la, pc, p, filelist): id = la._id diff --git a/kibot/out_render_3d.py b/kibot/out_render_3d.py index 23a5780e..65b58847 100644 --- a/kibot/out_render_3d.py +++ b/kibot/out_render_3d.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2021-2022 Salvador E. Tropea -# Copyright (c) 2021-2022 Instituto Nacional de Tecnología Industrial +# Copyright (c) 2021-2023 Salvador E. Tropea +# Copyright (c) 2021-2023 Instituto Nacional de Tecnología Industrial # License: GPL-3.0 # Project: KiBot (formerly KiPlot) # KiCad 6/6.0.1 bug: https://gitlab.com/kicad/code/kicad/-/issues/9890 @@ -14,12 +14,11 @@ Dependencies: """ import os import shlex -from shutil import rmtree import subprocess from .misc import (RENDER_3D_ERR, PCB_MAT_COLORS, PCB_FINISH_COLORS, SOLDER_COLORS, SILK_COLORS, KICAD_VERSION_6_0_2, MISSING_TOOL) from .gs import GS -from .kiplot import exec_with_retry, add_extra_options, load_sch, get_board_comps_data +from .kiplot import exec_with_retry, load_sch, get_board_comps_data from .optionable import Optionable from .out_base_3d import Base3DOptions, Base3D from .macros import macros, document, output_class # noqa: F401 @@ -301,22 +300,9 @@ class Render3DOptions(Base3DOptions): board_name = self.filter_components(highlight=set(self.expand_kf_components(self.highlight))) self.undo_show_components() cmd.extend([board_name, os.path.dirname(output)]) - cmd, video_remove = add_extra_options(cmd) # Execute it - ret = exec_with_retry(cmd) - # Remove the temporal PCB - self.remove_tmp_board(board_name) - self.remove_highlight_3D_file() - # Remove the downloaded 3D models - if self._tmp_dir: - rmtree(self._tmp_dir) - if ret: - logger.error(command+' returned %d', ret) - exit(RENDER_3D_ERR) - if video_remove: - video_name = os.path.join(self.expand_filename_pcb(GS.out_dir), 'pcbnew_3d_view_screencast.ogv') - if os.path.isfile(video_name): - os.remove(video_name) + exec_with_retry(self.add_extra_options(cmd), RENDER_3D_ERR) + self.remove_temporals() if self.auto_crop: _run_command([convert_command, output, '-trim', '+repage', '-trim', '+repage', output]) if self.transparent_background: diff --git a/kibot/out_step.py b/kibot/out_step.py index 1e4b43fd..a48a2c29 100644 --- a/kibot/out_step.py +++ b/kibot/out_step.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2020-2022 Salvador E. Tropea -# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial +# Copyright (c) 2020-2023 Salvador E. Tropea +# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial # License: GPL-3.0 # Project: KiBot (formerly KiPlot) # KiCad 6 bug: https://gitlab.com/kicad/code/kicad/-/issues/10075 @@ -13,14 +13,11 @@ Dependencies: """ import os import re -import shlex -from subprocess import check_output, STDOUT, CalledProcessError -from shutil import rmtree from .error import KiPlotConfigurationError from .misc import KICAD2STEP_ERR from .gs import GS from .out_base_3d import Base3DOptions, Base3D -from .kiplot import add_extra_options +from .kiplot import exec_with_retry from .macros import macros, document, output_class # noqa: F401 from . import log @@ -87,30 +84,9 @@ class STEPOptions(Base3DOptions): # The board board_name = self.filter_components() cmd.append(board_name) - cmd, video_remove = add_extra_options(cmd) - # Execute and inform is successful - logger.debug('Executing: '+shlex.join(cmd)) - # Ensure KIPRJMOD is correct: - # KiCad sets KIPRJMOD each time we call BOARD.Save() but then Python `os.environ` becomes unsynchronized - # We don't even know the actual value and any call to Save could destroy it - os.environ['KIPRJMOD'] = os.path.dirname(board_name) - try: - cmd_output = check_output(cmd, stderr=STDOUT) - except CalledProcessError as e: - logger.error('Failed to create Step file, error %d', e.returncode) - if e.output: - logger.debug('Output from command: '+e.output.decode()) - exit(KICAD2STEP_ERR) - finally: - self.remove_tmp_board(board_name) - # Remove the downloaded 3D models - if self._tmp_dir: - rmtree(self._tmp_dir) - if video_remove: - video_name = os.path.join(self.expand_filename_pcb(GS.out_dir), 'kicad2step_screencast.ogv') - if os.path.isfile(video_name): - os.remove(video_name) - logger.debug('Output from command:\n'+cmd_output.decode()) + # Execute it + exec_with_retry(self.add_extra_options(cmd, os.path.dirname(output)), KICAD2STEP_ERR) + self.remove_temporals() @output_class diff --git a/kibot/out_vrml.py b/kibot/out_vrml.py index 4fddfa72..1066e2ad 100644 --- a/kibot/out_vrml.py +++ b/kibot/out_vrml.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2022 Salvador E. Tropea -# Copyright (c) 2022 Instituto Nacional de Tecnología Industrial +# Copyright (c) 2022-2023 Salvador E. Tropea +# Copyright (c) 2022-2023 Instituto Nacional de Tecnología Industrial # License: GPL-3.0 # Project: KiBot (formerly KiPlot) """ @@ -13,7 +13,7 @@ import os from .gs import GS from .out_base_3d import Base3DOptions, Base3D from .misc import FAILED_EXECUTE -from .kiplot import exec_with_retry, add_extra_options +from .kiplot import exec_with_retry from .macros import macros, document, output_class # noqa: F401 from . import log @@ -75,19 +75,9 @@ class VRMLOptions(Base3DOptions): units = self.ref_units cmd.extend(['-x', str(x), '-y', str(x), '-u', units]) cmd.extend([board_name, os.path.dirname(name)]) - cmd, video_remove = add_extra_options(cmd) # Execute it - try: - ret = exec_with_retry(cmd) - finally: - self.remove_tmp_board(board_name) - if ret: - logger.error(command+' returned %d', ret) - exit(FAILED_EXECUTE) - if video_remove: - video_name = os.path.join(self.expand_filename_pcb(GS.out_dir), 'pcbnew_export_vrml_screencast.ogv') - if os.path.isfile(video_name): - os.remove(video_name) + exec_with_retry(self.add_extra_options(cmd), FAILED_EXECUTE) + self.remove_temporals() @output_class diff --git a/kibot/pre_base.py b/kibot/pre_base.py index 1e44fff7..115f71cc 100644 --- a/kibot/pre_base.py +++ b/kibot/pre_base.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2020-2022 Salvador E. Tropea -# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial +# Copyright (c) 2020-2023 Salvador E. Tropea +# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial # License: GPL-3.0 # Project: KiBot (formerly KiPlot) +import os +from shutil import rmtree from .gs import GS from .registrable import Registrable from .optionable import Optionable @@ -28,6 +30,7 @@ class BasePreFlight(Registrable): self._enabled = True self._expand_id = '' self._expand_ext = '' + self._files_to_remove = [] @staticmethod def add_preflight(o_pre): @@ -162,3 +165,21 @@ class BasePreFlight(Registrable): def check_tool(self, name): """ Looks for a dependency """ return GS.check_tool_dep(self._name, name, fatal=False) + + def add_extra_options(self, cmd, dir=None): + """ KiAuto extra options (debug, record, etc.) """ + cmd, video_remove = GS.add_extra_options(cmd) + if video_remove: + self._files_to_remove.append(os.path.join(dir or cmd[-1], GS.get_kiauto_video_name(cmd))) + return cmd + + def remove_temporals(self): + logger.debug('Removing temporal files') + for f in self._files_to_remove: + if os.path.isfile(f): + logger.debug('- File `{}`'.format(f)) + os.remove(f) + elif os.path.isdir(f): + logger.debug('- Dir `{}`'.format(f)) + rmtree(f) + self._files_to_remove = [] diff --git a/kibot/pre_run_drc.py b/kibot/pre_run_drc.py index db2ba33f..11a4d3a2 100644 --- a/kibot/pre_run_drc.py +++ b/kibot/pre_run_drc.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2020-2022 Salvador E. Tropea -# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial +# Copyright (c) 2020-2023 Salvador E. Tropea +# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial # License: GPL-3.0 # Project: KiBot (formerly KiPlot) """ @@ -15,7 +15,7 @@ from .macros import macros, pre_class # noqa: F401 from .error import KiPlotConfigurationError from .gs import GS from .optionable import Optionable -from .kiplot import exec_with_retry, load_board, add_extra_options +from .kiplot import exec_with_retry, load_board from .misc import DRC_ERROR from .log import get_logger @@ -61,13 +61,10 @@ class Run_DRC(BasePreFlight): # noqa: F821 cmd.append('-i') cmd.extend([GS.pcb_file, self.expand_dirname(GS.out_dir)]) # If we are in verbose mode enable debug in the child - cmd, video_remove = add_extra_options(cmd) + cmd = self.add_extra_options(cmd) logger.info('- Running the DRC') ret = exec_with_retry(cmd) - if video_remove: - video_name = os.path.join(self.expand_dirname(GS.out_dir), 'pcbnew_run_drc_screencast.ogv') - if os.path.isfile(video_name): - os.remove(video_name) + self.remove_temporals() if ret: if ret > 127: ret = -(256-ret) diff --git a/kibot/pre_run_erc.py b/kibot/pre_run_erc.py index 2d0c75fd..e2580a4c 100644 --- a/kibot/pre_run_erc.py +++ b/kibot/pre_run_erc.py @@ -15,7 +15,7 @@ from sys import exit from .macros import macros, pre_class # noqa: F401 from .gs import GS from .optionable import Optionable -from .kiplot import exec_with_retry, load_sch, add_extra_options +from .kiplot import exec_with_retry, load_sch from .error import KiPlotConfigurationError from .misc import ERC_ERROR from .log import get_logger @@ -60,13 +60,10 @@ class Run_ERC(BasePreFlight): # noqa: F821 cmd.extend(['-f', GS.filter_file]) cmd.extend([GS.sch_file, self.expand_dirname(GS.out_dir)]) # If we are in verbose mode enable debug in the child - cmd, video_remove = add_extra_options(cmd) + cmd = self.add_extra_options(cmd) logger.info('- Running the ERC') ret = exec_with_retry(cmd) - if video_remove: - video_name = os.path.join(self.expand_dirname(GS.out_dir), 'run_erc_eeschema_screencast.ogv') - if os.path.isfile(video_name): - os.remove(video_name) + self.remove_temporals() if ret: if ret > 127: ret = -(256-ret) diff --git a/kibot/pre_update_xml.py b/kibot/pre_update_xml.py index 2151a361..f78537b0 100644 --- a/kibot/pre_update_xml.py +++ b/kibot/pre_update_xml.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2020-2022 Salvador E. Tropea -# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial +# Copyright (c) 2020-2023 Salvador E. Tropea +# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial # License: GPL-3.0 # Project: KiBot (formerly KiPlot) """ @@ -16,7 +16,7 @@ import xml.etree.ElementTree as ET from .macros import macros, document, pre_class # noqa: F401 from .error import KiPlotConfigurationError from .gs import GS -from .kiplot import exec_with_retry, add_extra_options, load_board +from .kiplot import exec_with_retry, load_board from .misc import BOM_ERROR, NETLIST_DIFF, W_PARITY, MISSING_TOOL from .log import get_logger from .optionable import Optionable @@ -170,21 +170,14 @@ class Update_XML(BasePreFlight): # noqa: F821 out_dir = self.expand_dirname(GS.out_dir) cmd = [command, 'bom_xml', GS.sch_file, out_dir] # If we are in verbose mode enable debug in the child - cmd, video_remove = add_extra_options(cmd) + cmd = self.add_extra_options(cmd) # While creating the XML we run a BoM plug-in that creates a useless BoM # We remove it, unless this is already there side_effect_file = os.path.join(out_dir, GS.sch_basename+'.csv') - remove_side_effect_file = not os.path.isfile(side_effect_file) + if not os.path.isfile(side_effect_file): + self._files_to_remove.append(side_effect_file) logger.info('- Updating BoM in XML format') - ret = exec_with_retry(cmd) - if remove_side_effect_file and os.path.isfile(side_effect_file): - os.remove(side_effect_file) - if ret: - logger.error('Failed to update the BoM, error %d', ret) - exit(BOM_ERROR) - if video_remove: - video_name = os.path.join(self.expand_dirname(GS.out_dir), 'bom_xml_eeschema_screencast.ogv') - if os.path.isfile(video_name): - os.remove(video_name) + exec_with_retry(cmd, BOM_ERROR) + self.remove_temporals() if self._check_pcb_parity: self.check_pcb_parity()