monotone

monotone Mtn Source Tree

Root/monotone.cc

1// copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com>
2// all rights reserved.
3// licensed to the public under the terms of the GNU GPL (>= 2)
4// see the file COPYING for details
5
6#include <config.h>
7
8#include <popt.h>
9#include <cstdio>
10#include <iterator>
11#include <iostream>
12
13#include <stdlib.h>
14
15#include "app_state.hh"
16#include "commands.hh"
17#include "sanity.hh"
18#include "cleanup.hh"
19#include "file_io.hh"
20#include "transforms.hh"
21#include "ui.hh"
22
23#define OPT_VERBOSE 1
24#define OPT_HELP 2
25#define OPT_NOSTD 3
26#define OPT_NORC 4
27#define OPT_RCFILE 5
28#define OPT_DB_NAME 6
29#define OPT_KEY_NAME 7
30#define OPT_BRANCH_NAME 8
31#define OPT_QUIET 9
32#define OPT_VERSION 10
33
34// main option processing and exception handling code
35
36using namespace std;
37
38char * argstr = NULL;
39
40struct poptOption options[] =
41 {
42 {"verbose", 0, POPT_ARG_NONE, NULL, OPT_VERBOSE, "send log to stderr while running", NULL},
43 {"quiet", 0, POPT_ARG_NONE, NULL, OPT_QUIET, "suppress log and progress messages", NULL},
44 {"help", 0, POPT_ARG_NONE, NULL, OPT_HELP, "display help message", NULL},
45 {"nostd", 0, POPT_ARG_NONE, NULL, OPT_NOSTD, "do not load standard lua hooks", NULL},
46 {"norc", 0, POPT_ARG_NONE, NULL, OPT_NORC, "do not load a ~/.monotonerc lua file", NULL},
47 {"rcfile", 0, POPT_ARG_STRING, &argstr, OPT_RCFILE, "load extra rc file", NULL},
48 {"key", 0, POPT_ARG_STRING, &argstr, OPT_KEY_NAME, "set key for signatures", NULL},
49 {"db", 0, POPT_ARG_STRING, &argstr, OPT_DB_NAME, "set name of database", NULL},
50 {"branch", 0, POPT_ARG_STRING, &argstr, OPT_BRANCH_NAME, "select branch cert for operation", NULL},
51 {"version", 0, POPT_ARG_NONE, NULL, OPT_VERSION, "print version number, then exit", NULL},
52 { NULL, 0, 0, NULL, 0 }
53 };
54
55// there are 3 variables which serve as roots for our system.
56//
57// "global_sanity" is a global object, which contains the error logging
58// system, which is constructed once and used by any nana logging actions.
59// see cleanup.hh for it
60//
61// "cmds" is a static table in commands.cc which associates top-level
62// commands, given on the command-line, to various version control tasks.
63//
64// "app_state" is a non-static object type which contains all the
65// application state (filesystem, database, network, lua interpreter,
66// etc). you can make more than one of these, and feed them to a command in
67// the command table.
68
69// our main function is run inside a boost execution monitor. this monitor
70// portably sets up handlers for various fatal conditions (signals, win32
71// structured exceptions, etc) and provides a uniform reporting interface
72// to any exceptions it catches. we augment this with a helper atexit()
73// which will also dump our internal logs when an explicit clean shutdown
74// flag is not set.
75//
76// in other words, this program should *never* unexpectedly terminate
77// without dumping some diagnostics.
78
79static bool clean_shutdown;
80void dumper()
81{
82 if (!clean_shutdown)
83 global_sanity.dump_buffer();
84}
85
86
87struct utf8_argv
88{
89 int argc;
90 char **argv;
91
92 explicit utf8_argv(int ac, char **av)
93 : argc(ac),
94 argv(static_cast<char **>(malloc(ac * sizeof(char *))))
95 {
96 I(argv != NULL);
97 for (int i = 0; i < argc; ++i)
98 {
99external ext(av[i]);
100utf8 utf;
101system_to_utf8(ext, utf);
102argv[i] = static_cast<char *>(malloc(utf().size() + 1));
103I(argv[i] != NULL);
104memcpy(argv[i], utf().data(), utf().size());
105argv[i][utf().size()] = static_cast<char>(0);
106 }
107 }
108
109 ~utf8_argv()
110 {
111 if (argv != NULL)
112 {
113for (int i = 0; i < argc; ++i)
114 if (argv[i] != NULL)
115 free(argv[i]);
116free(argv);
117 }
118 }
119};
120
121int cpp_main(int argc, char ** argv)
122{
123
124 putenv("BOOST_PRG_MON_CONFIRM=no");
125 clean_shutdown = false;
126 atexit(&dumper);
127
128 // go-go gadget i18n
129
130 setlocale(LC_CTYPE, "");
131 setlocale(LC_MESSAGES, "");
132 bindtextdomain(PACKAGE, LOCALEDIR);
133 textdomain(PACKAGE);
134
135 // decode all argv values into a UTF-8 array
136
137 save_initial_path();
138 app_state app;
139 utf8_argv uv(argc, argv);
140
141 // prepare for arg parsing
142
143 cleanup_ptr<poptContext, poptContext>
144 ctx(poptGetContext(NULL, argc, (char const **) uv.argv, options, 0),
145&poptFreeContext);
146
147 // process main program options
148
149 int ret = 0;
150 int opt;
151 bool stdhooks = true, rcfile = true;
152 bool requested_help = false;
153
154 poptSetOtherOptionHelp(ctx(), "[OPTION...] command [ARGS...]\n");
155
156 vector<string> extra_rcfiles;
157
158 try
159 {
160 while ((opt = poptGetNextOpt(ctx())) > 0)
161{
162 switch(opt)
163 {
164 case OPT_VERBOSE:
165 global_sanity.set_verbose();
166 break;
167
168 case OPT_QUIET:
169 global_sanity.set_quiet();
170 break;
171
172 case OPT_NOSTD:
173 stdhooks = false;
174 break;
175
176 case OPT_NORC:
177 rcfile = false;
178 break;
179
180 case OPT_RCFILE:
181 extra_rcfiles.push_back(absolutify(tilde_expand(string(argstr))));
182 break;
183
184 case OPT_DB_NAME:
185 app.set_database(absolutify(tilde_expand(string(argstr))));
186 break;
187
188 case OPT_KEY_NAME:
189 app.set_signing_key(string(argstr));
190 break;
191
192 case OPT_BRANCH_NAME:
193 app.set_branch(string(argstr));
194 break;
195
196 case OPT_VERSION:
197 cout << PACKAGE_STRING << endl;
198 clean_shutdown = true;
199 return 0;
200
201 case OPT_HELP:
202 default:
203 requested_help = true;
204 break;
205 }
206}
207
208 // stop here if they asked for help
209
210 if (requested_help)
211{
212 if (poptPeekArg(ctx()))
213 {
214 string cmd(poptGetArg(ctx()));
215 throw usage(cmd);
216 }
217 else
218 throw usage("");
219}
220
221 // built-in rc settings are defaults
222
223 if (stdhooks)
224app.lua.add_std_hooks();
225
226 // ~/.monotonerc overrides that, and
227 // MT/monotonerc overrides *that*
228
229 if (rcfile)
230{
231 fs::path default_rcfile;
232 fs::path working_copy_rcfile;
233 app.lua.default_rcfilename(default_rcfile);
234 app.lua.working_copy_rcfilename(working_copy_rcfile);
235 app.lua.add_rcfile(default_rcfile);
236 app.lua.add_rcfile(working_copy_rcfile);
237}
238
239 // command-line rcfiles override even that
240
241 for (vector<string>::const_iterator i = extra_rcfiles.begin();
242 i != extra_rcfiles.end(); ++i)
243{
244 app.lua.add_rcfile(mkpath(*i));
245}
246
247 // main options processed, now invoke the
248 // sub-command w/ remaining args
249
250 if (!poptPeekArg(ctx()))
251{
252 throw usage("");
253}
254 else
255{
256 string cmd(poptGetArg(ctx()));
257 vector<utf8> args;
258 while(poptPeekArg(ctx()))
259 {
260 args.push_back(utf8(string(poptGetArg(ctx()))));
261 }
262 ret = commands::process(app, cmd, args);
263}
264 }
265 catch (usage & u)
266 {
267 poptPrintHelp(ctx(), stdout, 0);
268 cout << endl;
269 commands::explain_usage(u.which, cout);
270 clean_shutdown = true;
271 return 0;
272 }
273 catch (informative_failure & inf)
274 {
275 ui.inform(inf.what + string("\n"));
276 clean_shutdown = true;
277 return 1;
278 }
279 catch (...)
280 {
281 // nb: we dump here because it's nicer to get the log dump followed
282 // by the exception printout, when possible. this does *not* mean you
283 // can remove the atexit() hook above, since it dumps when the
284 // execution monitor traps sigsegv / sigabrt etc.
285 global_sanity.dump_buffer();
286 clean_shutdown = true;
287 throw;
288 }
289
290 clean_shutdown = true;
291 return ret;
292}

Archive Download this file

Branches

Tags

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