monotone

monotone Mtn Source Tree

Root/monotone.cc

1// Copyright (C) 2002 Graydon Hoare <graydon@pobox.com>
2//
3// This program is made available under the GNU GPL version 2.0 or
4// greater. See the accompanying file COPYING for details.
5//
6// This program is distributed WITHOUT ANY WARRANTY; without even the
7// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8// PURPOSE.
9
10
11#include "base.hh"
12#include <iterator>
13#include <iostream>
14#include <fstream>
15#include <sstream>
16#include <locale.h>
17#include <stdlib.h>
18
19#include "botan/botan.h"
20#include "i18n.h"
21#include "app_state.hh"
22#include "commands.hh"
23#include "sanity.hh"
24#include "cleanup.hh"
25#include "file_io.hh"
26#include "charset.hh"
27#include "ui.hh"
28#include "mt_version.hh"
29#include "option.hh"
30#include "paths.hh"
31#include "sha1.hh"
32#include "simplestring_xform.hh"
33#include "platform.hh"
34
35
36using std::cout;
37using std::cerr;
38using std::string;
39using std::ios_base;
40using std::ostringstream;
41using std::set;
42using std::string;
43using std::vector;
44using std::ios_base;
45
46// main option processing and exception handling code
47
48// options are split into two categories. the first covers global options,
49// which globally affect program behaviour. the second covers options
50// specific to one or more commands. these command-specific options are
51// defined in a single group, with the intent that any command-specific
52// option means the same thing for any command that uses it.
53//
54// "ui" is a global object, through which all messages to the user go.
55// see ui.hh for it
56//
57// "cmds" is a static table in commands.cc which associates top-level
58// commands, given on the command-line, to various version control tasks.
59//
60// "app_state" is a non-static object type which contains all the
61// application state (filesystem, database, network, lua interpreter,
62// etc). you can make more than one of these, and feed them to a command in
63// the command table.
64
65// this file defines cpp_main, which does option processing and sub-command
66// dispatching, and provides the outermost exception catch clauses. it is
67// called by main, in unix/main.cc or win32/main.cc; that function is
68// responsible for trapping fatal conditions reported by the operating
69// system (signals, win32 structured exceptions, etc).
70
71// this program should *never* unexpectedly terminate without dumping some
72// diagnostics. if the fatal condition is an invariant check or anything
73// else that produces a C++ exception caught in this file, the debug logs
74// will be dumped out. if the fatal condition is only caught in the lower-
75// level handlers in main.cc, at least we'll get a friendly error message.
76
77// Wrapper class which ensures proper setup and teardown of the global ui
78// object. (We do not want to use global con/destructors for this, as they
79// execute outside the protection of main.cc's signal handlers.)
80struct ui_library
81{
82 ui_library() { ui.initialize(); }
83 ~ui_library() { ui.deinitialize(); }
84};
85
86// This is in a separate procedure so it can be called from code that's called
87// before cpp_main(), such as program option object creation code. It's made
88// so it can be called multiple times as well.
89void localize_monotone()
90{
91 static int init = 0;
92 if (!init)
93 {
94 setlocale(LC_ALL, "");
95 bindtextdomain(PACKAGE, get_locale_dir().c_str());
96 textdomain(PACKAGE);
97 init = 1;
98 }
99}
100
101option::concrete_option_set
102read_global_options(options & opts, args_vector & args)
103{
104 option::concrete_option_set optset =
105 options::opts::all_options().instantiate(&opts);
106 optset.from_command_line(args);
107
108 return optset;
109}
110
111// read command-line options and return the command name
112commands::command_id read_options(option::concrete_option_set & optset, options & opts, args_vector & args)
113{
114 commands::command_id cmd;
115
116 if (!opts.args.empty())
117 {
118 // There are some arguments remaining in the command line. Try first
119 // to see if they are a command.
120 cmd = commands::complete_command(opts.args);
121 I(!cmd.empty());
122
123 // Reparse options now that we know what command-specific options
124 // are allowed.
125 options::options_type cmdopts = commands::command_options(cmd);
126 optset.reset();
127 optset = (options::opts::globals() | cmdopts).instantiate(&opts);
128 optset.from_command_line(args, false);
129
130 // Remove the command name from the arguments. Rember that the group
131 // is not taken into account.
132 I(opts.args.size() >= cmd.size() - 1);
133
134 for (args_vector::size_type i = 1; i < cmd.size(); i++)
135 {
136 I(cmd[i]().find(opts.args[0]()) == 0);
137 opts.args.erase(opts.args.begin());
138 }
139 }
140
141 return cmd;
142}
143
144int
145cpp_main(int argc, char ** argv)
146{
147 int ret = 0;
148
149 // go-go gadget i18n
150 localize_monotone();
151
152 // set up global ui object - must occur before anything that might try to
153 // issue a diagnostic
154 ui_library acquire_ui;
155
156 // we want to catch any early informative_failures due to charset
157 // conversion etc
158 try
159 {
160 // Set up the global sanity object. No destructor is needed and
161 // therefore no wrapper object is needed either.
162 global_sanity.initialize(argc, argv, setlocale(LC_ALL, 0));
163
164 // Set up secure memory allocation etc
165 Botan::LibraryInitializer acquire_botan("thread_safe=0 selftest=0 "
166 "seed_rng=1 use_engines=0 "
167 "secure_memory=1 fips140=0");
168
169 // Record where we are. This has to happen before any use of
170 // boost::filesystem.
171 save_initial_path();
172
173 // decode all argv values into a UTF-8 array
174 args_vector args;
175 for (int i = 1; i < argc; ++i)
176 {
177 external ex(argv[i]);
178 utf8 ut;
179 system_to_utf8(ex, ut);
180 args.push_back(arg_type(ut));
181 }
182
183 // find base name of executable, convert to utf8, and save it in the
184 // global ui object
185 {
186 utf8 argv0_u;
187 system_to_utf8(external(argv[0]), argv0_u);
188 string prog_name = system_path(argv0_u).basename()();
189 if (prog_name.rfind(".exe") == prog_name.size() - 4)
190 prog_name = prog_name.substr(0, prog_name.size() - 4);
191 ui.prog_name = prog_name;
192 I(!ui.prog_name.empty());
193 }
194
195 app_state app;
196 try
197 {
198 // read global options first
199 // command specific options will be read below
200 args_vector opt_args(args);
201 option::concrete_option_set optset = read_global_options(app.opts, opt_args);
202
203 if (app.opts.version_given)
204 {
205 print_version();
206 return 0;
207 }
208
209 if (app.opts.dbname_given)
210 {
211 if (!app.opts.dbname.empty())
212 app.db.set_filename(app.opts.dbname);
213 }
214
215 if (app.opts.key_dir_given || app.opts.conf_dir_given)
216 {
217 if (!app.opts.key_dir.empty())
218 app.keys.set_key_dir(app.opts.key_dir);
219 }
220
221 // at this point we allow a workspace (meaning search for it
222 // and if found read _MTN/options, but don't use the data quite
223 // yet, and read all the monotonercs). Processing the data
224 // from _MTN/options happens later.
225 // Certain commands may subsequently require a workspace or fail
226 // if we didn't find one at this point.
227 app.allow_workspace();
228
229 // now grab any command specific options and parse the command
230 // this needs to happen after the monotonercs have been read
231 commands::command_id cmd = read_options(optset, app.opts, opt_args);
232
233 if (!app.found_workspace)
234 global_sanity.set_dump_path((app.opts.conf_dir / "dump")
235 .as_external());
236
237 app.lua.hook_note_mtn_startup(args);
238
239 // stop here if they asked for help
240 if (app.opts.help)
241 {
242 throw usage(cmd);
243 }
244
245 // main options processed, now invoke the
246 // sub-command w/ remaining args
247 if (cmd.empty())
248 {
249 throw usage(commands::command_id());
250 }
251 else
252 {
253 commands::process(app, cmd, app.opts.args);
254 // The command will raise any problems itself through
255 // exceptions. If we reach this point, it is because it
256 // worked correctly.
257 return 0;
258 }
259 }
260 catch (option::option_error const & e)
261 {
262 N(false, i18n_format("%s") % e.what());
263 }
264 catch (usage & u)
265 {
266 // we send --help output to stdout, so that "mtn --help | less" works
267 // but we send error-triggered usage information to stderr, so that if
268 // you screw up in a script, you don't just get usage information sent
269 // merrily down your pipes.
270 std::ostream & usage_stream = (app.opts.help ? cout : cerr);
271
272 string visibleid;
273 if (!u.which.empty())
274 visibleid = join_words(vector< utf8 >(u.which.begin() + 1,
275 u.which.end()))();
276
277 usage_stream << F("Usage: %s [OPTION...] command [ARG...]") %
278 ui.prog_name << "\n\n";
279 usage_stream << options::opts::globals().instantiate(&app.opts).
280 get_usage_str() << '\n';
281
282 // Make sure to hide documentation that's not part of
283 // the current command.
284 options::options_type cmd_options =
285 commands::command_options(u.which);
286 if (!cmd_options.empty())
287 {
288 usage_stream << F("Options specific to '%s %s':") %
289 ui.prog_name % visibleid << "\n\n";
290 usage_stream << cmd_options.instantiate(&app.opts).
291 get_usage_str() << '\n';
292 }
293
294 commands::explain_usage(u.which, usage_stream);
295 if (app.opts.help)
296 return 0;
297 else
298 return 2;
299
300 }
301 }
302 catch (informative_failure & inf)
303 {
304 ui.inform(inf.what());
305 return 1;
306 }
307 catch (ios_base::failure const & ex)
308 {
309 // an error has already been printed
310 return 1;
311 }
312 catch (std::bad_alloc)
313 {
314 ui.inform(_("error: memory exhausted"));
315 return 1;
316 }
317 catch (std::exception const & ex)
318 {
319 ui.fatal_exception (ex);
320 return 3;
321 }
322 catch (...)
323 {
324 ui.fatal_exception ();
325 return 3;
326 }
327
328 // control cannot reach this point
329 ui.fatal("impossible: reached end of cpp_main");
330 return 3;
331}
332
333// Local Variables:
334// mode: C++
335// fill-column: 76
336// c-file-style: "gnu"
337// indent-tabs-mode: nil
338// End:
339// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status