blob: 6dfc64a8d3830f8b5a9f6260c8e7b7169b2e078d [file] [log] [blame]
#!/usr/bin/env python3
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from __future__ import annotations
import os
import subprocess
import sys
from pathlib import Path
from shutil import rmtree
from tempfile import mkdtemp
import yaml
from rich.console import Console
console = Console(color_system="standard", width=200)
AIRFLOW_ROOT_PATH = Path(__file__).parents[2].resolve()
AIRFLOW_DIST_PATH = AIRFLOW_ROOT_PATH / "dist"
REPRODUCIBLE_BUILD_YAML_PATH = AIRFLOW_ROOT_PATH / "reproducible_build.yaml"
AIRFLOW_CORE_ROOT_PATH = AIRFLOW_ROOT_PATH / "airflow-core"
AIRFLOW_CORE_SOURCES_PATH = AIRFLOW_CORE_ROOT_PATH / "src"
AIRFLOW_INIT_FILE = AIRFLOW_CORE_SOURCES_PATH / "airflow" / "__init__.py"
WWW_DIRECTORY = AIRFLOW_CORE_SOURCES_PATH / "airflow" / "www"
VERSION_SUFFIX = os.environ.get("VERSION_SUFFIX", "")
DISTRIBUTION_FORMAT = os.environ.get("DISTRIBUTION_FORMAT", "wheel")
def clean_build_directory():
console.print("[bright_blue]Cleaning build directories\n")
for egg_info_file in AIRFLOW_ROOT_PATH.glob("*egg-info*"):
rmtree(egg_info_file, ignore_errors=True)
rmtree(AIRFLOW_ROOT_PATH / "build", ignore_errors=True)
console.print("[green]Cleaned build directories\n\n")
def mark_git_directory_as_safe():
console.print(f"[bright_blue]Marking {AIRFLOW_ROOT_PATH} as safe directory for git commands.\n")
subprocess.run(
["git", "config", "--global", "--unset-all", "safe.directory"],
cwd=AIRFLOW_ROOT_PATH,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
check=False,
)
subprocess.run(
["git", "config", "--global", "--add", "safe.directory", AIRFLOW_ROOT_PATH],
cwd=AIRFLOW_ROOT_PATH,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
check=False,
)
console.print(f"[green]Marked {AIRFLOW_ROOT_PATH} as safe directory for git commands.\n")
def get_current_airflow_version() -> str:
console.print("[bright_blue]Checking airflow version\n")
airflow_version = subprocess.check_output(
[sys.executable, "-m", "hatch", "version"], text=True, cwd=AIRFLOW_ROOT_PATH
).strip()
console.print(f"[green]Airflow version: {airflow_version}\n")
return airflow_version
def apply_distribution_format_to_hatch_command(build_command: list[str], distribution_format: str):
if distribution_format in ["both", "sdist"]:
build_command.extend(["-t", "sdist"])
if distribution_format in ["both", "wheel"]:
build_command.extend(["-t", "wheel"])
def build_airflow_packages(distribution_format: str):
reproducible_date = yaml.safe_load(REPRODUCIBLE_BUILD_YAML_PATH.read_text())["source-date-epoch"]
envcopy = os.environ.copy()
envcopy["SOURCE_DATE_EPOCH"] = str(reproducible_date)
airflow_core_build_command = [sys.executable, "-m", "hatch", "build", "-t", "custom"]
apply_distribution_format_to_hatch_command(airflow_core_build_command, distribution_format)
console.print(f"[bright_blue]Building apache-airflow-core distributions: {distribution_format}\n")
build_process = subprocess.run(
airflow_core_build_command,
check=False,
capture_output=False,
cwd=AIRFLOW_CORE_ROOT_PATH,
env=envcopy,
)
if build_process.returncode != 0:
console.print("[red]Error building Airflow packages")
sys.exit(build_process.returncode)
airflow_build_command = [sys.executable, "-m", "hatch", "build"]
apply_distribution_format_to_hatch_command(airflow_build_command, distribution_format)
console.print(f"[bright_blue]Building apache-airflow distributions: {distribution_format}\n")
build_process = subprocess.run(
airflow_build_command,
check=False,
capture_output=False,
cwd=AIRFLOW_ROOT_PATH,
env=envcopy,
)
if build_process.returncode != 0:
console.print("[red]Error building Airflow packages")
sys.exit(build_process.returncode)
if distribution_format in ["both", "sdist"]:
console.print("[bright_blue]Checking if sdist packages can be built into wheels")
for glob_pattern in ["apache_airflow_core-*.tar.gz", "apache_airflow-*.tar.gz"]:
for sdist_distribution_file in AIRFLOW_DIST_PATH.glob(glob_pattern):
console.print(f"[bright_blue]Validate build wheel from sdist: {sdist_distribution_file.name}")
if "-sources.tar.gz" not in sdist_distribution_file.name:
# no need to delete - we are in temporary container
tmpdir = mkdtemp()
result = subprocess.run(
[
sys.executable,
"-m",
"pip",
"wheel",
"--wheel-dir",
tmpdir,
"--no-deps",
"--no-cache",
sdist_distribution_file.as_posix(),
],
check=False,
)
if result.returncode != 0:
console.print(f"[red]Error installing {sdist_distribution_file.name}")
sys.exit(result.returncode)
console.print(
f"[green]Sdist package {sdist_distribution_file.name} can be built into wheels"
)
console.print("[green]Sdist package is installed successfully.")
console.print("[green]Airflow packages built successfully")
clean_build_directory()
mark_git_directory_as_safe()
build_airflow_packages(DISTRIBUTION_FORMAT)
for file in AIRFLOW_DIST_PATH.glob("apache_airflow*"):
console.print(file.name)
console.print()