diff --git a/PyTeX/build/build/builder.py b/PyTeX/build/build/builder.py index 24c3798..def7bad 100644 --- a/PyTeX/build/build/builder.py +++ b/PyTeX/build/build/builder.py @@ -1,5 +1,5 @@ from pathlib import Path -from typing import Optional, Union, List, Tuple +from typing import Optional, Union, List, Tuple, Set from .enums import PyTeXRootDirType from .pytex_config import PyTeXConfig @@ -9,6 +9,7 @@ from ..versioning.version_info.version_info import VersionInfo, FileVersionInfo from .pytex_file import PyTeXSourceFile from .relative_path import RelativePath from .hashing import md5 +from .pytex_output_file import PyTeXOutputFile class PyTeXBuilder: @@ -26,17 +27,19 @@ class PyTeXBuilder: if isinstance(pytex_config, Path): self._root_dir = pytex_config.parent else: - self._root_dir: Path = Path('.') # Working directory + self._root_dir = Path('.') # Working directory else: self._root_dir = root_dir # Non-public attributes self._build_target_type: Optional[PyTeXRootDirType] = None self._old_version_info: Optional[VersionInfo] = None - self._modified_old_version_info: VersionInfo = VersionInfo() + self._output_files: List[PyTeXOutputFile] = [] self._pytex_files: List[PyTeXSourceFile] = [] - self._files_to_clean: List[RelativePath] = [] - self._files_to_overwrite: List[RelativePath] = [] + self._files_to_clean: Set[RelativePath] = set() + self._files_to_overwrite: Set[RelativePath] = set() + self._files_to_build: Set[PyTeXSourceFile] = set() + self._tmp_dir: Path = self._root_dir / '.pytex' def build_tex_sources(self) -> bool: self._build_target_type = PyTeXRootDirType.TEX_SOURCE @@ -156,6 +159,19 @@ class PyTeXBuilder: else: return FileVersionInfo() + def _pytex_file_lookup(self, name: str) -> PyTeXSourceFile: + matches = [ + source_file + for source_file in self._pytex_files + if source_file.relative_path.path.name == name + ] + if len(matches) >= 2: + raise NotImplementedError + elif len(matches) == 1: + return matches[0] + else: + raise NotImplementedError # what to do in this case? dependency does not exist... + def _check_output_directory_integrity(self): out_dir_files = [ RelativePath(self.target_root, file) @@ -168,25 +184,58 @@ class PyTeXBuilder: raise NotImplementedError # Not ok else: if self.pytex_config.overwrite_existing_files: - self._files_to_overwrite.append(file) + self._files_to_overwrite.add(file) else: - pass - # Not ok iff we are going to write this file + if file.relative_path in \ + {x.relative_path.relative_path for x in self._files_to_build}: + raise NotImplementedError + # Not ok iff we are going to write this file - def _update_old_version_info(self): - self._modified_old_version_info.files = [] # Make sure this is set so we can get references on it + def _dependencies_hash(self, pytex_output_file: PyTeXOutputFile) -> str: + t = pytex_output_file.dependencies + deps: Set[str] = set(t) + deps.add(pytex_output_file.source_file.relative_path.path.name) + hashes = set() + for dep in deps: + hashes.add( + self._pytex_file_lookup(dep).file_hash + ) + return md5(hashes) + + def _init_output_files(self): for source_file in self._pytex_files: for output_file in source_file.output_files: - self._modified_old_version_info.files.append( - self._old_version_lookup( - output_file + self._output_files.append( + PyTeXOutputFile( + output_file=output_file, + source_file=source_file, + last_version_info=self._old_version_lookup(output_file) ) ) + def _compute_files_to_build(self): + self._files_to_build = { + output_file.source_file for output_file in self._output_files + if self._dependencies_hash(output_file) != output_file.last_version_info.sources_hash + or output_file.last_version_info.file_hash != output_file.file_hash + } + + def _build_files(self): + for source_file in self._files_to_build: + import os + out_dir = self._tmp_dir / source_file.file_hash + out_dir.mkdir(exist_ok=False, parents=True) + source_file.format(self._tmp_dir / source_file.file_hash) + def _build(self) -> bool: logger.info("Starting build") self._load_pytex_files() logger.info(f"Found {len(self._pytex_files)} source files") - self._update_old_version_info() + self._init_output_files() + logger.info(f"Found {len(self._output_files)} potential files to build.") + self._compute_files_to_build() + logger.info(f"Needing to build {len(self._files_to_build)} many files.") + self._check_output_directory_integrity() + logger.info(f"Starting build") + self._build_files() return True -