mirror of https://github.com/zulip/zulip.git
manage: Edit help text to hide unwanted commands.
Remove unwanted error producing commands from the help text displayed by `./manage.py help` to avoid confusion. Fixes #18770.
This commit is contained in:
parent
1b51792459
commit
6a8a259356
106
manage.py
106
manage.py
|
@ -2,6 +2,7 @@
|
|||
import configparser
|
||||
import os
|
||||
import sys
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
if sys.version_info <= (3, 0):
|
||||
print("Error: Zulip is a Python 3 project, and cannot be run with Python 2.")
|
||||
|
@ -14,8 +15,112 @@ from scripts.lib.setup_path import setup_path
|
|||
|
||||
setup_path()
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
from django.core.management import ManagementUtility, get_commands
|
||||
from django.core.management.color import color_style
|
||||
|
||||
from scripts.lib.zulip_tools import assert_not_running_as_root
|
||||
|
||||
|
||||
def get_filtered_commands() -> Dict[str, str]:
|
||||
"""Because Zulip uses management commands in production, `manage.py
|
||||
help` is a form of documentation for users. Here we exclude from
|
||||
that documentation built-in commands that are not constructive for
|
||||
end users or even Zulip developers to run.
|
||||
|
||||
Ideally, we'd do further customization to display management
|
||||
commands with more organization in the help text, and also hide
|
||||
development-focused management commands in production.
|
||||
"""
|
||||
all_commands = get_commands()
|
||||
documented_commands = dict()
|
||||
documented_apps = [
|
||||
# "auth" removed because its commands are not applicable to Zulip.
|
||||
# "contenttypes" removed because we don't use that subsystem, and
|
||||
# even if we did.
|
||||
"django.core",
|
||||
"analytics",
|
||||
# "otp_static" removed because it's a 2FA internals detail.
|
||||
# "sessions" removed because it's just a cron job with a misleading
|
||||
# name, since all it does is delete expired sessions.
|
||||
# "social_django" removed for similar reasons to sessions.
|
||||
# "staticfiles" removed because its commands are only usefully run when
|
||||
# wrapped by Zulip tooling.
|
||||
# "two_factor" removed because it's a 2FA internals detail.
|
||||
"zerver",
|
||||
"zilencer",
|
||||
]
|
||||
documented_command_subsets = {
|
||||
"django.core": {
|
||||
"dbshell",
|
||||
"makemigrations",
|
||||
"migrate",
|
||||
"shell",
|
||||
"showmigrations",
|
||||
},
|
||||
}
|
||||
for command, app in all_commands.items():
|
||||
if app not in documented_apps:
|
||||
continue
|
||||
if app in documented_command_subsets:
|
||||
if command not in documented_command_subsets[app]:
|
||||
continue
|
||||
|
||||
documented_commands[command] = app
|
||||
return documented_commands
|
||||
|
||||
|
||||
class FilteredManagementUtility(ManagementUtility):
|
||||
"""Replaces the main_help_text function of ManagementUtility with one
|
||||
that calls our get_filtered_commands(), rather than the default
|
||||
get_commands() function.
|
||||
|
||||
All other change are just code style differences to pass the Zulip linter.
|
||||
"""
|
||||
|
||||
def main_help_text(self, commands_only: bool = False) -> str:
|
||||
"""Return the script's main help text, as a string."""
|
||||
if commands_only:
|
||||
usage = sorted(get_filtered_commands())
|
||||
else:
|
||||
usage = [
|
||||
"",
|
||||
f"Type '{self.prog_name} help <subcommand>' for help on a specific subcommand.",
|
||||
"",
|
||||
"Available subcommands:",
|
||||
]
|
||||
commands_dict = defaultdict(lambda: [])
|
||||
for name, app in get_filtered_commands().items():
|
||||
if app == "django.core":
|
||||
app = "django"
|
||||
else:
|
||||
app = app.rpartition(".")[-1]
|
||||
commands_dict[app].append(name)
|
||||
style = color_style()
|
||||
for app in sorted(commands_dict):
|
||||
usage.append("")
|
||||
usage.append(style.NOTICE(f"[{app}]"))
|
||||
for name in sorted(commands_dict[app]):
|
||||
usage.append(f" {name}")
|
||||
# Output an extra note if settings are not properly configured
|
||||
if self.settings_exception is not None:
|
||||
usage.append(
|
||||
style.NOTICE(
|
||||
"Note that only Django core commands are listed "
|
||||
f"as settings are not properly configured (error: {self.settings_exception})."
|
||||
)
|
||||
)
|
||||
|
||||
return "\n".join(usage)
|
||||
|
||||
|
||||
def execute_from_command_line(argv: Optional[List[str]] = None) -> None:
|
||||
"""Run a FilteredManagementUtility."""
|
||||
utility = FilteredManagementUtility(argv)
|
||||
utility.execute()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
assert_not_running_as_root()
|
||||
|
||||
|
@ -38,7 +143,6 @@ if __name__ == "__main__":
|
|||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "zproject.settings")
|
||||
from django.conf import settings
|
||||
from django.core.management import execute_from_command_line
|
||||
from django.core.management.base import CommandError
|
||||
|
||||
from scripts.lib.zulip_tools import log_management_command
|
||||
|
|
Loading…
Reference in New Issue