mirror of
https://github.com/hanzo-ml/kserve.git
synced 2026-10-30 20:53:49 +00:00
198 lines
6.0 KiB
Python
198 lines
6.0 KiB
Python
#!/usr/bin/env python3
|
|
|
|
# Copyright 2025 The KServe Authors.
|
|
#
|
|
# Licensed 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.
|
|
|
|
"""Bash script parsing and function extraction utilities."""
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
def extract_bash_function(script_file: Path, func_name: str) -> str:
|
|
"""Extract bash function from script file.
|
|
|
|
Args:
|
|
script_file: Path to bash script
|
|
func_name: Function name to extract (e.g., "install", "uninstall")
|
|
|
|
Returns:
|
|
Complete function code as string (empty if not found)
|
|
"""
|
|
lines = []
|
|
in_function = False
|
|
brace_count = 0
|
|
|
|
with open(script_file) as f:
|
|
for line in f:
|
|
if line.startswith(f"{func_name}() {{"):
|
|
in_function = True
|
|
brace_count = 0
|
|
|
|
if in_function:
|
|
lines.append(line.rstrip())
|
|
brace_count += line.count("{") - line.count("}")
|
|
if brace_count == 0 and len(lines) > 1:
|
|
break
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
def rename_bash_function(func_code: str, old_name: str, new_name: str) -> str:
|
|
"""Rename bash function and its calls within the code.
|
|
|
|
Args:
|
|
func_code: Original function code
|
|
old_name: Current function name
|
|
new_name: New function name
|
|
|
|
Returns:
|
|
Function code with renamed function definition and calls
|
|
"""
|
|
if not func_code:
|
|
return func_code
|
|
|
|
lines = func_code.split("\n")
|
|
|
|
# Rename function definition
|
|
if lines and lines[0].startswith(f"{old_name}() {{"):
|
|
lines[0] = f"{new_name}() {{"
|
|
|
|
# Rename function calls within the body
|
|
# Pattern matches function calls that appear:
|
|
# - At start of line (with optional leading whitespace)
|
|
# - After command separators: ; | & ( etc. (with optional whitespace)
|
|
# But NOT after other commands (like 'helm install' or 'kubectl apply')
|
|
# The pattern captures the prefix separately to preserve it
|
|
pattern = re.compile(
|
|
r"(^[ \t]*|[;|&(][ \t]*)(" + re.escape(old_name) + r")\b(?=\s|$|;|\||&|\))"
|
|
)
|
|
|
|
def replace_func(match):
|
|
# Preserve the prefix (whitespace/separator) and replace only the function name
|
|
return match.group(1) + new_name
|
|
|
|
for i in range(1, len(lines)): # Skip first line (function definition)
|
|
lines[i] = pattern.sub(replace_func, lines[i])
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
def deduplicate_variables(variables: list[str]) -> list[str]:
|
|
"""Remove duplicate variable declarations.
|
|
|
|
Keeps first occurrence of each variable name.
|
|
Handles multi-line array declarations (e.g., VAR=( ... )).
|
|
|
|
Args:
|
|
variables: List of variable declarations (e.g., ["VAR1=value", "VAR2=value"])
|
|
|
|
Returns:
|
|
List with duplicates removed
|
|
"""
|
|
seen = set()
|
|
result = []
|
|
in_array = None # Track if we're inside an array declaration
|
|
|
|
for var in variables:
|
|
# Check if this is the start of a variable declaration
|
|
match = re.match(r"^([A-Z_][A-Z0-9_]*)=", var)
|
|
|
|
if match:
|
|
var_name = match.group(1)
|
|
if var_name not in seen:
|
|
seen.add(var_name)
|
|
result.append(var)
|
|
# Check if this starts an array declaration
|
|
if "=(" in var and ")" not in var:
|
|
in_array = var_name
|
|
elif in_array == var_name:
|
|
# Skip duplicate array declaration start
|
|
in_array = None
|
|
elif in_array:
|
|
# This is a continuation of an array (indented lines or closing paren)
|
|
result.append(var)
|
|
# Check if array ends
|
|
if ")" in var:
|
|
in_array = None
|
|
|
|
return result
|
|
|
|
|
|
def inject_code_into_function(func_code: str, code_to_inject: str) -> str:
|
|
"""Inject code at the beginning of a bash function body.
|
|
|
|
Args:
|
|
func_code: Original function code
|
|
code_to_inject: Code to inject at the start of function body
|
|
|
|
Returns:
|
|
Function code with injected code
|
|
"""
|
|
if not func_code or not code_to_inject:
|
|
return func_code
|
|
|
|
lines = func_code.split("\n")
|
|
if not lines:
|
|
return func_code
|
|
|
|
# Find the opening brace line (e.g., "install_kserve_helm() {")
|
|
if not lines[0].endswith("{"):
|
|
return func_code
|
|
|
|
# Insert code after the opening brace
|
|
# Preserve indentation of first real line if exists
|
|
indent = " " # Default 4 spaces
|
|
if len(lines) > 1 and lines[1]:
|
|
# Extract indentation from first line
|
|
match = re.match(r"^(\s*)", lines[1])
|
|
if match:
|
|
indent = match.group(1)
|
|
|
|
# Indent the injected code
|
|
injected_lines = code_to_inject.split("\n")
|
|
indented_injection = "\n".join(
|
|
indent + line if line.strip() else line for line in injected_lines
|
|
)
|
|
|
|
# Insert after opening brace
|
|
result = [lines[0], indented_injection] + lines[1:]
|
|
return "\n".join(result)
|
|
|
|
|
|
def extract_common_functions(content: str) -> str:
|
|
"""Extract utility functions from common.sh.
|
|
|
|
Extracts content between '# Utility Functions' and '# Auto-initialization'.
|
|
|
|
Args:
|
|
content: Content of common.sh file
|
|
|
|
Returns:
|
|
Extracted utility functions section
|
|
"""
|
|
lines = content.split("\n")
|
|
|
|
start_idx = next(
|
|
(i for i, line in enumerate(lines) if "# Utility Functions" in line), None
|
|
)
|
|
end_idx = next(
|
|
(i for i, line in enumerate(lines) if "# Auto-initialization" in line), None
|
|
)
|
|
|
|
if start_idx is not None:
|
|
return "\n".join(lines[start_idx:end_idx] if end_idx else lines[start_idx:])
|
|
|
|
return content
|