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