Skip to content

Commit

Permalink
Merge pull request #1196 from mrapp-ke/merge-feature
Browse files Browse the repository at this point in the history
Merge feature into main branch
  • Loading branch information
boomer-merge-bot[bot] authored Jan 2, 2025
2 parents 735b90f + 4073361 commit b9ad6cc
Show file tree
Hide file tree
Showing 20 changed files with 248 additions and 183 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test_changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
- 'build_system/core/**'
- 'build_system/util/**'
- 'build_system/targets/*.py'
- 'build_system/targets/versioning/*'
- 'build_system/targets/changelog/*'
bugfix:
- *build_files
- '.changelog-bugfix.md'
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# MIT License

**Copyright (c) 2020 - 2024 Michael Rapp et al.**
**Copyright (c) 2020 - 2025 Michael Rapp et al.**

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

Expand Down
29 changes: 16 additions & 13 deletions build_system/core/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,34 +145,37 @@ def run(self, build_unit: BuildUnit, module: Module):
raise NotImplementedError('Class ' + type(self).__name__ + ' does not implement the "run" method')

# pylint: disable=unused-argument
def get_input_files(self, module: Module) -> List[str]:
def get_input_files(self, build_unit: BuildUnit, module: Module) -> List[str]:
"""
May be overridden by subclasses in order to return the input files required by the target.
:param module: The module, the target should be applied to
:return: A list that contains the input files
:param build_unit: The build unit, the target belongs to
:param module: The module, the target should be applied to
:return: A list that contains the input files
"""
return []

# pylint: disable=unused-argument
def get_output_files(self, module: Module) -> List[str]:
def get_output_files(self, build_unit: BuildUnit, module: Module) -> List[str]:
"""
May be overridden by subclasses in order to return the output files produced by the target.
:param module: The module, the target should be applied to
:return: A list that contains the output files
:param build_unit: The build unit, the target belongs to
:param module: The module, the target should be applied to
:return: A list that contains the output files
"""
return []

def get_clean_files(self, module: Module) -> List[str]:
def get_clean_files(self, build_unit: BuildUnit, module: Module) -> List[str]:
"""
May be overridden by subclasses in order to return the output files produced by the target that must be
cleaned.
:param module: The module, the target should be applied to
:return: A list that contains the files to be cleaned
:param build_unit: The build unit, the target belongs to
:param module: The module, the target should be applied to
:return: A list that contains the files to be cleaned
"""
return self.get_output_files(module)
return self.get_output_files(build_unit, module)

class Builder(Target.Builder):
"""
Expand Down Expand Up @@ -203,7 +206,7 @@ def build(self, build_unit: BuildUnit) -> Target:
return BuildTarget(self.target_name, self.dependencies, self.runnables, build_unit)

def __get_missing_output_files(self, runnable: Runnable, module: Module) -> Tuple[List[str], List[str]]:
output_files = runnable.get_output_files(module)
output_files = runnable.get_output_files(self.build_unit, module)
missing_output_files = [output_file for output_file in output_files if not path.exists(output_file)]

if output_files:
Expand All @@ -228,7 +231,7 @@ def __get_missing_output_files(self, runnable: Runnable, module: Module) -> Tupl
return output_files, missing_output_files

def __get_changed_input_files(self, runnable: Runnable, module: Module) -> Tuple[List[str], List[str]]:
input_files = runnable.get_input_files(module)
input_files = runnable.get_input_files(self.build_unit, module)
changed_input_files = [
input_file for input_file in input_files if self.change_detection.get_changed_files(module, *input_files)
]
Expand Down Expand Up @@ -299,7 +302,7 @@ def clean(self, module_registry: ModuleRegistry):
modules = module_registry.lookup(runnable.module_filter)

for module in modules:
clean_files = runnable.get_clean_files(module)
clean_files = runnable.get_clean_files(self.build_unit, module)
delete_files(*clean_files, accept_missing=True)


Expand Down
20 changes: 20 additions & 0 deletions build_system/targets/changelog/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""
Defines build targets for updating the project's changelog.
"""
from core.build_unit import BuildUnit
from core.targets import PhonyTarget, TargetBuilder

