start reworking of build scripts

This commit is contained in:
Maximilian Keßler 2021-10-22 09:57:35 +02:00
parent 90cd2b9200
commit 0bde1c9cc5
6 changed files with 265 additions and 74 deletions

108
build.py Normal file → Executable file
View File

@ -1,15 +1,101 @@
import sys #! /usr/bin/python3
from pathlib import Path import argparse
import pathlib
from build_scripts.build import build 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__": if __name__ == "__main__":
check_existence = True main()
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
)

View File

@ -1,69 +1,99 @@
from pathlib import Path from pathlib import Path
import git import git
from typing import Optional, Union, List
import PyTeX import PyTeX
from build_scripts.git_hook import get_latest_commit, is_recent 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): def pytex_msg(msg: str):
print('[PyTeX] Getting git repository information...') print('[PyTeX] ' + msg)
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
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 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( formatter = PyTeX.PackageFormatter(
package_name=file.with_suffix('').name, package_name=self.src_path.with_suffix('').name,
extra_header=extra_header) extra_header=[]) # TODO: extra header
print('[PyTeX] 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: 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( formatter = PyTeX.ClassFormatter(
class_name=file.with_suffix('').name, class_name=self.src_path.with_suffix('').name,
extra_header=extra_header) extra_header=[]) # TODO
print('[PyTeX] Writing class file {}'.format(formatter.file_name)) pytex_msg('Writing file {}'.format(formatter.file_name))
formatter.make_default_macros() formatter.make_default_macros()
formatter.format_file(input_path=file, output_dir=output_dir) formatter.format_file(self.src_path, self.build_path)
build_info = {
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': '', 'build_time': '',
'packages': { 'packages': {
'built': '', 'built': '',
@ -86,5 +116,4 @@ def build(src_dir: Path, build_dir: Path, check_existence: bool = True):
'dirty': '' 'dirty': ''
} }
} }
print(f'[PyTeX] Successfully built {num_packages} packages (skipped {num_skipped_packages}) ' pytex_msg('Build done')
f'and {num_classes} classes (skipped {num_skipped_classes}) in {build_dir}/')

View File

@ -1,9 +1,10 @@
import git import git
import datetime import datetime
from typing import Optional
from build_scripts.git_hook import git_describe, get_latest_commit 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(): def build_information():
@ -18,3 +19,58 @@ def build_information():
packages_version=repo_description, packages_version=repo_description,
packages_commit_hash=get_latest_commit(repo).hexsha[0:7] packages_commit_hash=get_latest_commit(repo).hexsha[0:7]
), BUILD_DETAILS)), repo_description ), 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

View File

@ -4,3 +4,7 @@ BUILD_DETAILS = [
" PyTeX version: {pytex_version} (commit {pytex_commit_hash})", " PyTeX version: {pytex_version} (commit {pytex_commit_hash})",
" LatexPackages version: {packages_version} (commit {packages_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'

View File

@ -1,14 +1,30 @@
import git
from .git_version import get_latest_commit 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)] modified_files = [item.a_path for item in repo.index.diff(None)]
if file in modified_files: if file in modified_files:
return True 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 parent in get_latest_commit(repo).parents:
newly_committed_files = [item.a_path for item in repo.index.diff(parent)] 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: if file in newly_committed_files:
return True return True
else:
return False return False

View File