From 90acc2baf7920d3c0f385ece3ab060d2a5060aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Ke=C3=9Fler?= Date: Fri, 22 Oct 2021 10:01:33 +0200 Subject: [PATCH] add build scripts --- build/__init__.py | 0 build/build/__init__.py | 5 ++ build/build/build.py | 116 +++++++++++++++++++++++++++++++ build/build/build_information.py | 76 ++++++++++++++++++++ build/build/config.py | 10 +++ build/git_hook/__init__.py | 9 +++ build/git_hook/git_version.py | 53 ++++++++++++++ build/git_hook/recent.py | 30 ++++++++ build/utils/__init__.py | 0 9 files changed, 299 insertions(+) create mode 100644 build/__init__.py create mode 100644 build/build/__init__.py create mode 100644 build/build/build.py create mode 100644 build/build/build_information.py create mode 100644 build/build/config.py create mode 100644 build/git_hook/__init__.py create mode 100644 build/git_hook/git_version.py create mode 100644 build/git_hook/recent.py create mode 100644 build/utils/__init__.py diff --git a/build/__init__.py b/build/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/build/build/__init__.py b/build/build/__init__.py new file mode 100644 index 0000000..3b3e07b --- /dev/null +++ b/build/build/__init__.py @@ -0,0 +1,5 @@ +from .build import build + +__all__ = [ + 'build' +] diff --git a/build/build/build.py b/build/build/build.py new file mode 100644 index 0000000..03b23a6 --- /dev/null +++ b/build/build/build.py @@ -0,0 +1,116 @@ +from pathlib import Path +from typing import Optional + +import PyTeX + +from .build_information import BuildInfo + + +def pytex_msg(msg: str): + print('[PyTeX] ' + msg) + + +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(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': '', + 'skipped': '' + }, + 'classes': { + 'built': '', + 'skipped': '' + }, + 'LatexPackages': { + 'version': '', + 'branch': '', + 'commit': '', + 'dirty': '' + }, + 'PyTeX': { + 'version': '', + 'branch': '', + 'commit': '', + 'dirty': '' + } + } + pytex_msg('Build done') diff --git a/build/build/build_information.py b/build/build/build_information.py new file mode 100644 index 0000000..e0a3bc3 --- /dev/null +++ b/build/build/build_information.py @@ -0,0 +1,76 @@ +import git +import datetime +from typing import Optional + +from PyTeX.build.git_hook import git_describe, get_latest_commit + +from .config import BUILD_DETAILS + + +def build_information(): + repo = git.Repo() + repo_description = git_describe(get_latest_commit(repo)) + pytex_repo = repo.submodule('PyTeX').module() + pytex_repo_description = git_describe(get_latest_commit(pytex_repo)) + return list(map(lambda line: line.format( + build_time=datetime.datetime.now().strftime('%Y/%m/%d %H:%M'), + pytex_version=pytex_repo_description, + pytex_commit_hash=get_latest_commit(pytex_repo).hexsha[0:7], + 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/build/config.py b/build/build/config.py new file mode 100644 index 0000000..a6d8ad0 --- /dev/null +++ b/build/build/config.py @@ -0,0 +1,10 @@ +BUILD_DETAILS = [ + "Build details:", + " Build time: {build_time}", + " 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/git_hook/__init__.py b/build/git_hook/__init__.py new file mode 100644 index 0000000..851f2bc --- /dev/null +++ b/build/git_hook/__init__.py @@ -0,0 +1,9 @@ +from .git_version import git_describe, get_history, get_latest_commit +from .recent import is_recent + +__all__ = [ + 'git_describe', + 'get_history', + 'get_latest_commit', + 'is_recent' +] diff --git a/build/git_hook/git_version.py b/build/git_hook/git_version.py new file mode 100644 index 0000000..ad9f179 --- /dev/null +++ b/build/git_hook/git_version.py @@ -0,0 +1,53 @@ +import git +from typing import Dict + + +def get_latest_commit(repo): + if repo.head.is_detached: + return repo.head.commit + else: + return repo.head.ref.commit + + +def get_history(commit: git.objects.commit.Commit, priority=0, depth=0) -> Dict: + commit_history = {commit.hexsha: { + 'priority': priority, + 'depth': depth + }} + try: + if len(commit.parents) > 0: + commit_history.update(get_history(commit.parents[0], priority, depth + 1)) + for parent in commit.parents[1:]: + commit_history.update(get_history(parent, priority + 1, depth + 1)) + except ValueError: + pass + return commit_history + + +def git_describe(commit: git.objects.commit.Commit): + commit_history = get_history(commit) + latest_tag = None + for tag in commit.repo.tags: + sha = tag.commit.hexsha + if sha in commit_history.keys(): + if latest_tag is None: + latest_tag = tag + elif commit_history[sha]['priority'] < commit_history[latest_tag.commit.hexsha]['priority']: + latest_tag = tag + elif commit_history[sha]['priority'] > commit_history[latest_tag.commit.hexsha]['priority']: + pass # move on + elif commit_history[sha]['depth'] < commit_history[latest_tag.commit.hexsha]['depth']: + latest_tag = tag + elif commit_history[sha]['depth'] > commit_history[latest_tag.commit.hexsha]['depth']: + pass # move on + elif tag.object.tagged_date > latest_tag.object.tagged_date: + latest_tag = tag + if latest_tag is None: + return "No tags found - cannot describe anything." + else: + msg = latest_tag.name + if commit_history[latest_tag.commit.hexsha]['depth'] != 0: + msg += "-{depth}".format(depth=commit_history[latest_tag.commit.hexsha]['depth']) + if commit.repo.is_dirty(untracked_files=True): + msg += '-*' + return msg diff --git a/build/git_hook/recent.py b/build/git_hook/recent.py new file mode 100644 index 0000000..2c86345 --- /dev/null +++ b/build/git_hook/recent.py @@ -0,0 +1,30 @@ +import git + +from .git_version import get_latest_commit +from typing import Union, Optional, List + + +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 + + 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/utils/__init__.py b/build/utils/__init__.py new file mode 100644 index 0000000..e69de29