from targets.changelog.changelog import print_current_version, print_latest_changelog, update_changelog_bugfix, \
update_changelog_feature, update_changelog_main, validate_changelog_bugfix, validate_changelog_feature, \
validate_changelog_main

TARGETS = TargetBuilder(BuildUnit.for_file(__file__)) \
.add_phony_target('validate_changelog_bugfix').set_functions(validate_changelog_bugfix) \
.add_phony_target('validate_changelog_feature').set_functions(validate_changelog_feature) \
.add_phony_target('validate_changelog_main').set_functions(validate_changelog_main) \
.add_phony_target('update_changelog_bugfix').set_functions(update_changelog_bugfix) \
.add_phony_target('update_changelog_feature').set_functions(update_changelog_feature) \
.add_phony_target('update_changelog_main').set_functions(update_changelog_main) \
.add_phony_target('print_version').set_functions(print_current_version) \
.add_phony_target('print_latest_changelog').set_functions(print_latest_changelog) \
.build()
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from util.io import TextFile
from util.log import Log

from targets.versioning.versioning import Version, get_current_version
from targets.version_files import Version, VersionFile

CHANGESET_FILE_MAIN = '.changelog-main.md'

Expand Down Expand Up @@ -341,7 +341,7 @@ def __merge_changesets(*changeset_files) -> List[Changeset]:

