瀏覽代碼

Refactor zipping in `reflex export` (#1668)

Martin Xu 1 年之前
父節點
當前提交
76b8af3b42
共有 2 個文件被更改,包括 79 次插入47 次删除
  1. 0 11
      reflex/reflex.py
  2. 79 36
      reflex/utils/build.py

+ 0 - 11
reflex/reflex.py

@@ -264,17 +264,6 @@ def export(
     # Post a telemetry event.
     telemetry.send("export", config.telemetry_enabled)
 
-    if zipping:
-        console.log(
-            """Backend & Frontend compiled. See [green bold]backend.zip[/green bold]
-            and [green bold]frontend.zip[/green bold]."""
-        )
-    else:
-        console.log(
-            """Backend & Frontend compiled. See [green bold]app[/green bold]
-            and [green bold].web/_static[/green bold] directories."""
-        )
-
 
 db_cli = typer.Typer()
 

+ 79 - 36
reflex/utils/build.py

@@ -6,9 +6,13 @@ import json
 import os
 import random
 import subprocess
+import zipfile
+from enum import Enum
 from pathlib import Path
 from typing import Optional, Union
 
+from rich.progress import MofNCompleteColumn, Progress, TimeElapsedColumn
+
 from reflex import constants
 from reflex.config import get_config
 from reflex.utils import console, path_ops, prerequisites, processes
@@ -85,6 +89,65 @@ def generate_sitemap_config(deploy_url: str):
         f.write(templates.SITEMAP_CONFIG(config=config))
 
 
+class _ComponentName(Enum):
+    BACKEND = "Backend"
+    FRONTEND = "Frontend"
+
+
+def _zip(
+    component_name: _ComponentName,
+    target: str,
+    root_dir: str,
+    dirs_to_exclude: set[str] | None = None,
+    files_to_exclude: set[str] | None = None,
+) -> None:
+    """Zip utility function.
+
+    Args:
+        component_name: The name of the component: backend or frontend.
+        target: The target zip file.
+        root_dir: The root directory to zip.
+        dirs_to_exclude: The directories to exclude.
+        files_to_exclude: The files to exclude.
+
+    """
+    dirs_to_exclude = dirs_to_exclude or set()
+    files_to_exclude = files_to_exclude or set()
+    files_to_zip: list[str] = []
+    # Traverse the root directory in a top-down manner. In this traversal order,
+    # we can modify the dirs list in-place to remove directories we don't want to include.
+    for root, dirs, files in os.walk(root_dir, topdown=True):
+        # Modify the dirs in-place so excluded and hidden directories are skipped in next traversal.
+        dirs[:] = [
+            d
+            for d in dirs
+            if (basename := os.path.basename(os.path.normpath(d)))
+            not in dirs_to_exclude
+            and not basename.startswith(".")
+        ]
+        # Modify the files in-place so the hidden files are excluded.
+        files[:] = [f for f in files if not f.startswith(".")]
+        files_to_zip += [
+            os.path.join(root, file) for file in files if file not in files_to_exclude
+        ]
+
+    # Create a progress bar for zipping the component.
+    progress = Progress(
+        *Progress.get_default_columns()[:-1],
+        MofNCompleteColumn(),
+        TimeElapsedColumn(),
+    )
+    task = progress.add_task(
+        f"Zipping {component_name.value}:", total=len(files_to_zip)
+    )
+
+    with progress, zipfile.ZipFile(target, "w", zipfile.ZIP_DEFLATED) as zipf:
+        for file in files_to_zip:
+            console.debug(f"{target}: {file}")
+            progress.advance(task)
+            zipf.write(file, os.path.relpath(file, root_dir))
+
+
 def export(
     backend: bool = True,
     frontend: bool = True,
@@ -132,42 +195,22 @@ def export(
 
     # Zip up the app.
     if zip:
-        if os.name == "posix":
-            posix_export(backend, frontend)
-        if os.name == "nt":
-            nt_export(backend, frontend)
-
-
-def nt_export(backend: bool = True, frontend: bool = True):
-    """Export for nt (Windows) systems.
-
-    Args:
-        backend: Whether to zip up the backend app.
-        frontend: Whether to zip up the frontend app.
-    """
-    cmd = r""
-    if frontend:
-        cmd = r'''powershell -Command "Set-Location .web/_static; Compress-Archive -Path .\* -DestinationPath ..\..\frontend.zip -Force"'''
-        os.system(cmd)
-    if backend:
-        cmd = r'''powershell -Command "Get-ChildItem -File | Where-Object { $_.Name -notin @('.web', 'assets', 'frontend.zip', 'backend.zip') } | Compress-Archive -DestinationPath backend.zip -Update"'''
-        os.system(cmd)
-
-
-def posix_export(backend: bool = True, frontend: bool = True):
-    """Export for posix (Linux, OSX) systems.
-
-    Args:
-        backend: Whether to zip up the backend app.
-        frontend: Whether to zip up the frontend app.
-    """
-    cmd = r""
-    if frontend:
-        cmd = r"cd .web/_static && zip -r ../../frontend.zip ./*"
-        os.system(cmd)
-    if backend:
-        cmd = r"zip -r backend.zip ./* -x .web/\* ./assets\* ./frontend.zip\* ./backend.zip\*"
-        os.system(cmd)
+        files_to_exclude = {constants.FRONTEND_ZIP, constants.BACKEND_ZIP}
+        if frontend:
+            _zip(
+                component_name=_ComponentName.FRONTEND,
+                target=constants.FRONTEND_ZIP,
+                root_dir=".web/_static",
+                files_to_exclude=files_to_exclude,
+            )
+        if backend:
+            _zip(
+                component_name=_ComponentName.BACKEND,
+                target=constants.BACKEND_ZIP,
+                root_dir=".",
+                dirs_to_exclude={"assets", "__pycache__"},
+                files_to_exclude=files_to_exclude,
+            )
 
 
 def setup_frontend(