Skip to content

Commit

Permalink
breaking change how (sub)project command initialization works
Browse files Browse the repository at this point in the history
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<Command> yourToolCommands = {
    ...
};

extern std::vector<Command> baseCommands;
void init() {
    registerCommands(&baseCommands);
    registerCommands(&yourToolCommands);
}
void (*initCommands)(void) = init;

instead of:
std::vector<Command> commands = {
    ...
}
  • Loading branch information
milot-mirdita committed Nov 19, 2023
1 parent 9b9383a commit 1c08685
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 97 deletions.
14 changes: 9 additions & 5 deletions cmake/MMseqsSetupDerivedTarget.cmake
Original file line number Diff line number Diff line change
@@ -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})
Expand Down
156 changes: 65 additions & 91 deletions src/commons/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,30 @@ extern const char *show_extended_help;
extern const char *show_bash_info;
extern bool hide_base_commands;

extern std::vector<Command> commands;
extern std::vector<Command> baseCommands;
extern std::vector<std::vector<Command>*> commands;
extern std::vector<Categories> 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";
Expand All @@ -57,21 +56,17 @@ void printUsage(bool showExtended) {

std::vector<int> 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;
}
}
}
}
Expand All @@ -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";
}
}
}
}
Expand All @@ -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 << " ";
Expand All @@ -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<MMseqsParameter *>::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<MMseqsParameter *>::const_iterator it = p.params->begin();
it != p.params->end(); ++it) {
for (std::vector<MMseqsParameter *>::const_iterator it = p.params->begin(); it != p.params->end(); ++it) {
Debug(Debug::INFO) << (*it)->name << " ";
}
Debug(Debug::INFO) << "\n";
Expand All @@ -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;
Expand All @@ -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) {
Expand All @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions src/commons/Command.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#include "Command.h"
#include "Parameters.h"

std::vector<std::vector<Command>*> commands;
void registerCommands(std::vector<Command>* cmd) {
commands.emplace_back(cmd);
}

std::vector<Categories> categories = {
{"Easy workflows for plain text input/output", COMMAND_EASY},
{"Main workflows for database input/output", COMMAND_MAIN},
Expand Down
2 changes: 2 additions & 0 deletions src/commons/Command.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,6 @@ struct Categories {
CommandMode mode;
};

void registerCommands(std::vector<Command>* cmd);

#endif
8 changes: 7 additions & 1 deletion src/mmseqs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Command> commands = {};

extern std::vector<Command> baseCommands;
void init() {
registerCommands(&baseCommands);
}
void (*initCommands)(void) = init;

std::vector<DatabaseDownload> externalDownloads = {};
std::vector<KmerThreshold> externalThreshold = {};

Expand Down

0 comments on commit 1c08685

Please sign in to comment.