szaszm commented on code in PR #1681:
URL: https://github.com/apache/nifi-minifi-cpp/pull/1681#discussion_r1385283642


##########
README.md:
##########
@@ -304,8 +304,30 @@ sudo brew install libpcap
 
 ### Bootstrapping
 
-- MiNiFi C++ offers a bootstrap script in the root of our github repo that 
will bootstrap the cmake and build process for you without the need to install 
dependencies yourself. To use this
-  process, please run the command `bootstrap.sh` from the root of the MiNiFi 
C++ source tree.
+MiNiFi C++ offers bootstrap scripts that will bootstrap the cmake and build 
process for you without the need to install dependencies yourself.
+
+#### Python based bootstrapping
+
+Set up a virtual environment in the bootstrap folder.
+```
+python -m venv venv

Review Comment:
   ```suggestion
   cd bootstrap
   python -m venv venv
   ```



##########
bootstrap/cli.py:
##########
@@ -0,0 +1,141 @@
+import os
+
+import inquirer
+
+from minifi_option import MinifiOptions
+from system_dependency import install_required
+
+
+def install_dependencies(minifi_options: MinifiOptions):
+    install_required(minifi_options)
+
+
+def run_cmake(minifi_options: MinifiOptions):
+    if not os.path.exists(minifi_options.build_dir):
+        os.mkdir(minifi_options.build_dir)
+    os.chdir(minifi_options.build_dir)
+    cmake_cmd = f"cmake -G Ninja {minifi_options.create_cmake_options_str()} 
{minifi_options.source_dir}"
+    print(f"Running {cmake_cmd}")
+    os.system(cmake_cmd)
+
+
+def do_build(minifi_options: MinifiOptions):
+    os.chdir(minifi_options.build_dir)
+    os.system("cmake --build .")
+
+
+def do_one_click_build(minifi_options: MinifiOptions) -> bool:
+    install_dependencies(minifi_options)
+    run_cmake(minifi_options)
+    do_build(minifi_options)
+    return True
+
+
+def modify_bool_options(minifi_options: MinifiOptions):
+    options = [inquirer.Checkbox(
+        "MiNiFi C++ options",
+        message="Select MiNiFi C++ components",
+        choices=[name for name, obj in minifi_options.bool_options.items()],
+        default=[name for name, obj in minifi_options.bool_options.items() if 
obj.value == "ON"]
+    )]
+
+    selection_result = inquirer.prompt(options)
+    for minifi_option in minifi_options.bool_options.values():
+        if minifi_option.name in selection_result:
+            minifi_option.value = "ON"
+        else:
+            minifi_option.value = "OFF"
+
+
+def main_menu(minifi_options: MinifiOptions):
+    done = False
+    while not done:
+        main_menu_options = {
+            f"Build dir: {minifi_options.build_dir}": build_dir_menu,
+            f"Build type: {minifi_options.build_type.value}": build_type_menu,
+            "Build options": bool_menu,
+            "One click build": do_one_click_build,
+            "Step by step build": step_by_step_menu,
+            "Exit": lambda options: True,
+        }
+
+        questions = [
+            inquirer.List(
+                "sub_menu",
+                message="Main Menu",
+                choices=[menu_option_name for menu_option_name in 
main_menu_options],
+            ),
+        ]
+
+        main_menu_prompt = inquirer.prompt(questions)
+        done = main_menu_options[main_menu_prompt["sub_menu"]](minifi_options)
+
+
+def build_type_menu(minifi_options: MinifiOptions) -> bool:
+    questions = [
+        inquirer.List(
+            "build_type",
+            message="Build type",
+            choices=minifi_options.build_type.possible_values,
+        ),
+    ]
+
+    answers = inquirer.prompt(questions)
+    minifi_options.build_type.value = answers["build_type"]
+    return False
+
+
+def build_dir_menu(minifi_options: MinifiOptions) -> bool:
+    questions = [
+        inquirer.Path('build_dir',
+                      message="Build directory",
+                      default=minifi_options.build_dir
+                      ),
+    ]
+    minifi_options.build_dir = inquirer.prompt(questions)["build_dir"]
+    return False
+
+
+def bool_menu(minifi_options: MinifiOptions) -> bool:
+    possible_values = [option_name for option_name in 
minifi_options.bool_options]
+    selected_values = [option.name for option in 
minifi_options.bool_options.values() if option.value == "ON"]
+    questions = [
+        inquirer.Checkbox(
+            "options",
+            message="MiNiFi C++ Options",
+            choices=possible_values,
+            default=selected_values
+        ),
+    ]
+
+    answers = inquirer.prompt(questions)
+    for bool_option in minifi_options.bool_options.values():
+        if bool_option.name in answers["options"]:
+            bool_option.value = "ON"
+        else:
+            bool_option.value = "OFF"
+
+    return False

Review Comment:
   This menu needs guidance on how to exit from it after selecting the options.
   
![image](https://github.com/apache/nifi-minifi-cpp/assets/1170582/041bf975-0bcd-4b95-9dfd-b46f2915136d)
   



##########
README.md:
##########
@@ -304,8 +304,30 @@ sudo brew install libpcap
 
 ### Bootstrapping
 
-- MiNiFi C++ offers a bootstrap script in the root of our github repo that 
will bootstrap the cmake and build process for you without the need to install 
dependencies yourself. To use this
-  process, please run the command `bootstrap.sh` from the root of the MiNiFi 
C++ source tree.
+MiNiFi C++ offers bootstrap scripts that will bootstrap the cmake and build 
process for you without the need to install dependencies yourself.
+
+#### Python based bootstrapping
+
+Set up a virtual environment in the bootstrap folder.
+```
+python -m venv venv
+source venv/bin/activate
+pip install -r requirements.txt
+```
+
+After that you can run the bootstrap script that will guide you through the 
configuration, dependency installation and build processes.

Review Comment:
   ```suggestion
   After that you can run the bootstrap script: `python main.py`. It will guide 
