From 1c086858ba029d970772c71c2ee77f47cb98dfae Mon Sep 17 00:00:00 2001 From: Milot Mirdita Date: Sun, 19 Nov 2023 19:22:49 +0900 Subject: [PATCH] breaking change how (sub)project command initialization works Subprojects have to now explicitly define an initCommands function that registers the projects commands with registerCommands. This allows for subprojects to exist on multiple levels, e.g. to make a sub-project of Foldseek. your_tool.cpp needs to include now something as follows: std::vector yourToolCommands = { ... }; extern std::vector baseCommands; void init() { registerCommands(&baseCommands); registerCommands(&yourToolCommands); } void (*initCommands)(void) = init; instead of: std::vector commands = { ... } --- cmake/MMseqsSetupDerivedTarget.cmake | 14 ++- src/commons/Application.cpp | 156 +++++++++++---------------- src/commons/Command.cpp | 5 + src/commons/Command.h | 2 + src/mmseqs.cpp | 8 +- 5 files changed, 88 insertions(+), 97 deletions(-) diff --git a/cmake/MMseqsSetupDerivedTarget.cmake b/cmake/MMseqsSetupDerivedTarget.cmake index a5a85fa90..f5248d8d8 100644 --- a/cmake/MMseqsSetupDerivedTarget.cmake +++ b/cmake/MMseqsSetupDerivedTarget.cmake @@ -1,12 +1,16 @@ include(AppendTargetProperty) function (mmseqs_setup_derived_target TARGET) - get_target_property(COMPILE_TMP mmseqs-framework COMPILE_FLAGS) - get_target_property(LINK_TMP mmseqs-framework LINK_FLAGS) - get_target_property(DEF_TMP mmseqs-framework COMPILE_DEFINITIONS) - get_target_property(INCL_TMP mmseqs-framework INCLUDE_DIRECTORIES) + set(SOURCE "${ARGN}") + if(NOT SOURCE) + set(SOURCE "mmseqs-framework") + endif() + get_target_property(COMPILE_TMP ${SOURCE} COMPILE_FLAGS) + get_target_property(LINK_TMP ${SOURCE} LINK_FLAGS) + get_target_property(DEF_TMP ${SOURCE} COMPILE_DEFINITIONS) + get_target_property(INCL_TMP ${SOURCE} INCLUDE_DIRECTORIES) - target_link_libraries(${TARGET} mmseqs-framework) + target_link_libraries(${TARGET} ${SOURCE}) append_target_property(${TARGET} COMPILE_FLAGS ${COMPILE_TMP}) append_target_property(${TARGET} LINK_FLAGS ${LINK_TMP}) set_property(TARGET ${TARGET} APPEND PROPERTY COMPILE_DEFINITIONS ${DEF_TMP}) diff --git a/src/commons/Application.cpp b/src/commons/Application.cpp index c99da844e..aa29c9c54 100644 --- a/src/commons/Application.cpp +++ b/src/commons/Application.cpp @@ -16,31 +16,30 @@ extern const char *show_extended_help; extern const char *show_bash_info; extern bool hide_base_commands; -extern std::vector commands; -extern std::vector baseCommands; +extern std::vector*> commands; extern std::vector categories; extern void (*validatorUpdate)(void); +extern void (*initCommands)(void); -Command *getCommandByName(const char *s) { - for (size_t i = 0; i < commands.size(); i++) { - Command &p = commands[i]; - if (!strcmp(s, p.cmd)) - return &p; - } - +const Command* getCommandByName(const char *s) { // allow base commands also to be called with a prefix, e.g. "mmseqs base:createdb" // this allows inheriting programs to find shadowed base modules const char *prefix = "base:"; const char *check = strncmp(s, prefix, strlen(prefix)) == 0 ? s + strlen(prefix) : s; - for (size_t i = 0; i < baseCommands.size(); i++) { - Command &p = baseCommands[i]; - if (!strcmp(check, p.cmd)) - return &p; + + for (size_t i = 0; i < commands.size(); i++) { + for (size_t j = 0; j < commands[i]->size(); j++) { + const Command &p = (*commands[i])[j]; + if (!strcmp(s, p.cmd)) + return &p; + if (i == 0 && !strcmp(check, p.cmd)) + return &p; + } } return NULL; } -int runCommand(Command *p, int argc, const char **argv) { +int runCommand(const Command *p, int argc, const char **argv) { Timer timer; int status = p->commandFunction(argc, argv, *p); Debug(Debug::INFO) << "Time for processing: " << timer.lap() << "\n"; @@ -57,21 +56,17 @@ void printUsage(bool showExtended) { std::vector showCategoryHeader(categories.size(), 0); for (size_t i = 0; i < categories.size(); ++i) { - for (size_t j = 0; j < commands.size(); j++) { - Command &p = commands[j]; - if (p.mode & categories[i].mode) { - showCategoryHeader[i] = 1; - break; - } - } + size_t start = 0; if (hide_base_commands) { - continue; - } - for (size_t j = 0; j < baseCommands.size(); j++) { - Command &p = baseCommands[j]; - if (p.mode & categories[i].mode) { - showCategoryHeader[i] = 1; - break; + start = commands.size() - 1; + } + for (size_t j = start; j < commands.size(); j++) { + for (size_t k = 0; k < commands[j]->size(); k++) { + const Command &p = (*commands[j])[k]; + if (p.mode & categories[i].mode) { + showCategoryHeader[i] = 1; + break; + } } } } @@ -93,24 +88,18 @@ void printUsage(bool showExtended) { usage << "\n" << std::setw(20) << categories[i].title << "\n"; for (size_t j = 0; j < commands.size(); j++) { - struct Command &p = commands[j]; - if (showExtended == false && (p.mode & COMMAND_EXPERT) != 0) { - continue; - } - if (p.mode & categories[i].mode) { - usage << std::left << std::setw(20) << " " + std::string(p.cmd) << "\t" << p.description << "\n"; + size_t start = 0; + if (hide_base_commands) { + start = commands.size() - 1; } - } - if (hide_base_commands) { - continue; - } - for (size_t j = 0; j < baseCommands.size(); j++) { - struct Command &p = baseCommands[j]; - if (showExtended == false && (p.mode & COMMAND_EXPERT) != 0) { - continue; - } - if (p.mode & categories[i].mode) { - usage << std::left << std::setw(20) << " " + std::string(p.cmd) << "\t" << p.description << "\n"; + for (size_t k = start; k < commands[j]->size(); k++) { + const Command &p = (*commands[j])[k]; + if (showExtended == false && (p.mode & COMMAND_EXPERT) != 0) { + continue; + } + if (p.mode & categories[i].mode) { + usage << std::left << std::setw(20) << " " + std::string(p.cmd) << "\t" << p.description << "\n"; + } } } } @@ -130,14 +119,12 @@ int shellcompletion(int argc, const char **argv) { // mmseqs programs if (argc == 0) { for (size_t i = 0; i < commands.size(); i++) { - struct Command &p = commands[i]; - if (p.mode & COMMAND_HIDDEN) - continue; - Debug(Debug::INFO) << p.cmd << " "; - } - if (hide_base_commands == false) { - for (size_t i = 0; i < baseCommands.size(); i++) { - struct Command &p = baseCommands[i]; + size_t start = 0; + if (hide_base_commands) { + start = commands.size() - 1; + } + for (size_t j = start; j < commands[i]->size(); j++) { + const Command &p = (*commands[i])[j]; if (p.mode & COMMAND_HIDDEN) continue; Debug(Debug::INFO) << p.cmd << " "; @@ -149,30 +136,19 @@ int shellcompletion(int argc, const char **argv) { // mmseqs parameters for given program if (argc == 1) { for (size_t i = 0; i < commands.size(); i++) { - struct Command &p = commands[i]; - if (strcmp(p.cmd, argv[0]) != 0) { - continue; - } - if (p.params == NULL) { - continue; + size_t start = 0; + if (hide_base_commands) { + start = commands.size() - 1; } - for (std::vector::const_iterator it = p.params->begin(); it != p.params->end(); ++it) { - Debug(Debug::INFO) << (*it)->name << " "; - } - Debug(Debug::INFO) << "\n"; - break; - } - if (hide_base_commands == false) { - for (size_t i = 0; i < baseCommands.size(); i++) { - struct Command &p = baseCommands[i]; + for (size_t j = start; j < commands[i]->size(); j++) { + const Command &p = (*commands[i])[j]; if (strcmp(p.cmd, argv[0]) != 0) { continue; } if (p.params == NULL) { continue; } - for (std::vector::const_iterator it = p.params->begin(); - it != p.params->end(); ++it) { + for (std::vector::const_iterator it = p.params->begin(); it != p.params->end(); ++it) { Debug(Debug::INFO) << (*it)->name << " "; } Debug(Debug::INFO) << "\n"; @@ -185,6 +161,10 @@ int shellcompletion(int argc, const char **argv) { } int main(int argc, const char **argv) { + if (initCommands != NULL) { + initCommands(); + } + if (argc < 2) { printUsage(false); return EXIT_SUCCESS; @@ -201,7 +181,7 @@ int main(int argc, const char **argv) { FileUtil::fixRlimitNoFile(); setenv("MMSEQS", argv[0], true); - Command *c = NULL; + const Command *c = NULL; if (strncmp(argv[1], "shellcompletion", strlen("shellcompletion")) == 0) { return shellcompletion(argc - 2, argv + 2); } else if ((c = getCommandByName(argv[1])) != NULL) { @@ -211,37 +191,31 @@ int main(int argc, const char **argv) { Debug(Debug::INFO) << "\nInvalid Command: " << argv[1] << "\n"; // Suggest some command that the user might have meant - size_t index = SIZE_MAX; + size_t indexI = SIZE_MAX; + size_t indexJ = SIZE_MAX; int maxDistance = 0; - for (size_t i = 0; i < commands.size(); ++i) { - struct Command &p = commands[i]; - if (p.mode & COMMAND_HIDDEN) { - continue; - } - - int distance = DistanceCalculator::localLevenshteinDistance(argv[1], p.cmd); - if (distance > maxDistance) { - maxDistance = distance; - index = i; + for (size_t i = 0; i < commands.size(); i++) { + size_t start = 0; + if (hide_base_commands) { + start = commands.size() - 1; } - } - - if (hide_base_commands == false) { - for (size_t i = 0; i < baseCommands.size(); ++i) { - struct Command &p = baseCommands[i]; - if (p.mode & COMMAND_HIDDEN) + for (size_t j = start; j < commands[i]->size(); j++) { + const Command &p = (*commands[i])[j]; + if (p.mode & COMMAND_HIDDEN) { continue; + } int distance = DistanceCalculator::localLevenshteinDistance(argv[1], p.cmd); if (distance > maxDistance) { maxDistance = distance; - index = i; + indexI = i; + indexJ = j; } } } - if (index != SIZE_MAX) { - Debug(Debug::WARNING) << "Did you mean \"" << argv[0] << " " << baseCommands[index].cmd << "\"?\n"; + if (indexI != SIZE_MAX && indexJ != SIZE_MAX) { + Debug(Debug::WARNING) << "Did you mean \"" << argv[0] << " " << (*commands[indexI])[indexJ].cmd << "\"?\n"; } return EXIT_FAILURE; diff --git a/src/commons/Command.cpp b/src/commons/Command.cpp index 677f46a03..ac6a8b14f 100644 --- a/src/commons/Command.cpp +++ b/src/commons/Command.cpp @@ -1,6 +1,11 @@ #include "Command.h" #include "Parameters.h" +std::vector*> commands; +void registerCommands(std::vector* cmd) { + commands.emplace_back(cmd); +} + std::vector categories = { {"Easy workflows for plain text input/output", COMMAND_EASY}, {"Main workflows for database input/output", COMMAND_MAIN}, diff --git a/src/commons/Command.h b/src/commons/Command.h index 5c5fd1ae4..308309e5a 100644 --- a/src/commons/Command.h +++ b/src/commons/Command.h @@ -108,4 +108,6 @@ struct Categories { CommandMode mode; }; +void registerCommands(std::vector* cmd); + #endif diff --git a/src/mmseqs.cpp b/src/mmseqs.cpp index cdbb3134e..f0a5be091 100644 --- a/src/mmseqs.cpp +++ b/src/mmseqs.cpp @@ -12,7 +12,13 @@ extern const char* MMSEQS_CURRENT_INDEX_VERSION; const char* index_version_compatible = MMSEQS_CURRENT_INDEX_VERSION; bool hide_base_commands = false; void (*validatorUpdate)(void) = 0; -std::vector commands = {}; + +extern std::vector baseCommands; +void init() { + registerCommands(&baseCommands); +} +void (*initCommands)(void) = init; + std::vector externalDownloads = {}; std::vector externalThreshold = {};