def __update_changelog(release_type: ReleaseType, *changeset_files):
merged_changesets = __merge_changesets(*changeset_files)
new_release = Release(version=get_current_version(),
new_release = Release(version=VersionFile().version,
release_date=date.today(),
release_type=release_type,
changesets=merged_changesets)
Expand Down Expand Up @@ -393,6 +393,13 @@ def update_changelog_bugfix():
__update_changelog(ReleaseType.PATCH, CHANGESET_FILE_BUGFIX)


def print_current_version():
"""
Prints the project's current version.
"""
return Log.info('%s', str(VersionFile().version))


def print_latest_changelog():
"""
Prints the changelog of the latest release.
Expand Down
8 changes: 4 additions & 4 deletions build_system/targets/compilation/cpp/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ def __init__(self):
def run(self, build_unit: BuildUnit, module: Module):
MesonSetup(build_unit, module, build_options=BUILD_OPTIONS).run()

def get_output_files(self, module: Module) -> List[str]:
def get_output_files(self, _: BuildUnit, module: Module) -> List[str]:
return [module.build_directory]

def get_clean_files(self, module: Module) -> List[str]:
def get_clean_files(self, build_unit: BuildUnit, module: Module) -> List[str]:
Log.info('Removing C++ build files from directory "%s"...', module.root_directory)
return super().get_clean_files(module)
return super().get_clean_files(build_unit, module)


class CompileCpp(PhonyTarget.Runnable):
Expand Down Expand Up @@ -70,6 +70,6 @@ def run(self, build_unit: BuildUnit, module: Module):
Log.info('Installing shared libraries from directory "%s" into source tree...', module.root_directory)
MesonInstall(build_unit, module).run()

def get_clean_files(self, module: Module) -> List[str]:
def get_clean_files(self, _: BuildUnit, module: Module) -> List[str]:
Log.info('Removing shared libraries installed from directory "%s" from source tree...', module.root_directory)
return module.find_installed_files()
8 changes: 4 additions & 4 deletions build_system/targets/compilation/cython/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ def run(self, build_unit: BuildUnit, module: Module):
.add_dependencies('cython') \
.run()

def get_output_files(self, module: Module) -> List[str]:
def get_output_files(self, _: BuildUnit, module: Module) -> List[str]:
return [module.build_directory]

def get_clean_files(self, module: Module) -> List[str]:
def get_clean_files(self, build_unit: BuildUnit, module: Module) -> List[str]:
Log.info('Removing Cython build files from directory "%s"...', module.root_directory)
return super().get_clean_files(module)
return super().get_clean_files(build_unit, module)


class CompileCython(PhonyTarget.Runnable):
Expand Down Expand Up @@ -69,6 +69,6 @@ def run(self, build_unit: BuildUnit, module: Module):
Log.info('Installing extension modules from directory "%s" into source tree...', module.root_directory)
MesonInstall(build_unit, module).run()

def get_clean_files(self, module: Module) -> List[str]:
def get_clean_files(self, _: BuildUnit, module: Module) -> List[str]:
Log.info('Removing extension modules installed from directory "%s" from source tree...', module.root_directory)
return module.find_installed_files()
8 changes: 4 additions & 4 deletions build_system/targets/documentation/cpp/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ def run(self, build_unit: BuildUnit, module: Module):
Doxygen(build_unit, module).run()
BreatheApidoc(build_unit, module).run()

def get_output_files(self, module: Module) -> List[str]:
def get_output_files(self, _: BuildUnit, module: Module) -> List[str]:
return [module.output_directory]

def get_input_files(self, module: Module) -> List[str]:
def get_input_files(self, _: BuildUnit, module: Module) -> List[str]:
return module.find_header_files()

def get_clean_files(self, module: Module) -> List[str]:
def get_clean_files(self, build_unit: BuildUnit, module: Module) -> List[str]:
Log.info('Removing C++ API documentation for directory "%s"...', module.root_directory)
return super().get_clean_files(module)
return super().get_clean_files(build_unit, module)


class ApidocIndexCpp(ApidocIndex):
Expand Down
8 changes: 4 additions & 4 deletions build_system/targets/documentation/python/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ def run(self, build_unit: BuildUnit, module: Module):
Log.info('Generating Python API documentation for directory "%s"...', module.root_directory)
SphinxApidoc(build_unit, module).run()

def get_output_files(self, module: Module) -> List[str]:
def get_output_files(self, _: BuildUnit, module: Module) -> List[str]:
return [module.output_directory]

def get_input_files(self, module: Module) -> List[str]:
def get_input_files(self, _: BuildUnit, module: Module) -> List[str]:
return module.find_source_files()

def get_clean_files(self, module: Module) -> List[str]:
def get_clean_files(self, build_unit: BuildUnit, module: Module) -> List[str]:
Log.info('Removing Python API documentation for directory "%s"...', module.root_directory)
return super().get_clean_files(module)
return super().get_clean_files(build_unit, module)


class ApidocIndexPython(ApidocIndex):
Expand Down
16 changes: 8 additions & 8 deletions build_system/targets/documentation/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,17 @@ def run_all(self, _: BuildUnit, modules: List[Module]):

TextFile(self.__index_file(template), accept_missing=True).write_lines(*new_lines)

def get_input_files(self, module: Module) -> List[str]:
def get_input_files(self, _: BuildUnit, module: Module) -> List[str]:
template = self.__get_template(module)
return [template] if template else []

def get_output_files(self, module: Module) -> List[str]:
def get_output_files(self, _: BuildUnit, module: Module) -> List[str]:
template = self.__get_template(module)
return [self.__index_file(template)] if template else []

def get_clean_files(self, module: Module) -> List[str]:
def get_clean_files(self, build_unit: BuildUnit, module: Module) -> List[str]:
Log.info('Removing index file referencing API documentation in directory "%s"', module.output_directory)
return super().get_clean_files(module)
return super().get_clean_files(build_unit, module)


class BuildDocumentation(BuildTarget.Runnable):
Expand All @@ -85,12 +85,12 @@ def run(self, build_unit: BuildUnit, module: Module):
SphinxBuild(build_unit, module, builder='linkcheck').run()
SphinxBuild(build_unit, module).run()

def get_input_files(self, module: Module) -> List[str]:
def get_input_files(self, _: BuildUnit, module: Module) -> List[str]:
return module.find_source_files()

def get_output_files(self, module: Module) -> List[str]:
def get_output_files(self, _: BuildUnit, module: Module) -> List[str]:
return [module.output_directory]

def get_clean_files(self, module: Module) -> List[str]:
def get_clean_files(self, build_unit: BuildUnit, module: Module) -> List[str]:
Log.info('Removing documentation generated for directory "%s"...', module.root_directory)
return super().get_clean_files(module)
return super().get_clean_files(build_unit, module)
6 changes: 3 additions & 3 deletions build_system/targets/packaging/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ def __init__(self, root_directory: str, wheel_directory_name: str):
self.wheel_directory_name = wheel_directory_name

@property
def package_name(self) -> str:
def pyproject_toml_file(self) -> str:
"""
The name of the Python package.
The path to the pyproject.toml file that specifies the meta-data of the package.
"""
return 'mlrl-' + self.subproject_name
return path.join(self.root_directory, 'pyproject.toml')

@property
def wheel_directory(self) -> str:
Expand Down
1 change: 1 addition & 0 deletions build_system/targets/packaging/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
build >= 1.2, < 1.3
wheel >= 0.45, < 0.46
toml >= 0.10, < 0.11
17 changes: 10 additions & 7 deletions build_system/targets/packaging/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from targets.packaging.build import Build
from targets.packaging.modules import PythonPackageModule
from targets.packaging.pip import PipInstallWheel
from targets.packaging.toml_file import TomlFile
from targets.paths import Project

MODULE_FILTER = PythonPackageModule.Filter()
Expand All @@ -31,7 +32,7 @@ def run(self, build_unit: BuildUnit, module: Module):
Log.info('Building Python wheels for directory "%s"...', module.root_directory)
Build(build_unit, module).run()

def get_input_files(self, module: Module) -> List[str]:
def get_input_files(self, _: BuildUnit, module: Module) -> List[str]:
file_search = Project.Python.file_search() \
.set_symlinks(False) \
.filter_by_file_type(
Expand All @@ -43,10 +44,10 @@ def get_input_files(self, module: Module) -> List[str]:
)
return file_search.list(module.root_directory)

def get_output_files(self, module: Module) -> List[str]:
def get_output_files(self, _: BuildUnit, module: Module) -> List[str]:
return [module.wheel_directory]

def get_clean_files(self, module: Module) -> List[str]:
def get_clean_files(self, _: BuildUnit, module: Module) -> List[str]:
clean_files = []
Log.info('Removing Python wheels from directory "%s"...', module.root_directory)
clean_files.append(module.wheel_directory)
Expand All @@ -71,10 +72,12 @@ def run(self, _: BuildUnit, module: Module):
Log.info('Installing Python wheels for directory "%s"...', module.root_directory)
PipInstallWheel().install_wheels(*module.find_wheels())

def get_input_files(self, module: Module) -> List[str]:
def get_input_files(self, _: BuildUnit, module: Module) -> List[str]:
return module.find_wheels()

def get_clean_files(self, module: Module) -> List[str]:
def get_clean_files(self, build_unit: BuildUnit, module: Module) -> List[str]:
Log.info('Uninstalling Python packages for directory "%s"...', module.root_directory)
PipInstallWheel().uninstall_packages(module.package_name)
return super().get_clean_files(module)
pyproject_toml_file = TomlFile(build_unit, module.pyproject_toml_file)
package_name = pyproject_toml_file.toml_dict['project']['name']
PipInstallWheel().uninstall_packages(package_name)
return super().get_clean_files(build_unit, module)
45 changes: 45 additions & 0 deletions build_system/targets/packaging/toml_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""
Author: Michael Rapp ([email protected])
Provides utilities for reading and writing TOML files via "toml".
"""
from functools import cached_property
from typing import Dict

from core.build_unit import BuildUnit
from util.io import TextFile, read_file
from util.pip import Pip


class TomlFile(TextFile):
"""
A TOML file.
"""

def __init__(self, build_unit: BuildUnit, file: str):
"""
:param build_unit: The build unit from which the TOML file is read
:param file: The path to the TOML file
"""
super().__init__(file)
self.build_unit = build_unit

@cached_property
def toml_dict(self) -> Dict:
"""
A dictionary that stores the content of the TOML file.
"""
Pip.for_build_unit(self.build_unit).install_packages('toml')
# pylint: disable=import-outside-toplevel
import toml
with read_file(self.file) as file:
toml_dict = toml.loads(file.read())
return toml_dict if toml_dict else {}

def write_lines(self, *lines: str):
super().write_lines(*lines)

try:
del self.toml_dict
except AttributeError:
pass
Loading

0 comments on commit b9ad6cc

Please sign in to comment.