rougail-output-doc/src/rougail/output_doc/changelog.py

191 lines
8.3 KiB
Python

"""
Silique (https://www.silique.fr)
Copyright (C) 2025
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from pathlib import Path
from json import loads
from .config import OutPuts
from .i18n import _
from .utils import calc_path
class Changelog: # pylint: disable=no-member,too-few-public-methods
"""Build changelog"""
def gen_doc_changelog(self):
"""Return changelog"""
self.level = self.rougailconfig["doc.title_level"]
self.previous_json_file = self.rougailconfig["doc.previous_json_file"]
with Path(self.previous_json_file).open() as outfh:
previous_doc = loads(outfh.read())
self.load()
self._added_variables = []
self._modified_variables = []
self._removed_variables = []
root = self.rougailconfig["doc.root"]
if root:
informations = self.informations
for family in root.split('.'):
informations = informations[family]["children"]
if previous_doc and family in previous_doc:
previous_doc = previous_doc[family]['children']
else:
previous_doc = {}
else:
informations = self.informations
self.formatter.options()
self.parser(previous_doc, informations)
return self.display()
def parser(self, previous_families, new_families):
done = []
for element in list(previous_families) + list(new_families):
if element in done:
continue
done.append(element)
previous = previous_families.get(element)
new = new_families.get(element)
if not previous:
if new["type"] == "variable":
self._added_variables.append(new)
else:
self.parser({}, new["children"])
elif not new:
if previous["type"] == "variable":
if "identifiers" in previous:
for identifiers in previous["identifiers"]:
self._removed_variables.append(calc_path(previous["path"], self.formatter, identifiers))
else:
self._removed_variables.append(calc_path(previous["path"], self.formatter))
else:
self.parser(previous["children"], {})
elif previous["type"] != new["type"]:
if previous["type"] == "variable":
if "identifiers" in previous:
for identifiers in previous["identifiers"]:
self._removed_variables.append(calc_path(previous["path"], self.formatter, identifiers))
else:
self._removed_variables.append(calc_path(previous["path"], self.formatter))
self.parser({}, new["children"])
else:
self._added_variables.append(new)
self.parser(previous["children"], {})
elif previous["type"] != "variable":
self.parser(previous["children"], new["children"])
else:
modified_attributes = {}
for prop in set(previous) | set(new):
prop_previous = previous.get(prop, [])
prop_new = new.get(prop, [])
if prop_previous != prop_new:
name = None
if (
isinstance(prop_previous, dict)
and "values" in prop_previous
):
name = prop_previous["name"]
local_prop_previous = prop_previous = prop_previous[
"values"
]
if not isinstance(prop_previous, list):
if prop == "default":
local_prop_previous = [prop_previous]
else:
local_prop_previous = prop_previous = [
prop_previous
]
elif isinstance(prop_previous, list):
local_prop_previous = prop_previous
else:
local_prop_previous = [prop_previous]
if isinstance(prop_new, dict) and "values" in prop_new:
name = prop_new["name"]
prop_new = prop_new["values"]
if not isinstance(prop_new, list):
prop_new = [prop_new]
if isinstance(prop_new, list):
prop_new = prop_new.copy()
else:
prop_new = [prop_new]
if isinstance(prop_previous, list):
prop_previous = [
p for p in prop_previous if p not in prop_new
]
elif prop_previous in prop_new:
prop_new.remove(prop_previous)
prop_previous = []
else:
prop_previous = [prop_previous]
prop_new = [p for p in prop_new if p not in local_prop_previous]
if prop_previous not in [None, []] or prop_new not in [
None,
[],
]:
modified_attributes[prop] = (name, prop_previous, prop_new)
if not modified_attributes:
continue
self._modified_variables.append((new, modified_attributes))
def display(self) -> str:
msg = ""
if self._added_variables:
if len(self._added_variables) == 1:
title = _("New variable")
else:
title = _("New variables")
for add in self._added_variables:
self.formatter.variable_to_string(add)
msg += self.formatter._run(
[
self.formatter.title(title, self.level),
self.formatter.table(),
self.formatter.end_family(self.level)
],
self.level,
dico_is_already_treated=True,
)
if self._modified_variables:
if len(self._modified_variables) == 1:
title = _("Modified variable")
else:
title = _("Modified variables")
for mod, modified_attributes in self._modified_variables:
self.formatter.variable_to_string(mod, modified_attributes)
msg += self.formatter._run(
[
self.formatter.title(title, self.level),
self.formatter.table(),
self.formatter.end_family(self.level)
],
self.level,
dico_is_already_treated=True,
)
if self._removed_variables:
if len(self._removed_variables) == 1:
title = _("Deleted variable")
else:
title = _("Deleted variables")
msg += self.formatter._run(
[
self.formatter.title(title, self.level),
self.formatter.list(self._removed_variables, inside_table=False),
self.formatter.end_family(self.level)
],
self.level,
dico_is_already_treated=True,
)
return msg