you through the configuration, dependency installation and build processes.
   ```



##########
bootstrap/system_dependency.py:
##########
@@ -0,0 +1,168 @@
+from __future__ import annotations
+
+import os
+import platform
+import sys
+from typing import Dict
+
+import distro
+
+from minifi_option import MinifiOptions
+
+
+def _query_yes_no(question: str, no_confirm: bool) -> bool:
+    valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False}
+
+    if no_confirm:
+        return True
+    while True:
+        print("{} [y/n]".format(question))
+        choice = input().lower()
+        if choice in valid:
+            return valid[choice]
+        else:
+            print("Please respond with 'yes' or 'no' " "(or 'y' or 'n').")
+
+
+def _get_system_identifier():
+    platform_system = platform.system()
+    if platform_system == "Linux":
+        return distro.id()
+    return platform_system
+
+
+def _replace_wholewords(target: str, replace_dict: Dict[str]):
+    words = target.split()
+    output_string = ' '.join(replace_dict.get(word, word) for word in words)
+    return output_string
+
+
+def _run_command_with_confirm(command: str, no_confirm: bool) -> bool:
+    if _query_yes_no("Running {}".format(command), no_confirm):
+        return os.system(command) == 0
+
+
+def _install_with_brew(dependencies_str: str, no_confirm: bool):
+    replace_dict = {"patch": "",
+                    "jni": "maven"}
+    command = "brew install {}".format(
+        _replace_wholewords(dependencies_str, replace_dict))
+    assert _run_command_with_confirm(command, no_confirm)
+
+
+def _install_with_apt(dependencies_str: str, no_confirm: bool):
+    replace_dict = {"libarchive": "liblzma-dev",
+                    "lua": "liblua5.1-0-dev",
+                    "python": "libpython3-dev",
+                    "libusb": "libusb-1.0-0-dev libusb-dev",
+                    "libpng": "libpng-dev",
+                    "libpcap": "libpcap-dev",
+                    "jni": "openjdk-8-jdk openjdk-8-source maven"}
+
+    command = "sudo apt install -y {}".format(
+        _replace_wholewords(dependencies_str, replace_dict))
+    assert _run_command_with_confirm(command, no_confirm)
+
+
+def _install_with_dnf(dependencies_str: str, no_confirm: bool):
+    replace_dict = {"gpsd": "gpsd-devel",
+                    "libpcap": "libpcap-devel",
+                    "lua": "lua-devel",
+                    "python": "python-devel",
+                    "jni": "java-1.8.0-openjdk java-1.8.0-openjdk-devel maven",
+                    "libpng": "libpng-devel",
+                    "libusb": "libusb-devel"}
+
+    command = "sudo dnf --enablerepo=crb install -y epel-release {}".format(
+        _replace_wholewords(dependencies_str, replace_dict))
+    assert _run_command_with_confirm(command, no_confirm)
+
+
+def _install_with_pacman(dependencies_str: str, no_confirm: bool):
+    replace_dict = {"g++": "gcc",
+                    "jni": "jdk8-openjdk maven"}
+    command = "sudo pacman --noconfirm -S {}".format(
+        _replace_wholewords(dependencies_str, replace_dict))
+    assert _run_command_with_confirm(command, no_confirm)
+
+
+def _install_with_winget(dependencies_str: str, no_confirm: bool):
+    replace_dict = {"lua": "DEVCOM.Lua",
+                    "python": "python",
+                    "patch": "",
+                    "bison": "",
+                    "flex": ""}
+    command = "winget install --disable-interactivity 
--accept-package-agreements {}".format(
+        _replace_wholewords(dependencies_str, replace_dict))
+    assert _run_command_with_confirm(command, no_confirm)
+
+
+def _install(dependencies_str: str, no_confirm: bool):

Review Comment:
   Only the missing dependencies should be installed. There are ways to query 
already installed packages with all package managers.



##########
bootstrap/system_dependency.py:
##########
@@ -0,0 +1,168 @@
+from __future__ import annotations
+
+import os
+import platform
+import sys
+from typing import Dict
+
+import distro
+
+from minifi_option import MinifiOptions
+
+
+def _query_yes_no(question: str, no_confirm: bool) -> bool:
+    valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False}
+
+    if no_confirm:
+        return True
+    while True:
+        print("{} [y/n]".format(question))
+        choice = input().lower()
+        if choice in valid:
+            return valid[choice]
+        else:
+            print("Please respond with 'yes' or 'no' " "(or 'y' or 'n').")
+
+
+def _get_system_identifier():
+    platform_system = platform.system()
+    if platform_system == "Linux":
+        return distro.id()
+    return platform_system
+
+
+def _replace_wholewords(target: str, replace_dict: Dict[str]):
+    words = target.split()
+    output_string = ' '.join(replace_dict.get(word, word) for word in words)
+    return output_string
+
+
+def _run_command_with_confirm(command: str, no_confirm: bool) -> bool:
+    if _query_yes_no("Running {}".format(command), no_confirm):
+        return os.system(command) == 0
+
+
+def _install_with_brew(dependencies_str: str, no_confirm: bool):
+    replace_dict = {"patch": "",
+                    "jni": "maven"}
+    command = "brew install {}".format(
+        _replace_wholewords(dependencies_str, replace_dict))
+    assert _run_command_with_confirm(command, no_confirm)
+
+
+def _install_with_apt(dependencies_str: str, no_confirm: bool):
+    replace_dict = {"libarchive": "liblzma-dev",
+                    "lua": "liblua5.1-0-dev",
+                    "python": "libpython3-dev",
+                    "libusb": "libusb-1.0-0-dev libusb-dev",
+                    "libpng": "libpng-dev",
+                    "libpcap": "libpcap-dev",
+                    "jni": "openjdk-8-jdk openjdk-8-source maven"}
+
+    command = "sudo apt install -y {}".format(
+        _replace_wholewords(dependencies_str, replace_dict))
+    assert _run_command_with_confirm(command, no_confirm)
+
+
+def _install_with_dnf(dependencies_str: str, no_confirm: bool):
+    replace_dict = {"gpsd": "gpsd-devel",
+                    "libpcap": "libpcap-devel",
+                    "lua": "lua-devel",
+                    "python": "python-devel",
+                    "jni": "java-1.8.0-openjdk java-1.8.0-openjdk-devel maven",
+                    "libpng": "libpng-devel",
+                    "libusb": "libusb-devel"}
+
+    command = "sudo dnf --enablerepo=crb install -y epel-release {}".format(
+        _replace_wholewords(dependencies_str, replace_dict))
+    assert _run_command_with_confirm(command, no_confirm)
+
+
+def _install_with_pacman(dependencies_str: str, no_confirm: bool):
+    replace_dict = {"g++": "gcc",
+                    "jni": "jdk8-openjdk maven"}
+    command = "sudo pacman --noconfirm -S {}".format(
+        _replace_wholewords(dependencies_str, replace_dict))
+    assert _run_command_with_confirm(command, no_confirm)
+
+
+def _install_with_winget(dependencies_str: str, no_confirm: bool):
+    replace_dict = {"lua": "DEVCOM.Lua",
+                    "python": "python",
+                    "patch": "",
+                    "bison": "",
+                    "flex": ""}
+    command = "winget install --disable-interactivity 
--accept-package-agreements {}".format(
+        _replace_wholewords(dependencies_str, replace_dict))
+    assert _run_command_with_confirm(command, no_confirm)
+
+
+def _install(dependencies_str: str, no_confirm: bool):
+    platform_system = platform.system()
+    if platform_system == "Darwin":
+        _install_with_brew(dependencies_str, no_confirm)
+    elif platform_system == "Linux":
+        distro_id = distro.id()
+        if distro_id == "ubuntu":
+            _install_with_apt(dependencies_str, no_confirm)
+        elif "arch" in distro_id or "manjaro" in distro_id:
+            _install_with_pacman(dependencies_str, no_confirm)
+        elif "rocky" in distro_id:
+            _install_with_dnf(dependencies_str, no_confirm)
+        else:
+            sys.exit(f"Unsupported platform {distro_id} exiting")
+    elif platform_system == "Windows":
+        _install_with_winget(dependencies_str, no_confirm)
+    else:
+        sys.exit(f"Unsupported platform {platform_system} exiting")
+
+
+def _create_system_dependencies(minifi_options: MinifiOptions) -> str:
+    system_dependencies = {'patch': 'patch', 'make': 'make'}
+    if minifi_options.is_enabled("ENABLE_EXPRESSION_LANGUAGE"):
+        system_dependencies['bison'] = 'bison'
+        system_dependencies['flex'] = 'flex'
+    if minifi_options.is_enabled("ENABLE_LIBARCHIVE"):
+        system_dependencies['libarchive'] = 'libarchive'
+    if minifi_options.is_enabled("ENABLE_PCAP"):
+        system_dependencies['libpcap'] = 'libpcap'
+    if minifi_options.is_enabled("ENABLE_USB_CAMERA"):
+        system_dependencies['libusb'] = 'libusb'
+        system_dependencies['libpng'] = 'libpng'
+    if minifi_options.is_enabled("ENABLE_GPS"):
+        system_dependencies['gpsd'] = 'gpsd'
+    if minifi_options.is_enabled("ENABLE_COAP"):
+        system_dependencies['automake'] = 'automake'
+        system_dependencies['autoconf'] = 'autoconf'
+        system_dependencies['libtool'] = 'libtool'
+    if minifi_options.is_enabled("ENABLE_LUA_SCRIPTING"):
+        system_dependencies['lua'] = 'lua'
+    if minifi_options.is_enabled("ENABLE_PYTHON_SCRIPTING"):
+        system_dependencies['python'] = 'python'
+    if minifi_options.is_enabled("MINIFI_OPENSSL"):
+        system_dependencies['openssl'] = 'perl'
+    if minifi_options.is_enabled("ENABLE_JNI"):
+        system_dependencies['jni'] = ''
+    return " ".join(str(value) for value in system_dependencies.values())
+
+
+def install_required(minifi_options: MinifiOptions):
+    _install(_create_system_dependencies(minifi_options), 
minifi_options.no_confirm)
+
+
+def install_compiler(no_confirm: bool) -> str:
+    print("For CMake to work we need a working compiler")

Review Comment:
   This should check first whether a compiler is already available on the 
system.



##########
bootstrap/system_dependency.py:
##########
@@ -0,0 +1,168 @@
+from __future__ import annotations
+
+import os
+import platform
+import sys
+from typing import Dict
+
+import distro
+
+from minifi_option import MinifiOptions
+
+
+def _query_yes_no(question: str, no_confirm: bool) -> bool:
+    valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False}
+
+    if no_confirm:
+        return True
+    while True:
+        print("{} [y/n]".format(question))
+        choice = input().lower()
+        if choice in valid:
+            return valid[choice]
+        else:
+            print("Please respond with 'yes' or 'no' " "(or 'y' or 'n').")
+
+
+def _get_system_identifier():
+    platform_system = platform.system()
+    if platform_system == "Linux":
+        return distro.id()
+    return platform_system
+
+
+def _replace_wholewords(target: str, replace_dict: Dict[str]):
+    words = target.split()
+    output_string = ' '.join(replace_dict.get(word, word) for word in words)
+    return output_string
+
+
+def _run_command_with_confirm(command: str, no_confirm: bool) -> bool:
+    if _query_yes_no("Running {}".format(command), no_confirm):
+        return os.system(command) == 0
+
+
+def _install_with_brew(dependencies_str: str, no_confirm: bool):
+    replace_dict = {"patch": "",
+                    "jni": "maven"}
+    command = "brew install {}".format(
+        _replace_wholewords(dependencies_str, replace_dict))
+    assert _run_command_with_confirm(command, no_confirm)
+
+
+def _install_with_apt(dependencies_str: str, no_confirm: bool):
+    replace_dict = {"libarchive": "liblzma-dev",
+                    "lua": "liblua5.1-0-dev",
+                    "python": "libpython3-dev",
+                    "libusb": "libusb-1.0-0-dev libusb-dev",
+                    "libpng": "libpng-dev",
+                    "libpcap": "libpcap-dev",
+                    "jni": "openjdk-8-jdk openjdk-8-source maven"}
+
+    command = "sudo apt install -y {}".format(
+        _replace_wholewords(dependencies_str, replace_dict))
+    assert _run_command_with_confirm(command, no_confirm)
+
+
+def _install_with_dnf(dependencies_str: str, no_confirm: bool):
+    replace_dict = {"gpsd": "gpsd-devel",
+                    "libpcap": "libpcap-devel",
+                    "lua": "lua-devel",
+                    "python": "python-devel",
+                    "jni": "java-1.8.0-openjdk java-1.8.0-openjdk-devel maven",
+                    "libpng": "libpng-devel",
+                    "libusb": "libusb-devel"}
+
+    command = "sudo dnf --enablerepo=crb install -y epel-release {}".format(
+        _replace_wholewords(dependencies_str, replace_dict))
+    assert _run_command_with_confirm(command, no_confirm)
+
+
+def _install_with_pacman(dependencies_str: str, no_confirm: bool):
+    replace_dict = {"g++": "gcc",
+                    "jni": "jdk8-openjdk maven"}
+    command = "sudo pacman --noconfirm -S {}".format(
+        _replace_wholewords(dependencies_str, replace_dict))
+    assert _run_command_with_confirm(command, no_confirm)
+
+
+def _install_with_winget(dependencies_str: str, no_confirm: bool):
+    replace_dict = {"lua": "DEVCOM.Lua",
+                    "python": "python",
+                    "patch": "",
+                    "bison": "",
+                    "flex": ""}
+    command = "winget install --disable-interactivity 
--accept-package-agreements {}".format(
+        _replace_wholewords(dependencies_str, replace_dict))
+    assert _run_command_with_confirm(command, no_confirm)
+
+
+def _install(dependencies_str: str, no_confirm: bool):
+    platform_system = platform.system()
+    if platform_system == "Darwin":
+        _install_with_brew(dependencies_str, no_confirm)
+    elif platform_system == "Linux":
+        distro_id = distro.id()
+        if distro_id == "ubuntu":
+            _install_with_apt(dependencies_str, no_confirm)
+        elif "arch" in distro_id or "manjaro" in distro_id:
+            _install_with_pacman(dependencies_str, no_confirm)
+        elif "rocky" in distro_id:
+            _install_with_dnf(dependencies_str, no_confirm)
+        else:
+            sys.exit(f"Unsupported platform {distro_id} exiting")
+    elif platform_system == "Windows":
+        _install_with_winget(dependencies_str, no_confirm)
+    else:
+        sys.exit(f"Unsupported platform {platform_system} exiting")
+
+
+def _create_system_dependencies(minifi_options: MinifiOptions) -> str:
+    system_dependencies = {'patch': 'patch', 'make': 'make'}
+    if minifi_options.is_enabled("ENABLE_EXPRESSION_LANGUAGE"):
+        system_dependencies['bison'] = 'bison'
+        system_dependencies['flex'] = 'flex'
+    if minifi_options.is_enabled("ENABLE_LIBARCHIVE"):
+        system_dependencies['libarchive'] = 'libarchive'
+    if minifi_options.is_enabled("ENABLE_PCAP"):
+        system_dependencies['libpcap'] = 'libpcap'
+    if minifi_options.is_enabled("ENABLE_USB_CAMERA"):
+        system_dependencies['libusb'] = 'libusb'
+        system_dependencies['libpng'] = 'libpng'
+    if minifi_options.is_enabled("ENABLE_GPS"):
+        system_dependencies['gpsd'] = 'gpsd'
+    if minifi_options.is_enabled("ENABLE_COAP"):
+        system_dependencies['automake'] = 'automake'
+        system_dependencies['autoconf'] = 'autoconf'
+        system_dependencies['libtool'] = 'libtool'
+    if minifi_options.is_enabled("ENABLE_LUA_SCRIPTING"):
+        system_dependencies['lua'] = 'lua'
+    if minifi_options.is_enabled("ENABLE_PYTHON_SCRIPTING"):
+        system_dependencies['python'] = 'python'
+    if minifi_options.is_enabled("MINIFI_OPENSSL"):
+        system_dependencies['openssl'] = 'perl'
+    if minifi_options.is_enabled("ENABLE_JNI"):
+        system_dependencies['jni'] = ''

Review Comment:
   This is missing.
   ```
   CMake Error at 
bootstrap/venv/lib/python3.10/site-packages/cmake/data/share/cmake-3.26/Modules/FindPackageHandleStandardArgs.cmake:230
 (message):
     Could NOT find JNI (missing: JAVA_INCLUDE_PATH JAVA_INCLUDE_PATH2 AWT)
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscr...@nifi.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to