chore: import upstream snapshot with attribution
This commit is contained in:
+140
@@ -0,0 +1,140 @@
|
||||
import argparse
|
||||
import contextlib
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import zipfile
|
||||
from collections.abc import Generator
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Package:
|
||||
# name of the package on PyPI.
|
||||
pypi_name: str
|
||||
# type of the package, one of "dev", "skinny", "tracing", "release"
|
||||
type: str
|
||||
# path to the package relative to the root of the repository
|
||||
build_path: str
|
||||
|
||||
|
||||
DEV = Package("mlflow", "dev", ".")
|
||||
RELEASE = Package("mlflow", "release", ".")
|
||||
SKINNY = Package("mlflow-skinny", "skinny", "libs/skinny")
|
||||
TRACING = Package("mlflow-tracing", "tracing", "libs/tracing")
|
||||
|
||||
PACKAGES = [
|
||||
DEV,
|
||||
SKINNY,
|
||||
RELEASE,
|
||||
TRACING,
|
||||
]
|
||||
|
||||
JS_BUILD_DIR = Path("mlflow/server/js/build")
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Build MLflow package.")
|
||||
parser.add_argument(
|
||||
"--package-type",
|
||||
help="Package type to build. Default is 'dev'.",
|
||||
choices=[p.type for p in PACKAGES],
|
||||
default="dev",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--sha",
|
||||
help="If specified, include the SHA in the wheel name as a build tag.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def restore_changes() -> Generator[None, None, None]:
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
subprocess.check_call([
|
||||
"git",
|
||||
"restore",
|
||||
"README.md",
|
||||
"pyproject.toml",
|
||||
])
|
||||
|
||||
|
||||
def validate_ui_assets_pre_build(package: Package) -> None:
|
||||
if package != RELEASE:
|
||||
return
|
||||
if not JS_BUILD_DIR.exists() or not any(JS_BUILD_DIR.iterdir()):
|
||||
raise RuntimeError("Build the UI first before building the release package.")
|
||||
|
||||
|
||||
def validate_ui_assets_post_build(wheel_path: Path, package: Package) -> None:
|
||||
ui_asset_prefix = f"{JS_BUILD_DIR.as_posix()}/"
|
||||
with zipfile.ZipFile(wheel_path) as zf:
|
||||
has_ui_assets = any(name.startswith(ui_asset_prefix) for name in zf.namelist())
|
||||
if package == RELEASE:
|
||||
if not has_ui_assets:
|
||||
raise RuntimeError(
|
||||
f"UI assets are missing from the release wheel: {wheel_path}. "
|
||||
"Build the UI first before building the release package."
|
||||
)
|
||||
elif package in (SKINNY, TRACING):
|
||||
if has_ui_assets:
|
||||
raise RuntimeError(
|
||||
f"UI assets should not be included in the {package.type} wheel: {wheel_path}."
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
|
||||
# Initialize submodules (e.g., mlflow/assistant/skills)
|
||||
subprocess.check_call(["git", "submodule", "update", "--init", "--recursive"])
|
||||
|
||||
# Clean up build artifacts generated by previous builds
|
||||
paths_to_clean_up = ["build"]
|
||||
for pkg in PACKAGES:
|
||||
paths_to_clean_up += [
|
||||
f"{pkg.build_path}/dist",
|
||||
f"{pkg.build_path}/{pkg.pypi_name}.egg_info",
|
||||
]
|
||||
for path in map(Path, paths_to_clean_up):
|
||||
if not path.exists():
|
||||
continue
|
||||
if path.is_file():
|
||||
path.unlink()
|
||||
else:
|
||||
shutil.rmtree(path)
|
||||
|
||||
package = next(p for p in PACKAGES if p.type == args.package_type)
|
||||
|
||||
validate_ui_assets_pre_build(package)
|
||||
|
||||
with restore_changes():
|
||||
pyproject = Path("pyproject.toml")
|
||||
if package == RELEASE:
|
||||
pyproject.write_text(Path("pyproject.release.toml").read_text())
|
||||
|
||||
DIST_DIR = Path("dist").resolve()
|
||||
DIST_DIR.mkdir(exist_ok=True)
|
||||
subprocess.check_call([
|
||||
sys.executable,
|
||||
"-m",
|
||||
"build",
|
||||
package.build_path,
|
||||
"--outdir",
|
||||
DIST_DIR,
|
||||
])
|
||||
|
||||
wheel = next(DIST_DIR.glob("mlflow*.whl"))
|
||||
validate_ui_assets_post_build(wheel, package)
|
||||
|
||||
if args.sha:
|
||||
name, version, rest = wheel.name.split("-", 2)
|
||||
build_tag = f"0.sha.{args.sha}" # build tag must start with a digit
|
||||
wheel.rename(wheel.with_name(f"{name}-{version}-{build_tag}-{rest}"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user