Files
jcloud-docsgen/src/jcloud_docsgen/cli/cli.py
T

180 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('syntax error in project source code')
except KeyboardInterrupt:
return 130
except BrokenPipeError:
return 141
return 0