my eye

__main__.py

"""Command line tools for the web."""

import inspect
import json
import logging
import pathlib
import time
import webbrowser

import gevent
import txt
import webagt
from rich.pretty import pprint

import web
import web.host
from web.host import console, providers

__all__ = ["main"]


main = txt.application("web", web.__doc__)


@main.register()
class Apps:
    """Show installed web apps."""

    def run(self, stdin, log):
        for pkg, apps in web.get_apps().items():
            for name, _, ns, obj in apps:
                print(f"{name} {ns}:{obj[0]}")
        return 0


@main.register()
class Fnord:
    def run(self, stdin, log):
        # import asyncio
        # asyncio.run(web.serve("web:abba", port=9999))
        web.StandaloneServer(web.abba, 9999).run()


@main.register()
class Run:
    """Run a web app locally."""

    def setup(self, add_arg):
        add_arg("app", help="name of web application")
        add_arg("--port", help="port to serve on")
        add_arg("--socket", help="file socket to serve on")
        add_arg("--watch", default=".", help="directory to watch for changes")

    def run(self, stdin, log):
        import asyncio

        if self.port:
            webbrowser.open(f"http://localhost:{self.port}")
            asyncio.run(web.serve(self.app, port=self.port, watch_dir=self.watch))
        elif self.socket:
            asyncio.run(web.serve(self.app, socket=self.socket, watch_dir=self.watch))
        else:
            print("must provide a port or a socket")
            return 1
        return 0

        # for pkg, apps in web.get_apps().items():
        #     for name, _, ns, obj in apps:
        #         if self.app == name:
        #             web.serve(ns, obj)
        #             return 0
        # return 1


def get_providers(provider_type):
    return [
        name.lower()
        for name, obj in inspect.getmembers(providers, inspect.isclass)
        if issubclass(obj, provider_type) and obj is not provider_type
    ]


@main.register()
class Config:
    """Config your environments."""

    def setup(self, add_arg):
        add_arg("--token", help="API access token")
        add_arg(
            "--host",
            choices=get_providers(providers.Host),
            help="machine host",
        )
        add_arg(
            "--registrar",
            choices=get_providers(providers.Registrar),
            help="domain registrars",
        )

    def run(self, stdin, log):
        if self.host:
            if not self.token:
                try:
                    if input("Do you need to create a new token? ") in "yY":
                        webbrowser.open(
                            "https://cloud.digitalocean.com/account/api/tokens/new"
                        )
                    self.token = input("Token: ")
                except EOFError:
                    return 1
            web.host.update_config(host=self.host, host_token=self.token)
        elif self.registrar:
            web.host.update_config(registrar=self.registrar, registrar_token=self.token)
        return 0


@main.register()
class Init:
    """Initialize a website."""

    def setup(self, add_arg):
        add_arg("name", help="name of website")
        add_arg("package", help="name of PyPI package to install")
        add_arg("app", help="name of web app to run")
        add_arg("--domain", help="domain name of website")

    def run(self, stdin, log):
        logging.basicConfig(
            level=logging.DEBUG,
            filename="debug.log",
            filemode="w",
            force=True,
            format="%(levelname)s:%(asctime)s:%(name)s:%(message)s",
        )
        config = web.host.get_config()
        if "host" not in config:
            console.print(f"No host configured.")
            return 1
        machines = config.get("machines", {})
        versions = web.host.Machine.versions
        start_time = time.time()
        total_time = 27
        with console.status(f"[bold green]~{total_time} minutes remaining") as status:

            def update_status():
                while True:
                    remaining_time = total_time - round((time.time() - start_time) / 60)
                    if remaining_time < 1:
                        status.update("Finishing up..")
                        return
                    status.update(f"[bold green]~{remaining_time} minutes remaining")
                    gevent.sleep(1)

            gevent.spawn(update_status)
            machine, secret = web.host.setup_website(self.name, self.package, self.app)
            webbrowser.open(f"https://{machine.address}?secret={secret}")
            web.host.finish_setup(machine)
            time.sleep(2)
        console.rule(f"[green]Bootstrapped {self.package} at {machine.address}")
        machines[self.name] = machine.address
        web.host.update_config(machines=machines)
        return 0


@main.register()
class Host:
    """Manage your host."""

    def run(self, stdin, log):
        config = web.host.get_config()
        if config["host"] == "digitalocean":
            host = providers.DigitalOcean(config["host_token"])
        else:
            console.print(f"Host {config['host']} not available.")
            return 1
        for machine in host.machines:
            console.rule(f"[bold red]{machine['name']}")
            pprint(machine)
        return 0


@main.register()
class Registrar:
    """Manage your registrar."""

    def run(self, stdin, log):
        config = web.host.get_config()
        if config["registrar"] == "dynadot":
            registrar = providers.Dynadot(config["registrar_token"])
        else:
            console.print(f"Registrar {config['registrar']} not available.")
            return 1
        for domain in registrar.domains:
            print(domain)
        return 0


@main.register()
class Scaffold:
    """Scaffold the null site."""

    def run(self, stdin, log):
        example_py = pathlib.Path("example.py")
        if example_py.exists():
            print("example.py already exists")
            return 1
        with example_py.open("w") as fp:
            fp.write(
                '''"""A null site."""

import web

app = web.application(__name__)

@app.control("")
class Home:
    def get(self):
        return
'''
            )
        return 0


if __name__ == "__main__":
    main()

# nuitka-project: --include-package=gevent.signal
# nuitka-project: --include-package=gunicorn.glogging
# nuitka-project: --include-package=gunicorn.workers.sync
# nuitka-project: --include-package=web.framework.templates
# nuitka-project: --include-package=web.host.templates
## nuitka-project: --include-package-data=mf2py
## nuitka-project: --include-package-data=selenium