monotone

monotone Mtn Source Tree

Root/app_state.cc

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

Archive Download this file

Branches

Tags

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