Browse Source

ref: move sentry.runner.__init__.main to sentry.runner.main.main (#69963)

first step in breaking some nasty import cycles in sentry.runner.*

<!-- Describe your PR here. -->
anthony sottile 10 months ago
parent
commit
41515a30dd
4 changed files with 148 additions and 146 deletions
  1. 1 1
      setup.cfg
  2. 1 1
      src/sentry/__main__.py
  3. 0 144
      src/sentry/runner/__init__.py
  4. 146 0
      src/sentry/runner/main.py

+ 1 - 1
setup.cfg

@@ -32,7 +32,7 @@ where = src
 
 [options.entry_points]
 console_scripts =
-    sentry = sentry.runner:main
+    sentry = sentry.__main__:main
 sentry.apps =
     # TODO: This can be removed once the getsentry tests no longer check for this app
     auth_activedirectory = sentry.auth.providers.saml2.activedirectory

+ 1 - 1
src/sentry/__main__.py

@@ -1,4 +1,4 @@
-from .runner import main
+from .runner.main import main
 
 if __name__ == "__main__":
     main()

+ 0 - 144
src/sentry/runner/__init__.py

@@ -1,110 +1,12 @@
 from __future__ import annotations
 
-import logging
 import os
-import sys
 from typing import Any
 
 import click
-import sentry_sdk
 
-import sentry
 from sentry.utils.imports import import_string
 
-# Parse out a pretty version for use with --version
-version_string = sentry.__semantic_version__
-
-
-@click.group(context_settings={"max_content_width": 150})
-@click.option(
-    "--config",
-    default="",
-    envvar="SENTRY_CONF",
-    help="Path to configuration files.",
-    metavar="PATH",
-)
-@click.version_option(version=version_string)
-def cli(config: str) -> None:
-    """Sentry is cross-platform crash reporting built with love.
-
-    The configuration file is looked up in the `~/.sentry` config
-    directory but this can be overridden with the `SENTRY_CONF`
-    environment variable or be explicitly provided through the
-    `--config` parameter.
-    """
-    # Elevate --config option to SENTRY_CONF env var, and just assume this
-    # always will exist down the line
-    if config:
-        os.environ["SENTRY_CONF"] = config
-    os.environ.setdefault("SENTRY_CONF", "~/.sentry")
-
-
-# TODO(mattrobenolt): Autodiscover commands?
-for cmd in map(
-    import_string,
-    (
-        "sentry.runner.commands.backup.backup",
-        "sentry.runner.commands.backup.export",
-        "sentry.runner.commands.backup.import_",
-        "sentry.runner.commands.cleanup.cleanup",
-        "sentry.runner.commands.config.config",
-        "sentry.runner.commands.configoptions.configoptions",
-        "sentry.runner.commands.createuser.createuser",
-        "sentry.runner.commands.devserver.devserver",
-        "sentry.runner.commands.django.django",
-        "sentry.runner.commands.exec.exec_",
-        "sentry.runner.commands.sendmail.sendmail",
-        "sentry.runner.commands.execfile.execfile",
-        "sentry.runner.commands.files.files",
-        "sentry.runner.commands.help.help",
-        "sentry.runner.commands.init.init",
-        "sentry.runner.commands.killswitches.killswitches",
-        "sentry.runner.commands.migrations.migrations",
-        "sentry.runner.commands.plugins.plugins",
-        "sentry.runner.commands.queues.queues",
-        "sentry.runner.commands.repair.repair",
-        "sentry.runner.commands.run.run",
-        "sentry.runner.commands.start.start",
-        "sentry.runner.commands.tsdb.tsdb",
-        "sentry.runner.commands.upgrade.upgrade",
-        "sentry.runner.commands.permissions.permissions",
-        "sentry.runner.commands.devservices.devservices",
-        "sentry.runner.commands.performance.performance",
-        "sentry.runner.commands.spans.spans",
-        "sentry.runner.commands.spans.write_hashes",
-        "sentry.runner.commands.openai.openai",
-        "sentry.runner.commands.llm.llm",
-    ),
-):
-    cli.add_command(cmd)
-
-
-def make_django_command(
-    name: str, django_command: str | None = None, help: str | None = None
-) -> click.Command:
-    "A wrapper to convert a Django subcommand a Click command"
-    if django_command is None:
-        django_command = name
-
-    @click.command(
-        name=name,
-        help=help,
-        add_help_option=False,
-        context_settings=dict(ignore_unknown_options=True),
-    )
-    @click.argument("management_args", nargs=-1, type=click.UNPROCESSED)
-    @click.pass_context
-    def inner(ctx: click.Context, management_args: tuple[str, ...]) -> None:
-        from sentry.runner.commands.django import django
-
-        ctx.params["management_args"] = (django_command,) + management_args
-        ctx.forward(django)
-
-    return inner
-
-
-cli.add_command(make_django_command("shell", help="Run a Python interactive interpreter."))
-
 
 def configure(*, skip_service_validation: bool = False) -> None:
     """
@@ -131,21 +33,6 @@ def configure(*, skip_service_validation: bool = False) -> None:
     _configure(ctx, py, yaml, skip_service_validation)
 
 
-def get_prog() -> str:
-    """
-    Extract the proper program executable.
-
-    In the case of `python -m sentry`, we want to detect this and
-    make sure we return something useful rather than __main__.py
-    """
-    try:
-        if os.path.basename(sys.argv[0]) in ("__main__.py", "-c"):
-            return "%s -m sentry" % sys.executable
-    except (AttributeError, TypeError, IndexError):
-        pass
-    return "sentry"
-
-
 class UnknownCommand(ImportError):
     pass
 
@@ -162,34 +49,3 @@ def call_command(name: str, obj: object = None, **kwargs: Any) -> None:
             command.invoke(ctx)
         except click.Abort:
             click.echo("Aborted!", err=True)
-
-
-def main() -> None:
-    func = cli
-    kwargs = {
-        "prog_name": get_prog(),
-        "obj": {},
-        "max_content_width": 100,
-    }
-    # This variable is *only* set as part of direnv/.envrc, thus, we cannot affect production
-    if os.environ.get("SENTRY_DEVSERVICES_DSN"):
-        # We do this here because `configure_structlog` executes later
-        logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.INFO)
-        logger = logging.getLogger(__name__)
-
-        logger.info(
-            "The Sentry runner will report development issues to Sentry.io. "
-            "Use SENTRY_DEVENV_NO_REPORT to avoid reporting issues."
-        )
-        try:
-            func(**kwargs)
-        except Exception as e:
-            # This reports errors sentry-devservices
-            with sentry_sdk.init(dsn=os.environ["SENTRY_DEVSERVICES_DSN"]):
-                if os.environ.get("USER"):
-                    sentry_sdk.set_user({"username": os.environ.get("USER")})
-                sentry_sdk.capture_exception(e)
-                logger.info("We have reported the error below to Sentry")
-            raise
-    else:
-        func(**kwargs)

+ 146 - 0
src/sentry/runner/main.py

@@ -0,0 +1,146 @@
+import logging
+import os
+import sys
+
+import click
+import sentry_sdk
+
+import sentry
+from sentry.utils.imports import import_string
+
+
+@click.group(context_settings={"max_content_width": 150})
+@click.option(
+    "--config",
+    default="",
+    envvar="SENTRY_CONF",
+    help="Path to configuration files.",
+    metavar="PATH",
+)
+@click.version_option(version=sentry.__semantic_version__)
+def cli(config: str) -> None:
+    """Sentry is cross-platform crash reporting built with love.
+
+    The configuration file is looked up in the `~/.sentry` config
+    directory but this can be overridden with the `SENTRY_CONF`
+    environment variable or be explicitly provided through the
+    `--config` parameter.
+    """
+    # Elevate --config option to SENTRY_CONF env var, and just assume this
+    # always will exist down the line
+    if config:
+        os.environ["SENTRY_CONF"] = config
+    os.environ.setdefault("SENTRY_CONF", "~/.sentry")
+
+
+# TODO(mattrobenolt): Autodiscover commands?
+for cmd in map(
+    import_string,
+    (
+        "sentry.runner.commands.backup.backup",
+        "sentry.runner.commands.backup.export",
+        "sentry.runner.commands.backup.import_",
+        "sentry.runner.commands.cleanup.cleanup",
+        "sentry.runner.commands.config.config",
+        "sentry.runner.commands.configoptions.configoptions",
+        "sentry.runner.commands.createuser.createuser",
+        "sentry.runner.commands.devserver.devserver",
+        "sentry.runner.commands.django.django",
+        "sentry.runner.commands.exec.exec_",
+        "sentry.runner.commands.sendmail.sendmail",
+        "sentry.runner.commands.execfile.execfile",
+        "sentry.runner.commands.files.files",
+        "sentry.runner.commands.help.help",
+        "sentry.runner.commands.init.init",
+        "sentry.runner.commands.killswitches.killswitches",
+        "sentry.runner.commands.migrations.migrations",
+        "sentry.runner.commands.plugins.plugins",
+        "sentry.runner.commands.queues.queues",
+        "sentry.runner.commands.repair.repair",
+        "sentry.runner.commands.run.run",
+        "sentry.runner.commands.start.start",
+        "sentry.runner.commands.tsdb.tsdb",
+        "sentry.runner.commands.upgrade.upgrade",
+        "sentry.runner.commands.permissions.permissions",
+        "sentry.runner.commands.devservices.devservices",
+        "sentry.runner.commands.performance.performance",
+        "sentry.runner.commands.spans.spans",
+        "sentry.runner.commands.spans.write_hashes",
+        "sentry.runner.commands.openai.openai",
+        "sentry.runner.commands.llm.llm",
+    ),
+):
+    cli.add_command(cmd)
+
+
+def _make_django_command(
+    name: str, django_command: str | None = None, help: str | None = None
+) -> click.Command:
+    "A wrapper to convert a Django subcommand a Click command"
+    if django_command is None:
+        django_command = name
+
+    @click.command(
+        name=name,
+        help=help,
+        add_help_option=False,
+        context_settings=dict(ignore_unknown_options=True),
+    )
+    @click.argument("management_args", nargs=-1, type=click.UNPROCESSED)
+    @click.pass_context
+    def inner(ctx: click.Context, management_args: tuple[str, ...]) -> None:
+        from sentry.runner.commands.django import django
+
+        ctx.params["management_args"] = (django_command,) + management_args
+        ctx.forward(django)
+
+    return inner
+
+
+cli.add_command(_make_django_command("shell", help="Run a Python interactive interpreter."))
+
+
+def _get_prog() -> str:
+    """
+    Extract the proper program executable.
+
+    In the case of `python -m sentry`, we want to detect this and
+    make sure we return something useful rather than __main__.py
+    """
+    try:
+        if os.path.basename(sys.argv[0]) in ("__main__.py", "-c"):
+            return "%s -m sentry" % sys.executable
+    except (AttributeError, TypeError, IndexError):
+        pass
+    return "sentry"
+
+
+def main() -> None:
+    func = cli
+    kwargs = {
+        "prog_name": _get_prog(),
+        "obj": {},
+        "max_content_width": 100,
+    }
+    # This variable is *only* set as part of direnv/.envrc, thus, we cannot affect production
+    if os.environ.get("SENTRY_DEVSERVICES_DSN"):
+        # We do this here because `configure_structlog` executes later
+        logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.INFO)
+        logger = logging.getLogger(__name__)
+
+        logger.info(
+            "The Sentry runner will report development issues to Sentry.io. "
+            "Use SENTRY_DEVENV_NO_REPORT to avoid reporting issues."
+        )
+        try:
+            func(**kwargs)
+        except Exception as e:
+            # This reports errors sentry-devservices
+            with sentry_sdk.init(dsn=os.environ["SENTRY_DEVSERVICES_DSN"]):
+                if os.environ.get("USER"):
+                    sentry_sdk.set_user({"username": os.environ.get("USER")})
+                sentry_sdk.capture_exception(e)
+                logger.info("We have reported the error below to Sentry")
+            raise
+    else:
+        func(**kwargs)