diff --git a/.github/workflows/linux_test.yml b/.github/workflows/linux_test.yml index 9d09ff7e..f08518c9 100644 --- a/.github/workflows/linux_test.yml +++ b/.github/workflows/linux_test.yml @@ -42,12 +42,11 @@ jobs: - name: Set up dependencies run: | - bash ./setup_dependencies_apt.sh + bash ./resources/scripts/setup_dependencies_apt.sh - name: Install latest clang if: matrix.cc == 'clang' run: | - bash ./setup_dependencies_apt.sh wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh sudo ./llvm.sh 18 diff --git a/CMakeLists.txt b/CMakeLists.txt index 88f766e4..7cc50b93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,9 +135,6 @@ endif() ################ TgBot lib + Boost creates a warning ################ add_definitions(-DBOOST_BIND_GLOBAL_PLACEHOLDERS) -if(ENFORCE_EN_US) - add_definitions(-DLOCALE_EN_US) -endif() ##################################################################### ######################## Include directories ######################## @@ -194,43 +191,39 @@ set(SRC_LIST ) ##################################################################### -######### Commands modules (The commands handler of the bot) ######### -################ Commands module in a single file list ################ -set(CMD_MODULES_SINGLE_LIST alive flash possibility decide delay decho - randsticker fileid clone spam cmd) -if (NOT WIN32) - set(CMD_MODULES_SINGLE_LIST ${CMD_MODULES_SINGLE_LIST} ibash restart) -endif() -extend_set_if(ENABLE_RUNTIME_COMMAND CMD_MODULES_SINGLE_LIST rtload) -######################## Commands sources list ######################## -set(CMD_MODULES_SOURCES_LIST compilers_impl database_impl bash_impl timer_impl - ${CMD_MODULES_SINGLE_LIST}) -######################## Commands modules list ######################## -set(CMD_MODULES_LIST database bash ubash ${CMD_MODULES_SINGLE_LIST} - starttimer stoptimer saveid start c cpp go python) -####################### Commands modules defines ####################### -set(COMMANDS_CWD src/command_modules) -set(COMMANDS_GEN_FILE ${COMMANDS_CWD}/gen/cmds.gen.cpp) -########## Generate commands modules list in compile time (cpp) ########## -macro(append_cmdlib lib) - string(APPEND COMMANDS_MODULES_DECL "extern void loadcmd_${lib}(CommandModule &cmd);\n") - string(APPEND COMMANDS_MODULES_PTR "&loadcmd_${lib}") -endmacro() - -list(GET CMD_MODULES_LIST 0 COMMANDS_MODULES_FIRST_ELEM) -append_cmdlib(${COMMANDS_MODULES_FIRST_ELEM}) -foreach(lib ${CMD_MODULES_LIST}) - if (${lib} STREQUAL ${COMMANDS_MODULES_FIRST_ELEM}) - continue() - endif() - string(APPEND COMMANDS_MODULES_PTR ",\n") - append_cmdlib(${lib}) -endforeach() +########## Generate commands modules list in compile time (python) ########## +find_package (Python3 COMPONENTS Interpreter REQUIRED) +set(GENERATE_CMDMODULE_STRINGS ${CMAKE_SOURCE_DIR}/resources/scripts/command_modules_helper.py) +execute_process( + COMMAND ${Python3_EXECUTABLE} ${GENERATE_CMDMODULE_STRINGS} get_cmd_filenames ${CMAKE_SOURCE_DIR}/resources/commands_list.txt + OUTPUT_VARIABLE CMD_MODULES_SOURCES_LIST + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${Python3_EXECUTABLE} ${GENERATE_CMDMODULE_STRINGS} get_cmd_names ${CMAKE_SOURCE_DIR}/resources/commands_list.txt + OUTPUT_VARIABLE CMD_MODULES_LIST + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${Python3_EXECUTABLE} ${GENERATE_CMDMODULE_STRINGS} gen_ptr ${CMD_MODULES_LIST} + OUTPUT_VARIABLE COMMANDS_MODULES_PTR + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY +) +execute_process( + COMMAND ${Python3_EXECUTABLE} ${GENERATE_CMDMODULE_STRINGS} gen_decl ${CMD_MODULES_LIST} + OUTPUT_VARIABLE COMMANDS_MODULES_DECL + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY +) ########## Generate commands modules list in compile time (cpp) ########## foreach(lib ${CMD_MODULES_SOURCES_LIST}) - extend_set(SRC_LIST ${COMMANDS_CWD}/${lib}.cpp) + extend_set(SRC_LIST src/command_modules/${lib}.cpp) endforeach() -#################### Include to TgBotCommandModules ################# +#################### Include to TgBot++ ################# +set(COMMANDS_GEN_FILE src/command_modules/gen/cmds.gen.cpp) configure_file(${COMMANDS_GEN_FILE}.in ${CMAKE_BINARY_DIR}/${COMMANDS_GEN_FILE}) extend_set(SRC_LIST ${CMAKE_BINARY_DIR}/${COMMANDS_GEN_FILE}) ##################################################################### diff --git a/resources/.loadignore b/resources/.loadignore index dfda0489..1570a1f7 100644 --- a/resources/.loadignore +++ b/resources/.loadignore @@ -1 +1,2 @@ -about.html.in \ No newline at end of file +about.html.in +commands_list.txt \ No newline at end of file diff --git a/resources/commands_list.txt b/resources/commands_list.txt new file mode 100644 index 00000000..8cc8c9c2 --- /dev/null +++ b/resources/commands_list.txt @@ -0,0 +1,27 @@ +# Used by command_modules_helper.py +# Syntax: commandname ([!win32]) ([infile ]) + +alive +flash +possibility +decide +delay +decho +randsticker +fileid +clone +spam +cmd +ibash [!win32] +restart [!win32] +bash [infile bash_impl] +ubash [infile bash_impl] +starttimer [infile timer_impl] +stoptimer [infile timer_impl] +database [infile database_impl] +saveid [infile database_impl] +start [infile alive] +c [infile compilers_impl] +cpp [infile compilers_impl] +go [infile compilers_impl] +python [infile compilers_impl] \ No newline at end of file diff --git a/resources/scripts/command_modules_helper.py b/resources/scripts/command_modules_helper.py new file mode 100644 index 00000000..bb503fd9 --- /dev/null +++ b/resources/scripts/command_modules_helper.py @@ -0,0 +1,79 @@ +import sys + +""" +Just a utility script to support dynamic list of commands compiled into. +""" + +if len(sys.argv) < 3: + print('Usage: %s gen_decl|gen_ptr|get_cmd_filenames|get_cmd_commands args...' % sys.argv[0], file=sys.stderr) + sys.exit(1) + +command = sys.argv[1] +libs = sys.argv[2:] + +def parse_command_list(file): + filenames = [] + commands = [] + with open(file, 'r') as f: + for line in f.readlines(): + if line.startswith('#'): + continue + if line.strip() == '': + continue + if len(line.split('[')) > 2 or len(line.split(']')) > 2: + print('Invalid line "%s", Two options in one line:' % line, file=sys.stderr) + continue + command = line.split('[')[0].strip() + if command in commands: + print('Duplicate command: %s' % command, file=sys.stderr) + continue + commands.append(command) + if '[' and ']' in line: + opt = line.split('[')[1].split(']')[0].strip() + # Parse options + if opt.startswith('!'): + # NOT platform declaration + match line[1:]: + case 'win32': + if sys.platform in ['win32', 'cygwin', 'msys']: + print('Ignore command: %s (Not Win32)' % command) + # TODO: Add more platforms + elif opt.startswith('infile'): + if opt.find(' ') == -1: + print('Invalid option: %s' % opt, file=sys.stderr) + continue + str = opt.split(' ')[1] + if str not in filenames: + filenames.append(str) + continue + else: + print('Invalid option: %s' % opt, file=sys.stderr) + continue + filenames.append(command) + return filenames, commands + +if command == 'gen_decl': + """ Generate command module loader functions' forward declarations. """ + decls = '' + for lib in libs: + decls += f"extern void loadcmd_{lib}(CommandModule &cmd);\n" + print(decls) +elif command == 'gen_ptr': + """ Generate command module loader functions' pointers. """ + ptrs = '' + for lib in libs: + ptrs += ' ' * 8 + f"&loadcmd_{lib},\n" + print(ptrs) +elif command == 'get_cmd_filenames': + """ Get list of command module filenames. """ + filenames, _ = parse_command_list(sys.argv[2]) + for filename in filenames: + print(filename, end=';') +elif command == 'get_cmd_names': + """ Get list of command module name lists. """ + _, commands = parse_command_list(sys.argv[2]) + for command in commands: + print(command, end=';') +else: + print(f"Unknown command: {command}", file=sys.stderr) + sys.exit(1) \ No newline at end of file diff --git a/setup_dependencies_apt.sh b/resources/scripts/setup_dependencies_apt.sh similarity index 100% rename from setup_dependencies_apt.sh rename to resources/scripts/setup_dependencies_apt.sh diff --git a/src/command_modules/gen/cmds.gen.cpp.in b/src/command_modules/gen/cmds.gen.cpp.in index 71561127..33044ea9 100644 --- a/src/command_modules/gen/cmds.gen.cpp.in +++ b/src/command_modules/gen/cmds.gen.cpp.in @@ -5,7 +5,7 @@ void CommandModuleManager::loadCommandModules(Bot &bot) { std::vector cmdModuleFunctions = { - @COMMANDS_MODULES_PTR@ +@COMMANDS_MODULES_PTR@ }; for (const auto &fn : cmdModuleFunctions) { CommandModule module; diff --git a/src/command_modules/rtload.cpp b/src/command_modules/rtload.cpp deleted file mode 100644 index bb440739..00000000 --- a/src/command_modules/rtload.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include - -#include -#include -#include -#include - -#include "CommandModule.h" -#include "RTCommandLoader.h" -#include "command_modules/compiler/CompilerInTelegram.h" - -void RTLoadCommandFn(Bot& bot, const Message::Ptr message) { - static int count = 0; - std::string compiler; - if (!findCompiler(ProgrammingLangs::CXX, compiler)) { - bot_sendReplyMessage(bot, message, "No CXX compiler found!"); - return; - } - auto p = FS::getPathForType(FS::PathType::MODULES_INSTALLED) / - ("libdlload_" + std::to_string(count)); - auto libcmdmod = - FS::getPathForType(FS::PathType::BUILD_ROOT) / "libTgBotCommandModules"; - auto libtg = FS::getPathForType(FS::PathType::BUILD_ROOT) / "libTgBot"; - FS::appendDylibExtension(p); - compiler += " -o " + p.string() + - " {libcmdmod} {libtg} -I{src}/src/include " - "-I{src}/lib/include -I{src}/src" - " -include {src}/src/command_modules/runtime/cmd_dynamic.h " - "-std=c++20 -shared"; - boost::replace_all(compiler, "{src}", - FS::getPathForType(FS::PathType::GIT_ROOT).string()); - boost::replace_all(compiler, "{libcmdmod}", - FS::appendDylibExtension(libcmdmod).string()); - boost::replace_all(compiler, "{libtg}", - FS::appendDylibExtension(libtg).string()); - CompilerInTgForCCppImpl impl(bot, compiler, "dltmp.cc"); - std::filesystem::remove(p); - impl.run(message); - if (FS::exists(p)) { - if (RTCommandLoader::getInstance().loadOneCommand(p)) { - bot_sendReplyMessage(bot, message, "Command loaded!"); - count++; - } else { - bot_sendReplyMessage(bot, message, "Failed to load command!"); - } - } -} - -void loadcmd_rtload(CommandModule& module) { - module.command = "rtload"; - module.description = "Runtime load command"; - module.flags = CommandModule::Flags::None; - module.fn = RTLoadCommandFn; -} \ No newline at end of file