2021-10-22 10:57:16 +02:00
|
|
|
import json
|
2021-10-22 10:01:33 +02:00
|
|
|
from pathlib import Path
|
|
|
|
from typing import Optional
|
|
|
|
|
2021-10-22 10:12:28 +02:00
|
|
|
import git
|
|
|
|
|
2021-10-22 10:01:33 +02:00
|
|
|
import PyTeX
|
|
|
|
|
|
|
|
from .build_information import BuildInfo
|
|
|
|
|
2021-10-22 12:56:00 +02:00
|
|
|
from PyTeX.build.git_hook.recent import is_recent
|
2021-10-22 13:39:56 +02:00
|
|
|
from PyTeX.build.git_hook.git_version import get_latest_commit
|
2021-10-22 12:56:00 +02:00
|
|
|
|
|
|
|
BUILD_INFO_FILENAME = 'build_info.json'
|
|
|
|
|
2021-10-22 10:01:33 +02:00
|
|
|
|
|
|
|
def pytex_msg(msg: str):
|
|
|
|
print('[PyTeX] ' + msg)
|
|
|
|
|
|
|
|
|
|
|
|
class TexFileToFormat:
|
2021-10-22 11:58:56 +02:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
src_path: Path,
|
|
|
|
build_dir: Path,
|
|
|
|
latex_name: str,
|
2021-10-22 12:56:00 +02:00
|
|
|
current_build_info: BuildInfo,
|
|
|
|
last_build_info: Optional[dict],
|
2021-10-22 11:58:56 +02:00
|
|
|
allow_dirty: bool = False,
|
|
|
|
overwrite_existing_files: bool = False,
|
|
|
|
build_all: bool = False):
|
2021-10-22 10:01:33 +02:00
|
|
|
self.src_path = src_path
|
|
|
|
self.build_path = build_dir
|
2021-10-22 10:57:16 +02:00
|
|
|
self.tex_name = latex_name # Still an identifier on how to name the package when being formatted
|
2021-10-22 12:56:00 +02:00
|
|
|
self.current_build_info = current_build_info
|
|
|
|
self.last_build_info = last_build_info
|
2021-10-22 11:58:56 +02:00
|
|
|
self.allow_dirty = allow_dirty
|
|
|
|
self.overwrite_existing_files: overwrite_existing_files
|
|
|
|
self.build_all = build_all
|
2021-10-22 10:01:33 +02:00
|
|
|
|
2021-10-22 13:51:31 +02:00
|
|
|
self.dirty = not is_recent(self.src_path, self.current_build_info.package_repo, compare=None)
|
2021-10-22 13:39:56 +02:00
|
|
|
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
|
2021-10-22 12:56:00 +02:00
|
|
|
|
|
|
|
def format(self) -> dict:
|
2021-10-22 13:39:56 +02:00
|
|
|
if self.dirty or self.pytex_dirty:
|
|
|
|
if not self.allow_dirty:
|
|
|
|
raise Exception(
|
|
|
|
'{file} is dirty, but writing dirty files not allowed.'.format(
|
|
|
|
file=self.src_path.name if self.dirty else 'Submodule PyTeX')
|
|
|
|
)
|
|
|
|
# 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
|
2021-10-22 13:56:09 +02:00
|
|
|
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
|
2021-10-22 13:39:56 +02:00
|
|
|
else:
|
2021-10-22 13:51:31 +02:00
|
|
|
return self.last_build_info
|
2021-10-22 13:39:56 +02:00
|
|
|
|
|
|
|
def __format(self) -> dict:
|
2021-10-22 10:01:33 +02:00
|
|
|
if '.pysty' in self.src_path.name:
|
|
|
|
formatter = PyTeX.PackageFormatter(
|
|
|
|
package_name=self.src_path.with_suffix('').name,
|
2021-10-22 12:56:00 +02:00
|
|
|
extra_header=self.current_build_info.header)
|
2021-10-22 11:58:56 +02:00
|
|
|
elif '.pycls' in self.src_path.name:
|
2021-10-22 10:01:33 +02:00
|
|
|
formatter = PyTeX.ClassFormatter(
|
|
|
|
class_name=self.src_path.with_suffix('').name,
|
2021-10-22 12:56:00 +02:00
|
|
|
extra_header=self.current_build_info.header)
|
2021-10-22 11:58:56 +02:00
|
|
|
else:
|
|
|
|
exit(1)
|
2021-10-22 10:01:33 +02:00
|
|
|
pytex_msg('Writing file {}'.format(formatter.file_name))
|
|
|
|
formatter.make_default_macros()
|
|
|
|
formatter.format_file(self.src_path, self.build_path)
|
2021-10-22 10:57:16 +02:00
|
|
|
info = {
|
|
|
|
'name': formatter.file_name,
|
|
|
|
'source file': self.src_path.name,
|
2021-10-22 12:56:00 +02:00
|
|
|
'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,
|
|
|
|
'dirty': self.dirty
|
2021-10-22 10:57:16 +02:00
|
|
|
}
|
|
|
|
return info
|
2021-10-22 10:01:33 +02:00
|
|
|
|
|
|
|
|
|
|
|
def build(
|
|
|
|
src_dir: Optional[Path] = None,
|
|
|
|
build_dir: Optional[Path] = None,
|
|
|
|
input_file: Optional[Path] = None,
|
|
|
|
author: Optional[str] = None,
|
|
|
|
latex_name: str = 'prepend-author', # name handling
|
|
|
|
recursive: bool = False, # input control
|
|
|
|
include_timestamp: bool = False, # header
|
|
|
|
include_pytex_version: bool = False, # header
|
|
|
|
include_license: bool = False, # header
|
|
|
|
include_git_version: bool = False, # header
|
|
|
|
include_pytex_info_text: bool = False, # header
|
2021-10-22 11:58:56 +02:00
|
|
|
use_git: bool = False, # versioning (not implemented yet)
|
2021-10-22 10:01:33 +02:00
|
|
|
allow_dirty: bool = False, # versioning
|
|
|
|
overwrite_existing_files: bool = False, # output control
|
|
|
|
build_all: bool = False, # output control / versioning
|
|
|
|
write_build_information: bool = True, # meta
|
|
|
|
):
|
|
|
|
pytex_msg('Getting git repository information...')
|
|
|
|
current_build_info = BuildInfo(
|
|
|
|
include_timestamp=include_timestamp,
|
|
|
|
include_pytex_version=include_pytex_version,
|
|
|
|
include_license=include_license,
|
|
|
|
include_git_version=include_git_version,
|
|
|
|
include_pytex_info_text=include_pytex_info_text,
|
|
|
|
author=author,
|
2021-10-22 13:39:56 +02:00
|
|
|
pytex_repo=git.Repo(__file__, search_parent_directories=True),
|
|
|
|
packages_repo=git.Repo(src_dir, search_parent_directories=True)
|
2021-10-22 10:01:33 +02:00
|
|
|
)
|
2021-10-22 10:57:16 +02:00
|
|
|
input_dir = src_dir if src_dir else input_file.parent
|
|
|
|
output_dir = build_dir if build_dir else input_file.parent
|
|
|
|
|
2021-10-22 12:56:00 +02:00
|
|
|
last_build_info_file = output_dir / BUILD_INFO_FILENAME
|
|
|
|
if last_build_info_file.exists():
|
|
|
|
with open(output_dir / 'build_info.json', 'r') as f:
|
|
|
|
last_build_info = json.load(f)
|
|
|
|
else:
|
|
|
|
last_build_info = None
|
2021-10-22 10:01:33 +02:00
|
|
|
|
|
|
|
files = []
|
|
|
|
if input_file:
|
|
|
|
files.append(input_file)
|
|
|
|
if src_dir:
|
|
|
|
if recursive:
|
|
|
|
for file in src_dir.rglob('*.pysty'):
|
|
|
|
files.append(file)
|
|
|
|
for file in src_dir.rglob('*.pycls'):
|
|
|
|
files.append(file)
|
|
|
|
else:
|
|
|
|
for file in src_dir.glob('*.pysty'):
|
|
|
|
files.append(file)
|
|
|
|
for file in src_dir.glob('*.pycls'):
|
|
|
|
files.append(file)
|
|
|
|
|
|
|
|
sources_to_build = []
|
|
|
|
for file in files:
|
2021-10-22 12:56:00 +02:00
|
|
|
if last_build_info:
|
|
|
|
last_build_info_for_this_file = next(
|
|
|
|
(info for info in last_build_info['tex_sources'] if info['source file'] == file.name), {})
|
|
|
|
else:
|
|
|
|
last_build_info_for_this_file = None
|
2021-10-22 10:01:33 +02:00
|
|
|
sources_to_build.append(
|
|
|
|
TexFileToFormat(
|
|
|
|
src_path=file,
|
2021-10-22 10:57:16 +02:00
|
|
|
build_dir=output_dir / file.parent.relative_to(input_dir),
|
|
|
|
latex_name=latex_name,
|
2021-10-22 12:56:00 +02:00
|
|
|
current_build_info=current_build_info,
|
|
|
|
last_build_info=last_build_info_for_this_file,
|
2021-10-22 11:58:56 +02:00
|
|
|
allow_dirty=allow_dirty,
|
|
|
|
overwrite_existing_files=overwrite_existing_files,
|
|
|
|
build_all=build_all
|
2021-10-22 10:01:33 +02:00
|
|
|
))
|
|
|
|
|
2021-10-22 10:57:16 +02:00
|
|
|
info_dict = {
|
2021-10-22 10:01:33 +02:00
|
|
|
'build_time': '',
|
2021-10-22 11:58:56 +02:00
|
|
|
'source files': {
|
2021-10-22 10:57:16 +02:00
|
|
|
'version': current_build_info.packages_version,
|
|
|
|
'commit': current_build_info.packages_hash,
|
2021-10-22 11:58:56 +02:00
|
|
|
'dirty': current_build_info.package_repo.is_dirty(untracked_files=True)
|
2021-10-22 10:01:33 +02:00
|
|
|
},
|
2021-10-22 11:58:56 +02:00
|
|
|
'pytex': {
|
2021-10-22 10:57:16 +02:00
|
|
|
'version': current_build_info.pytex_version,
|
|
|
|
'commit': current_build_info.pytex_hash,
|
2021-10-22 11:58:56 +02:00
|
|
|
'dirty': current_build_info.pytex_repo.is_dirty(untracked_files=True)
|
2021-10-22 10:57:16 +02:00
|
|
|
},
|
|
|
|
'tex_sources': [
|
|
|
|
|
|
|
|
]
|
2021-10-22 10:01:33 +02:00
|
|
|
}
|
2021-10-22 10:57:16 +02:00
|
|
|
|
|
|
|
for source in sources_to_build:
|
|
|
|
info = source.format()
|
|
|
|
info_dict['tex_sources'].append(info)
|
2021-10-22 11:58:56 +02:00
|
|
|
|
|
|
|
if write_build_information:
|
|
|
|
with open(output_dir / 'build_info.json', 'w') as f:
|
|
|
|
json.dump(info_dict, f, indent=4)
|
2021-10-22 10:01:33 +02:00
|
|
|
pytex_msg('Build done')
|