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
78// Wrapper class to ensure Botan is properly initialized and deinitialized.
79struct botan_library
80{
81 botan_library() {
82 Botan::InitializerOptions options("thread_safe=0 selftest=0 seed_rng=1 "
83 "use_engines=0 secure_memory=1 "
84 "fips140=0");
85 Botan::LibraryInitializer::initialize(options);
86 }
87 ~botan_library() {
88 Botan::LibraryInitializer::deinitialize();
89 }
90};
91
92// Similarly, for the global ui object. (We do not want to use global
93// con/destructors for this, as they execute outside the protection of
94// main.cc's signal handlers.)
95struct ui_library
96{
97 ui_library() {
98 ui.initialize();
99 }
100 ~ui_library() {
101 ui.deinitialize();
102 }
103};
104
105
106// This is in a separate procedure so it can be called from code that's called
107// before cpp_main(), such as program option object creation code. It's made
108// so it can be called multiple times as well.
109void localize_monotone()
110{
111 static int init = 0;
112 if (!init)
113 {
114 setlocale(LC_ALL, "");
115 bindtextdomain(PACKAGE, get_locale_dir().c_str());
116 textdomain(PACKAGE);
117 init = 1;
118 }
119}
120
121option::concrete_option_set
122read_global_options(options & opts, args_vector & args)
123{
124 option::concrete_option_set optset =
125 options::opts::all_options().instantiate(&opts);
126 optset.from_command_line(args);
127
128 return optset;
129}
130
131// read command-line options and return the command name
132commands::command_id read_options(option::concrete_option_set & optset, options & opts, args_vector & args)
133{
134 commands::command_id cmd;
135
136 if (!opts.args.empty())
137 {
138 // There are some arguments remaining in the command line. Try first
139 // to see if they are a command.
140 cmd = commands::complete_command(opts.args);
141 I(!cmd.empty());
142
143 // Reparse options now that we know what command-specific options
144 // are allowed.
145 options::options_type cmdopts = commands::command_options(cmd);
146 optset.reset();
147 optset = (options::opts::globals() | cmdopts).instantiate(&opts);
148 optset.from_command_line(args, false);
149
150 // Remove the command name from the arguments. Rember that the group
151 // is not taken into account.
152 I(opts.args.size() >= cmd.size() - 1);
153
154 for (args_vector::size_type i = 1; i < cmd.size(); i++)
155 {
156 I(cmd[i]().find(opts.args[0]()) == 0);
157 opts.args.erase(opts.args.begin());
158 }
159 }
160
161 return cmd;
162}
163
164int
165cpp_main(int argc, char ** argv)
166{
167 int ret = 0;
168
169 // go-go gadget i18n
170 localize_monotone();
171
172 // set up global ui object - must occur before anything that might try to
173 // issue a diagnostic
174 ui_library acquire_ui;
175
176 // we want to catch any early informative_failures due to charset
177 // conversion etc
178 try
179 {
180 // Set up the global sanity object. No destructor is needed and
181 // therefore no wrapper object is needed either.
182 global_sanity.initialize(argc, argv, setlocale(LC_ALL, 0));
183
184 // Set up secure memory allocation etc
185 botan_library acquire_botan;
186
187 // Record where we are. This has to happen before any use of
188 // boost::filesystem.
189 save_initial_path();
190
191 // decode all argv values into a UTF-8 array
192 args_vector args;
193 for (int i = 1; i < argc; ++i)
194 {
195 external ex(argv[i]);
196 utf8 ut;
197 system_to_utf8(ex, ut);
198 args.push_back(arg_type(ut));
199 }
200
201 // find base name of executable, convert to utf8, and save it in the
202 // global ui object
203 {
204 utf8 argv0_u;
205 system_to_utf8(external(argv[0]), argv0_u);
206 string prog_name = system_path(argv0_u).basename()();
207 if (prog_name.rfind(".exe") == prog_name.size() - 4)
208 prog_name = prog_name.substr(0, prog_name.size() - 4);
209 ui.prog_name = prog_name;
210 I(!ui.prog_name.empty());
211 }
212
213 app_state app;
214 try
215 {
216 // read global options first
217 // command specific options will be read below
218 args_vector opt_args(args);
219 option::concrete_option_set optset = read_global_options(app.opts, opt_args);
220
221 if (app.opts.version_given)
222 {
223 print_version();
224 return 0;
225 }
226
227 if (app.opts.dbname_given)
228 {
229 if (!app.opts.dbname.empty())
230 app.db.set_filename(app.opts.dbname);
231 }
232
233 if (app.opts.key_dir_given || app.opts.conf_dir_given)
234 {
235 if (!app.opts.key_dir.empty())
236 app.keys.set_key_dir(app.opts.key_dir);
237 }
238
239 // at this point we allow a workspace (meaning search for it
240 // and if found read _MTN/options, but don't use the data quite
241 // yet, and read all the monotonercs). Processing the data
242 // from _MTN/options happens later.
243 // Certain commands may subsequently require a workspace or fail
244 // if we didn't find one at this point.
245 app.allow_workspace();
246
247 // now grab any command specific options and parse the command
248 // this needs to happen after the monotonercs have been read
249 commands::command_id cmd = read_options(optset, app.opts, opt_args);
250
251 if (!app.found_workspace)
252 global_sanity.set_dump_path((app.opts.conf_dir / "dump")
253 .as_external());
254
255 app.lua.hook_note_mtn_startup(args);
256
257 // stop here if they asked for help
258 if (app.opts.help)
259 {
260 throw usage(cmd);
261 }
262
263 // main options processed, now invoke the
264 // sub-command w/ remaining args
265 if (cmd.empty())
266 {
267 throw usage(commands::command_id());
268 }
269 else
270 {
271 commands::process(app, cmd, app.opts.args);
272 // The command will raise any problems itself through
273 // exceptions. If we reach this point, it is because it
274 // worked correctly.
275 return 0;
276 }
277 }
278 catch (option::option_error const & e)
279 {
280 N(false, i18n_format("%s") % e.what());
281 }
282 catch (usage & u)
283 {
284 // we send --help output to stdout, so that "mtn --help | less" works
285 // but we send error-triggered usage information to stderr, so that if
286 // you screw up in a script, you don't just get usage information sent
287 // merrily down your pipes.
288 std::ostream & usage_stream = (app.opts.help ? cout : cerr);
289
290 string visibleid;
291 if (!u.which.empty())
292 visibleid = join_words(vector< utf8 >(u.which.begin() + 1,
293 u.which.end()))();
294
295 usage_stream << F("Usage: %s [OPTION...] command [ARG...]") %
296 ui.prog_name << "\n\n";
297 usage_stream << options::opts::globals().instantiate(&app.opts).
298 get_usage_str() << '\n';
299
300 // Make sure to hide documentation that's not part of
301 // the current command.
302 options::options_type cmd_options =
303 commands::command_options(u.which);
304 if (!cmd_options.empty())
305 {
306 usage_stream << F("Options specific to '%s %s':") %
307 ui.prog_name % visibleid << "\n\n";
308 usage_stream << cmd_options.instantiate(&app.opts).
309 get_usage_str() << '\n';
310 }
311
312 commands::explain_usage(u.which, usage_stream);
313 if (app.opts.help)
314 return 0;
315 else
316 return 2;
317
318 }
319 }
320 catch (informative_failure & inf)
321 {
322 ui.inform(inf.what());
323 return 1;
324 }
325 catch (ios_base::failure const & ex)
326 {
327 // an error has already been printed
328 return 1;
329 }
330 catch (std::bad_alloc)
331 {
332 ui.inform(_("error: memory exhausted"));
333 return 1;
334 }
335 catch (std::exception const & ex)
336 {
337 ui.fatal_exception (ex);
338 return 3;
339 }
340 catch (...)
341 {
342 ui.fatal_exception ();
343 return 3;
344 }
345
346 // control cannot reach this point
347 ui.fatal("impossible: reached end of cpp_main");
348 return 3;
349}
350
351// Local Variables:
352// mode: C++
353// fill-column: 76
354// c-file-style: "gnu"
355// indent-tabs-mode: nil
356// End:
357// 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