mirror of
https://github.com/langgenius/dify.git
synced 2026-05-30 05:37:48 +08:00
Co-authored-by: XW <wei.xu1@wiz.ai> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
72 lines
2.6 KiB
Python
72 lines
2.6 KiB
Python
"""JSON persistence for versioned cross-environment migration packages.
|
|
|
|
The package service validates file shape and serializes only structured package
|
|
entities. It does not perform CLI rendering or database access, keeping it safe
|
|
to reuse from Click adapters, tests, and future import/export services.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from dataclasses import asdict
|
|
from datetime import UTC, datetime
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from services.data_migration.entities import (
|
|
ImportOptions,
|
|
MigrationDataError,
|
|
MigrationMetadata,
|
|
MigrationPackage,
|
|
SourceTenant,
|
|
TargetTenantSelector,
|
|
)
|
|
|
|
PACKAGE_VERSION = "1"
|
|
|
|
|
|
class MigrationPackageService:
|
|
def load_package(self, path: str | Path) -> MigrationPackage:
|
|
package_path = Path(path)
|
|
with package_path.open(encoding="utf-8") as file:
|
|
raw = json.load(file)
|
|
if not isinstance(raw, dict):
|
|
raise MigrationDataError("Migration package JSON must be an object.")
|
|
package = MigrationPackage.from_mapping(raw)
|
|
if package.metadata.version != PACKAGE_VERSION:
|
|
raise MigrationDataError(f"Unsupported migration package version: {package.metadata.version}")
|
|
return package
|
|
|
|
def save_package(self, package: MigrationPackage, path: str | Path, *, overwrite: bool) -> None:
|
|
package_path = Path(path)
|
|
if package_path.exists() and not overwrite:
|
|
raise MigrationDataError(f"Output file already exists: {package_path}")
|
|
package_path.parent.mkdir(parents=True, exist_ok=True)
|
|
with package_path.open("w", encoding="utf-8") as file:
|
|
json.dump(self.to_mapping(package), file, ensure_ascii=False, indent=2)
|
|
file.write("\n")
|
|
|
|
def build_empty_package(
|
|
self,
|
|
*,
|
|
source_tenant_id: str,
|
|
source_tenant_name: str,
|
|
include_secrets: bool,
|
|
import_options: ImportOptions | None = None,
|
|
target_tenant: TargetTenantSelector | None = None,
|
|
) -> MigrationPackage:
|
|
return MigrationPackage(
|
|
metadata=MigrationMetadata(
|
|
version=PACKAGE_VERSION,
|
|
source_scope="single",
|
|
source_tenants=[SourceTenant(id=source_tenant_id, name=source_tenant_name)],
|
|
target_tenant=target_tenant,
|
|
created_at=datetime.now(UTC).replace(microsecond=0).isoformat().replace("+00:00", "Z"),
|
|
include_secrets=include_secrets,
|
|
import_options=import_options or ImportOptions(),
|
|
)
|
|
)
|
|
|
|
def to_mapping(self, package: MigrationPackage) -> dict[str, Any]:
|
|
return asdict(package)
|