aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-06-30 16:59:10 +0100
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-06-30 16:59:10 +0100
commit8c5c387788f9eff1578a5fd554e5d27ee050b328 (patch)
treedc0b2701ccdc4520a855d0136e4964eee396e11a
parentf0ad5da7527e13ae2f9d64b04c43973c80acb2f1 (diff)
downloadpaludis-8c5c387788f9eff1578a5fd554e5d27ee050b328.tar.gz
paludis-8c5c387788f9eff1578a5fd554e5d27ee050b328.tar.xz
cave aliases / scripts
Fixes: ticket:901
-rw-r--r--misc/common-makefile.am1
-rw-r--r--src/clients/cave/Makefile.am11
-rw-r--r--src/clients/cave/command_factory.cc43
-rw-r--r--src/clients/cave/command_line.cc9
-rw-r--r--src/clients/cave/script_command.cc84
-rw-r--r--src/clients/cave/script_command.hh49
6 files changed, 194 insertions, 3 deletions
diff --git a/misc/common-makefile.am b/misc/common-makefile.am
index e10e805..91881b4 100644
--- a/misc/common-makefile.am
+++ b/misc/common-makefile.am
@@ -11,6 +11,7 @@ LOG_COMPILER = \
ACCERSO_OPTIONS="" \
ADJUTRIX_OPTIONS="" \
APPAREO_OPTIONS="" \
+ CAVE_COMMANDS_PATH="" \
CAVE_OPTIONS="" \
CAVE_CONFIG_OPTIONS="" \
CAVE_CONTENTS_OPTIONS="" \
diff --git a/src/clients/cave/Makefile.am b/src/clients/cave/Makefile.am
index 0b7189e..746c31c 100644
--- a/src/clients/cave/Makefile.am
+++ b/src/clients/cave/Makefile.am
@@ -61,7 +61,7 @@ cave.1 : man-cave
./man-cave > $@
$(command_MANS) : man-cave
- if ! ./man-cave `echo $@ | sed -e 's.^cave-..' -e 's,\.1$$,,'` > $@ ; then rm -f $@ ; exit 1 ; fi
+ if ! env CAVE_COMMANDS_PATH="" ./man-cave `echo $@ | sed -e 's.^cave-..' -e 's,\.1$$,,'` > $@ ; then rm -f $@ ; exit 1 ; fi
cave_SOURCES = \
cave.cc
@@ -140,6 +140,7 @@ libcave_a_SOURCES = \
format_plain_metadata_key.cc format_plain_metadata_key.hh \
format_string.cc format_string.hh \
formats.cc formats.hh \
+ script_command.cc script_command.hh \
select_format_for_spec.cc select_format_for_spec.hh \
match_qpns.cc match_qpns.hh \
owner_common.cc owner_common.hh \
@@ -165,6 +166,8 @@ EXTRA_DIST = \
DISTCLEANFILES = $(man_MANS) $(noinst_DATA)
+CLEANFILES += .keep
+
lib_LTLIBRARIES = libcavematchextras_@PALUDIS_PC_SLOT@.la
libcavematchextras_@PALUDIS_PC_SLOT@_la_SOURCES = match_extras.cc match_extras.hh
@@ -172,3 +175,9 @@ libcavematchextras_@PALUDIS_PC_SLOT@_la_CXXFLAGS = $(AM_CXXFLAGS) @PCRECPPDEPS_C
libcavematchextras_@PALUDIS_PC_SLOT@_la_LIBADD = @PCRECPPDEPS_LIBS@
libcavematchextras_@PALUDIS_PC_SLOT@_la_LDFLAGS = -version-info @VERSION_LIB_CURRENT@:@VERSION_LIB_REVISION@:0
+cavecommandsdir = $(libexecdir)/cave/commands
+cavecommands_DATA = .keep
+
+.keep :
+ touch $@
+
diff --git a/src/clients/cave/command_factory.cc b/src/clients/cave/command_factory.cc
index 1a06c3a..2acb1ab 100644
--- a/src/clients/cave/command_factory.cc
+++ b/src/clients/cave/command_factory.cc
@@ -18,12 +18,20 @@
*/
#include "command_factory.hh"
+#include "script_command.hh"
+
#include <paludis/util/instantiation_policy-impl.hh>
#include <paludis/util/private_implementation_pattern-impl.hh>
#include <paludis/util/make_shared_ptr.hh>
#include <paludis/util/wrapped_forward_iterator-impl.hh>
#include <paludis/util/member_iterator-impl.hh>
+#include <paludis/util/tokeniser.hh>
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/options.hh>
+#include <paludis/util/system.hh>
#include <tr1/functional>
+#include <vector>
#include <map>
#include "cmd_config.hh"
@@ -65,7 +73,7 @@
using namespace paludis;
using namespace cave;
-typedef std::map<std::string, std::tr1::function<const std::tr1::shared_ptr<Command> ()> > Handlers;
+typedef std::map<std::string, std::tr1::function<const std::tr1::shared_ptr<cave::Command> ()> > Handlers;
namespace paludis
{
@@ -89,11 +97,42 @@ namespace
{
return make_shared_ptr(new T_);
}
+
+ const std::tr1::shared_ptr<ScriptCommand> make_script_command(const std::string & s, const FSEntry & f)
+ {
+ return make_shared_ptr(new ScriptCommand(s, f));
+ }
}
CommandFactory::CommandFactory() :
PrivateImplementationPattern<CommandFactory>(new Implementation<CommandFactory>)
{
+ std::vector<std::string> paths;
+ tokenise<delim_kind::AnyOfTag, delim_mode::DelimiterTag>(getenv_with_default("CAVE_COMMANDS_PATH", LIBEXECDIR "/cave/commands"),
+ ":", "", std::back_inserter(paths));
+ for (std::vector<std::string>::const_iterator t(paths.begin()), t_end(paths.end()) ;
+ t != t_end ; ++t)
+ {
+ FSEntry path(*t);
+ if (! path.exists())
+ continue;
+
+ for (DirIterator s(path, DirIteratorOptions() + dio_inode_sort), s_end ;
+ s != s_end ; ++s)
+ {
+ if (s->is_regular_file_or_symlink_to_regular_file() && s->has_permission(fs_ug_others, fs_perm_execute))
+ {
+ std::string command_name(s->basename());
+ std::string::size_type p(command_name.rfind('.'));
+ if (std::string::npos != p)
+ command_name.erase(p);
+
+ _imp->handlers.erase(command_name);
+ _imp->handlers.insert(std::make_pair(command_name, std::tr1::bind(&make_script_command, command_name, *s)));
+ }
+ }
+ }
+
_imp->handlers.insert(std::make_pair("config", std::tr1::bind(&make_command<ConfigCommand>)));
_imp->handlers.insert(std::make_pair("contents", std::tr1::bind(&make_command<ContentsCommand>)));
_imp->handlers.insert(std::make_pair("display-resolution", std::tr1::bind(&make_command<DisplayResolutionCommand>)));
@@ -135,7 +174,7 @@ CommandFactory::~CommandFactory()
{
}
-const std::tr1::shared_ptr<Command>
+const std::tr1::shared_ptr<cave::Command>
CommandFactory::create(const std::string & s) const
{
Handlers::const_iterator i(_imp->handlers.find(s));
diff --git a/src/clients/cave/command_line.cc b/src/clients/cave/command_line.cc
index dcfda65..14e9c58 100644
--- a/src/clients/cave/command_line.cc
+++ b/src/clients/cave/command_line.cc
@@ -29,10 +29,19 @@ CaveCommandLine::CaveCommandLine() :
a_log_level(&g_global_options, "log-level", '\0')
{
add_usage_line("[ --environment class:suffix ] [ --log-level level ] COMMAND [ARGS...]");
+
add_description_line("For the COMMAND argument, see 'cave help' for a list of common commands, "
"or 'cave help --all' for all commands. To see documentation for a command named "
"'foo', use 'man cave-foo'.");
+ add_description_line("In addition to built-in commands, cave will also look in the directories "
+ "named in the colon-separated CAVE_COMMANDS_PATH environment variable, or, if unset, '"
+ LIBEXECDIR "/cave/commands'. Any executables in this path will also be available as "
+ "commands (with any file extension stripped); these executables may use the $CAVE "
+ "environment variable to get access to the main cave program.");
add_description_line("Arguments specified after the COMMAND are handled by the individual "
"commands. Arguments before the COMMAND are global arguments shared by all commands.");
+
+ add_environment_variable("CAVE_COMMANDS_PATH", "Colon-separated paths in which to look for "
+ "additional commands.");
}
diff --git a/src/clients/cave/script_command.cc b/src/clients/cave/script_command.cc
new file mode 100644
index 0000000..dd83966
--- /dev/null
+++ b/src/clients/cave/script_command.cc
@@ -0,0 +1,84 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2010 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "script_command.hh"
+#include "exceptions.hh"
+#include <paludis/args/args.hh>
+#include <paludis/args/do_help.hh>
+#include <paludis/args/escape.hh>
+#include <paludis/util/private_implementation_pattern-impl.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/stringify.hh>
+#include <iostream>
+#include <cstdlib>
+
+#include "command_command_line.hh"
+
+using namespace paludis;
+using namespace cave;
+using std::cout;
+using std::endl;
+
+namespace paludis
+{
+ template <>
+ struct Implementation<ScriptCommand>
+ {
+ const FSEntry executable;
+
+ Implementation(const FSEntry & e) :
+ executable(e)
+ {
+ }
+ };
+}
+
+ScriptCommand::ScriptCommand(const std::string &, const FSEntry & e) :
+ PrivateImplementationPattern<ScriptCommand>(new Implementation<ScriptCommand>(e))
+{
+}
+
+ScriptCommand::~ScriptCommand()
+{
+}
+
+int
+ScriptCommand::run(
+ const std::tr1::shared_ptr<Environment> &,
+ const std::tr1::shared_ptr<const Sequence<std::string > > & args
+ )
+{
+ std::string arg_str;
+ for (Sequence<std::string>::ConstIterator n(args->begin()), n_end(args->end()) ;
+ n != n_end ; ++n)
+ arg_str = " " + args::escape(*n);
+
+ paludis::Command cmd(stringify(_imp->executable) + arg_str);
+ become_command(cmd);
+
+ throw InternalError(PALUDIS_HERE, "become_command failed");
+}
+
+std::tr1::shared_ptr<args::ArgsHandler>
+ScriptCommand::make_doc_cmdline()
+{
+ throw InternalError(PALUDIS_HERE, "no script cmdline");
+}
+
diff --git a/src/clients/cave/script_command.hh b/src/clients/cave/script_command.hh
new file mode 100644
index 0000000..c06199a
--- /dev/null
+++ b/src/clients/cave/script_command.hh
@@ -0,0 +1,49 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2010 Ciaran McCreesh
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_SRC_CLIENTS_CAVE_SCRIPT_COMMAND_HH
+#define PALUDIS_GUARD_SRC_CLIENTS_CAVE_SCRIPT_COMMAND_HH 1
+
+#include "command.hh"
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/fs_entry-fwd.hh>
+
+namespace paludis
+{
+ namespace cave
+ {
+ class PALUDIS_VISIBLE ScriptCommand :
+ private PrivateImplementationPattern<ScriptCommand>,
+ public Command
+ {
+ public:
+ ScriptCommand(const std::string &, const FSEntry &);
+ ~ScriptCommand();
+
+ int run(
+ const std::tr1::shared_ptr<Environment> &,
+ const std::tr1::shared_ptr<const Sequence<std::string > > & args
+ ) PALUDIS_ATTRIBUTE((noreturn));
+
+ std::tr1::shared_ptr<args::ArgsHandler> make_doc_cmdline() PALUDIS_ATTRIBUTE((noreturn));
+ };
+ }
+}
+
+#endif