monotone

monotone Mtn Source Tree

Root/app_state.cc

1#include <iostream>
2#include <string>
3#include <vector>
4#include <cstdlib> // for strtoul()
5
6#include <boost/filesystem/path.hpp>
7#include <boost/filesystem/operations.hpp>
8#include <boost/filesystem/convenience.hpp>
9#include <boost/filesystem/exception.hpp>
10
11#include "app_state.hh"
12#include "database.hh"
13#include "file_io.hh"
14#include "sanity.hh"
15#include "transforms.hh"
16#include "work.hh"
17#include "platform.hh"
18
19// copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com>
20// all rights reserved.
21// licensed to the public under the terms of the GNU GPL (>= 2)
22// see the file COPYING for details
23
24using namespace std;
25
26static string const database_option("database");
27static string const branch_option("branch");
28static string const key_option("key");
29static string const keydir_option("keydir");
30
31app_state::app_state()
32 : branch_name(""), db(system_path()), keys(this), stdhooks(true),
33 rcfiles(true), diffs(false),
34 no_merges(false), set_default(false), verbose(false), search_root("/"),
35 cvspull_full(),
36 depth(-1), last(-1), diff_format(unified_diff), diff_args_provided(false),
37 use_lca(false), execute(false), bind_address(""), bind_port(""),
38 missing(false), unknown(false),
39 confdir(get_default_confdir()), have_set_key_dir(false)
40{
41 db.set_app(this);
42 lua.set_app(this);
43 keys.set_key_dir(confdir / "keys");
44}
45
46app_state::~app_state()
47{
48}
49
50void
51app_state::set_is_explicit_option (int option_id)
52{
53 explicit_option_map[option_id] = true;
54}
55
56bool
57app_state::is_explicit_option(int option_id) const
58{
59 std::map<int, bool>::const_iterator i = explicit_option_map.find(option_id);
60 if (i == explicit_option_map.end()) return false;
61 return i->second;
62}
63
64void
65app_state::allow_working_copy()
66{
67 L(F("initializing from directory %s\n") % fs::initial_path().string());
68 found_working_copy = find_and_go_to_working_copy(search_root);
69
70 if (found_working_copy)
71 {
72 read_options();
73
74 if (!options[database_option]().empty())
75 {
76 system_path dbname = system_path(options[database_option]);
77 db.set_filename(dbname);
78 }
79
80 if (!options[keydir_option]().empty())
81 {
82 system_path keydir = system_path(options[keydir_option]);
83 set_key_dir(keydir);
84 }
85
86 if (branch_name().empty())
87 branch_name = options[branch_option];
88 L(F("branch name is '%s'\n") % branch_name());
89 internalize_rsa_keypair_id(options[key_option], signing_key);
90
91 if (global_sanity.filename.empty())
92 {
93 bookkeeping_path dump_path;
94 get_local_dump_path(dump_path);
95 L(F("setting dump path to %s\n") % dump_path);
96 // the 'true' means that, e.g., if we're running checkout, then it's
97 // okay for dumps to go into our starting working dir's MT rather
98 // than the checked-out dir's MT.
99 global_sanity.filename = system_path(dump_path, false);
100 }
101 }
102 load_rcfiles();
103}
104
105void
106app_state::require_working_copy(std::string const & explanation)
107{
108 N(found_working_copy,
109 F("working copy directory required but not found%s%s")
110 % (explanation.empty() ? "" : "\n") % explanation);
111 write_options();
112}
113
114void
115app_state::create_working_copy(system_path const & new_dir)
116{
117 N(!new_dir.empty(), F("invalid directory ''"));
118
119 L(F("creating working copy in %s\n") % new_dir);
120
121 mkdir_p(new_dir);
122 go_to_working_copy(new_dir);
123
124 N(!directory_exists(bookkeeping_root),
125 F("monotone bookkeeping directory '%s' already exists in '%s'\n")
126 % bookkeeping_root % new_dir);
127
128 L(F("creating bookkeeping directory '%s' for working copy in '%s'\n")
129 % bookkeeping_root % new_dir);
130
131 mkdir_p(bookkeeping_root);
132
133 make_branch_sticky();
134
135 write_options();
136
137 blank_user_log();
138
139 if (lua.hook_use_inodeprints())
140 enable_inodeprints();
141
142 load_rcfiles();
143}
144
145void
146app_state::set_restriction(path_set const & valid_paths,
147 vector<utf8> const & paths,
148 bool respect_ignore)
149{
150 static file_path root = file_path_internal("");
151 restrictions.clear();
152 excludes.clear();
153 for (vector<utf8>::const_iterator i = paths.begin(); i != paths.end(); ++i)
154 {
155 file_path p = file_path_external(*i);
156
157 if (respect_ignore && lua.hook_ignore_file(p))
158 {
159 L(F("'%s' ignored by restricted path set\n") % p);
160 continue;
161 }
162
163 N(p == root || valid_paths.find(p) != valid_paths.end(),
164 F("unknown path '%s'\n") % p);
165
166 L(F("'%s' added to restricted path set\n") % p);
167 restrictions.insert(p);
168 }
169
170 for (std::set<utf8>::const_iterator i = exclude_patterns.begin();
171 i != exclude_patterns.end(); ++i)
172 {
173 file_path p = file_path_external(*i);
174
175 if (respect_ignore && lua.hook_ignore_file(p))
176 {
177 L(F("'%s' ignored by excluded path set\n") % p);
178 continue;
179 }
180
181 N(p == root || valid_paths.find(p) != valid_paths.end(),
182 F("unknown path '%s'\n") % p);
183
184 L(F("'%s' added to excluded path set\n") % p);
185 excludes.insert(p);
186 }
187
188 // if user supplied a depth but provided no paths
189 // assume current directory
190 if ((depth != -1) && restrictions.empty())
191 {
192 restrictions.insert(file_path_external(utf8(".")));
193 }
194}
195
196bool
197app_state::restriction_includes(file_path const & path)
198{
199 static file_path root = file_path_internal("");
200
201 if (restrictions.empty())
202 {
203 if (!excludes.empty())
204 {
205 if (excludes.find(root) != excludes.end())
206 return false;
207 fs::path test = fs::path(path.as_external(), fs::native);
208
209 while (!test.empty())
210 {
211 L(F("checking excluded path set for '%s'\n") % test.string());
212
213 file_path p = file_path_internal(test.string());
214 path_set::const_iterator i = excludes.find(p);
215
216 if (i != excludes.end())
217 {
218 L(F("path '%s' found in excluded path set; '%s' excluded\n")
219 % test.string() % path);
220 return false;
221 }
222
223 test = test.branch_path();
224 }
225 }
226 return true;
227 }
228
229 bool user_supplied_depth = (depth != -1);
230
231 fs::path test = fs::path(path.as_external(), fs::native);
232 long branch_depth = 0;
233 long max_depth = depth + 1;
234
235 while (!test.empty())
236 {
237 L(F("checking restricted path set for '%s'\n") % test.string());
238
239 file_path p = file_path_internal(test.string());
240 path_set::const_iterator i = restrictions.find(p);
241 path_set::const_iterator j = excludes.find(p);
242
243 if (i != restrictions.end())
244 {
245 L(F("path '%s' found in restricted path set; '%s' included\n")
246 % test.string() % path);
247 return true;
248 }
249 else if (j != excludes.end())
250 {
251 L(F("path '%s' found in excluded path set; '%s' excluded\n")
252 % test.string() % path);
253 return false;
254 }
255
256 if (user_supplied_depth && (max_depth == branch_depth)) return false;
257 test = test.branch_path();
258 ++branch_depth;
259 }
260
261 // a path that normalizes to "." means that the restriction has been
262 // essentially cleared (all files are included). rather than be
263 // careful about what goes in to the restricted path set we just
264 // check for this special case here.
265 if (restrictions.find(root) != restrictions.end())
266 {
267 return (!user_supplied_depth) || (branch_depth <= max_depth);
268 }
269
270 return false;
271}
272
273void
274app_state::set_database(system_path const & filename)
275{
276 if (!filename.empty()) db.set_filename(filename);
277
278 options[database_option] = filename.as_internal();
279}
280
281void
282app_state::set_key_dir(system_path const & filename)
283{
284 if (!filename.empty())
285 {
286 keys.set_key_dir(filename);
287 have_set_key_dir = true;
288 }
289
290 options[keydir_option] = filename.as_internal();
291}
292
293void
294app_state::set_branch(utf8 const & branch)
295{
296 branch_name = branch();
297}
298
299void
300app_state::make_branch_sticky()
301{
302 options[branch_option] = branch_name();
303 if (found_working_copy)
304 {
305 // already have a working copy, can (must) write options directly,
306 // because no-one else will do so
307 // if we don't have a working copy yet, then require_working_copy (for
308 // instance) will call write_options when it finds one.
309 write_options();
310 }
311}
312
313void
314app_state::set_signing_key(utf8 const & key)
315{
316 internalize_rsa_keypair_id(key, signing_key);
317
318 options[key_option] = key;
319}
320
321void
322app_state::add_key_to_push(utf8 const & key)
323{
324 rsa_keypair_id k;
325 internalize_rsa_keypair_id(key, k);
326 keys_to_push.push_back(k);
327}
328
329void
330app_state::set_root(system_path const & path)
331{
332 require_path_is_directory(path,
333 F("search root '%s' does not exist") % path,
334 F("search root '%s' is not a directory\n") % path);
335 search_root = path;
336 L(F("set search root to %s\n") % search_root);
337}
338
339void
340app_state::set_message(utf8 const & m)
341{
342 message = m;
343}
344
345void
346app_state::set_message_file(utf8 const & m)
347{
348 message_file = m;
349}
350
351void
352app_state::set_date(utf8 const & d)
353{
354 date = d;
355}
356
357void
358app_state::set_author(utf8 const & a)
359{
360 author = a;
361}
362
363void
364app_state::set_depth(long d)
365{
366 N(d >= 0,
367 F("negative depth not allowed\n"));
368 depth = d;
369}
370
371void
372app_state::set_since(utf8 const & s)
373{
374 sync_since = s;
375}
376
377void
378app_state::set_last(long l)
379{
380 N(l > 0,
381 F("negative or zero last not allowed\n"));
382 last = l;
383}
384
385void
386app_state::set_pidfile(system_path const & p)
387{
388 pidfile = p;
389}
390
391void
392app_state::add_revision(utf8 const & selector)
393{
394 revision_selectors.push_back(selector);
395}
396
397void
398app_state::add_exclude(utf8 const & exclude_pattern)
399{
400 exclude_patterns.insert(exclude_pattern);
401}
402
403void
404app_state::set_diff_format(diff_type dtype)
405{
406 diff_format = dtype;
407}
408
409void
410app_state::set_diff_args(utf8 const & args)
411{
412 diff_args_provided = true;
413 diff_args = args;
414}
415
416void
417app_state::set_stdhooks(bool b)
418{
419 stdhooks = b;
420}
421
422void
423app_state::set_rcfiles(bool b)
424{
425 rcfiles = b;
426}
427
428void
429app_state::set_verbose(bool b)
430{
431 verbose = b;
432}
433
434void
435app_state::add_rcfile(utf8 const & filename)
436{
437 extra_rcfiles.push_back(filename);
438}
439
440void
441app_state::set_confdir(system_path const & cd)
442{
443 confdir = cd;
444 if (!have_set_key_dir)
445 keys.set_key_dir(cd / "keys");
446}
447
448system_path
449app_state::get_confdir()
450{
451 return confdir;
452}
453
454// rc files are loaded after we've changed to the working copy directory so
455// that MT/monotonerc can be loaded between ~/.monotone/monotonerc and other
456// rcfiles
457
458void
459app_state::load_rcfiles()
460{
461 // built-in rc settings are defaults
462
463 if (stdhooks)
464 lua.add_std_hooks();
465
466 // ~/.monotone/monotonerc overrides that, and
467 // MT/monotonerc overrides *that*
468
469 if (rcfiles)
470 {
471 system_path default_rcfile;
472 bookkeeping_path working_copy_rcfile;
473 lua.default_rcfilename(default_rcfile);
474 lua.working_copy_rcfilename(working_copy_rcfile);
475 lua.load_rcfile(default_rcfile, false);
476 lua.load_rcfile(working_copy_rcfile, false);
477 }
478
479 // command-line rcfiles override even that
480
481 for (vector<utf8>::const_iterator i = extra_rcfiles.begin();
482 i != extra_rcfiles.end(); ++i)
483 {
484 lua.load_rcfile(*i);
485 }
486}
487
488void
489app_state::read_options()
490{
491 bookkeeping_path o_path;
492 get_options_path(o_path);
493 try
494 {
495 if (path_exists(o_path))
496 {
497 data dat;
498 read_data(o_path, dat);
499 read_options_map(dat, options);
500 }
501 }
502 catch(std::exception & e)
503 {
504 W(F("Failed to read options file %s") % o_path);
505 }
506}
507
508void
509app_state::write_options()
510{
511 bookkeeping_path o_path;
512 get_options_path(o_path);
513 try
514 {
515 data dat;
516 write_options_map(dat, options);
517 write_data(o_path, dat);
518 }
519 catch(std::exception & e)
520 {
521 W(F("Failed to write options file %s") % o_path);
522 }
523}

Archive Download this file

Branches

Tags

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