#!/usr/bin/python3
"""
*File:* find_and_modify_specfile
*Author:* Anthony NORA
*Date:* 14/11/2024

*Description:*
    Script to find and modify the specfile of a project from within a koji buildroot.

*License:*
    *Copyright (C) 2020-2025 "IoT.bzh"*

    *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.*
"""

import argparse
import logging
import os
import re
import subprocess

LOG_LEVEL = logging.DEBUG
ENABLE_RPMSPEC_4_19_WORKAROUND = False

# Handle the arguments
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument('--directory', type=str, default='/builddir/build', help='Top directory to be used by rpmbuild')
arg_parser.add_argument('--logFile', type=str, default='/tmp/audit-mock-specfile.log', help='Location of the logging file')
args = arg_parser.parse_args()

buildDir = args.directory

# Handle cleanly the logs
logger = logging.getLogger('find_and_modify_specfile')
logger.setLevel(LOG_LEVEL)
logger_format = logging.Formatter(fmt="[%(levelname)6s] [%(name)22s] : %(message)s", datefmt='%d/%m/%Y %I:%M:%S %p')
# STDERR logger
stderr_logger = logging.StreamHandler()
stderr_logger.setLevel(LOG_LEVEL)
stderr_logger.setFormatter(logger_format)
# File logger
file_logger = logging.FileHandler(args.logFile)
file_logger.setLevel(LOG_LEVEL)
file_logger.setFormatter(logger_format)
# Add handlers
logger.addHandler(stderr_logger)
logger.addHandler(file_logger)

# find_spec_file: looks for a spec file in a given path
def find_spec_file(start_path):
    logger.debug(f"Searching for spec file in: {start_path}")
    for root, _, files in os.walk(start_path):
        for file in files:
            if file.endswith(".spec"):
                return os.path.join(root, file)
    return None

os.system("rpm -ivh /builddir/*.src.rpm")

spec_path = None
spec_path = find_spec_file("/builddir")

if not spec_path:
    logger.error("Spec-file not found!")
    # Create the information message
    info_msg = "Environment variables:\n"
    for key, value in os.environ.items():
        info_msg += f"{key}: {value}\n"
    # Print info
    logger.info(info_msg)
    # Exit
    exit(1)
else:
    logger.info(f"Spec-file path found: {spec_path}")

try:
    # Set default command line (no workaround)
    rpmspec_cmd_line = ["rpmspec", "-P", spec_path]
    
    # Try to get the rpmspec version to know if we need to apply the workaround
    rpmspec_version = subprocess.check_output(["rpmspec", "--version"], universal_newlines=True)
    if "4.19" in rpmspec_version:
        # Need to apply the workaround
        ENABLE_RPMSPEC_4_19_WORKAROUND = True
        rpmspec_cmd_line = ["rpmspec", "--define", "build #%%build", "-P", spec_path]

    # Run the rpmspec command line!
    expanded_content = subprocess.check_output(rpmspec_cmd_line, universal_newlines=True)

except subprocess.CalledProcessError as e:
    logger.error(f"Error expanding spec file: {e}")
    exit(1)

logger.debug(f"Found spec-file content:\n{expanded_content}")

build_section = re.search(r"%build.*?(?=%\w+|\Z)", expanded_content, re.DOTALL)
if build_section:
    build_content = build_section.group()
    # The regular expression used here is created to take into account that the "cmake" command can be on several lines (with the "\" character) 
    cmake_match = re.search(r"(cmake.*(?:\\\n.*)*?(?<!\\)\n)", build_content)
    if cmake_match:
        cmake_cmd = cmake_match.group(1)
        modified_cmake = cmake_cmd.rstrip() + " -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\nexit 0\n"
        expanded_content = expanded_content.replace(cmake_cmd, modified_cmake)
    else:
        # Default string to replace
        build_macro_to_replace = "%build"
        
        # Check if we need to apply the workaround
        if ENABLE_RPMSPEC_4_19_WORKAROUND:
            build_macro_to_replace = "#%build"

        expanded_content = expanded_content.replace(build_macro_to_replace, "%build\nexit 0\n")
    
expanded_content = "%global debug_package %{nil}\n" + expanded_content

with open(spec_path, "w") as f:
    f.write(expanded_content)

logger.info("Spec-file modified")
logger.debug(f"New content:\n{expanded_content}")

try:
    # Create the command to run until the spec-file until the "%build" section included
    command_to_run = ["rpmbuild", "-v", "-D", f"_topdir {buildDir}", "-bc", spec_path, "--nodeps"]
    
    # Log what we are doing
    command_str = " ".join(command_to_run)
    logger.debug(f"About to run: '{command_str}'")
    
    # Run the 'rpmbuild' command
    result = subprocess.run(command_to_run, capture_output=True, text=True, check=False)
    
    # Log the command results
    if result.returncode > 0:
        logger.error(f"'rpmbuild' command exit with code {result.returncode}")
    else:
        logger.info(f"'rpmbuild' command exit with code {result.returncode}")
    
    # Log the output as debug
    logger.debug(f"'rpmbuild' command STDOUT:\n{result.stdout}")
    logger.debug(f"'rpmbuild' command STDERR:\n{result.stderr}")

    logger.debug("Walking through the '/builddir/' directory...")
    for root, dirs, files in os.walk("/builddir"):
        for file in files:
            file_path = os.path.join(root, file)
            logger.debug(f"File found: {file_path}")

except Exception as e:
    logger.error(f"An error occurred while running rpmbuild: {e}")
