blob: 38e426a4d1c1127485b66b3c5aa53f1b4e9a06ea [file] [log] [blame]
# 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.
import argparse
import logging
import os
import shutil
import subprocess
import sys
from tasks import cpp, java, javascript, kotlin, rust, python, go, format
from tasks.common import is_windows
# Configure logging
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
# Migration Strategy:
# This script supports a gradual migration from the shell script (run_ci.sh) to Python.
# You can control which languages use the Python implementation by setting environment variables.
#
# To use the shell script for a specific language, set the corresponding environment variable to "0".
# To use the Python implementation, set it to "1" or leave it unset (default is Python).
#
# Example:
# # Use shell script for Java, Python implementation for everything else
# export USE_PYTHON_JAVA=0
# python run_ci.py java --version 17
#
# # Use shell script for multiple languages
# export USE_PYTHON_JAVA=0 USE_PYTHON_CPP=0 USE_PYTHON_RUST=0
# python run_ci.py cpp
#
# Available environment variables:
# USE_PYTHON_CPP - C++ implementation
# USE_PYTHON_RUST - Rust implementation
# USE_PYTHON_JAVASCRIPT - JavaScript implementation
# USE_PYTHON_JAVA - Java implementation
# USE_PYTHON_KOTLIN - Kotlin implementation
# USE_PYTHON_PYTHON - Python implementation
# USE_PYTHON_GO - Go implementation
# USE_PYTHON_FORMAT - Format implementation
#
# By default, JavaScript, Rust, and C++ use the Python implementation,
# while Java, Kotlin, Python, Go, and Format use the shell script implementation.
# Environment variables to control which languages use the Python implementation
# Default to the status quo before migration:
# - JavaScript, Rust, and C++ use Python implementation
# - Java, Kotlin, Python, Go, and Format use shell script implementation
USE_PYTHON_CPP = os.environ.get("USE_PYTHON_CPP", "1") == "1"
USE_PYTHON_RUST = os.environ.get("USE_PYTHON_RUST", "1") == "1"
USE_PYTHON_JAVASCRIPT = os.environ.get("USE_PYTHON_JAVASCRIPT", "1") == "1"
USE_PYTHON_JAVA = os.environ.get("USE_PYTHON_JAVA", "0") == "1"
USE_PYTHON_KOTLIN = os.environ.get("USE_PYTHON_KOTLIN", "0") == "1"
USE_PYTHON_PYTHON = os.environ.get("USE_PYTHON_PYTHON", "0") == "1"
USE_PYTHON_GO = os.environ.get("USE_PYTHON_GO", "0") == "1"
USE_PYTHON_FORMAT = os.environ.get("USE_PYTHON_FORMAT", "0") == "1"
def run_shell_script(command, *args):
"""Run the shell script with the given command and arguments."""
script_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "run_ci.sh")
if is_windows():
# On Windows, try to use bash if available
bash_path = shutil.which("bash")
if bash_path:
cmd = [bash_path, script_path, command]
cmd.extend(args)
logging.info(f"Falling back to shell script with bash: {' '.join(cmd)}")
sys.exit(subprocess.call(cmd))
else:
logging.error(
"Bash is not available on this Windows system. Cannot run shell script."
)
logging.error(
"Please install Git Bash, WSL, or Cygwin to run shell scripts on Windows."
)
logging.error(
"Alternatively, set USE_PYTHON_JAVA=1 to use the Python implementation."
)
sys.exit(1)
else:
# On Unix-like systems, run the script directly
cmd = [script_path, command]
cmd.extend(args)
logging.info(f"Falling back to shell script: {' '.join(cmd)}")
sys.exit(subprocess.call(cmd))
def parse_args():
"""Parse command-line arguments and dispatch to the appropriate task module."""
parser = argparse.ArgumentParser(
description="Fory CI Runner",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.set_defaults(func=lambda: parser.print_help())
subparsers = parser.add_subparsers(dest="command")
# C++ subparser
cpp_parser = subparsers.add_parser(
"cpp",
description="Run C++ CI",
help="Run C++ CI",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
cpp_parser.add_argument(
"--install-deps-only",
action="store_true",
help="Only install dependencies without running tests",
)
cpp_parser.set_defaults(func=lambda install_deps_only: cpp.run(install_deps_only))
# Rust subparser
rust_parser = subparsers.add_parser(
"rust",
description="Run Rust CI",
help="Run Rust CI",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
rust_parser.set_defaults(func=rust.run)
# JavaScript subparser
js_parser = subparsers.add_parser(
"javascript",
description="Run JavaScript CI",
help="Run JavaScript CI",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
js_parser.set_defaults(func=javascript.run)
# Java subparser
java_parser = subparsers.add_parser(
"java",
description="Run Java CI",
help="Run Java CI",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
java_parser.add_argument(
"--version",
choices=[
"8",
"11",
"17",
"21",
"25",
"windows_java21",
"integration_tests",
"graalvm",
],
default=None,
help="Java version to use for testing",
)
java_parser.add_argument(
"--release",
action="store_true",
help="Release to Maven Central",
)
java_parser.add_argument(
"--install-jdks",
action="store_true",
help="Install JDKs",
)
java_parser.add_argument(
"--install-fory",
action="store_true",
help="Install Fory",
)
java_parser.set_defaults(func=java.run)
# Kotlin subparser
kotlin_parser = subparsers.add_parser(
"kotlin",
description="Run Kotlin CI",
help="Run Kotlin CI",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
kotlin_parser.set_defaults(func=kotlin.run)
# Python subparser
python_parser = subparsers.add_parser(
"python",
description="Run Python CI",
help="Run Python CI",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
python_parser.set_defaults(func=python.run)
# Go subparser
go_parser = subparsers.add_parser(
"go",
description="Run Go CI",
help="Run Go CI",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
go_parser.set_defaults(func=go.run)
# Format subparser
format_parser = subparsers.add_parser(
"format",
description="Run format checks",
help="Run format checks",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
format_parser.set_defaults(func=format.run)
args = parser.parse_args()
# If no arguments were provided, print help and exit
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
# Extract arguments to pass to the function
arg_dict = vars(args)
func = arg_dict.pop("func")
command = arg_dict.pop("command", None)
# Call the appropriate function with the remaining arguments
if command == "java":
if USE_PYTHON_JAVA:
func(**arg_dict)
else:
if not arg_dict.get("version"):
func(**arg_dict)
return
# Map Python version argument to shell script command
version = arg_dict.get("version", "17")
release = arg_dict.get("release", False)
if release:
logging.info("Release mode requested - using Python implementation")
func(**arg_dict)
# For windows_java21 on Windows, use the Python implementation directly
elif version == "windows_java21" and is_windows():
logging.info(
"Using Python implementation for windows_java21 on Windows"
)
func(**arg_dict)
elif version == "integration_tests":
run_shell_script("integration_tests")
elif version == "windows_java21":
run_shell_script("windows_java21")
elif version == "graalvm":
run_shell_script("graalvm_test")
else:
run_shell_script(f"java{version}")
elif command == "cpp":
if USE_PYTHON_CPP:
func(arg_dict.get("install_deps_only", False))
else:
if arg_dict.get("install_deps_only", False):
run_shell_script("install_bazel")
else:
run_shell_script("cpp")
elif command == "rust":
if USE_PYTHON_RUST:
func()
else:
run_shell_script("rust")
elif command == "javascript":
if USE_PYTHON_JAVASCRIPT:
func()
else:
run_shell_script("javascript")
elif command == "kotlin":
if USE_PYTHON_KOTLIN:
func()
else:
run_shell_script("kotlin")
elif command == "python":
if USE_PYTHON_PYTHON:
func()
else:
run_shell_script("python")
elif command == "go":
if USE_PYTHON_GO:
func()
else:
run_shell_script("go")
pass
elif command == "format":
if USE_PYTHON_FORMAT:
func()
else:
run_shell_script("format")
else:
func()
if __name__ == "__main__":
parse_args()