Coverage for src / mafw / devtools / cli / documentation / server.py: 96%

47 statements  

« prev     ^ index     » next       coverage.py v7.14.0, created at 2026-06-28 13:34 +0000

1# Copyright 2025–2026 European Union 

2# Author: Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu) 

3# SPDX-License-Identifier: EUPL-1.2 

4"""CLI commands for managing a local documentation server.""" 

5 

6from __future__ import annotations 

7 

8from pathlib import Path 

9 

10import click 

11 

12from mafw.devtools.documentation.server import ( 

13 SERVER_DEFAULT_DIRECTORY, 

14 ServerStatusEnum, 

15 get_server_status, 

16 read_server_metadata, 

17 server_default_directory, 

18 server_metadata_path, 

19 server_start_impl, 

20 server_stop_by_metadata, 

21) 

22from mafw.tools.click_extensions import AbbreviateGroup 

23 

24 

25@click.group(cls=AbbreviateGroup) 

26def server() -> None: 

27 """Manage a local web server for browsing documentation over HTTP.""" 

28 

29 

30@server.command(name='start') 

31@click.option('-b', '--bind', 'address', default='127.0.0.1', help='IP address to bind (default: 127.0.0.1).') 

32@click.option('-p', '--port', default=8000, type=int, help='Port number where to listen (default: 8000).') 

33@click.option( 

34 '-d', 

35 '--directory', 

36 default=SERVER_DEFAULT_DIRECTORY, 

37 type=click.Path(file_okay=False, dir_okay=True, path_type=Path), 

38 help='Folder to serve (default: docs/build).', 

39) 

40@click.option( 

41 '-l', 

42 '--log-file', 

43 default=Path('doc-server.log'), 

44 type=click.Path(dir_okay=False, path_type=Path), 

45 help='Log file for server output (default: doc-server.log).', 

46) 

47@click.option('-f', '--force-restart', is_flag=True, default=False, help='Force restart if already running.') 

48def server_start(address: str, port: int, directory: Path, log_file: Path, force_restart: bool) -> None: 

49 """Start a local documentation server (python -m http.server).""" 

50 server_start_impl(address=address, port=port, directory=directory, log_file=log_file, force_restart=force_restart) 

51 

52 

53@server.command(name='status') 

54def server_status() -> None: 

55 """Show the current status of the local documentation server.""" 

56 directory = server_default_directory() 

57 meta_path = server_metadata_path(directory) 

58 

59 try: 

60 status, metadata = get_server_status(directory) 

61 except click.ClickException as e: 

62 raise click.ClickException(f'{e} (while reading: {meta_path})') from e 

63 

64 if status == ServerStatusEnum.unknown: 

65 print('status: unknown (metadata not found)') 

66 return 

67 

68 assert metadata is not None 

69 url = f'http://{metadata["address"]}:{metadata["port"]}' 

70 print(f'status: {status} ({url})') 

71 

72 

73@server.command(name='stop') 

74def server_stop() -> None: 

75 """Stop the local documentation server.""" 

76 directory = server_default_directory() 

77 server_stop_by_metadata(directory, require_metadata=True) 

78 

79 

80@server.command(name='restart') 

81def server_restart() -> None: 

82 """Restart the local documentation server.""" 

83 directory = server_default_directory() 

84 metadata = read_server_metadata(directory) 

85 if metadata is None: 

86 server_stop_by_metadata(directory, require_metadata=False) 

87 server_start_impl( 

88 address='127.0.0.1', port=8000, directory=directory, log_file=Path('doc-server.log'), force_restart=False 

89 ) 

90 return 

91 

92 address = metadata.get('address', '127.0.0.1') 

93 port = metadata.get('port', 8000) 

94 directory_value = metadata.get('directory', str(directory)) 

95 log_file_value = metadata.get('log_file', str(Path('doc-server.log').resolve())) 

96 

97 server_stop_by_metadata(directory, require_metadata=False) 

98 server_start_impl( 

99 address=str(address), 

100 port=int(port), 

101 directory=Path(directory_value), 

102 log_file=Path(log_file_value), 

103 force_restart=False, 

104 )