# from [221b45f4b0c008da11516b07ca2048fc2a21ce03]
# to [a8f6acf503875a2c432c971ea16a86b7f31e88da]
#
# patch "options_list.hh"
# from [fa4f0a044e96e403f838eba547e1a1d83219071c]
# to [309fa72238b0810abd6be18d04264fcfe2ac7ee6]
---
+++
@@ -0,0 +1,985 @@
+// Copyright (C) 2002 Graydon Hoare
+// 2007 Julio M. Merino Vidal
+//
+// This program is made available under the GNU GPL version 2.0 or
+// greater. See the accompanying file COPYING for details.
+//
+// This program is distributed WITHOUT ANY WARRANTY; without even the
+// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+// PURPOSE.
+
+#include "base.hh"
+#include "cmd.hh"
+
+#include "lua.hh"
+#include "app_state.hh"
+#include "options_applicator.hh"
+#include "work.hh"
+#include "ui.hh"
+#include "mt_version.hh"
+#include "charset.hh"
+#include "simplestring_xform.hh"
+#include "vocab_cast.hh"
+
+#ifndef _WIN32
+#include
+#include
+#else
+#include
+#endif
+
+#include
+#include
+
+using std::string;
+using std::stringstream;
+using std::vector;
+using std::set;
+using std::ostream;
+using std::make_pair;
+using std::cout;
+using boost::lexical_cast;
+
+//
+// Definition of top-level commands, used to classify the real commands
+// in logical groups.
+//
+// These top level commands, while part of the final identifiers and defined
+// as regular command groups, are handled separately. The user should not
+// see them except through the help command.
+//
+// XXX This is to easily maintain compatibilty with older versions. But
+// maybe this should be revised, because exposing the top level category
+// (being optional, of course), may not be a bad idea.
+//
+
+CMD_GROUP(__root__, "__root__", "", NULL, "", "");
+
+CMD_GROUP_NO_COMPLETE(automation, "automation", "", CMD_REF(__root__),
+ N_("Commands that aid in scripted execution"),
+ "");
+CMD_GROUP(database, "database", "", CMD_REF(__root__),
+ N_("Commands that manipulate the database"),
+ "");
+CMD_GROUP(debug, "debug", "", CMD_REF(__root__),
+ N_("Commands that aid in program debugging"),
+ "");
+CMD_GROUP(informative, "informative", "", CMD_REF(__root__),
+ N_("Commands for information retrieval"),
+ "");
+CMD_GROUP(key_and_cert, "key_and_cert", "", CMD_REF(__root__),
+ N_("Commands to manage keys and certificates"),
+ "");
+CMD_GROUP(network, "network", "", CMD_REF(__root__),
+ N_("Commands that access the network"),
+ "");
+CMD_GROUP(packet_io, "packet_io", "", CMD_REF(__root__),
+ N_("Commands for packet reading and writing"),
+ "");
+CMD_GROUP(vcs, "vcs", "", CMD_REF(__root__),
+ N_("Commands for interaction with other version control systems"),
+ "");
+CMD_GROUP(review, "review", "", CMD_REF(__root__),
+ N_("Commands to review revisions"),
+ "");
+CMD_GROUP(tree, "tree", "", CMD_REF(__root__),
+ N_("Commands to manipulate the tree"),
+ "");
+CMD_GROUP(variables, "variables", "", CMD_REF(__root__),
+ N_("Commands to manage persistent variables"),
+ "");
+CMD_GROUP(workspace, "workspace", "", CMD_REF(__root__),
+ N_("Commands that deal with the workspace"),
+ "");
+CMD_GROUP(user, "user", "", CMD_REF(__root__),
+ N_("Commands defined by the user"),
+ "");
+
+namespace commands {
+
+ void remove_command_name_from_args(command_id const & ident,
+ args_vector & args,
+ size_t invisible_length)
+ {
+ MM(ident);
+ MM(args);
+ MM(invisible_length);
+ I(ident.empty() || args.size() >= ident.size() - invisible_length);
+ for (args_vector::size_type i = invisible_length; i < ident.size(); i++)
+ {
+ I(ident[i]().find(args[0]()) == 0);
+ args.erase(args.begin());
+ }
+ }
+
+ void reapply_options(app_state & app,
+ command const * cmd,
+ command_id const & cmd_ident,
+ command const * subcmd,
+ command_id const & subcmd_full_ident,
+ size_t subcmd_invisible_length,
+ args_vector const & subcmd_cmdline,
+ vector > const * const separate_params)
+ {
+ I(cmd);
+ options::opts::all_options().instantiate(&app.opts).reset();
+
+ cmd->preset_options(app.opts);
+
+ option::concrete_option_set optset
+ = (options::opts::globals() | cmd->opts())
+ .instantiate(&app.opts);
+
+ optset.from_command_line(app.reset_info.default_args);
+
+ if (subcmd)
+ {
+ args_vector subcmd_defaults;
+ app.lua.hook_get_default_command_options(subcmd_full_ident,
+ subcmd_defaults);
+ (options::opts::globals() | subcmd->opts())
+ .instantiate(&app.opts)
+ .from_command_line(subcmd_defaults);
+ }
+
+ // at this point we process the data from _MTN/options if
+ // the command needs it.
+ if ((subcmd ? subcmd : cmd)->use_workspace_options())
+ {
+ workspace::check_format();
+ workspace::get_options(app.opts);
+ }
+
+ optset.from_command_line(app.reset_info.cmdline_args);
+
+ if (subcmd)
+ {
+ app.opts.args.clear();
+ option::concrete_option_set subcmd_optset
+ = (options::opts::globals() | subcmd->opts())
+ .instantiate(&app.opts);
+ if (!separate_params)
+ {
+ /* the first argument here is only ever modified if the second is 'true' */
+ subcmd_optset.from_command_line(const_cast(subcmd_cmdline));
+ }
+ else
+ {
+ subcmd_optset.from_key_value_pairs(*separate_params);
+ app.opts.args = subcmd_cmdline;
+ }
+ remove_command_name_from_args(subcmd_full_ident, app.opts.args,
+ subcmd_invisible_length);
+ }
+ else
+ {
+ remove_command_name_from_args(cmd_ident, app.opts.args);
+ }
+ }
+
+ // monotone.cc calls this function after option processing.
+ void process(app_state & app, command_id const & ident,
+ args_vector const & args)
+ {
+ static bool process_called(false);
+ I(!process_called);
+ process_called = true;
+
+ command const * cmd = CMD_REF(__root__)->find_command(ident);
+ app.reset_info.cmd = cmd;
+
+ string visibleid = join_words(vector< utf8 >(ident.begin() + 1,
+ ident.end()))();
+
+ I(cmd->is_leaf() || cmd->is_group());
+ E(!(cmd->is_group() && cmd->parent() == CMD_REF(__root__)),
+ origin::user,
+ F("command '%s' is invalid; it is a group") % join_words(ident));
+
+ if (!cmd->is_leaf())
+ {
+ // args used in the command name have not been stripped yet
+ remove_command_name_from_args(ident, app.opts.args);
+
+ E(!args.empty(), origin::user,
+ F("no subcommand specified for '%s'") % visibleid);
+
+ E(false, origin::user,
+ F("could not match '%s' to a subcommand of '%s'") %
+ join_words(args) % visibleid);
+ }
+
+ L(FL("executing command '%s'") % visibleid);
+
+ reapply_options(app, cmd, ident);
+
+ // intentional leak
+ // we don't want the options to be reset, so don't destruct this
+ new options_applicator(app.opts, options_applicator::for_primary_cmd);
+
+ cmd->exec(app, ident, args);
+ }
+
+ // Prints the abstract description of the given command or command group
+ // properly indented. The tag starts at column two. The description has
+ // to start, at the very least, two spaces after the tag's end position;
+ // this is given by the colabstract parameter.
+ static void describe(const string & tag, const string & abstract,
+ const string & subcommands, size_t colabstract,
+ ostream & out)
+ {
+ I(colabstract > 0);
+
+ size_t col = 0;
+ out << " " << tag << " ";
+ col += display_width(utf8(tag + " ", origin::internal));
+
+ out << string(colabstract - col, ' ');
+ col = colabstract;
+ string desc(abstract);
+ if (!subcommands.empty())
+ {
+ desc += " (" + subcommands + ')';
+ }
+ out << format_text(desc, colabstract, col) << '\n';
+ }
+
+ class cmd_ptr_compare
+ {
+ public:
+ bool operator()(command const * const a, command const * const b) const
+ {
+ return a->primary_name()() < b->primary_name()();
+ }
+ };
+
+ static void explain_children(command::children_set const & children,
+ bool show_hidden_commands,
+ ostream & out)
+ {
+ I(!children.empty());
+
+ vector< command const * > sorted;
+
+ size_t colabstract = 0;
+ for (command::children_set::const_iterator i = children.begin();
+ i != children.end(); i++)
+ {
+ command const * child = *i;
+
+ if (child->hidden() && !show_hidden_commands)
+ continue;
+
+ size_t len = display_width(join_words(child->names(), ", ")) +
+ display_width(utf8(" "));
+ if (colabstract < len)
+ colabstract = len;
+
+ sorted.push_back(child);
+ }
+
+ sort(sorted.begin(), sorted.end(), cmd_ptr_compare());
+
+ for (vector< command const * >::const_iterator i = sorted.begin();
+ i != sorted.end(); i++)
+ {
+ command const * child = *i;
+ describe(join_words(child->names(), ", ")(), child->abstract(),
+ join_words(child->subcommands(show_hidden_commands), ", ")(),
+ colabstract, out);
+ }
+ }
+
+ static command const *
+ find_command(command_id const & ident)
+ {
+ command const * cmd = CMD_REF(__root__)->find_command(ident);
+
+ // This function is only used internally with an identifier returned
+ // by complete_command. Therefore, it must always exist.
+ I(cmd != NULL);
+
+ return cmd;
+ }
+
+ static void explain_cmd_usage(command_id const & ident,
+ bool show_hidden_commands,
+ ostream & out)
+ {
+ I(ident.size() >= 1);
+
+ vector< string > lines;
+ command const * cmd = find_command(ident);
+
+ string visibleid = join_words(vector< utf8 >(ident.begin() + 1,
+ ident.end()))();
+
+ // Print command parameters.
+ string params = cmd->params();
+ split_into_lines(params, lines);
+
+ if (visibleid.empty())
+ out << format_text(F("Commands in group '%s':") %
+ join_words(ident)())
+ << "\n\n";
+ else
+ {
+ if (!cmd->children().empty())
+ out << format_text(F("Subcommands of '%s %s':") %
+ prog_name % visibleid)
+ << "\n\n";
+ else if (!lines.empty())
+ out << format_text(F("Syntax specific to '%s %s':") %
+ prog_name % visibleid)
+ << "\n\n";
+ }
+
+ // lines might be empty, but only when specific syntax is to be
+ // displayed, not in the other cases.
+ if (!lines.empty())
+ {
+ for (vector::const_iterator j = lines.begin();
+ j != lines.end(); ++j)
+ out << " " << visibleid << ' ' << *j << '\n';
+ out << '\n';
+ }
+
+ // Explain children, if any.
+ if (!cmd->is_leaf())
+ {
+ explain_children(cmd->children(), show_hidden_commands, out);
+ out << '\n';
+ }
+
+ // Print command description.
+ if (visibleid.empty())
+ out << format_text(F("Purpose of group '%s':") %
+ join_words(ident)())
+ << "\n\n";
+ else
+ out << format_text(F("Description for '%s %s':") %
+ prog_name % visibleid)
+ << "\n\n";
+ out << format_text(cmd->desc(), 2) << "\n\n";
+
+ // Print all available aliases.
+ if (cmd->names().size() > 1)
+ {
+ command::names_set othernames = cmd->names();
+ othernames.erase(ident[ident.size() - 1]);
+ out << format_text(F("Aliases: %s.") %
+ join_words(othernames, ", ")(), 2)
+ << '\n';
+ }
+ }
+
+ void explain_usage(command_id const & ident,
+ bool show_hidden_commands,
+ ostream & out)
+ {
+ command const * cmd = find_command(ident);
+
+ if (ident.empty())
+ {
+ out << format_text(F("Command groups:")) << "\n\n";
+ explain_children(CMD_REF(__root__)->children(),
+ show_hidden_commands,
+ out);
+ out << '\n'
+ << format_text(F("For information on a specific command, type "
+ "'mtn help [subcommand_name ...]'."))
+ << "\n\n"
+ << format_text(F("To see more details about the commands of a "
+ "particular group, type 'mtn help '."))
+ << "\n\n"
+ << format_text(F("Note that you can always abbreviate a command "
+ "name as long as it does not conflict with other "
+ "names."))
+ << "\n";
+ }
+ else
+ explain_cmd_usage(ident, show_hidden_commands, out);
+ }
+
+ options::options_type command_options(command_id const & ident)
+ {
+ command const * cmd = find_command(ident);
+ return cmd->opts();
+ }
+
+ // Lua-defined user commands.
+ class cmd_lua : public command
+ {
+ lua_State *st;
+ std::string const f_name;
+ public:
+ cmd_lua(std::string const & primary_name,
+ std::string const & params,
+ std::string const & abstract,
+ std::string const & desc,
+ lua_State *L_st,
+ std::string const & func_name) :
+ command(primary_name, "", CMD_REF(user), false, false, params,
+ abstract, desc, true,
+ options::options_type() | options::opts::none, true),
+ st(L_st), f_name(func_name)
+ {
+ // because user commands are inserted after the normal
+ // initialisation process
+ CMD_REF(user)->children().insert(this);
+ }
+
+ void exec(app_state & app, command_id const & execid,
+ args_vector const & args) const
+ {
+ I(st);
+ I(app.lua.check_lua_state(st));
+
+ app_state* app_p = get_app_state(st);
+ I(app_p == & app);
+
+ Lua ll(st);
+ ll.func(f_name);
+
+ for (args_vector::const_iterator it = args.begin();
+ it != args.end(); ++it)
+ ll.push_str((*it)());
+
+ app.mtn_automate_allowed = true;
+
+ ll.call(args.size(),0);
+
+ app.mtn_automate_allowed = false;
+
+ E(ll.ok(), origin::user,
+ F("Call to user command %s (lua command: %s) failed.")
+ % primary_name() % f_name);
+ }
+ };
+}
+
+LUAEXT(alias_command, )
+{
+ const char *old_cmd = luaL_checkstring(LS, -2);
+ const char *new_cmd = luaL_checkstring(LS, -1);
+ E(old_cmd && new_cmd, origin::user,
+ F("%s called with an invalid parameter") % "alias_command");
+
+ args_vector args;
+ args.push_back(arg_type(old_cmd, origin::user));
+ commands::command_id id = commands::complete_command(args);
+ commands::command *old_cmd_p = CMD_REF(__root__)->find_command(id);
+
+ old_cmd_p->add_alias(utf8(new_cmd));
+
+ lua_pushboolean(LS, true);
+ return 1;
+}
+
+
+LUAEXT(register_command, )
+{
+ const char *cmd_name = luaL_checkstring(LS, -5);
+ const char *cmd_params = luaL_checkstring(LS, -4);
+ const char *cmd_abstract = luaL_checkstring(LS, -3);
+ const char *cmd_desc = luaL_checkstring(LS, -2);
+ const char *cmd_func = luaL_checkstring(LS, -1);
+
+ E(cmd_name && cmd_params && cmd_abstract && cmd_desc && cmd_func,
+ origin::user,
+ F("%s called with an invalid parameter") % "register_command");
+
+ // leak this - commands can't be removed anyway
+ new commands::cmd_lua(cmd_name, cmd_params, cmd_abstract, cmd_desc,
+ LS, cmd_func);
+
+ lua_pushboolean(LS, true);
+ return 1;
+}
+
+// Miscellaneous commands and related functions for which there is no
+// better file.
+
+CMD_NO_WORKSPACE(help, "help", "", CMD_REF(informative),
+ N_("command [ARGS...]"),
+ N_("Displays help about commands and options"),
+ "",
+ options::opts::show_hidden_commands)
+{
+ if (args.size() < 1)
+ {
+ app.opts.help = true;
+ throw usage(command_id());
+ }
+
+ command_id id = commands::complete_command(args);
+ app.opts.help = true;
+ throw usage(id);
+}
+
+CMD_NO_WORKSPACE(version, "version", "", CMD_REF(informative), "",
+ N_("Shows the program version"),
+ "",
+ options::opts::full)
+{
+ E(args.empty(), origin::user,
+ F("no arguments allowed"));
+
+ if (app.opts.full)
+ print_full_version();
+ else
+ print_version();
+}
+
+CMD_HIDDEN(crash, "crash", "", CMD_REF(debug),
+ "{ N | E | I | double-throw | exception | signal }",
+ N_("Triggers the specified kind of crash"),
+ "",
+ options::opts::none)
+{
+ if (args.size() != 1)
+ throw usage(execid);
+ bool spoon_exists(false);
+ if (idx(args,0)() == "N")
+ E(spoon_exists, origin::user, i18n_format("There is no spoon."));
+ else if (idx(args,0)() == "E")
+ E(spoon_exists, origin::system, i18n_format("There is no spoon."));
+ else if (idx(args,0)() == "I")
+ {
+ I(spoon_exists);
+ }
+ else if (idx(args,0)() == "double-throw")
+ {
+ // This code is rather picky, for example I(false) in the destructor
+ // won't always work like it should; see http://bugs.debian.org/516862
+ class throwing_dtor
+ {
+ public:
+ throwing_dtor() {}
+ ~throwing_dtor()
+ {
+ throw std::exception();
+ }
+ };
+ throwing_dtor td;
+ throw std::exception();
+ }
+#define maybe_throw(ex) if(idx(args,0)()==#ex) throw ex("There is no spoon.")
+#define maybe_throw_bare(ex) if(idx(args,0)()==#ex) throw ex()
+ else maybe_throw_bare(std::bad_alloc);
+ else maybe_throw_bare(std::bad_cast);
+ else maybe_throw_bare(std::bad_typeid);
+ else maybe_throw_bare(std::bad_exception);
+ else maybe_throw_bare(std::exception);
+ else maybe_throw(std::domain_error);
+ else maybe_throw(std::invalid_argument);
+ else maybe_throw(std::length_error);
+ else maybe_throw(std::out_of_range);
+ else maybe_throw(std::range_error);
+ else maybe_throw(std::overflow_error);
+ else maybe_throw(std::underflow_error);
+ else maybe_throw(std::logic_error);
+ else maybe_throw(std::runtime_error);
+ else
+ {
+#ifndef _WIN32
+ try
+ {
+ int signo = boost::lexical_cast(idx(args,0)());
+ if (0 < signo && signo <= 15)
+ {
+ raise(signo);
+ // control should not get here...
+ I(!"crash: raise returned");
+ }
+ }
+ catch (boost::bad_lexical_cast&)
+ { // fall through and throw usage
+ }
+#endif
+ throw usage(execid);
+ }
+#undef maybe_throw
+#undef maybe_throw_bare
+}
+
+static string
+man_italic(string const & content)
+{
+ return "\\fI" + content + "\\fP";
+}
+
+static string
+man_bold(string const & content)
+{
+ return "\\fB" + content + "\\fP";
+}
+
+static string
+man_definition(vector const & labels, string const & content, int width = -1)
+{
+ string out;
+ out += ".IP \"" + (*labels.begin()) + "\"";
+
+ if (width != -1)
+ out += " " + lexical_cast(width);
+ out += "\n";
+
+ if (labels.size() > 1)
+ {
+ out += ".PD 0\n";
+ for (vector::const_iterator i = labels.begin() + 1;
+ i < labels.end(); ++i)
+ {
+ out += ".IP \"" + (*i) + "\"\n";
+ }
+ out += ".PD\n";
+ }
+ out += content;
+ if (content.rfind('\n') != (content.size() - 1))
+ out += "\n";
+ return out;
+}
+
+static string
+man_definition(string const & label, string const & content, int width = -1)
+{
+ vector labels;
+ labels.push_back(label);
+ return man_definition(labels, content, width);
+}
+
+static string
+man_indent(string const & content)
+{
+ return ".RS\n" + content + ".RE\n";
+}
+
+static string
+man_subsection(string const & content)
+{
+ return ".SS \"" + content + "\"\n";
+}
+
+static string
+man_section(string const & content)
+{
+ return ".SH \"" + uppercase(content) + "\"\n";
+}
+
+static string
+man_title(string const & title)
+{
+ return ".TH \"" + title + "\" 1 "+
+ "\"" + date_t::now().as_formatted_localtime("%Y-%m-%d") + "\" " +
+ "\"" + PACKAGE_STRING + "\"\n";
+}
+
+static string
+get_options_string(options::options_type const & optset, options & opts, int width = -1)
+{
+ vector names;
+ vector descriptions;
+ unsigned int maxnamelen;
+
+ optset.instantiate(&opts).get_usage_strings(
+ names, descriptions, maxnamelen, opts.show_hidden_commands
+ );
+
+ string out;
+ vector::const_iterator name;
+ vector::const_iterator desc;
+ for (name = names.begin(), desc = descriptions.begin();
+ name != names.end(); ++name, ++desc)
+ {
+ if (name->empty())
+ continue;
+ out += man_definition(*name, *desc, width);
+ }
+ return out;
+}
+
+static string
+get_commands(options & opts, commands::command const * group)
+{
+ vector sorted_commands;
+ commands::command::children_set commands = group->children();
+ for (commands::command::children_set::const_iterator i = commands.begin();
+ i != commands.end(); ++i)
+ {
+ commands::command * command = *i;
+ if (command->hidden() && !opts.show_hidden_commands)
+ continue;
+
+ // there are no top level commands, so this must be an
+ // empty group - skip it
+ if (group->is_leaf())
+ continue;
+
+ sorted_commands.push_back(command);
+ }
+
+ sort(sorted_commands.begin(),
+ sorted_commands.end(),
+ commands::cmd_ptr_compare());
+
+ string out;
+ for (vector::const_iterator i = sorted_commands.begin();
+ i != sorted_commands.end(); ++i)
+ {
+ commands::command const * command = *i;
+
+ // don't print sub groups explicitely, just their leaves
+ if (!command->is_leaf())
+ {
+ out += get_commands(opts, command);
+ continue;
+ }
+
+ // this builds a list of already formatted command calls
+ // which are used as label for the specific command section
+ vector cmd_calls;
+
+ //
+ // newline characters in the parameter section mark
+ // alternative call syntaxes which we expand here, i.e.
+ // a command "do-foo" with an alias of "foo" and an argument
+ // list of "BAR\nBAR BAZ" will be expanded to
+ //
+ // do-foo BAR
+ // do-foo BAR BAZ
+ // foo BAR
+ // foo BAR BAZ
+ //
+ vector params;
+ if (!command->params().empty())
+ split_into_lines(command->params(), params);
+
+ vector main_ident = command->ident();
+ typedef set > ident_set;
+ ident_set idents;
+
+ commands::command::names_set allnames = command->names();
+ for (set::const_iterator i = allnames.begin();
+ i != allnames.end(); ++i)
+ {
+ vector full_ident;
+ for (vector::const_iterator j = main_ident.begin() + 1;
+ j < main_ident.end() - 1; ++j)
+ {
+ full_ident.push_back((*j)());
+ }
+ full_ident.push_back((*i)());
+ idents.insert(full_ident);
+ }
+
+ for (ident_set::const_iterator i = idents.begin();
+ i != idents.end(); ++i)
+ {
+ string call, name;
+ // cannot use join_words here, since this only
+ // works on containers
+ join_lines(*i, name, " ");
+
+ if (params.size() == 0)
+ {
+ call = man_bold(name);
+ cmd_calls.push_back(call);
+ continue;
+ }
+
+ for (vector::const_iterator j = params.begin();
+ j < params.end(); ++j)
+ {
+ call = man_bold(name) + " " + *j;
+ cmd_calls.push_back(call);
+ }
+ }
+
+ string cmd_desc;
+ cmd_desc += command->desc() + "\n";
+
+ // this prints an indented list of available command options
+ options::options_type cmd_options =
+ commands::command_options(main_ident);
+ if (!cmd_options.empty())
+ {
+ cmd_desc += man_indent(get_options_string(cmd_options, opts, 4));
+ }
+
+ // compile everything into a man definition
+ out += man_definition(cmd_calls, cmd_desc, 4);
+ }
+
+ return out;
+}
+
+static string
+get_command_groups(options & opts)
+{
+ vector sorted_groups;
+ commands::command::children_set groups = CMD_REF(__root__)->children();
+ for (commands::command::children_set::const_iterator i = groups.begin();
+ i != groups.end(); ++i)
+ {
+ commands::command * group = *i;
+ if (group->hidden() && !opts.show_hidden_commands)
+ continue;
+
+ // there are no top level commands, so this must be an
+ // empty group - skip it
+ if (group->is_leaf())
+ continue;
+
+ sorted_groups.push_back(group);
+ }
+
+ sort(sorted_groups.begin(),
+ sorted_groups.end(),
+ commands::cmd_ptr_compare());
+
+ string out;
+ for (vector::const_iterator i = sorted_groups.begin();
+ i != sorted_groups.end(); ++i)
+ {
+ commands::command const * group = *i;
+ out += man_subsection(
+ (F("command group '%s'") % group->primary_name()).str()
+ );
+ out += group->desc() + "\n";
+
+ out += get_commands(opts, group);
+ }
+
+ return out;
+}
+
+CMD_PRESET_OPTIONS(manpage)
+{
+ opts.formatted = isatty(STDOUT_FILENO);
+}
+CMD_NO_WORKSPACE(manpage, "manpage", "", CMD_REF(informative), "",
+ N_("Generate a manual page from monotone's command help"),
+ "",
+ options::opts::show_hidden_commands | options::opts::formatted)
+{
+ stringstream ss;
+ ss << man_title("monotone");
+ ss << man_section(_("Name"));
+
+ ss << _("monotone - a distributed version control system") << "\n";
+ ss << man_section(_("Synopsis"));
+ ss << man_bold(prog_name) << " "
+ << man_italic(_("[options...] command [arguments...]"))
+ << "\n";
+
+ ss << man_section(_("Description"));
+ ss << _("monotone is a highly reliable, very customizable distributed "
+ "version control system that provides lightweight branches, "
+ "history-sensitive merging and a flexible trust setup. "
+ "monotone has an easy-to-learn command set and comes with a rich "
+ "interface for scripting purposes and thorough documentation.")
+ << "\n\n";
+ ss << (F("For more information on monotone, visit %s.")
+ % man_bold("http://www.monotone.ca")).str()
+ << "\n\n";
+ ss << (F("The complete documentation, including a tutorial for a quick start "
+ "with the system, can be found online on %s.")
+ % man_bold("http://www.monotone.ca/docs")).str() << "\n";
+
+ ss << man_section(_("Global Options"));
+ ss << get_options_string(options::opts::globals(), app.opts, 25) << "\n";
+
+ ss << man_section(_("Commands"));
+ ss << get_command_groups(app.opts);
+
+ ss << man_section(_("See Also"));
+ ss << (F("info %s and the documentation on %s")
+ % prog_name % man_bold("http://monotone.ca/docs")).str() << "\n";
+
+ ss << man_section("Bugs");
+ ss << (F("Please report bugs to %s.")
+ % man_bold("http://savannah.nongnu.org/bugs/?group=monotone")).str()<< "\n";
+
+ ss << man_section("Authors");
+ ss << _("monotone was written originally by Graydon Hoare "
+ " in 2004 and has since then received "
+ "numerous contributions from many individuals. "
+ "A complete list of authors can be found in AUTHORS.")
+ << "\n\n";
+ ss << _("Nowadays, monotone is maintained by a collective of enthusiastic "
+ "programmers, known as the monotone developement team.") << "\n";
+
+ ss << man_section("Copyright");
+ ss << (F("monotone and this man page is Copyright (c) 2004 - %s by "
+ "the monotone development team.")
+ % date_t::now().as_formatted_localtime("%Y")).str() << "\n";
+
+ if (!app.opts.formatted)
+ {
+ cout << ss.str();
+ return;
+ }
+
+ string cmd;
+ E(app.lua.hook_get_man_page_formatter_command(cmd) && !cmd.empty(),
+ origin::user, F("no man page formatter command configured"));
+
+ FILE * fp = popen(cmd.c_str(), "w");
+ E(fp != NULL, origin::system,
+ F("could not execute man page formatter command '%s': %s")
+ % cmd % strerror(errno));
+
+ I(fprintf(fp, ss.str().c_str()) != -1);
+ pclose(fp);
+}
+
+// There isn't really a better place for this function.
+
+void
+process_commit_message_args(options const & opts,
+ bool & given,
+ utf8 & log_message,
+ utf8 const & message_prefix)
+{
+ // can't have both a --message and a --message-file ...
+ E(!opts.message_given || !opts.msgfile_given, origin::user,
+ F("--message and --message-file are mutually exclusive"));
+
+ if (opts.message_given)
+ {
+ string msg;
+ join_lines(opts.message, msg);
+ log_message = utf8(msg, origin::user);
+ if (!opts.no_prefix && message_prefix().length() != 0)
+ log_message = utf8(message_prefix() + "\n\n" + log_message(),
+ origin::user);
+ given = true;
+ }
+ else if (opts.msgfile_given)
+ {
+ data dat;
+ read_data_for_command_line(opts.msgfile, dat);
+ external dat2 = typecast_vocab(dat);
+ system_to_utf8(dat2, log_message);
+ if (!opts.no_prefix && message_prefix().length() != 0)
+ log_message = utf8(message_prefix() + "\n\n" + log_message(),
+ origin::user);
+ given = true;
+ }
+ else if (message_prefix().length() != 0)
+ {
+ log_message = message_prefix;
+ given = true;
+ }
+ else
+ given = false;
+}
+
+// Local Variables:
+// mode: C++
+// fill-column: 76
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:
--- options_list.hh
+++ options_list.hh
@@ -0,0 +1,658 @@
+// Copyright (C) 2006 Timothy Brownawell
+// 2008-2010 Stephen Leake
+//
+// This program is made available under the GNU GPL version 2.0 or
+// greater. See the accompanying file COPYING for details.
+//
+// This program is distributed WITHOUT ANY WARRANTY; without even the
+// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+// PURPOSE.
+
+/*
+ * This is a list of all options that monotone can take, what variables
+ * they get put into, and how they get there. There are 6 important macros
+ * available here (and only here):
+ *
+ * OPTSET(name)
+ * Defines a set of related options, which can easily be allowed for
+ * a particular command or reset together. It is named
+ * 'options::opts::name'.
+ *
+ * This is used primarily for convenience in specifying options for the
+ * CMD macro. Especially if several options always go together, they
+ * can be grouped into an optset and then only that optset has to be
+ * specified as an argument to the CMD macro when declaring commands
+ * that use all of those options.
+ *
+ * This is also used for resettable options; any option that has a
+ * reset flag needs to be directly in an optset that *only* contains
+ * (directly or through OPTSET_REL) the optvar's that should be
+ * re-initialized when the reset flag is given. Because the
+ * SIMPLE_OPTION family all declare an optset containing only the
+ * one option and its one optvar, you don't typically need to care
+ * about this.
+ *
+ * OPTSET_REL(parent, child)
+ * Declare a relationship between two optsets, so that if the parent
+ * is reset or allowed for a command the child will also be.
+ *
+ * For example "diff" takes all of the options that "automate diff"
+ * takes, plus some additional ones. So there is a line below,
+ * "OPTSET_REL(diff_options, au_diff_options)", and then "diff" takes
+ * options::opts::diff_options and "automate diff" takes
+ * options::opts::au_diff_options. Options that only apply to "diff"
+ * go in the diff_options optset, while options that apply to both
+ * go in the au_diff_options optset.
+ *
+ * OPTVAR(optset, type, name, default)
+ * Defines a variable 'type options::name' which is initialized to
+ * 'type (default)' and belongs to the named optset. When the optset
+ * is reset, this variable will be reset to 'type (default)'.
+ *
+ * OPTION(optset, name, hasarg, optstring, description)
+ * Declare an option named 'options::opts::name', which belongs to the
+ * given optset. 'optstring' can look like "foo", in which case it is
+ * specified as "--foo", or it can look like "foo,f", in which case it
+ * is specified as either "--foo" or "-f". The description is a
+ * translatable help text. 'hasarg' is a bool indicating whether this
+ * option takes an argument.
+ *
+ * Some expansions of this macro expect a function body, which looks
+ * like 'void (std::string const & arg)'. This is the 'setter' function
+ * for this option, and is called when the option is parsed. If the
+ * option was declared to not take an argument, 'arg' is empty.
+ * Otherwise, it is the given argument. In any case this function
+ * should set the option variables for this option and throw a
+ * 'bad_arg_internal' if this fails. The variables that are set must be
+ * part of the same optset as the option, or they won't get reset
+ * properly. When the function body is needed, 'option_bodies' will
+ * be defined.
+ *
+ *
+ * HIDE(option)
+ * Do not show the named option in normal help output. Hidden options
+ * are shown by the --hidden option.
+ *
+ * In general, options should be hidden if they are introduced for
+ * testing purposes.
+ *
+ * DEPRECATE(option, reason, deprecated_in, will_remove_in)
+ * Do not show the named option in help output (even with --hidden), and
+ * give a warning if it is used. The reason should be
+ * gettext_noopt("some text here") as it is translatable.
+ *
+ *
+ * Option Strings
+ *
+ * Options can have a long name, a short name, and a 'reset' name. The
+ * long and short names run the function body in the '#ifdef
+ * option_bodies'. The 'reset' name is slightly different, it makes the
+ * optset that the option belongs to get reset. This means that if you
+ * have several related options in the same optset, you probably *don't*
+ * want to specify a reset name for any of them.
+ *
+ * If you want an option to belong to an optset and also be resettable,
+ * you can use OPTSET_REL to make the desired optset include the option's
+ * personal optset.
+ *
+ * The option string format is "long,s/reset". "--long" and "-s" are
+ * the long and short names, and set the option. "--reset" is the
+ * reset name, and resets the option. An option *must* have a long
+ * and/or short name, but isn't required to have a reset name. So
+ * "/foo" is invalid, but "foo,f", "foo/no-foo", "f/no-f", and
+ * "foo,f/no-foo" are all allowed.
+ */
+
+/*
+ * If you want different *default* values for an option based on what command
+ * is being run (for example --with-header/--no-with-header for 'diff' and
+ * 'automate diff'), use CMD_PRESET_OPTIONS(cmdname) { ... } defined in cmd.hh.
+ * It doesn't go in this file, but rather in the file where the command is
+ * defined (ideally immediately before the CMD() declaration for that same
+ * command, just to be consistent).
+ */
+
+#ifdef option_bodies
+template
+void set_simple_option(T & t, std::string const & arg)
+{ t = T(arg, origin::user); }
+template
+void set_simple_option(std::vector & t, std::string const & arg)
+{ t.push_back(T(arg, origin::user)); }
+template
+void set_simple_option(std::set & t, std::string const & arg)
+{ t.insert(T(arg, origin::user)); }
+template<>
+void set_simple_option(bool & t, std::string const & arg)
+{ t = true; }
+void set_simple_option(u8 & t, std::string const & arg)
+{
+ long l = boost::lexical_cast(arg);
+ if (l < 0 || l > 255)
+ throw bad_arg_internal(F("must be between 0 and 255").str());
+ else
+ t = (u8)l;
+}
+template<>
+void set_simple_option(std::string & t, std::string const & arg)
+{ t = arg; }
+void set_simple_option(date_t & t, std::string const & arg)
+{
+ try { t = date_t(arg); }
+ catch (std::exception & e)
+ { throw bad_arg_internal(e.what()); }
+}
+template<>
+void set_simple_option(std::vector & t, std::string const & arg)
+{ t.push_back(arg); }
+template<>
+void set_simple_option(std::set & t, std::string const & arg)
+{ t.insert(arg); }
+template<>
+void set_simple_option(enum_string & t, std::string const & arg)
+{ t.set(arg); }
+template<>
+void set_simple_option(enum_string_set & t, std::string const & arg)
+{ t.add(arg); }
+
+# define SIMPLE_OPTION_BODY(name) { set_simple_option(name, arg); }
+#else
+# define SIMPLE_OPTION_BODY(name)
+#endif
+/*
+ * This is a 'magic' option, and Does The Right Thing based on its data type:
+ * * If it's a bool, it will be true if the option is given and false if
+ * not given (or reset), and will not take an argument.
+ * * If it's a string or vocab type, it will be set to the argument if
+ * given, and set to the empty value (default constructor) if reset
+ * or not given.
+ * * If it's a container (vector/set) of strings or vocab types, each
+ * time the option is given the argument will be added to the collection
+ * (with push_back or insert), and the collection will be empty if the
+ * option is not given or is reset.
+ */
+#define SIMPLE_INITIALIZED_OPTION(name, optstring, type, init, description) \
+ OPTSET(name) \
+ OPTVAR(name, type, name, init) \
+ OPTION(name, name, has_arg(), optstring, description) \
+ SIMPLE_OPTION_BODY(name)
+
+#define SIMPLE_OPTION(name, optstring, type, description) \
+ SIMPLE_INITIALIZED_OPTION(name, optstring, type, , description)
+
+#define GROUPED_SIMPLE_OPTION(group, name, optstring, type, description) \
+ OPTSET_REL(group, name) \
+ SIMPLE_OPTION(name, optstring, type, description)
+
+
+// because 'default_' is constructor arguments, and may need to be a list
+// This doesn't work if fed through SIMPLE_INITIALIZED_OPTION (it wouldn't
+// work with the other 2 SIMPLE_OPTION macros either, but it wouldn't make
+// sense in the first place with those).
+#define COMMA ,
+
+OPTSET(globals)
+
+// this is a magic option
+OPTVAR(globals, args_vector, args, )
+OPTION(globals, positionals, true, "--", "")
+#ifdef option_bodies
+{
+ args.push_back(arg_type(arg, origin::user));
+}
+#endif
+// this is a more magic option
+OPTION(globals, xargs, true, "xargs,@",
+ gettext_noop("insert command line arguments taken from the given file"))
+#ifdef option_bodies
+{
+}
+#endif
+
+
+SIMPLE_OPTION(author, "author", utf8, gettext_noop("override author for commit"))
+
+SIMPLE_OPTION(automate_stdio_size, "automate-stdio-size",
+ restricted_long<1>,
+ gettext_noop("block size in bytes for \"automate stdio\" output"))
+
+SIMPLE_OPTION(auto_update, "update/no-update", bool,
+ gettext_noop("automatically update the workspace, if it is clean and the base "
+ "revision is a head of an affected branch"))
+
+OPTSET(bind_opts)
+GROUPED_SIMPLE_OPTION(bind_opts, bind_uris, "bind", std::vector,
+ gettext_noop("address:port to listen on (default :4691)"))
+HIDE(no_transport_auth)
+GROUPED_SIMPLE_OPTION(bind_opts, no_transport_auth, "no-transport-auth", bool,
+ gettext_noop("disable transport authentication"))
+HIDE(bind_stdio)
+GROUPED_SIMPLE_OPTION(bind_opts, bind_stdio, "stdio", bool,
+ gettext_noop("serve netsync on stdio"))
+
+HIDE(max_netsync_version)
+SIMPLE_OPTION(max_netsync_version, "max-netsync-version", u8,
+ gettext_noop("cause monotone to lie about the maximum netsync "
+ "protocol version that it supports, mostly for debugging"))
+HIDE(min_netsync_version)
+SIMPLE_OPTION(min_netsync_version, "min-netsync-version", u8,
+ gettext_noop("cause monotone to lie about the minimum netsync "
+ "protocol version it supports, useful for debugging or "
+ "if you want to prevent use of older protocol versions"))
+
+SIMPLE_OPTION(remote_stdio_host, "remote-stdio-host", arg_type,
+ gettext_noop("sets the host (and optionally the port) for a "
+ "remote netsync action"))
+
+SIMPLE_OPTION(branch, "branch,b", branch_name,
+ gettext_noop("select branch cert for operation"))
+
+SIMPLE_OPTION(brief, "brief/no-brief", bool,
+ gettext_noop("print a brief version of the normal output"))
+
+SIMPLE_OPTION(revs_only, "revs-only", bool,
+ gettext_noop("annotate using full revision ids only"))
+
+OPTVAR(globals, system_path, conf_dir, get_default_confdir() COMMA origin::user)
+OPTION(globals, conf_dir, true, "confdir",
+ gettext_noop("set location of configuration directory"))
+#ifdef option_bodies
+{
+ conf_dir = system_path(arg, origin::user);
+ if (!key_dir_given)
+ key_dir = (conf_dir / "keys");
+}
+#endif
+
+GROUPED_SIMPLE_OPTION(globals, no_default_confdir, "no-default-confdir/allow-default-confdir", bool,
+ gettext_noop("forbid use of the default confdir"))
+
+SIMPLE_OPTION(date, "date", date_t,
+ gettext_noop("override date/time for commit"))
+
+OPTSET(date_formats)
+OPTSET_REL(globals, date_formats)
+OPTVAR(date_formats, std::string, date_fmt, )
+OPTION(date_formats, date_fmt, true, "date-format",
+ gettext_noop("strftime(3) format specification for printing dates"))
+#ifdef option_bodies
+{
+ date_fmt = arg;
+ no_format_dates = false;
+}
+#endif
+GROUPED_SIMPLE_OPTION(date_formats, no_format_dates,
+ "no-format-dates", bool,
+ gettext_noop("print date certs exactly as stored in the database"))
+
+
+OPTVAR(globals, db_type, dbname_type, )
+OPTVAR(globals, std::string, dbname_alias, )
+OPTVAR(globals, system_path, dbname, )
+OPTION(globals, dbname, true, "db,d", gettext_noop("set name of database"))
+#ifdef option_bodies
+{
+ if (arg == memory_db_identifier)
+ {
+ dbname_type = memory_db;
+ }
+ else if (arg.size() > 0 && arg.substr(0, 1) == ":")
+ {
+ dbname_alias = arg;
+ dbname_type = managed_db;
+ }
+ else
+ {
+ dbname = system_path(arg, origin::user);
+ dbname_type = unmanaged_db;
+ }
+}
+#endif
+
+HIDE(roster_cache_performance_log)
+GROUPED_SIMPLE_OPTION(globals, roster_cache_performance_log, "roster-cache-performance-log",
+ system_path,
+ gettext_noop("log roster cache statistic to the given file"))
+
+SIMPLE_OPTION(depth, "depth", restricted_long<0>,
+ gettext_noop("limit the number of levels of directories to descend"))
+
+
+OPTSET(diff_options)
+OPTSET(au_diff_options)
+OPTSET_REL(diff_options, au_diff_options)
+
+GROUPED_SIMPLE_OPTION(diff_options, external_diff_args, "diff-args", std::string,
+ gettext_noop("argument to pass external diff hook"))
+GROUPED_SIMPLE_OPTION(au_diff_options, reverse, "reverse", bool,
+ gettext_noop("reverse order of diff"))
+GROUPED_SIMPLE_OPTION(diff_options, no_show_encloser, "no-show-encloser/show-encloser", bool,
+ gettext_noop("do not show the function containing each block of changes"))
+OPTSET_REL(au_diff_options, with_header)
+SIMPLE_OPTION(with_header, "with-header/without-header", bool,
+ gettext_noop("show the matching cset in the diff header"))
+
+OPTVAR(diff_options, diff_type, diff_format, unified_diff)
+OPTION(diff_options, diff_context, false, "context",
+ gettext_noop("use context diff format"))
+#ifdef option_bodies
+{
+ diff_format = context_diff;
+}
+#endif
+OPTION(diff_options, diff_external, false, "external",
+ gettext_noop("use external diff hook for generating diffs"))
+#ifdef option_bodies
+{
+ diff_format = external_diff;
+}
+#endif
+OPTION(diff_options, diff_unified, false, "unified",
+ gettext_noop("use unified diff format"))
+#ifdef option_bodies
+{
+ diff_format = unified_diff;
+}
+#endif
+
+
+SIMPLE_OPTION(diffs, "diffs/no-diffs", bool, gettext_noop("print diffs along with logs"))
+
+SIMPLE_OPTION(attrs_to_drop, "drop-attr", std::set,
+ gettext_noop("when rosterifying, drop attrs entries with the given key"))
+
+SIMPLE_OPTION(dryrun, "dry-run/no-dry-run", bool,
+ gettext_noop("don't perform the operation, just show what would have happened"))
+
+SIMPLE_OPTION(drop_bad_certs, "drop-bad-certs", bool,
+ gettext_noop("drop certs signed by keys we don't know about"))
+
+GROUPED_SIMPLE_OPTION(globals, dump, "dump", system_path,
+ gettext_noop("file to dump debugging log to, on failure"))
+
+SIMPLE_OPTION(exclude, "exclude", args_vector,
+ gettext_noop("leave out anything described by its argument"))
+SIMPLE_OPTION(include, "include", args_vector,
+ gettext_noop("include anything described by its argument"))
+
+SIMPLE_OPTION(bookkeep_only, "bookkeep-only", bool,
+ gettext_noop("only update monotone's internal bookkeeping, not the filesystem"))
+
+SIMPLE_OPTION(move_conflicting_paths,
+ "move-conflicting-paths/no-move-conflicting-paths",
+ bool,
+ gettext_noop("move conflicting, unversioned paths into _MTN/resolutions "
+ "before proceeding with any workspace change"))
+
+OPTSET_REL(globals, ssh_sign)
+SIMPLE_INITIALIZED_OPTION(ssh_sign, "ssh-sign", enum_string, "yes,no,only,check",
+ gettext_noop("controls use of ssh-agent. valid arguments are: "
+ "'yes' to use ssh-agent to make signatures if possible, "
+ "'no' to force use of monotone's internal code, "
+ "'only' to force use of ssh-agent, "
+ "'check' to sign with both and compare"))
+
+SIMPLE_OPTION(force_duplicate_key, "force-duplicate-key", bool,
+ gettext_noop("force genkey to not error out when the named key "
+ "already exists"))
+
+
+GROUPED_SIMPLE_OPTION(globals, help, "help,h", bool, gettext_noop("display help message"))
+
+SIMPLE_OPTION(show_hidden_commands, "hidden/no-hidden", bool,
+ gettext_noop("show hidden commands and options"))
+
+GROUPED_SIMPLE_OPTION(globals, ignore_suspend_certs, "ignore-suspend-certs/no-ignore-suspend-certs", bool,
+ gettext_noop("do not ignore revisions marked as suspended"))
+
+GROUPED_SIMPLE_OPTION(globals, non_interactive, "non-interactive/interactive", bool,
+ gettext_noop("do not prompt the user for input"))
+
+GROUPED_SIMPLE_OPTION(globals, key, "key,k/use-default-key", external_key_name,
+ gettext_noop("sets the key for signatures, using either the key "
+ "name or the key hash"))
+
+GROUPED_SIMPLE_OPTION(globals, key_dir, "keydir", system_path,
+ gettext_noop("set location of key store"))
+
+SIMPLE_OPTION(keys_to_push, "key-to-push", std::vector,
+ gettext_noop("push the specified key even if it hasn't signed anything"))
+
+SIMPLE_OPTION(last, "last", restricted_long<1>,
+ gettext_noop("limit log output to the last number of entries"))
+
+GROUPED_SIMPLE_OPTION(globals, log, "log", system_path,
+ gettext_noop("file to write the log to"))
+
+OPTSET(messages)
+GROUPED_SIMPLE_OPTION(messages, message, "message,m", std::vector,
+ gettext_noop("set commit changelog message"))
+GROUPED_SIMPLE_OPTION(messages, msgfile, "message-file", utf8,
+ gettext_noop("set filename containing commit changelog message"))
+HIDE(no_prefix)
+GROUPED_SIMPLE_OPTION(messages, no_prefix, "no-prefix", bool,
+ gettext_noop("no prefix to message"))
+
+SIMPLE_OPTION(missing, "missing", bool,
+ gettext_noop("perform the operations for files missing from workspace"))
+
+SIMPLE_OPTION(next, "next", restricted_long<1>,
+ gettext_noop("limit log output to the next number of entries"))
+
+SIMPLE_OPTION(no_files, "no-files/files", bool,
+ gettext_noop("exclude files when printing logs"))
+
+SIMPLE_OPTION(no_graph, "no-graph/graph", bool,
+ gettext_noop("do not use ASCII graph to display ancestry"))
+
+SIMPLE_OPTION(no_ignore, "no-respect-ignore/respect-ignore", bool,
+ gettext_noop("do not ignore any files"))
+
+SIMPLE_OPTION(no_merges, "no-merges/merges", bool,
+ gettext_noop("exclude merges when printing logs"))
+
+#ifdef WIN32
+# define NORC_TEXT gettext_noop("do not load %APPDATA%\\monotone\\monotonerc or " \
+ "_MTN\\monotonerc lua files")
+#else
+# define NORC_TEXT gettext_noop("do not load ~/.monotone/monotonerc or " \
+ "_MTN/monotonerc lua files")
+#endif
+GROUPED_SIMPLE_OPTION(globals, norc, "no-standard-rcfiles/standard-rcfiles", bool, NORC_TEXT)
+#undef NORC_TEXT
+
+GROUPED_SIMPLE_OPTION(globals, nostd, "no-builtin-rcfile/builtin-rcfile", bool,
+ gettext_noop("do not load the built-in lua file with the default hooks"))
+
+DEPRECATE(old_norc, gettext_noop("please use --no-standard-rcfiles instead"), 1.0, 2.0)
+OPTION(globals, old_norc, false, "norc",
+ gettext_noop("old version of --no-standard-rcfiles"))
+#ifdef option_bodies
+{ norc = true; }
+#endif
+DEPRECATE(old_nostd, gettext_noop("please use --no-builtin-rcfile instead"), 1.0, 2.0)
+OPTION(globals, old_nostd, false, "nostd",
+ gettext_noop("old version of --no-builtin-rcfile"))
+#ifdef option_bodies
+{ nostd = true; }
+#endif
+
+GROUPED_SIMPLE_OPTION(globals, extra_rcfiles, "rcfile/clear-rcfiles", args_vector,
+ gettext_noop("load extra lua file"))
+
+SIMPLE_OPTION(pidfile, "pid-file/no-pid-file", system_path,
+ gettext_noop("record process id of server"))
+
+OPTSET(verbosity)
+OPTSET_REL(globals, verbosity)
+OPTVAR(verbosity, int, verbosity, 0)
+OPTION(verbosity, set_verbosity, true, "verbosity",
+ gettext_noop("set verbosity level: 0 is default; 1 is print debug messages; "
+ "-1 is hide tickers and progress messages; -2 is also hide warnings"))
+#ifdef option_bodies
+{
+ verbosity = boost::lexical_cast(arg);
+}
+#endif
+
+OPTION(globals, debug, false, "debug",
+ gettext_noop("print debug log to stderr while running (--verbosity=1)"))
+#ifdef option_bodies
+{
+ verbosity = 1;
+}
+#endif
+
+SIMPLE_OPTION(full, "full/concise", bool,
+ gettext_noop("print detailed information"))
+
+OPTION(verbosity, quiet, false, "quiet,q",
+ gettext_noop("suppress verbose, informational and progress messages (set verbosity to -1)"))
+#ifdef option_bodies
+{
+ if (verbosity > -1)
+ verbosity = -1;
+}
+#endif
+
+DEPRECATE(reallyquiet, gettext_noop("please use --verbosity=-2"), 1.0, 2.0)
+OPTION(verbosity, reallyquiet, false, "reallyquiet",
+ gettext_noop("suppress warning, verbose, informational and progress messages (set verbosity to -2)"))
+#ifdef option_bodies
+{
+ verbosity = -2;
+}
+#endif
+
+SIMPLE_OPTION(formatted, "formatted/plain", bool,
+ gettext_noop("automatically run the output through nroff (default if the output is a terminal)"))
+
+
+GROUPED_SIMPLE_OPTION(globals, timestamps, "timestamps", bool,
+ gettext_noop("show timestamps in front of errors, warnings and progress messages"))
+
+SIMPLE_OPTION(recursive, "recursive,R/no-recursive", bool,
+ gettext_noop("also operate on the contents of any listed directories"))
+
+SIMPLE_OPTION(revision, "revision,r",args_vector,
+ gettext_noop("select revision id for operation"))
+
+GROUPED_SIMPLE_OPTION(globals, root, "root", std::string,
+ gettext_noop("limit search for workspace to specified root"))
+
+GROUPED_SIMPLE_OPTION(globals, no_workspace, "no-workspace/allow-workspace", bool,
+ gettext_noop("don't look for a workspace"))
+
+SIMPLE_OPTION(set_default, "set-default/no-set-default", bool,
+ gettext_noop("use the current netsync arguments and options "
+ "as the future default"))
+
+OPTSET_REL(globals, ticker)
+SIMPLE_INITIALIZED_OPTION(ticker, "ticker", enum_string, "count,dot,none",
+ gettext_noop("set ticker style (count|dot|none)"))
+
+SIMPLE_OPTION(from, "from/clear-from", args_vector,
+ gettext_noop("revision(s) to start logging at"))
+
+SIMPLE_OPTION(to, "to/clear-to", args_vector,
+ gettext_noop("revision(s) to stop logging at"))
+
+SIMPLE_OPTION(unknown, "unknown/no-unknown", bool,
+ gettext_noop("perform the operations for unknown files from workspace"))
+
+GROUPED_SIMPLE_OPTION(globals, version, "version", bool,
+ gettext_noop("print version number, then exit"))
+
+
+OPTSET(automate_inventory_opts)
+
+OPTSET_REL(automate_inventory_opts, no_ignored)
+SIMPLE_OPTION(no_ignored, "no-ignored/ignored", bool,
+ gettext_noop("don't output ignored files"))
+OPTSET_REL(automate_inventory_opts, no_unknown)
+SIMPLE_OPTION(no_unknown, "no-unknown/unknown",bool,
+ gettext_noop("don't output unknown files"))
+OPTSET_REL(automate_inventory_opts, no_unchanged)
+SIMPLE_OPTION(no_unchanged, "no-unchanged/unchanged", bool,
+ gettext_noop("don't output unchanged files"))
+OPTSET_REL(automate_inventory_opts, no_corresponding_renames)
+SIMPLE_OPTION(no_corresponding_renames, "no-corresponding-renames/corresponding-renames", bool,
+ gettext_noop("don't output corresponding renames if restricted on such nodes"))
+
+
+OPTSET(resolve_conflicts_opts)
+OPTVAR(resolve_conflicts_opts, bookkeeping_path,
+ resolve_conflicts_file, "_MTN/conflicts")
+
+OPTION(resolve_conflicts_opts, resolve_conflicts_file, true, "resolve-conflicts-file",
+ gettext_noop("use file to resolve conflicts"))
+#ifdef option_bodies
+{
+ // we can't call bookkeeping_path::external_string_is_bookkeeping_path
+ // here, because we haven't found the workspace yet.
+ E(bookkeeping_path::internal_string_is_bookkeeping_path(utf8(arg, origin::user)),
+ origin::user,
+ F("conflicts file must be under _MTN"));
+ resolve_conflicts_file = bookkeeping_path(arg, origin::user);
+ resolve_conflicts = true;
+}
+#endif
+
+OPTSET_REL(resolve_conflicts_opts, resolve_conflicts)
+SIMPLE_OPTION(resolve_conflicts, "resolve-conflicts/no-resolve-conflicts", bool,
+ gettext_noop("specify conflict resolutions in a file, instead of interactively"))
+
+OPTSET(conflicts_opts)
+OPTVAR(conflicts_opts, bookkeeping_path, conflicts_file, bookkeeping_path("_MTN/conflicts"))
+
+OPTION(conflicts_opts, conflicts_file, true, "conflicts-file",
+ gettext_noop("file in which to store conflicts"))
+#ifdef option_bodies
+{
+ // we can't call bookkeeping_path::external_string_is_bookkeeping_path
+ // here, because we haven't found the workspace yet.
+ E(bookkeeping_path::internal_string_is_bookkeeping_path(utf8(arg, origin::user)),
+ origin::user,
+ F("conflicts file must be under _MTN"));
+ conflicts_file = bookkeeping_path(arg, origin::user);
+}
+#endif
+
+SIMPLE_OPTION(use_one_changelog, "use-one-changelog", bool,
+ gettext_noop("use only one changelog cert for the git commit message"))
+
+SIMPLE_OPTION(authors_file, "authors-file", system_path,
+ gettext_noop("file mapping author names from original to new values"))
+
+SIMPLE_OPTION(branches_file, "branches-file", system_path,
+ gettext_noop("file mapping branch names from original to new values "))
+
+SIMPLE_INITIALIZED_OPTION(refs, "refs", enum_string_set, "revs,roots,leaves",
+ gettext_noop("include git refs for 'revs', 'roots' or 'leaves'"))
+
+SIMPLE_OPTION(log_revids, "log-revids/no-log-revids", bool,
+ gettext_noop("include revision ids in commit logs"))
+
+SIMPLE_OPTION(log_certs, "log-certs/no-log-certs", bool,
+ gettext_noop("include standard cert values in commit logs"))
+
+SIMPLE_OPTION(import_marks, "import-marks", system_path,
+ gettext_noop("load the internal marks table before exporting revisions"))
+
+SIMPLE_OPTION(export_marks, "export-marks", system_path,
+ gettext_noop("save the internal marks table after exporting revisions"))
+
+// clean up after ourselves
+#undef SIMPLE_OPTION
+#undef SIMPLE_OPTION_BODY
+#undef GROUPED_SIMPLE_OPTION
+#undef SIMPLE_INITIALIZED_OPTION
+#undef COMMA
+
+// Local Variables:
+// mode: C++
+// fill-column: 76
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: