Skip to content

Commit f09a289

Browse files
committed
language plugins
1 parent e06216c commit f09a289

28 files changed

+629
-261
lines changed

continuous_delivery_scripts/generate_docs.py

Lines changed: 6 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,16 @@
22
# Copyright (C) 2020 Arm Mbed. All rights reserved.
33
# SPDX-License-Identifier: Apache-2.0
44
#
5-
"""Generates documentation using Pdoc."""
5+
"""Generates documentation."""
6+
import argparse
7+
import logging
68
import os
79
import shutil
810
import sys
9-
10-
import argparse
11-
import logging
1211
from pathlib import Path
13-
from subprocess import check_call
14-
from typing import List
1512

13+
from continuous_delivery_scripts.language_specifics import get_language_specifics
1614
from continuous_delivery_scripts.utils.configuration import configuration, ConfigurationVariable
17-
from continuous_delivery_scripts.utils.filesystem_helpers import TemporaryDirectory
1815
from continuous_delivery_scripts.utils.logging import log_exception
1916

2017
logger = logging.getLogger(__name__)
@@ -26,40 +23,11 @@ def _clear_previous_docs(output_directory: Path) -> None:
2623
shutil.rmtree(str(output_directory))
2724

2825

29-
def _generate_pdoc_command_list(output_directory: Path, module: str) -> List[str]:
30-
return [
31-
"pdoc",
32-
"--html",
33-
f"{module}",
34-
"--output-dir",
35-
f"{str(output_directory)}",
36-
"--force",
37-
"--config",
38-
"show_type_annotations=True",
39-
]
40-
41-
4226
def generate_documentation(output_directory: Path, module_to_document: str) -> None:
43-
"""Ensures the documentation is in the correct location.
44-
45-
Pdoc nests its docs output in a folder with the module's name.
46-
This process removes this unwanted folder.
47-
"""
27+
"""Generates the documentation."""
4828
_clear_previous_docs(output_directory)
4929
os.makedirs(str(output_directory), exist_ok=True)
50-
with TemporaryDirectory() as temp_dir:
51-
_call_pdoc(temp_dir, module_to_document)
52-
docs_contents_dir = temp_dir.joinpath(module_to_document)
53-
if docs_contents_dir.exists() and docs_contents_dir.is_dir():
54-
for element in docs_contents_dir.iterdir():
55-
shutil.move(str(element), str(output_directory))
56-
57-
58-
def _call_pdoc(output_directory: Path, module: str) -> None:
59-
"""Calls Pdoc for generating the docs."""
60-
logger.info("Creating Pdoc documentation.")
61-
command_list = _generate_pdoc_command_list(output_directory, module)
62-
check_call(command_list)
30+
get_language_specifics().generate_code_documentation(output_directory, module_to_document)
6331

6432

6533
def generate_docs(output_directory: Path, module: str) -> int:
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""Language plugins Loader."""
2+
3+
import logging
4+
from typing import Optional, Dict, cast
5+
6+
from continuous_delivery_scripts.utils.configuration import configuration, ConfigurationVariable
7+
from continuous_delivery_scripts.utils.language_specifics_base import BaseLanguage
8+
9+
# this import is needed for plugin subclass detection
10+
from continuous_delivery_scripts.plugins import * # noqa
11+
12+
logger = logging.getLogger(__name__)
13+
14+
15+
def _all_language_plugins() -> Dict[str, BaseLanguage]:
16+
"""Get all language plugins which inherit from BaseLanguage (with the exception of other base class).
17+
18+
:return: A list of classes containing language plugins
19+
"""
20+
all_plugins = BaseLanguage.__subclasses__()
21+
return {
22+
la.get_related_language().lower().strip(): la
23+
for la in [lang() for lang in all_plugins if lang != BaseLanguage] # type: ignore
24+
}
25+
26+
27+
def _sanitise_program_language() -> str:
28+
return str(configuration.get_value(ConfigurationVariable.PROGRAMMING_LANGUAGE)).lower().strip()
29+
30+
31+
def _fetch_project_language_specifics() -> BaseLanguage:
32+
return cast(BaseLanguage, _all_language_plugins().get(_sanitise_program_language()))
33+
34+
35+
class PluginLoader:
36+
"""Plugin loader."""
37+
38+
_instance: Optional[BaseLanguage] = None
39+
40+
def __init__(self) -> None:
41+
"""Initialiser."""
42+
if not PluginLoader._instance:
43+
PluginLoader._instance = _fetch_project_language_specifics()
44+
45+
@property
46+
def languageSpecifics(self) -> BaseLanguage:
47+
"""Gets project language specifics."""
48+
return cast(BaseLanguage, PluginLoader._instance)
49+
50+
51+
def get_language_specifics() -> BaseLanguage:
52+
"""Gets the language specific actions."""
53+
return PluginLoader().languageSpecifics

continuous_delivery_scripts/license_files.py

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,12 @@
1515
from datetime import datetime
1616
from continuous_delivery_scripts.utils.configuration import configuration, ConfigurationVariable
1717
from continuous_delivery_scripts.utils.logging import set_log_level, log_exception
18-
from continuous_delivery_scripts.utils.python_helpers import flatten_dictionary
18+
from continuous_delivery_scripts.utils.python.python_helpers import flatten_dictionary
19+
from continuous_delivery_scripts.language_specifics import get_language_specifics
1920
from pathlib import Path
2021

2122
logger = logging.getLogger(__name__)
2223

23-
LICENCE_HEADER_TEMPLATE = """Copyright (C) {date} {author}. All rights reserved.
24-
SPDX-License-Identifier: {licence_identifier}
25-
"""
26-
2724
FILES_TO_IGNORE = ["*.yml", "*.yaml"]
2825

2926

@@ -34,7 +31,9 @@ def add_licence_header(verbose_count: int) -> None:
3431
"""
3532
# copyright (https://github.com/knipknap/copyright) was first considered but
3633
# comprises quite a few bugs and does not seem active anymore.
37-
template_string = _generate_header_template()
34+
if not get_language_specifics().can_add_licence_headers():
35+
return
36+
template_string = get_language_specifics().generate_source_licence_header_template()
3837
with tempfile.NamedTemporaryFile(suffix=".tmpl", delete=False) as template_file:
3938
template_file_path = Path(template_file.name)
4039
logger.debug(f"Creates template file in {str(template_file_path)}")
@@ -44,15 +43,6 @@ def add_licence_header(verbose_count: int) -> None:
4443
_call_licensehearders(copyright_config, verbose_count)
4544

