pc.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. """Pynecone CLI to create, run, and deploy apps."""
  2. import os
  3. import httpx
  4. import typer
  5. from pynecone import constants, utils
  6. # Create the app.
  7. cli = typer.Typer()
  8. @cli.command()
  9. def version():
  10. """Get the Pynecone version."""
  11. utils.console.print(constants.VERSION)
  12. @cli.command()
  13. def init():
  14. """Initialize a new Pynecone app.
  15. Raises:
  16. Exit: If the app directory is invalid.
  17. """
  18. app_name = utils.get_default_app_name()
  19. # Make sure they don't name the app "pynecone".
  20. if app_name == constants.MODULE_NAME:
  21. utils.console.print(
  22. f"[red]The app directory cannot be named [bold]{constants.MODULE_NAME}."
  23. )
  24. raise typer.Exit()
  25. with utils.console.status(f"[bold]Initializing {app_name}"):
  26. # Set up the web directory.
  27. utils.install_bun()
  28. utils.initialize_web_directory()
  29. # Set up the app directory, only if the config doesn't exist.
  30. if not os.path.exists(constants.CONFIG_FILE):
  31. utils.create_config(app_name)
  32. utils.initialize_app_directory(app_name)
  33. # Finish initializing the app.
  34. utils.console.log(f"[bold green]Finished Initializing: {app_name}")
  35. @cli.command()
  36. def run(
  37. env: constants.Env = constants.Env.DEV,
  38. frontend: bool = True,
  39. backend: bool = True,
  40. ):
  41. """Run the app.
  42. Args:
  43. env: The environment to run the app in.
  44. frontend: Whether to run the frontend.
  45. backend: Whether to run the backend.
  46. Raises:
  47. Exit: If the app is not initialized.
  48. """
  49. # Check that the app is initialized.
  50. if frontend and not utils.is_initialized():
  51. utils.console.print(
  52. "[red]The app is not initialized. Run [bold]pc init[/bold] first."
  53. )
  54. raise typer.Exit()
  55. # Check that the template is up to date.
  56. if frontend and not utils.is_latest_template():
  57. utils.console.print(
  58. "[red]The base app template has updated. Run [bold]pc init[/bold] again."
  59. )
  60. raise typer.Exit()
  61. # Get the app module.
  62. utils.console.rule("[bold]Starting Pynecone App")
  63. app = utils.get_app()
  64. # Get the frontend and backend commands, based on the environment.
  65. frontend_cmd = backend_cmd = None
  66. if env == constants.Env.DEV:
  67. frontend_cmd, backend_cmd = utils.run_frontend, utils.run_backend
  68. if env == constants.Env.PROD:
  69. frontend_cmd, backend_cmd = utils.run_frontend_prod, utils.run_backend_prod
  70. assert frontend_cmd and backend_cmd, "Invalid env"
  71. # Run the frontend and backend.
  72. if frontend:
  73. frontend_cmd(app.app)
  74. if backend:
  75. backend_cmd(app.__name__)
  76. @cli.command()
  77. def deploy(dry_run: bool = False):
  78. """Deploy the app to the hosting service.
  79. Args:
  80. dry_run: Whether to run a dry run.
  81. """
  82. # Get the app config.
  83. config = utils.get_config()
  84. config.api_url = utils.get_production_backend_url()
  85. # Check if the deploy url is set.
  86. if config.deploy_url is None:
  87. typer.echo("This feature is coming soon!")
  88. return
  89. # Compile the app in production mode.
  90. typer.echo("Compiling production app")
  91. app = utils.get_app().app
  92. utils.export_app(app, zip=True)
  93. # Exit early if this is a dry run.
  94. if dry_run:
  95. return
  96. # Deploy the app.
  97. data = {"userId": config.username, "projectId": config.app_name}
  98. original_response = httpx.get(config.deploy_url, params=data)
  99. response = original_response.json()
  100. print("response", response)
  101. frontend = response["frontend_resources_url"]
  102. backend = response["backend_resources_url"]
  103. # Upload the frontend and backend.
  104. with open(constants.FRONTEND_ZIP, "rb") as f:
  105. response = httpx.put(frontend, data=f) # type: ignore
  106. with open(constants.BACKEND_ZIP, "rb") as f:
  107. response = httpx.put(backend, data=f) # type: ignore
  108. main = cli
  109. if __name__ == "__main__":
  110. main()