Skip to content

Commit

Permalink
Merge pull request #16 from Never-Over/db-redis-shells
Browse files Browse the repository at this point in the history
Add CLI entrypoints and shell methods on PostgresService, RedisService
  • Loading branch information
emdoyle authored Apr 12, 2024
2 parents b1efb1f + 50ad6e3 commit 111a000
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 26 deletions.
49 changes: 33 additions & 16 deletions bridge/cli/bridge.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import argparse

from bridge.cli.init import initialize_platform
from bridge.cli.db import open_database_shell
from bridge.cli.init import initialize
from bridge.cli.redis import open_redis_shell
from bridge.framework import Framework


def detect_framework() -> Framework:
# TODO: auto-detect framework (assuming Django)
return Framework.DJANGO


def main():
# Create the top-level parser for the 'bridge' command
parser = argparse.ArgumentParser(prog="bridge")
# TODO: tie this version output to the version in pyproject.toml
parser.add_argument("--version", action="version", version="%(prog)s 0.0.22")
subparsers = parser.add_subparsers(dest="command", help="sub-command help")
subparsers = parser.add_subparsers(dest="command")

# Parser for 'init' command
init_parser = subparsers.add_parser(
Expand All @@ -19,25 +27,34 @@ def main():
help="Platform where you want to deploy this app",
choices=["render", "railway", "heroku"],
)
init_parser.add_argument(
"--wsgi-path",
help="Path to your WSGI application callable (ex: myapp.wsgi:application)",
required=False,
)
init_parser.add_argument(
"--asgi-path",
help="Path to your ASGI application callable (ex: myapp.asgi:application)",
required=False,
)

# Parser for db
db_parser = subparsers.add_parser("db", help="Interact with the database")
db_subparsers = db_parser.add_subparsers(dest="db_command")
db_subparsers.add_parser("shell", help="Open a database shell (psql)")

# Parser for redis
redis_parser = subparsers.add_parser("redis", help="Interact with Redis")
redis_subparsers = redis_parser.add_subparsers(dest="redis_command")
redis_subparsers.add_parser("shell", help="Open a Redis shell (redis-cli)")

# Parse the arguments
args = parser.parse_args()
framework = detect_framework()

# TODO: pattern for additional config from the CLI
if args.command == "init":
# Additional validation for the arguments
if args.command == "init" and args.wsgi_path and args.asgi_path:
parser.error("Both WSGI and ASGI paths cannot be provided")
initialize_platform(args.init_platform)
initialize(framework=framework, platform=args.init_platform)
elif args.command == "db":
if args.db_command == "shell":
open_database_shell()
else:
db_parser.print_help()
elif args.command == "redis":
if args.redis_command == "shell":
open_redis_shell()
else:
redis_parser.print_help()
else:
parser.print_help()

Expand Down
10 changes: 10 additions & 0 deletions bridge/cli/db/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import docker

from bridge.service.postgres import PostgresService


def open_database_shell():
client = docker.from_env()
postgres_service = PostgresService(client=client)
postgres_service.start()
postgres_service.shell()
5 changes: 3 additions & 2 deletions bridge/cli/init/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from bridge.cli.errors import ActionCancelledError
from bridge.cli.init.render import build_render_init_config, initialize_render_platform
from bridge.console import log_info, log_task
from bridge.framework import Framework


def initialize_platform(platform: str):
def initialize(framework: Framework, platform: str):
if platform == "render":
# Build config outside of log_task to avoid TUI interaction with status spinner
try:
config = build_render_init_config()
config = build_render_init_config(framework=framework)
except ActionCancelledError as e:
log_info(str(e))
return
Expand Down
10 changes: 2 additions & 8 deletions bridge/cli/init/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,14 @@
)
from bridge.cli.init.templates.deploy_to_render_button import button_exists_in_content
from bridge.console import console, log_warning
from bridge.framework.base import Framework
from bridge.framework import Framework
from bridge.utils.filesystem import (
resolve_dot_bridge,
resolve_project_dir,
set_executable,
)


def detect_framework() -> Framework:
# TODO: auto-detect framework (assuming Django)
return Framework.DJANGO


def detect_django_settings_module(project_name: str = "") -> str:
settings_path = Path(project_name) / "settings.py"
if os.path.exists(settings_path):
Expand Down Expand Up @@ -99,10 +94,9 @@ def script_dir(self) -> str:
return f"bridge-{self.framework.value}-render"


def build_render_init_config() -> RenderPlatformInitConfig:
def build_render_init_config(framework: Framework) -> RenderPlatformInitConfig:
# NOTE: this method may request user input directly on the CLI
# to determine configuration when it cannot be auto-detected
framework = detect_framework()
project_name = resolve_project_dir().name
app_path = detect_application_callable(project_name=project_name)
bridge_path = resolve_dot_bridge()
Expand Down
10 changes: 10 additions & 0 deletions bridge/cli/redis/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import docker

from bridge.service.redis import RedisService


def open_redis_shell():
client = docker.from_env()
postgres_service = RedisService(client=client)
postgres_service.start()
postgres_service.shell()
3 changes: 3 additions & 0 deletions bridge/framework/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from bridge.framework.base import Framework

__all__ = ["Framework"]
23 changes: 23 additions & 0 deletions bridge/service/postgres.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from time import sleep
from typing import Optional, Union

Expand Down Expand Up @@ -58,3 +59,25 @@ def ensure_ready(self):
return
except psycopg.OperationalError:
sleep(0.1)

def shell(self):
# Open a shell to the Postgres container
# NOTE: This entirely replaces the currently running process!
os.execvp(
"docker",
[
"docker",
"exec",
"-it",
self.config.name,
"psql",
"-U",
self.config.environment.POSTGRES_USER,
"-d",
self.config.environment.POSTGRES_DB,
"-h",
self.config.environment.POSTGRES_HOST,
"-p",
self.config.environment.POSTGRES_PORT,
],
)
6 changes: 6 additions & 0 deletions bridge/service/redis.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from time import sleep
from typing import Optional

Expand Down Expand Up @@ -38,3 +39,8 @@ def ensure_ready(self):
return # Redis is ready and responding
except redis.ConnectionError:
sleep(0.1)

def shell(self):
# Open a shell to the Redis container
# NOTE: This entirely replaces the currently running process!
os.execvp("docker", ["docker", "exec", "-it", self.config.name, "redis-cli"])

0 comments on commit 111a000

Please sign in to comment.