Skip to content

Commit

Permalink
Merge Repositories (#110)
Browse files Browse the repository at this point in the history
All plugins, test plugins, and schemas are now housed in a single repository using optional dependencies.
  • Loading branch information
Behemyth authored Nov 20, 2024
1 parent 43b613e commit 27aa21b
Show file tree
Hide file tree
Showing 101 changed files with 5,749 additions and 865 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ __pypackages__/
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/extensions.json
/.mypy_cache
node_modules/
build/
5 changes: 3 additions & 2 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"recommendations": [
"ms-python.mypy-type-checker",
"ms-python.pylint",
"ms-python.black-formatter"
"ms-python.black-formatter",
"asciidoctor.asciidoctor-vscode",
"charliermarsh.ruff"
]
}
8 changes: 7 additions & 1 deletion cppython/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@

"""The CPPython project.
This module serves as the entry point for the CPPython project, a Python-based
solution for managing C++ dependencies. It includes core functionality, plugin
interfaces, and utility functions that facilitate the integration and management
of various tools and systems.
"""
100 changes: 46 additions & 54 deletions cppython/builder.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
"""Defines the data and routines for building a CPPython project type"""

import logging
from importlib import metadata
from importlib.metadata import entry_points
from inspect import getmodule
from logging import Logger
from typing import Any

