diff --git a/src/bin/pkgman/Command.cpp b/src/bin/pkgman/Command.cpp new file mode 100644 index 0000000000..31c4b48c8f --- /dev/null +++ b/src/bin/pkgman/Command.cpp @@ -0,0 +1,107 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + */ + + +#include "Command.h" + +#include + + +static int +compare_commands_by_name(const Command* a, const Command* b) +{ + return a->Name().Compare(b->Name()); +} + + +// #pragma mark - Command + + +Command::Command(const BString& name, const BString& shortUsage, + const BString& longUsage) + : + fName(name), + fShortUsage(shortUsage), + fLongUsage(longUsage) +{ + fShortUsage.ReplaceAll("%command%", fName); + fLongUsage.ReplaceAll("%command%", fName); +} + + +Command::~Command() +{ +} + + +void +Command::Init(const char* programName) +{ + fShortUsage.ReplaceAll("%program%", programName); + fLongUsage.ReplaceAll("%program%", programName); +} + + +void +Command::PrintUsage(bool error) const +{ + fprintf(error ? stderr : stdout, "%s", fLongUsage.String()); +} + + +void +Command::PrintUsageAndExit(bool error) const +{ + PrintUsage(error); + exit(error ? 1 : 0); +} + + +// #pragma mark - CommandManager + + +/*static*/ CommandManager* +CommandManager::Default() +{ + static CommandManager* manager = new CommandManager; + return manager; +} + + +void +CommandManager::RegisterCommand(Command* command) +{ + fCommands.AddItem(command); +} + + +void +CommandManager::InitCommands(const char* programName) +{ + for (int32 i = 0; Command* command = fCommands.ItemAt(i); i++) + command->Init(programName); + + fCommands.SortItems(&compare_commands_by_name); +} + + +void +CommandManager::GetCommands(const char* prefix, CommandList& _commands) +{ + for (int32 i = 0; Command* command = fCommands.ItemAt(i); i++) { + if (command->Name().StartsWith(prefix)) + _commands.AddItem(command); + } +} + + +CommandManager::CommandManager() + : + fCommands(20, true) +{ +} diff --git a/src/bin/pkgman/Command.h b/src/bin/pkgman/Command.h new file mode 100644 index 0000000000..4d9c6ccc23 --- /dev/null +++ b/src/bin/pkgman/Command.h @@ -0,0 +1,86 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + */ +#ifndef COMMAND_H +#define COMMAND_H + + +#include +#include + + +class Command { +public: + Command(const BString& name, + const BString& shortUsage, + const BString& longUsage); + virtual ~Command(); + + void Init(const char* programName); + + const BString& Name() const { return fName; } + const BString& ShortUsage() const { return fShortUsage; } + const BString& LongUsage() const { return fName; } + + void PrintUsage(bool error) const; + void PrintUsageAndExit(bool error) const; + + virtual int Execute(int argc, const char* const* argv) = 0; + +private: + BString fName; + BString fShortUsage; + BString fLongUsage; +}; + + +typedef BObjectList CommandList; + + +class CommandManager { +public: + static CommandManager* Default(); + + void RegisterCommand(Command* command); + void InitCommands(const char* programName); + + const CommandList& Commands() const + { return fCommands; } + void GetCommands(const char* prefix, + CommandList& _commands); + +private: + CommandManager(); + +private: + CommandList fCommands; +}; + + +template +struct CommandRegistrar { + CommandRegistrar() + { + CommandManager::Default()->RegisterCommand(new CommandType); + } +}; + + +#define DEFINE_COMMAND(className, name, shortUsage, longUsage) \ + struct className : Command { \ + className() \ + : \ + Command(name, shortUsage, longUsage) \ + { \ + } \ + \ + virtual int Execute(int argc, const char* const* argv); \ + }; \ + static CommandRegistrar sRegister##className; + + +#endif // COMMAND_H diff --git a/src/bin/pkgman/Jamfile b/src/bin/pkgman/Jamfile index de9b873e36..c985ecfa51 100644 --- a/src/bin/pkgman/Jamfile +++ b/src/bin/pkgman/Jamfile @@ -3,6 +3,7 @@ SubDir HAIKU_TOP src bin pkgman ; UsePrivateHeaders shared support ; BinCommand pkgman : + Command.cpp command_add_repo.cpp command_drop_repo.cpp command_list_repos.cpp diff --git a/src/bin/pkgman/command_add_repo.cpp b/src/bin/pkgman/command_add_repo.cpp index ba34b524c2..b63583bf9e 100644 --- a/src/bin/pkgman/command_add_repo.cpp +++ b/src/bin/pkgman/command_add_repo.cpp @@ -16,6 +16,7 @@ #include #include +#include "Command.h" #include "DecisionProvider.h" #include "JobStateListener.h" #include "pkgman.h" @@ -27,23 +28,21 @@ using namespace BPackageKit; // TODO: internationalization! -static const char* kCommandUsage = - "Usage: %s add-repo [ ...]\n" +static const char* const kShortUsage = + " %command% \n" + " Adds the repository with the given .\n"; + +static const char* const kLongUsage = + "Usage: %program% %command% [ ...]\n" "Adds one or more repositories by downloading them from the given URL(s).\n" - "\n" -; + "\n"; -static void -print_command_usage_and_exit(bool error) -{ - fprintf(error ? stderr : stdout, kCommandUsage, kProgramName); - exit(error ? 1 : 0); -} +DEFINE_COMMAND(AddRepoCommand, "add-repo", kShortUsage, kLongUsage) int -command_add_repo(int argc, const char* const* argv) +AddRepoCommand::Execute(int argc, const char* const* argv) { bool asUserRepository = false; @@ -61,7 +60,7 @@ command_add_repo(int argc, const char* const* argv) switch (c) { case 'h': - print_command_usage_and_exit(false); + PrintUsageAndExit(false); break; case 'u': @@ -69,14 +68,14 @@ command_add_repo(int argc, const char* const* argv) break; default: - print_command_usage_and_exit(true); + PrintUsageAndExit(true); break; } } // The remaining arguments are repo URLs, i. e. at least one more argument. if (argc < optind + 1) - print_command_usage_and_exit(true); + PrintUsageAndExit(true); const char* const* repoURLs = argv + optind; int urlCount = argc - optind; diff --git a/src/bin/pkgman/command_drop_repo.cpp b/src/bin/pkgman/command_drop_repo.cpp index fecdd87e9a..e026757b8c 100644 --- a/src/bin/pkgman/command_drop_repo.cpp +++ b/src/bin/pkgman/command_drop_repo.cpp @@ -14,6 +14,7 @@ #include #include +#include "Command.h" #include "DecisionProvider.h" #include "JobStateListener.h" #include "pkgman.h" @@ -25,23 +26,21 @@ using namespace BPackageKit; // TODO: internationalization! -static const char* kCommandUsage = - "Usage: %s drop-repo \n" +static const char* const kShortUsage = + " %command% \n" + " Drops the repository with the given .\n"; + +static const char* const kLongUsage = + "Usage: %program% %command% \n" "Drops (i.e. removes) the repository with the given name.\n" - "\n" -; + "\n"; -static void -print_command_usage_and_exit(bool error) -{ - fprintf(error ? stderr : stdout, kCommandUsage, kProgramName); - exit(error ? 1 : 0); -} +DEFINE_COMMAND(DropRepoCommand, "drop-repo", kShortUsage, kLongUsage) int -command_drop_repo(int argc, const char* const* argv) +DropRepoCommand::Execute(int argc, const char* const* argv) { bool yesMode = false; @@ -59,7 +58,7 @@ command_drop_repo(int argc, const char* const* argv) switch (c) { case 'h': - print_command_usage_and_exit(false); + PrintUsageAndExit(false); break; case 'y': @@ -67,14 +66,14 @@ command_drop_repo(int argc, const char* const* argv) break; default: - print_command_usage_and_exit(true); + PrintUsageAndExit(true); break; } } // The remaining argument is a repo name, i. e. one more argument. if (argc != optind + 1) - print_command_usage_and_exit(true); + PrintUsageAndExit(true); const char* repoName = argv[optind]; diff --git a/src/bin/pkgman/command_list_repos.cpp b/src/bin/pkgman/command_list_repos.cpp index 244404dca2..e0465121ac 100644 --- a/src/bin/pkgman/command_list_repos.cpp +++ b/src/bin/pkgman/command_list_repos.cpp @@ -21,6 +21,7 @@ #include #include +#include "Command.h" #include "pkgman.h" @@ -30,24 +31,22 @@ using namespace BPackageKit; -static const char* kCommandUsage = +static const char* const kShortUsage = + " %command%\n" + " Lists all repositories.\n"; + +static const char* const kLongUsage = "Usage:\n" - " %s list-repos [options]\n" + " %program% %command% [options]\n" "Lists all configured package repositories.\n" - "\n" -; + "\n"; -static void -print_command_usage_and_exit(bool error) -{ - fprintf(error ? stderr : stdout, kCommandUsage, kProgramName); - exit(error ? 1 : 0); -} +DEFINE_COMMAND(ListReposCommand, "list-repos", kShortUsage, kLongUsage) int -command_list_repos(int argc, const char* const* argv) +ListReposCommand::Execute(int argc, const char* const* argv) { bool verbose = false; @@ -65,7 +64,7 @@ command_list_repos(int argc, const char* const* argv) switch (c) { case 'h': - print_command_usage_and_exit(false); + PrintUsageAndExit(false); break; case 'v': @@ -73,14 +72,14 @@ command_list_repos(int argc, const char* const* argv) break; default: - print_command_usage_and_exit(true); + PrintUsageAndExit(true); break; } } // No remaining arguments. if (argc != optind) - print_command_usage_and_exit(true); + PrintUsageAndExit(true); BStringList repositoryNames(20); BPackageRoster roster; diff --git a/src/bin/pkgman/command_refresh.cpp b/src/bin/pkgman/command_refresh.cpp index 176f5d2878..50764c99c6 100644 --- a/src/bin/pkgman/command_refresh.cpp +++ b/src/bin/pkgman/command_refresh.cpp @@ -15,6 +15,7 @@ #include #include +#include "Command.h" #include "DecisionProvider.h" #include "JobStateListener.h" #include "pkgman.h" @@ -26,23 +27,22 @@ using namespace BPackageKit; // TODO: internationalization! -static const char* kCommandUsage = - "Usage: %s refresh [ ...]\n" +static const char* const kShortUsage = + " %command% [ ...]\n" + " Refreshes all or just the given repositories.\n"; + +static const char* const kLongUsage = + "Usage: %program% %command% [ ...]\n" "Refreshes all or just the given repositories.\n" - "\n" -; + "\n"; -static void -print_command_usage_and_exit(bool error) -{ - fprintf(error ? stderr : stdout, kCommandUsage, kProgramName); - exit(error ? 1 : 0); -} +DEFINE_COMMAND(RefreshCommand, "refresh", kShortUsage, kLongUsage) + int -command_refresh(int argc, const char* const* argv) +RefreshCommand::Execute(int argc, const char* const* argv) { while (true) { static struct option sLongOptions[] = { @@ -57,11 +57,11 @@ command_refresh(int argc, const char* const* argv) switch (c) { case 'h': - print_command_usage_and_exit(false); + PrintUsageAndExit(false); break; default: - print_command_usage_and_exit(true); + PrintUsageAndExit(true); break; } } diff --git a/src/bin/pkgman/command_resolve_dependencies.cpp b/src/bin/pkgman/command_resolve_dependencies.cpp index e585f6dea4..73882332d3 100644 --- a/src/bin/pkgman/command_resolve_dependencies.cpp +++ b/src/bin/pkgman/command_resolve_dependencies.cpp @@ -20,6 +20,7 @@ #include +#include "Command.h" #include "pkgman.h" #include "RepositoryBuilder.h" @@ -30,8 +31,12 @@ using namespace BPackageKit; -static const char* kCommandUsage = - "Usage: %s resolve-dependencies [ ] ...\n" +static const char* const kShortUsage = + " %command% [ ] ...\n" + " Resolves all packages a given package depends on.\n"; + +static const char* const kLongUsage = + "Usage: %program% %command% [ ] ...\n" "Resolves and lists all packages a given package depends on. Fails, if\n" "not all dependencies could be resolved.\n" "\n" @@ -46,16 +51,11 @@ static const char* kCommandUsage = " \n" " Can follow a to specify the priority of that\n" " repository. The default priority is 0.\n" - "\n" -; + "\n"; -static void -print_command_usage_and_exit(bool error) -{ - fprintf(error ? stderr : stdout, kCommandUsage, kProgramName); - exit(error ? 1 : 0); -} +DEFINE_COMMAND(ResolveDependenciesCommand, "resolve-dependencies", kShortUsage, + kLongUsage) static void @@ -107,7 +107,7 @@ verify_result(const BSolverResult& result, BSolverPackage* specifiedPackage) int -command_resolve_dependencies(int argc, const char* const* argv) +ResolveDependenciesCommand::Execute(int argc, const char* const* argv) { while (true) { static struct option sLongOptions[] = { @@ -122,11 +122,11 @@ command_resolve_dependencies(int argc, const char* const* argv) switch (c) { case 'h': - print_command_usage_and_exit(false); + PrintUsageAndExit(false); break; default: - print_command_usage_and_exit(true); + PrintUsageAndExit(true); break; } } @@ -134,7 +134,7 @@ command_resolve_dependencies(int argc, const char* const* argv) // The remaining arguments are the package (info) file and the repository // directories (at least one), optionally with priorities. if (argc < optind + 2) - print_command_usage_and_exit(true); + PrintUsageAndExit(true); const char* packagePath = argv[optind++]; int repositoryDirectoryCount = argc - optind; diff --git a/src/bin/pkgman/command_search.cpp b/src/bin/pkgman/command_search.cpp index 41334e26ac..f65db3eefc 100644 --- a/src/bin/pkgman/command_search.cpp +++ b/src/bin/pkgman/command_search.cpp @@ -19,6 +19,7 @@ #include +#include "Command.h" #include "pkgman.h" #include "RepositoryBuilder.h" @@ -34,8 +35,12 @@ using namespace BPackageKit; typedef std::map PackagePathMap; -static const char* kCommandUsage = - "Usage: %s search \n" +static const char* const kShortUsage = + " %command% \n" + " Searches for packages matching .\n"; + +static const char* const kLongUsage = + "Usage: %program% %command% \n" "Searches for packages matching .\n" "\n" "Options:\n" @@ -43,16 +48,10 @@ static const char* kCommandUsage = " Only find installed packages.\n" " -u, --uninstalled-only\n" " Only find not installed packages.\n" - "\n" -; + "\n"; -static void -print_command_usage_and_exit(bool error) -{ - fprintf(error ? stderr : stdout, kCommandUsage, kProgramName); - exit(error ? 1 : 0); -} +DEFINE_COMMAND(SearchCommand, "search", kShortUsage, kLongUsage) static int @@ -68,7 +67,7 @@ get_terminal_width() int -command_search(int argc, const char* const* argv) +SearchCommand::Execute(int argc, const char* const* argv) { bool installedOnly = false; bool uninstalledOnly = false; @@ -88,7 +87,7 @@ command_search(int argc, const char* const* argv) switch (c) { case 'h': - print_command_usage_and_exit(false); + PrintUsageAndExit(false); break; case 'i': @@ -102,14 +101,14 @@ command_search(int argc, const char* const* argv) break; default: - print_command_usage_and_exit(true); + PrintUsageAndExit(true); break; } } // The remaining argument is the search string. if (argc != optind + 1) - print_command_usage_and_exit(true); + PrintUsageAndExit(true); const char* searchString = argv[optind++]; diff --git a/src/bin/pkgman/pkgman.cpp b/src/bin/pkgman/pkgman.cpp index 66117001fa..eddf6fbbf3 100644 --- a/src/bin/pkgman/pkgman.cpp +++ b/src/bin/pkgman/pkgman.cpp @@ -11,34 +11,19 @@ #include #include +#include "Command.h" + extern const char* __progname; const char* kProgramName = __progname; -static const char* kUsage = +static const char* const kUsage = "Usage: %s \n" - "Creates, inspects, or extracts a Haiku package.\n" + "Manages packages and package repository.\n" "\n" "Commands:\n" - " add-repo \n" - " Adds the repository with the given .\n" - "\n" - " drop-repo \n" - " Drops the repository with the given .\n" - "\n" - " list-repos\n" - " Lists all repositories.\n" - "\n" - " refresh [ ...]\n" - " Refreshes all or just the given repositories.\n" - "\n" - " resolve-dependencies [ ] ...\n" - " Resolves all packages a given package depends on.\n" - "\n" - " search \n" - " Searches for packages matching .\n" - "\n" + "%s" "Common Options:\n" " -h, --help - Print this usage info.\n" ; @@ -47,7 +32,14 @@ static const char* kUsage = void print_usage_and_exit(bool error) { - fprintf(error ? stderr : stdout, kUsage, kProgramName); + BString commandsUsage; + const CommandList& commands = CommandManager::Default()->Commands(); + for (int32 i = 0; Command* command = commands.ItemAt(i); i++) + commandsUsage << command->ShortUsage() << '\n'; + + fprintf(error ? stderr : stdout, kUsage, kProgramName, + commandsUsage.String()); + exit(error ? 1 : 0); } @@ -55,33 +47,19 @@ print_usage_and_exit(bool error) int main(int argc, const char* const* argv) { + CommandManager::Default()->InitCommands(kProgramName); + if (argc < 2) print_usage_and_exit(true); const char* command = argv[1]; - if (strncmp(command, "add-r", 5) == 0) - return command_add_repo(argc - 1, argv + 1); - - if (strncmp(command, "drop-r", 6) == 0) - return command_drop_repo(argc - 1, argv + 1); - - if (strncmp(command, "list-r", 6) == 0) - return command_list_repos(argc - 1, argv + 1); - - if (strncmp(command, "refr", 4) == 0) - return command_refresh(argc - 1, argv + 1); - - if (strcmp(command, "resolve-dependencies") == 0) - return command_resolve_dependencies(argc - 1, argv + 1); - - if (strcmp(command, "search") == 0) - return command_search(argc - 1, argv + 1); - if (strcmp(command, "help") == 0) print_usage_and_exit(false); - else + + CommandList commands; + CommandManager::Default()->GetCommands(command, commands); + if (commands.CountItems() != 1) print_usage_and_exit(true); - // never gets here - return 0; + return commands.ItemAt(0)->Execute(argc - 1, argv + 1); } diff --git a/src/bin/pkgman/pkgman.h b/src/bin/pkgman/pkgman.h index c2a2fe9d6e..eb308853c0 100644 --- a/src/bin/pkgman/pkgman.h +++ b/src/bin/pkgman/pkgman.h @@ -34,12 +34,6 @@ do { \ void print_usage_and_exit(bool error); -int command_add_repo(int argc, const char* const* argv); -int command_drop_repo(int argc, const char* const* argv); -int command_list_repos(int argc, const char* const* argv); -int command_refresh(int argc, const char* const* argv); -int command_resolve_dependencies(int argc, const char* const* argv); -int command_search(int argc, const char* const* argv); #endif // PKGMAN_H