4645

47-
def _generate_header_template() -> str:
48-
"""Generates the header template which is put at the top of source files."""
49-
return LICENCE_HEADER_TEMPLATE.format(
50-
licence_identifier=configuration.get_value(ConfigurationVariable.FILE_LICENCE_IDENTIFIER),
51-
author="${owner}",
52-
date="${years}",
53-
)
54-
55-
5646
def _call_licensehearders(config: dict, verbose_count: int) -> None:
5747
"""Runs licenseheaders tool."""
5848
args = ["licenseheaders"]
@@ -83,7 +73,7 @@ def get_tool_config(template_file: Path) -> dict:
8373
"projname": configuration.get_value(ConfigurationVariable.PROJECT_NAME),
8474
"tmpl": str(template_file),
8575
"years": copyright_dates,
86-
"additional-extensions": "python=.toml",
76+
"additional-extensions": "python=.toml c=.go",
8777
"exclude": FILES_TO_IGNORE,
8878
}
8979

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""Language specific actions."""
2+
import glob
3+
import os
4+
5+
all_plugin_files = [
6+
os.path.splitext(os.path.basename(filename))[0]
7+
for filename in glob.glob(os.path.join(os.path.dirname(__file__), "*.py"))
8+
]
9+
__all__ = all_plugin_files
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""Plugin for Golang projects."""
2+
import logging
3+
from pathlib import Path
4+
from typing import Optional
5+
from continuous_delivery_scripts.utils.language_specifics_base import BaseLanguage, get_language_from_file_name
6+
from continuous_delivery_scripts.spdx_report.spdx_project import SpdxProject
7+
8+
logger = logging.getLogger(__name__)
9+
10+
11+
class Go(BaseLanguage):
12+
"""Specific actions for a Golang project."""
13+
14+
def get_related_language(self) -> str:
15+
"""Gets the related language."""
16+
return get_language_from_file_name(__file__)
17+
18+
def package_software(self) -> None:
19+
"""No operation."""
20+
super().package_software()
21+
22+
def release_package_to_repository(self) -> None:
23+
"""No operation."""
24+
super().release_package_to_repository()
25+
26+
def check_credentials(self) -> None:
27+
"""Checks any credentials."""
28+
super().check_credentials()
29+
30+
def generate_code_documentation(self, output_directory: Path, module_to_document: str) -> None:
31+
"""Generates the code documentation."""
32+
super().generate_code_documentation(output_directory, module_to_document)
33+
# TODO
34+
35+
def can_add_licence_headers(self) -> bool:
36+
"""States that licence headers can be added."""
37+
return True
38+
39+
def can_get_project_metadata(self) -> bool:
40+
"""States whether project metadata can be retrieved."""
41+
return False
42+
43+
def get_current_spdx_project(self) -> Optional[SpdxProject]:
44+
"""Gets current SPDX description."""
45+
# TODO
46+
return None
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""No Operation plugin."""
2+
import logging
3+
from pathlib import Path
4+
5+
from continuous_delivery_scripts.spdx_report.spdx_project import SpdxProject
6+
from continuous_delivery_scripts.utils.language_specifics_base import BaseLanguage, get_language_from_file_name
7+
from typing import Optional
8+
9+
logger = logging.getLogger(__name__)
10+
11+
12+
class NoOp(BaseLanguage):
13+
"""Specific actions for a NoOp project."""
14+
15+
def get_related_language(self) -> str:
16+
"""Gets the related language."""
17+
return get_language_from_file_name(__file__)
18+
19+
def package_software(self) -> None:
20+
"""No Op."""
21+
super().package_software()
22+
23+
def release_package_to_repository(self) -> None:
24+
"""No Op."""
25+
super().release_package_to_repository()
26+
27+
def check_credentials(self) -> None:
28+
"""No Op."""
29+
super().check_credentials()
30+
31+
def generate_code_documentation(self, output_directory: Path, module_to_document: str) -> None:
32+
"""No Op."""
33+
super().generate_code_documentation(output_directory, module_to_document)
34+
35+
def can_add_licence_headers(self) -> bool:
36+
"""No Op."""
37+
return False
38+
39+
def can_get_project_metadata(self) -> bool:
40+
"""No Op."""
41+
"""States whether project metadata can be retrieved."""
42+
return False
43+
44+
def get_current_spdx_project(self) -> Optional[SpdxProject]:
45+
"""No Op."""
46+
return None

0 commit comments

Comments
 (0)