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