diff --git a/build.py b/build.py old mode 100644 new mode 100755 index 256263a..3b88776 --- a/build.py +++ b/build.py @@ -1,15 +1,101 @@ -import sys -from pathlib import Path +#! /usr/bin/python3 +import argparse +import pathlib from build_scripts.build import build +from build_scripts.build.config import FILENAME_TYPE_RAW_NAME, FILENAME_TYPE_PREPEND_AUTHOR + + +def main(): + parser = argparse.ArgumentParser(description='Incrementally build LatexPackages with PyTeX') + input_group = parser.add_mutually_exclusive_group(required=True) + output_group = parser.add_mutually_exclusive_group() + input_group.add_argument( + '-s', '--source-dir', + metavar='SRC_DIR', + help='Relative or absolute path to source directory of .pysty or .pycls files', + type=pathlib.Path, + nargs='?', + default='./src', + dest='src_dir' + ) + output_group.add_argument( + '-b', '--build-dir', + metavar='BUILD_DIR', + help='Relativ or absolute path to output directory for processed packages and classes', + type=pathlib.Path, + nargs='?', + default='./build', + dest='build_dir' + ) + parser.add_argument( + '-r', '--recursive', + help='Recursively search subdirectories for files. Default: false', + action='store_true', + dest='recursive' + ) + input_group.add_argument( + '-i', '--input-file', + metavar='FILE', + help='Filename to be built. Can be in valid .pysty or .pycls format', + type=pathlib.Path, + dest='input_file' + ) + output_group.add_argument( + '-n', '--name', + help='Name of the package / class to be formatted.', + type=str, + choices=[FILENAME_TYPE_RAW_NAME, FILENAME_TYPE_PREPEND_AUTHOR], + default=FILENAME_TYPE_PREPEND_AUTHOR, + dest='latex_name' + ) + parser.add_argument( + '-g', '--git-version', + help='Insert git version information into build. This assumes your input' + 'files are located in a git repository. Default: false', + action='store_true', + dest='use_git' + ) + parser.add_argument( + '-d', '--allow-dirty', + help='If git flag is set, allow building of a dirty repo. Default: false', + action='store_true', + dest='allow_dirty' + ) + parser.add_argument( + '-p', + '--pytex-version', + help='Write PyTeX version information into built LaTeX files', + action='store_true', + dest='include_pytex_version' + ) + parser.add_argument( + '-t', '--build-time', + help='Insert build time into built LaTeX files', + action='store_true', + dest='include_timestamp' + ) + parser.add_argument( + '-l', '--license', + help='Insert MIT license into package header', + action='store_true', + dest='include_license' + ) + parser.add_argument( + '-a', '--author', + help='Set author of packages', + type=str, + dest='author' + ) + parser.add_argument( + '-f', '--force', + help='Overwrite unknown existing files without confirmation', + action='store_true', + dest='overwrite_existing_files' + ) + args = parser.parse_args() + build(**vars(args)) + if __name__ == "__main__": - check_existence = True - if len(sys.argv) == 2: - if sys.argv[1] == '--only-new': - check_existence = False - build( - src_dir=Path('./src').resolve(), - build_dir=Path('./build').resolve(), - check_existence=check_existence - ) + main() diff --git a/build_scripts/build/build.py b/build_scripts/build/build.py index 88415b1..367842b 100644 --- a/build_scripts/build/build.py +++ b/build_scripts/build/build.py @@ -1,69 +1,99 @@ from pathlib import Path import git +from typing import Optional, Union, List import PyTeX from build_scripts.git_hook import get_latest_commit, is_recent -from .build_information import build_information +from .build_information import build_information, BuildInfo -def build(src_dir: Path, build_dir: Path, check_existence: bool = True): - print('[PyTeX] Getting git repository information...') - extra_header, repo_description = build_information() - print('[PyTeX] Building version {version} of LatexPackages'.format(version=repo_description)) - print('[PyTeX] Latest commit message: ' + get_latest_commit(git.Repo()).message.strip()) - if git.Repo().is_dirty(untracked_files=True): - extra_header += ['WARNING: Local changes to git repository detected.', - ' The build will not be reproducible (!)'] - num_packages = 0 - num_skipped_packages = 0 - num_classes = 0 - num_skipped_classes = 0 +def pytex_msg(msg: str): + print('[PyTeX] ' + msg) - for file in src_dir.rglob('*.pysty'): - output_dir = build_dir / str(file.parent.relative_to(src_dir)) - if not is_recent(file, git.Repo()): - if not check_existence: - print('[PyTex] Skipping file {file} since it was not modified since last build'.format(file=file.name)) - num_skipped_packages += 1 - continue - else: - if (output_dir / ('mkessler-' + str(file.with_suffix('.sty').name))).exists(): - print('[PyTex] Skipping file {file} since it was not modified since ' - 'last build and already exists'.format(file=file.name)) - num_skipped_packages += 1 - continue - num_packages += 1 - formatter = PyTeX.PackageFormatter( - package_name=file.with_suffix('').name, - extra_header=extra_header) - print('[PyTeX] Writing file {}'.format(formatter.file_name)) +class TexFileToFormat: + def __init__(self, src_path: Path, build_dir: Path): + self.src_path = src_path + self.build_path = build_dir + + def format(self): + if '.pysty' in self.src_path.name: + formatter = PyTeX.PackageFormatter( + package_name=self.src_path.with_suffix('').name, + extra_header=[]) # TODO: extra header + else: + formatter = PyTeX.ClassFormatter( + class_name=self.src_path.with_suffix('').name, + extra_header=[]) # TODO + pytex_msg('Writing file {}'.format(formatter.file_name)) formatter.make_default_macros() - formatter.format_file(file, output_dir) - for file in src_dir.rglob('*.pycls'): - output_dir = build_dir / str(file.parent.relative_to(src_dir)) - if not is_recent(file, git.Repo()): - if not check_existence: - print('[PyTex] Skipping file {file} since it was not modified since last build'.format(file=file.name)) - num_skipped_classes += 1 - continue - else: - if (output_dir / ('mkessler-' + str(file.with_suffix('.cls').name))).exists(): - print('[PyTex] Skipping file {file} since it was not modified since ' - 'last build and already exists'.format(file=file.name)) - num_skipped_classes += 1 - continue - output_dir = build_dir / str(file.parent.relative_to(src_dir)) - num_classes += 1 - formatter = PyTeX.ClassFormatter( - class_name=file.with_suffix('').name, - extra_header=extra_header) - print('[PyTeX] Writing class file {}'.format(formatter.file_name)) - formatter.make_default_macros() - formatter.format_file(input_path=file, output_dir=output_dir) - build_info = { + formatter.format_file(self.src_path, self.build_path) + + +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 + use_git: bool = False, # versioning + 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, + pytex_repo=None, # TODO + packages_repo=None # TODO + ) + old_build_info = {} # TODO: read this in from file + # extra_header += ['WARNING: Local changes to git repository detected.', + # ' The build will not be reproducible (!)'] + + 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) + + input_dir = src_dir if src_dir else input_file.parent + output_dir = build_dir if build_dir else input_file.parent + sources_to_build = [] + for file in files: + sources_to_build.append( + TexFileToFormat( + src_path=file, + build_dir=output_dir / file.parent.relative_to(input_dir) + )) + + for source in sources_to_build: + source.format() + + current_build_info = { 'build_time': '', 'packages': { 'built': '', @@ -86,5 +116,4 @@ def build(src_dir: Path, build_dir: Path, check_existence: bool = True): 'dirty': '' } } - print(f'[PyTeX] Successfully built {num_packages} packages (skipped {num_skipped_packages}) ' - f'and {num_classes} classes (skipped {num_skipped_classes}) in {build_dir}/') + pytex_msg('Build done') diff --git a/build_scripts/build/build_information.py b/build_scripts/build/build_information.py index 217c3d9..46bc486 100644 --- a/build_scripts/build/build_information.py +++ b/build_scripts/build/build_information.py @@ -1,9 +1,10 @@ import git import datetime +from typing import Optional from build_scripts.git_hook import git_describe, get_latest_commit -from .config import BUILD_DETAILS +from .config import BUILD_DETAILS, DATE_FORMAT def build_information(): @@ -18,3 +19,58 @@ def build_information(): packages_version=repo_description, packages_commit_hash=get_latest_commit(repo).hexsha[0:7] ), BUILD_DETAILS)), repo_description + + +class BuildInfo: + def __init__( + self, + include_timestamp: bool = False, + include_pytex_version: bool = False, + include_license: bool = False, + include_git_version: bool = False, + include_pytex_info_text: bool = False, + author: Optional[str] = None, + pytex_repo: Optional[git.Repo] = None, + packages_repo: Optional[git.Repo] = None): + self.author = author + + self._pytex_repo = pytex_repo + self._packages_repo = packages_repo + self._pytex_repo_commit = None + self._packages_repo_commit = None + self._pytex_repo_version = None + self._packages_repo_version = None + + self._header = None + + self.get_repo_commits() + self.get_repo_version() + + self.create_header( + 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 + ) + + def get_repo_commits(self): + if self._packages_repo: + self._packages_repo_commit = get_latest_commit(self._packages_repo) + if self._pytex_repo: + self._pytex_repo_commit = get_latest_commit(self._pytex_repo) + + def get_repo_version(self): + if self._packages_repo_commit: + self._packages_repo_version = git_describe(self._packages_repo_commit) + if self._pytex_repo_commit: + self._pytex_repo_version = git_describe(self._pytex_repo_commit) + + def create_header( + self, + include_timestamp: bool = False, + include_pytex_version: bool = False, + include_license: bool = False, + include_git_version: bool = False, + include_pytex_info_text: bool = False): + pass diff --git a/build_scripts/build/config.py b/build_scripts/build/config.py index c69f02c..a6d8ad0 100644 --- a/build_scripts/build/config.py +++ b/build_scripts/build/config.py @@ -4,3 +4,7 @@ BUILD_DETAILS = [ " PyTeX version: {pytex_version} (commit {pytex_commit_hash})", " LatexPackages version: {packages_version} (commit {packages_commit_hash})" ] + +FILENAME_TYPE_PREPEND_AUTHOR = 'prepend-author' +FILENAME_TYPE_RAW_NAME = 'raw' +DATE_FORMAT = '%Y/%m/%d %H:%M' diff --git a/build_scripts/git_hook/recent.py b/build_scripts/git_hook/recent.py index acc7480..2c86345 100644 --- a/build_scripts/git_hook/recent.py +++ b/build_scripts/git_hook/recent.py @@ -1,14 +1,30 @@ +import git + from .git_version import get_latest_commit +from typing import Union, Optional, List -def is_recent(file, repo): +def is_recent(file, repo, compare: Optional[Union[git.Commit, List[git.Commit]]] = None) -> Optional[bool]: modified_files = [item.a_path for item in repo.index.diff(None)] if file in modified_files: return True - for parent in get_latest_commit(repo).parents: - newly_committed_files = [item.a_path for item in repo.index.diff(parent)] - if file in newly_committed_files: - return True - return False + newly_committed_files = [] + if type(compare) == git.Commit: + newly_committed_files = [item.a_path for item in repo.index.diff(compare)] + elif type(compare) == list: + for commit in compare: + for item in repo.index.diff(commit): + newly_committed_files.append(item.a_path) + elif type is None: + for parent in get_latest_commit(repo).parents: + for item in repo.index.diff(parent): + newly_committed_files.append(item.a_path) + else: + print("Invalid argument type for compare") + return None + if file in newly_committed_files: + return True + else: + return False diff --git a/build_scripts/utils/__init__.py b/build_scripts/utils/__init__.py new file mode 100644 index 0000000..e69de29