generated from jCloud/repository-template
Limited the lengths of all lines to 79 characters (if possible). Additionally, some other lines were breaked for consistence.
176 lines
5.1 KiB
Python
176 lines
5.1 KiB
Python
# Copyright 2026 jCloud
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
'''
|
|
The command line interface
|
|
'''
|
|
|
|
import argparse
|
|
import pathlib
|
|
import sys
|
|
from .languages.python import VALID_SECTIONS as VALID_PYTHON_SECTIONS
|
|
|
|
__all__ = [
|
|
'existing_directory',
|
|
'error',
|
|
'create_argument_parser',
|
|
'main'
|
|
]
|
|
|
|
_LANG_PYTHON = 'python'
|
|
_PROGRAM_NAME = 'jcloud-docsgen'
|
|
|
|
def existing_directory(path: str) -> pathlib.Path:
|
|
_path = path
|
|
path = pathlib.Path(_path)
|
|
if not path.exists():
|
|
raise argparse.ArgumentTypeError(
|
|
f'{_path}: no such file or directory'
|
|
)
|
|
if not path.is_dir():
|
|
raise argparse.ArgumentTypeError(f'{_path}: not a directory')
|
|
return path
|
|
|
|
def error(message: str, exit_code: int = 1):
|
|
'''
|
|
Shows an error message and returns the exit code.
|
|
|
|
:param message: The error message to show.
|
|
:type message: str
|
|
:param exit_code: The exit code.
|
|
:type exit_code: int
|
|
'''
|
|
|
|
print(f'{_PROGRAM_NAME}: error: {message}', file = sys.stderr)
|
|
return exit_code
|
|
|
|
def create_argument_parser() -> argparse.ArgumentParser:
|
|
'''
|
|
Prepares a parser to parse the command-line arguments using
|
|
argparse.
|
|
|
|
:return: The parser.
|
|
:rtype: argparse.ArgumentParser
|
|
'''
|
|
|
|
common_parser = argparse.ArgumentParser(add_help = False)
|
|
common_parser.add_argument(
|
|
'project_directory',
|
|
type = existing_directory,
|
|
nargs = '?',
|
|
default = pathlib.Path('.'),
|
|
help = 'The directory of the project'
|
|
)
|
|
common_parser.add_argument(
|
|
'-o',
|
|
'--output-dir',
|
|
type = pathlib.Path,
|
|
help = 'the output directory the documentation will be written to'
|
|
)
|
|
|
|
argument_parser = argparse.ArgumentParser()
|
|
|
|
subparsers = argument_parser.add_subparsers(
|
|
dest = 'language',
|
|
required = True
|
|
)
|
|
|
|
python_parser = subparsers.add_parser(
|
|
_LANG_PYTHON,
|
|
parents = [common_parser],
|
|
help = 'generate documentation for Python project'
|
|
)
|
|
python_parser.add_argument(
|
|
'-s',
|
|
'--sections',
|
|
nargs = '+',
|
|
choices = VALID_PYTHON_SECTIONS,
|
|
help = 'the sections to be included in the documentation'
|
|
)
|
|
python_parser.add_argument(
|
|
'-S',
|
|
'--sections-exclude',
|
|
nargs = '+',
|
|
default = [],
|
|
choices = VALID_PYTHON_SECTIONS,
|
|
help = (
|
|
'the sections to be excluded in the documentation. '
|
|
'If a section shall be included AND excluded, it is excluded.'
|
|
)
|
|
)
|
|
python_parser.add_argument(
|
|
'-H',
|
|
'--allow-html',
|
|
action = 'store_true',
|
|
help = (
|
|
'indicates whether HTML is allowed in the documentation. '
|
|
'By default, HTML is disabled.'
|
|
)
|
|
)
|
|
python_parser.add_argument(
|
|
'-T',
|
|
'--allow-tables',
|
|
action = 'store_true',
|
|
help = (
|
|
'indicates whether Markdown tables are allowed in the '
|
|
'documentation. By default, Markdown tables are disabled. '
|
|
'Warning: Markdown tables are not CommonMark.'
|
|
)
|
|
)
|
|
|
|
return argument_parser
|
|
|
|
def main(argv = None) -> int:
|
|
argument_parser = create_argument_parser()
|
|
args = argument_parser.parse_args(argv)
|
|
|
|
if args.output_dir is None:
|
|
args.output_dir = args.project_directory / 'docs/reference'
|
|
|
|
try:
|
|
if args.language == _LANG_PYTHON:
|
|
from .languages.python import generate
|
|
generate(
|
|
args.project_directory,
|
|
args.output_dir,
|
|
include_sections = args.sections,
|
|
exclude_sections = args.sections_exclude,
|
|
allow_html = args.allow_html,
|
|
allow_tables = args.allow_tables
|
|
)
|
|
except FileNotFoundError as exc:
|
|
return error(f'{exc.filename}: no such file or directory')
|
|
except NotADirectoryError as exc:
|
|
return error(f'{exc.filename}: not a directory')
|
|
except IsADirectoryError as exc:
|
|
return error(f'{exc.filename}: is a directory')
|
|
except FileExistsError as exc:
|
|
return error(f'{exc.filename}: file already exists')
|
|
except PermissionError as exc:
|
|
return error(f'{exc.filename}: permission denied')
|
|
except OSError as exc:
|
|
return error(f'{exc.filename}: {exc.args[1]}')
|
|
except UnicodeError:
|
|
return error('invalid text encoding')
|
|
except SyntaxError:
|
|
# TODO: add a custom exception class to clearify that a project
|
|
# parsing syntax error is meant.
|
|
return error(f'syntax error in project source code')
|
|
except KeyboardInterrupt:
|
|
return 130
|
|
except BrokenPipeError:
|
|
return 141
|
|
|
|
return 0
|