Moved SCH/PCB replace common code to a base class

- Also added the missing file (oops!)
This commit is contained in:
Salvador E. Tropea 2021-12-03 17:55:20 -03:00
parent 72d60e5034
commit a404444e39
3 changed files with 185 additions and 93 deletions

115
kibot/pre_any_replace.py Normal file
View File

@ -0,0 +1,115 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021 Salvador E. Tropea
# Copyright (c) 2021 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
import os
import re
import sys
from subprocess import run, PIPE
from .error import KiPlotConfigurationError
from .misc import FAILED_EXECUTE, W_EMPTREP, W_BADCHARS
from .optionable import Optionable
from .pre_base import BasePreFlight
from .macros import macros, document, pre_class # noqa: F401
from . import log
logger = log.get_logger()
class TagReplaceBase(Optionable):
""" Tags to be replaced """
def __init__(self):
super().__init__()
self._unkown_is_error = True
with document:
self.tag = ''
""" Name of the tag to replace. Use `version` for a tag named `@version@` """
self.tag_delimiter = '@'
""" Character used to indicate the beginning and the end of a tag.
Don't change it unless you really know about KiCad's file formats """
self.text = ''
""" Text to insert instead of the tag """
self.command = ''
""" Command to execute to get the text, will be used only if `text` is empty """
self.before = ''
""" Text to add before the output of `command` """
self.after = ''
""" Text to add after the output of `command` """
self._relax_check = False
def config(self, parent):
super().config(parent)
if not self.tag:
raise KiPlotConfigurationError("No tag to replace specified ({})".format(str(self._tree)))
self.tag = self.tag_delimiter + re.escape(self.tag) + self.tag_delimiter
class Base_ReplaceOptions(Optionable):
""" PCB/SCH replacement options """
def __init__(self):
super().__init__()
with document:
self.date_command = ''
""" Command to get the date to use in the schematic.
git log -1 --format='%as' -- $KIBOT_PCB_NAME
Will return the date in YYYY-MM-DD format.
date -d @`git log -1 --format='%at' -- $KIBOT_PCB_NAME` +%Y-%m-%d_%H-%M-%S
Will return the date in YYYY-MM-DD_HH-MM-SS format """
self.replace_tags = TagReplaceBase
""" [dict|list(dict)] Tag or tags to replace """
def config(self, parent):
super().config(parent)
if isinstance(self.replace_tags, type):
self.replace_tags = []
elif isinstance(self.replace_tags, TagReplaceBase):
self.replace_tags = [self.replace_tags]
class Base_Replace(BasePreFlight): # noqa: F821
""" [dict] Replaces tags in the PCB/schematic. I.e. to insert the git hash or last revision date """
def __init__(self, name, value):
super().__init__(name, value)
self._context = '' # PCB/SCH
@classmethod
def get_example(cls):
""" Returns a YAML value for the example config """
return ("\n date_command: \"git log -1 --format='%as' -- $KIBOT_{}_NAME\""
"\n replace_tags:"
"\n - tag: '@git_hash@'"
"\n command: 'git log -1 --format=\"%h\" $KIBOT_{}_NAME'"
"\n before: 'Git hash: <'"
"\n after: '>'\n".format(cls._context, cls._context))
def replace(self, file):
logger.debug('Applying replacements to `{}`'.format(file))
with open(file, 'rt') as f:
content = f.read()
os.environ['KIBOT_' + type(self)._context + '_NAME'] = file
o = self._value
for r in o.replace_tags:
text = r.text
if not text:
cmd = ['/bin/bash', '-c', r.command]
result = run(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
if result.returncode:
logger.error('Failed to execute:\n{}\nreturn code {}'.format(r.command, result.returncode))
sys.exit(FAILED_EXECUTE)
if not result.stdout:
logger.warning(W_EMPTREP+"Empty value from `{}` skipping it".format(r.command))
continue
text = result.stdout.strip()
text = r.before + text + r.after
if not r._relax_check:
new_text = re.sub(r'["\\\\\s]', '_', text)
if new_text != text:
logger.warning(W_BADCHARS+"Replace text can't contain double quotes, backslashes or white spaces ({})".
format(text))
text = new_text
logger.debug('- ' + r.tag + ' -> ' + text)
content = re.sub(r.tag, text, content, flags=re.MULTILINE)
os.rename(file, file + '-bak')
with open(file, 'wt') as f:
f.write(content)

56
kibot/pre_pcb_replace.py Normal file
View File

@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021 Salvador E. Tropea
# Copyright (c) 2021 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
from .gs import GS
from .pre_any_replace import TagReplaceBase, Base_ReplaceOptions, Base_Replace
from .macros import macros, document, pre_class # noqa: F401
from . import log
logger = log.get_logger()
class TagReplacePCB(TagReplaceBase):
""" Tags to be replaced for an PCB """
def __init__(self):
super().__init__()
self._help_command += ".\nKIBOT_PCB_NAME variable is the name of the current PCB"
class PCB_ReplaceOptions(Base_ReplaceOptions):
""" PCB replacement options """
def __init__(self):
super().__init__()
self.replace_tags = TagReplacePCB
@pre_class
class PCB_Replace(Base_Replace): # noqa: F821
""" [dict] Replaces tags in the schematic. I.e. to insert the git hash or last revision date """
_context = 'PCB'
def __init__(self, name, value):
o = PCB_ReplaceOptions()
o.set_tree(value)
o.config(self)
super().__init__(name, o)
@classmethod
def get_doc(cls):
return cls.__doc__, PCB_ReplaceOptions
def apply(self):
o = self._value
if o.date_command:
# Convert it into another replacement
t = TagReplacePCB()
t.tag = r'^ \(date (\S+|"(?:[^"]|\\")+")\)$'
t.command = o.date_command
t.before = ' (date "'
t.after = '")'
t._relax_check = True
o.replace_tags.append(t)
self.replace(GS.pcb_file)
# Force the schematic reload
GS.board = None

View File

@ -4,130 +4,51 @@
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
import os
import re
import sys
from subprocess import run, PIPE
from .gs import GS
from .error import KiPlotConfigurationError
from .optionable import Optionable
from .kiplot import load_sch
from .misc import W_EMPTREP, FAILED_EXECUTE, W_BADCHARS
from .pre_any_replace import TagReplaceBase, Base_ReplaceOptions, Base_Replace
from .macros import macros, document, pre_class # noqa: F401
from . import log
logger = log.get_logger()
class TagReplace(Optionable):
""" Tags to be replaced """
class TagReplaceSCH(TagReplaceBase):
""" Tags to be replaced for an SCH """
def __init__(self):
super().__init__()
self._unkown_is_error = True
with document:
self.tag = ''
""" Name of the tag to replace. Use `version` for a tag named `@version@` """
self.tag_delimiter = '@'
""" Character used to indicate the beginning and the end of a tag.
Don't change it unless you really know about KiCad's file formats """
self.text = ''
""" Text to insert instead of the tag """
self.command = ''
""" Command to execute to get the text, will be used only if `text` is empty.
KIBOT_SCH_NAME variable is the name of the current sheet.
KIBOT_TOP_SCH_NAME variable is the name of the top sheet """
self.before = ''
""" Text to add before the output of `command` """
self.after = ''
""" Text to add after the output of `command` """
self._relax_check = False
def config(self, parent):
super().config(parent)
if not self.tag:
raise KiPlotConfigurationError("No tag to replace specified ({})".format(str(self._tree)))
self.tag = self.tag_delimiter + re.escape(self.tag) + self.tag_delimiter
self._help_command += (".\nKIBOT_SCH_NAME variable is the name of the current sheet."
"\nKIBOT_TOP_SCH_NAME variable is the name of the top sheet")
class SCH_ReplaceOptions(Optionable):
""" A list of filter entries """
class SCH_ReplaceOptions(Base_ReplaceOptions):
""" SCH replacement options """
def __init__(self):
super().__init__()
with document:
self.date_command = ''
""" Command to get the date to use in the schematic.
git log -1 --format='%as' -- $KIBOT_SCH_NAME
Will return the date in YYYY-MM-DD format.
date -d @`git log -1 --format='%at' -- $KIBOT_SCH_NAME` +%Y-%m-%d_%H-%M-%S
Will return the date in YYYY-MM-DD_HH-MM-SS format """
self.replace_tags = TagReplace
""" [dict|list(dict)] Tag or tags to replace """
def config(self, parent):
super().config(parent)
if isinstance(self.replace_tags, type):
self.replace_tags = []
elif isinstance(self.replace_tags, TagReplace):
self.replace_tags = [self.replace_tags]
self._help_date_command = self._help_date_command.replace('PCB', 'SCH')
self.replace_tags = TagReplaceSCH
@pre_class
class SCH_Replace(BasePreFlight): # noqa: F821
class SCH_Replace(Base_Replace): # noqa: F821
""" [dict] Replaces tags in the schematic. I.e. to insert the git hash or last revision date """
_context = 'SCH'
def __init__(self, name, value):
o = SCH_ReplaceOptions()
o.set_tree(value)
o.config(self)
super().__init__(name, o)
def get_example():
""" Returns a YAML value for the example config """
return ("\n date_command: \"git log -1 --format='%as' -- $KIBOT_SCH_NAME\""
"\n replace_tags:"
"\n - tag: '@git_hash@'"
"\n command: 'git log -1 --format=\"%h\" $KIBOT_SCH_NAME'"
"\n before: 'Git hash: <'"
"\n after: '>'\n")
@classmethod
def get_doc(cls):
return cls.__doc__, SCH_ReplaceOptions
def replace_in_sch(self, file):
logger.debug('Applying replacements to `{}`'.format(file))
with open(file, 'rt') as f:
content = f.read()
os.environ['KIBOT_SCH_NAME'] = file
o = self._value
for r in o.replace_tags:
text = r.text
if not text:
cmd = ['/bin/bash', '-c', r.command]
result = run(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
if result.returncode:
logger.error('Failed to execute:\n{}\nreturn code {}'.format(r.command, result.returncode))
sys.exit(FAILED_EXECUTE)
if not result.stdout:
logger.warning(W_EMPTREP+"Empty value from `{}` skipping it".format(r.command))
continue
text = result.stdout.strip()
text = r.before + text + r.after
if not r._relax_check:
new_text = re.sub(r'["\\\\\s]', '_', text)
if new_text != text:
logger.warning(W_BADCHARS+"Replace text can't contain double quotes, backslashes or white spaces ({})".
format(text))
text = new_text
logger.debug('- ' + r.tag + ' -> ' + text)
content = re.sub(r.tag, text, content, flags=re.MULTILINE)
os.rename(file, file + '-bak')
with open(file, 'wt') as f:
f.write(content)
def apply(self):
o = self._value
if o.date_command:
# Convert it into another replacement
t = TagReplace()
t = TagReplaceSCH()
t.tag = '^Date \"(.*)\"$'
t.command = o.date_command
t.before = 'Date "'
@ -137,6 +58,6 @@ class SCH_Replace(BasePreFlight): # noqa: F821
load_sch()
os.environ['KIBOT_TOP_SCH_NAME'] = GS.sch_file
for file in GS.sch.get_files():
self.replace_in_sch(file)
self.replace(file)
# Force the schematic reload
GS.sch = None