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