From 36338152d0d62188bb7a961633fb2a114c686100 Mon Sep 17 00:00:00 2001 From: Nixevol Date: Fri, 31 Jul 2026 17:46:55 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=85=BC=E5=AE=B9=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=9C=AA=E8=A7=A3=E5=8E=8B=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++++-- aidocs/project_context.md | 4 ++-- scripts/build_offline_package.py | 20 ++++++++++++++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5714624..a63ef99 100644 --- a/README.md +++ b/README.md @@ -52,9 +52,9 @@ docker build -t interference-etl-runtime:1.1 . python scripts\build_offline_package.py ``` -The generated `dist/InterferenceETL-offline-1.1.zip` contains `main.py` plus `openpyxl`, `et_xmlfile`, and `PyMySQL`. The builder verifies imports using the standard `python:3.13.11-slim` image, so the uploaded workspace does not need an online `pip install` or a custom runtime image. The ZIP is 325,489 bytes with SHA-256 `4F655D35F89A826F28A41578C9EE3E347CE31A27619D3D06AE0FD9587660DCAF`. +The generated `dist/InterferenceETL-offline-1.1.zip` contains `main.py`, a ZIP execution entry point, and `openpyxl`, `et_xmlfile`, and `PyMySQL`. The builder verifies both imports and ZIP execution using the standard `python:3.13.11-slim` image, so the uploaded workspace does not need an online `pip install` or a custom runtime image. -Create the project, then upload and extract the ZIP in its Script Management workspace. Use these project settings: +Create the project, then upload and extract the ZIP in its Script Management workspace. The normal file tree should contain `main.py` at `/workspace/main.py`. Use these project settings: ```text Name: InterferenceETL @@ -65,6 +65,8 @@ Run command: python main.py Timeout: 1800 seconds ``` +If the server keeps the ZIP as one file instead of extracting it, use `python InterferenceETL-offline-1.1.zip` as the run command. The ZIP contains `__main__.py` for this mode. + Configure only the Metrix source settings in the project environment: ```json diff --git a/aidocs/project_context.md b/aidocs/project_context.md index acb4fba..52b3f4b 100644 --- a/aidocs/project_context.md +++ b/aidocs/project_context.md @@ -22,9 +22,9 @@ ## 2026-07-31: Self-contained Script Management package -- `scripts/build_offline_package.py` copies the three runtime distributions from the verified dependency image, adds the application files, and creates a ZIP that Metrix can extract without preserving executable bits or symlinks. +- `scripts/build_offline_package.py` copies the three runtime distributions from the verified dependency image, adds the application files and `__main__.py`, and creates a ZIP that Metrix can extract without preserving executable bits or symlinks. The archive can also run directly as `python InterferenceETL-offline-1.1.zip` when a Script Management server stores the upload without extracting it. - The builder runs an import check inside `python:3.13.11-slim`; the package therefore needs neither a custom server image nor online package installation. -- Current artifact: `dist/InterferenceETL-offline-1.1.zip`, 325,489 bytes, SHA-256 `4F655D35F89A826F28A41578C9EE3E347CE31A27619D3D06AE0FD9587660DCAF`. The builder excludes bytecode caches, and the ignored `dist/` directory is the only location for this generated package. +- The builder excludes bytecode caches, and the ignored `dist/` directory is the only location for this generated package. ## 2026-07-31: Fixed CGI and database configuration diff --git a/scripts/build_offline_package.py b/scripts/build_offline_package.py index 4a7e56e..19ee7dd 100644 --- a/scripts/build_offline_package.py +++ b/scripts/build_offline_package.py @@ -14,6 +14,7 @@ DEFAULT_IMAGE = "interference-etl-runtime:1.1" DEFAULT_BASE_IMAGE = "python:3.13.11-slim" DEFAULT_OUTPUT = PROJECT_ROOT / "dist" / "InterferenceETL-offline-1.1.zip" PACKAGE_FILES = ("main.py", "requirements.txt", "README.md") +PACKAGE_ENTRYPOINT = "from main import main\nraise SystemExit(main())\n" COPY_DEPENDENCIES = r""" from importlib.metadata import distribution @@ -56,6 +57,7 @@ def build(output: Path, runtime_image: str, base_image: str) -> Path: ) for name in PACKAGE_FILES: shutil.copy2(PROJECT_ROOT / name, staging / name) + (staging / "__main__.py").write_text(PACKAGE_ENTRYPOINT, encoding="utf-8") subprocess.run( [ "docker", @@ -74,6 +76,24 @@ def build(output: Path, runtime_image: str, base_image: str) -> Path: ], check=True, ) + subprocess.run( + [ + "docker", + "run", + "--rm", + "-e", + "PYTHONDONTWRITEBYTECODE=1", + "-v", + f"{staging}:/workspace:ro", + "-w", + "/workspace", + base_image, + "python", + "__main__.py", + "--help", + ], + check=True, + ) if output.exists(): output.unlink() with zipfile.ZipFile(output, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as archive: