generated from jCloud/repository-template
179 lines
5.1 KiB
Python
179 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
|