pytex/build/utils/pytex_file.py
2022-01-13 21:02:47 +01:00

153 lines
6.8 KiB
Python

from pathlib import Path
from typing import Optional, List
from PyTeX.build.git_hook import is_recent, get_latest_commit
from PyTeX import PackageFormatter, ClassFormatter, DictionaryFormatter
from PyTeX.errors import *
from .pytex_msg import pytex_msg
from PyTeX.utils import md5
from .build_information import BuildInfo
class TexFileToFormat:
def __init__(
self,
src_path: Path,
build_root: Path,
src_root: Path,
latex_name: str,
current_build_info: BuildInfo,
last_build_info: Optional[List[dict]],
allow_dirty: bool = False,
overwrite_existing_files: bool = False,
build_all: bool = False):
self.src_path = src_path
self.build_root = build_root
self.src_root = src_root
self.build_path = build_root / src_path.parent.relative_to(src_root)
self.latex_name = latex_name # Still an identifier on how to name the package when being formatted
self.current_build_info = current_build_info
self.last_build_info_all = last_build_info
self.last_build_info = self.last_build_info_all[0] if self.last_build_info_all else None
self.allow_dirty = allow_dirty
self.overwrite_existing_files: overwrite_existing_files
self.build_all = build_all
self._header: Optional[List[str]] = None
self.__format_header()
self.dirty = not is_recent(self.src_path, self.current_build_info.package_repo, compare=None)
self.pytex_dirty: bool = self.current_build_info.pytex_repo.is_dirty(
working_tree=True,
untracked_files=True
)
if self.last_build_info:
self.recent: bool = is_recent(
file=self.src_path,
repo=self.current_build_info.package_repo,
compare=self.current_build_info.package_repo.commit(self.last_build_info['source commit hash'])
)
self.pytex_recent: bool = get_latest_commit(
self.current_build_info.pytex_repo
).hexsha == self.last_build_info['pytex commit hash']
else:
self.recent = False
self.pytex_recent = False
def format(self) -> List[dict]:
if self.dirty or self.pytex_dirty:
if not self.allow_dirty:
raise SubmoduleDirtyForbiddenError
# TODO: add this to the header...?
return self.__format() # Dirty files are always built, since we have no information about them
elif self.build_all:
return self.__format() # Build file since we build all of them
elif not self.pytex_recent or not self.recent:
return self.__format() # Build file since either pytex or package repo is not recent
elif self.last_build_info and self.last_build_info['dirty']:
return self.__format() # Build file since we do not know in what state it is
else:
return self.last_build_info_all
def __format_header(self):
new_header = []
if self.current_build_info.header:
for line in self.current_build_info.header:
if '.pysty' in self.src_path.name:
latex_file_type = 'package'
elif '.pycls' in self.src_path.name:
latex_file_type = 'class'
elif '.pydict' in self.src_path.name:
latex_file_type = 'dictionary'
else:
raise ProgrammingError
new_header.append(line.format(
source_file=self.src_path.name,
latex_file_type=latex_file_type
))
self._header = new_header
def __format(self) -> List[dict]:
if self.src_path.name.endswith('.pysty'):
formatter = PackageFormatter(
package_name=self.src_path.with_suffix('').name,
author=self.current_build_info.author,
extra_header=self._header,
tex_version='LaTeX2e',
version=self.current_build_info.packages_version,
latex_name=self.latex_name)
elif self.src_path.name.endswith('.pycls'):
formatter = ClassFormatter(
class_name=self.src_path.with_suffix('').name,
author=self.current_build_info.author,
extra_header=self._header,
tex_version='LaTeX2e',
version=self.current_build_info.packages_version,
latex_name=self.latex_name)
elif self.src_path.name.endswith('.pysty3'):
formatter = PackageFormatter(
package_name=self.src_path.with_suffix('').name,
author=self.current_build_info.author,
extra_header=self._header,
tex_version='LaTeX3',
version=self.current_build_info.packages_version,
latex_name=self.latex_name)
elif self.src_path.name.endswith('.pycls3'):
formatter = ClassFormatter(
class_name=self.src_path.with_suffix('').name,
author=self.current_build_info.author,
extra_header=self._header,
tex_version='LaTeX3',
version=self.current_build_info.packages_version,
latex_name=self.latex_name)
elif self.src_path.name.endswith('.pydict'):
formatter = DictionaryFormatter(
kind=self.src_path.with_suffix('').name,
author=self.current_build_info.author,
header=self._header
)
else:
raise ProgrammingError
formatter.make_default_macros()
written_files = formatter.format_file(
input_path=self.src_path,
output_dir=self.build_path,
relative_name=str(self.src_path.relative_to(self.src_root)),
last_build_info=self.last_build_info_all)
build_infos = []
for written_file in written_files:
info = {
'name': str(self.src_path.parent.relative_to(self.src_root)) + "/" + written_file,
'source file': str(self.src_path.relative_to(self.src_root)),
'build time': self.current_build_info.build_time,
'source version': self.current_build_info.packages_version,
'source commit hash': self.current_build_info.packages_hash,
'pytex version': self.current_build_info.pytex_version,
'pytex commit hash': self.current_build_info.pytex_hash,
'md5sum': md5(self.build_root / self.src_path.parent.relative_to(self.src_root) / written_file),
'dirty': self.dirty
}
build_infos.append(info)
pytex_msg('Written file {}'.format(written_file))
return build_infos