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, DocstripFormatter 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' elif '.dtx' in self.src_path.name: latex_file_type = 'ERROR' 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 ) elif self.src_path.name.endswith('.dtx'): formatter = DocstripFormatter(name=self.src_path.with_suffix('').name) 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