from cppython_core.exceptions import PluginError
from cppython_core.plugin_schema.generator import Generator
from cppython_core.plugin_schema.provider import Provider
from cppython_core.plugin_schema.scm import SCM
from cppython_core.resolution import (
from cppython.core.plugin_schema.generator import Generator
from cppython.core.plugin_schema.provider import Provider
from cppython.core.plugin_schema.scm import SCM
from cppython.core.resolution import (
PluginBuildData,
PluginCPPythonData,
resolve_cppython,
Expand All @@ -21,7 +20,7 @@
resolve_provider,
resolve_scm,
)
from cppython_core.schema import (
from cppython.core.schema import (
CoreData,
CorePluginData,
CPPythonGlobalConfiguration,
Expand All @@ -32,15 +31,16 @@
ProjectConfiguration,
ProjectData,
)

from cppython.data import Data, Plugins
from cppython.defaults import DefaultSCM
from cppython.utility.exception import PluginError


class Resolver:
"""The resolution of data sources for the builder"""

def __init__(self, project_configuration: ProjectConfiguration, logger: Logger) -> None:

"""Initializes the resolver"""
self._project_configuration = project_configuration
self._logger = logger

Expand All @@ -56,19 +56,18 @@ def generate_plugins(
Returns:
The resolved plugin data
"""

raw_generator_plugins = self.find_generators()
generator_plugins = self.filter_plugins(
raw_generator_plugins,
cppython_local_configuration.generator_name,
"Generator",
'Generator',
)

raw_provider_plugins = self.find_providers()
provider_plugins = self.filter_plugins(
raw_provider_plugins,
cppython_local_configuration.provider_name,
"Provider",
'Provider',
)

scm_plugins = self.find_source_managers()
Expand All @@ -80,7 +79,8 @@ def generate_plugins(

return PluginBuildData(generator_type=generator_type, provider_type=provider_type, scm_type=scm_type)

def generate_cppython_plugin_data(self, plugin_build_data: PluginBuildData) -> PluginCPPythonData:
@staticmethod
def generate_cppython_plugin_data(plugin_build_data: PluginBuildData) -> PluginCPPythonData:
"""Generates the CPPython plugin data from the resolved plugins
Args:
Expand All @@ -89,15 +89,15 @@ def generate_cppython_plugin_data(self, plugin_build_data: PluginBuildData) -> P
Returns:
The plugin data used by CPPython
"""

return PluginCPPythonData(
generator_name=plugin_build_data.generator_type.name(),
provider_name=plugin_build_data.provider_type.name(),
scm_name=plugin_build_data.scm_type.name(),
)

@staticmethod
def generate_pep621_data(
self, pep621_configuration: PEP621Configuration, project_configuration: ProjectConfiguration, scm: SCM | None
pep621_configuration: PEP621Configuration, project_configuration: ProjectConfiguration, scm: SCM | None
) -> PEP621Data:
"""Generates the PEP621 data from configuration sources
Expand All @@ -111,13 +111,13 @@ def generate_pep621_data(
"""
return resolve_pep621(pep621_configuration, project_configuration, scm)

def resolve_global_config(self) -> CPPythonGlobalConfiguration:
@staticmethod
def resolve_global_config() -> CPPythonGlobalConfiguration:
"""Generates the global configuration object
Returns:
The global configuration object
"""

return CPPythonGlobalConfiguration()

def find_generators(self) -> list[type[Generator]]:
Expand All @@ -129,24 +129,23 @@ def find_generators(self) -> list[type[Generator]]:
Returns:
The list of generator plugin types
"""

group_name = "generator"
group_name = 'generator'
plugin_types: list[type[Generator]] = []

# Filter entries by type
for entry_point in list(metadata.entry_points(group=f"cppython.{group_name}")):
for entry_point in list(entry_points(group=f'cppython.{group_name}')):
loaded_type = entry_point.load()
if not issubclass(loaded_type, Generator):
self._logger.warning(
f"Found incompatible plugin. The '{loaded_type.name()}' plugin must be an instance of"
f" '{group_name}'"
)
else:
self._logger.warning(f"{group_name} plugin found: {loaded_type.name()} from {getmodule(loaded_type)}")
self._logger.warning(f'{group_name} plugin found: {loaded_type.name()} from {getmodule(loaded_type)}')
plugin_types.append(loaded_type)

if not plugin_types:
raise PluginError(f"No {group_name} plugin was found")
raise PluginError(f'No {group_name} plugin was found')

return plugin_types

Expand All @@ -159,24 +158,23 @@ def find_providers(self) -> list[type[Provider]]:
Returns:
The list of provider plugin types
"""

group_name = "provider"
group_name = 'provider'
plugin_types: list[type[Provider]] = []

# Filter entries by type
for entry_point in list(metadata.entry_points(group=f"cppython.{group_name}")):
for entry_point in list(entry_points(group=f'cppython.{group_name}')):
loaded_type = entry_point.load()
if not issubclass(loaded_type, Provider):
self._logger.warning(
f"Found incompatible plugin. The '{loaded_type.name()}' plugin must be an instance of"
f" '{group_name}'"
)
else:
self._logger.warning(f"{group_name} plugin found: {loaded_type.name()} from {getmodule(loaded_type)}")
self._logger.warning(f'{group_name} plugin found: {loaded_type.name()} from {getmodule(loaded_type)}')
plugin_types.append(loaded_type)

if not plugin_types:
raise PluginError(f"No {group_name} plugin was found")
raise PluginError(f'No {group_name} plugin was found')

return plugin_types

Expand All @@ -189,30 +187,29 @@ def find_source_managers(self) -> list[type[SCM]]:
Returns:
The list of source control manager plugin types
"""

group_name = "scm"
group_name = 'scm'
plugin_types: list[type[SCM]] = []

# Filter entries by type
for entry_point in list(metadata.entry_points(group=f"cppython.{group_name}")):
for entry_point in list(entry_points(group=f'cppython.{group_name}')):
loaded_type = entry_point.load()
if not issubclass(loaded_type, SCM):
self._logger.warning(
f"Found incompatible plugin. The '{loaded_type.name()}' plugin must be an instance of"
f" '{group_name}'"
)
else:
self._logger.warning(f"{group_name} plugin found: {loaded_type.name()} from {getmodule(loaded_type)}")
self._logger.warning(f'{group_name} plugin found: {loaded_type.name()} from {getmodule(loaded_type)}')
plugin_types.append(loaded_type)

if not plugin_types:
raise PluginError(f"No {group_name} plugin was found")
raise PluginError(f'No {group_name} plugin was found')

return plugin_types

def filter_plugins[
T: DataPlugin
](self, plugin_types: list[type[T]], pinned_name: str | None, group_name: str) -> list[type[T]]:
def filter_plugins[T: DataPlugin](
self, plugin_types: list[type[T]], pinned_name: str | None, group_name: str
) -> list[type[T]]:
"""Finds and filters data plugins
Args:
Expand All @@ -226,13 +223,12 @@ def filter_plugins[
Returns:
The list of applicable plugins
"""

# Lookup the requested plugin if given
if pinned_name is not None:
for loaded_type in plugin_types:
if loaded_type.name() == pinned_name:
self._logger.warning(
f"Using {group_name} plugin: {loaded_type.name()} from {getmodule(loaded_type)}"
f'Using {group_name} plugin: {loaded_type.name()} from {getmodule(loaded_type)}'
)
return [loaded_type]

Expand All @@ -243,13 +239,13 @@ def filter_plugins[
# Deduce types
for loaded_type in plugin_types:
self._logger.warning(
f"A {group_name} plugin is supported: {loaded_type.name()} from {getmodule(loaded_type)}"
f'A {group_name} plugin is supported: {loaded_type.name()} from {getmodule(loaded_type)}'
)
supported_types.append(loaded_type)

# Fail
if supported_types is None:
raise PluginError(f"No {group_name} could be deduced from the root directory.")
raise PluginError(f'No {group_name} could be deduced from the root directory.')

return supported_types

Expand All @@ -260,21 +256,20 @@ def select_scm(self, scm_plugins: list[type[SCM]], project_data: ProjectData) ->
scm_plugins: The list of SCM plugin types
project_data: The project data
Raises:
PluginError: Raised if no SCM plugin was found that supports the given data
Returns:
The selected SCM plugin type
"""

for scm_type in scm_plugins:
if scm_type.features(project_data.pyproject_file.parent).repository:
return scm_type

raise PluginError("No SCM plugin was found that supports the given path")
self._logger.info('No SCM plugin was found that supports the given path')

return DefaultSCM

@staticmethod
def solve(
self, generator_types: list[type[Generator]], provider_types: list[type[Provider]]
generator_types: list[type[Generator]], provider_types: list[type[Provider]]
) -> tuple[type[Generator], type[Provider]]:
"""Selects the first generator and provider that can work together
Expand All @@ -288,7 +283,6 @@ def solve(
Returns:
A tuple of the selected generator and provider plugin types
"""

combos: list[tuple[type[Generator], type[Provider]]] = []

for generator_type in generator_types:
Expand All @@ -300,12 +294,12 @@ def solve(
break

if not combos:
raise PluginError("No provider that supports a given generator could be deduced")
raise PluginError('No provider that supports a given generator could be deduced')

return combos[0]

@staticmethod
def create_scm(
self,
core_data: CoreData,
scm_type: type[SCM],
) -> SCM:
Expand All @@ -318,7 +312,6 @@ def create_scm(
Returns:
The constructed source control manager
"""

cppython_plugin_data = resolve_cppython_plugin(core_data.cppython_data, scm_type)
scm_data = resolve_scm(core_data.project_data, cppython_plugin_data)

Expand All @@ -344,7 +337,6 @@ def create_generator(
Returns:
The constructed generator
"""

cppython_plugin_data = resolve_cppython_plugin(core_data.cppython_data, generator_type)

generator_data = resolve_generator(core_data.project_data, cppython_plugin_data)
Expand Down Expand Up @@ -380,7 +372,6 @@ def create_provider(
Returns:
A constructed provider plugins
"""

cppython_plugin_data = resolve_cppython_plugin(core_data.cppython_data, provider_type)

provider_data = resolve_provider(core_data.project_data, cppython_plugin_data)
Expand All @@ -403,6 +394,7 @@ class Builder:
"""Helper class for building CPPython projects"""

def __init__(self, project_configuration: ProjectConfiguration, logger: Logger) -> None:
"""Initializes the builder"""
self._project_configuration = project_configuration
self._logger = logger

Expand All @@ -413,7 +405,7 @@ def __init__(self, project_configuration: ProjectConfiguration, logger: Logger)
self._logger.addHandler(logging.StreamHandler())
self._logger.setLevel(levels[project_configuration.verbosity])

self._logger.info("Logging setup complete")
self._logger.info('Logging setup complete')

self._resolver = Resolver(self._project_configuration, self._logger)

Expand All @@ -428,12 +420,12 @@ def build(
Args:
pep621_configuration: The PEP621 configuration
cppython_local_configuration: The local configuration
plugin_build_data: Plugin override data. If it exists, the build will use the given types instead of resolving them
plugin_build_data: Plugin override data. If it exists, the build will use the given types
instead of resolving them
Returns:
The built data object
"""

project_data = resolve_project_configuration(self._project_configuration)

if plugin_build_data is None:
Expand Down
7 changes: 6 additions & 1 deletion cppython/console/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@

"""Console interface for the CPPython project.
This module provides a command-line interface (CLI) for interacting with the
CPPython project. It includes commands for managing project configurations,
installing dependencies, and updating project data.
"""
Loading

0 comments on commit 27aa21b

Please sign in to comment.