monotone

monotone Mtn Source Tree

Root/work.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 <boost/regex.hpp>
7#include <sstream>
8
9#include "app_state.hh"
10#include "file_io.hh"
11#include "sanity.hh"
12#include "vocab.hh"
13#include "work.hh"
14
15// working copy / book-keeping file code
16
17using namespace boost;
18using namespace std;
19
20string const work_file_name("work");
21
22class addition_builder : public tree_walker
23{
24 app_state & app;
25 work_set & work;
26 manifest_map & man;
27 bool & rewrite_work;
28public:
29 addition_builder(app_state & a,
30 work_set & w,
31 manifest_map & m,
32 bool & rw) :
33 app(a), work(w), man(m), rewrite_work(rw)
34 {};
35 virtual void visit_file(file_path const & path);
36};
37
38void addition_builder::visit_file(file_path const & path)
39{
40
41 if (book_keeping_file(path()))
42 {
43 P(F("skipping book-keeping file %s\n") % path);
44 return;
45 }
46
47 if (app.lua.hook_ignore_file(path))
48 {
49 P(F("skipping ignorable file %s\n") % path);
50 return;
51 }
52
53 N(work.renames.find(path) == work.renames.end(),
54 F("adding file %s, also scheduled for source of rename") % path);
55
56 for (rename_set::const_iterator i = work.renames.begin();
57 i != work.renames.end(); ++i)
58 N(!(path == i->second),
59 F("adding file %s, also scheduled for target of rename") % path);
60
61 if (work.adds.find(path) != work.adds.end())
62 {
63 P(F("skipping %s, already present in working copy add set\n") % path);
64 return;
65 }
66
67 if (work.dels.find(path) != work.dels.end())
68 {
69 P(F("removing %s from working copy delete set\n") % path);
70 work.dels.erase(path);
71 rewrite_work = true;
72 }
73 else if (man.find(path) != man.end())
74 {
75 P(F("skipping %s, already present in manifest\n") % path);
76 return;
77 }
78 else
79 {
80 P(F("adding %s to working copy add set\n") % path);
81 work.adds.insert(path);
82 rewrite_work = true;
83 }
84}
85
86void build_addition(file_path const & path,
87 app_state & app,
88 work_set & work,
89 manifest_map & man,
90 bool & rewrite_work)
91{
92 addition_builder build(app, work, man, rewrite_work);
93 walk_tree(path, build);
94}
95
96
97
98class deletion_builder : public tree_walker
99{
100 app_state & app;
101 work_set & work;
102 manifest_map & man;
103 bool & rewrite_work;
104public:
105 deletion_builder(app_state & a,
106 work_set & w,
107 manifest_map & m,
108 bool & rw) :
109 app(a), work(w), man(m), rewrite_work(rw)
110 {};
111 virtual void visit_file(file_path const & path);
112};
113
114void deletion_builder::visit_file(file_path const & path)
115{
116
117 if (book_keeping_file(path()))
118 {
119 P(F("skipping book-keeping file %s\n") % path);
120 return;
121 }
122
123 if (app.lua.hook_ignore_file(path))
124 {
125 P(F("skipping ignorable file %s\n") % path);
126 return;
127 }
128
129 N(work.renames.find(path) == work.renames.end(),
130 F("deleting file %s, also scheduled for source of rename") % path);
131
132 for (rename_set::const_iterator i = work.renames.begin();
133 i != work.renames.end(); ++i)
134 N(!(path == i->second),
135 F("deleting file %s, also scheduled for target of rename") % path);
136
137 if (work.dels.find(path) != work.dels.end())
138 {
139 P(F("skipping %s, already present in working copy delete set\n") % path);
140 return;
141 }
142
143 if (work.adds.find(path) != work.adds.end())
144 {
145 P(F("removing %s from working copy add set\n") % path);
146 work.adds.erase(path);
147 rewrite_work = true;
148 }
149 else if (man.find(path) == man.end())
150 {
151 P(F("skipping %s, does not exist in manifest\n") % path);
152 return;
153 }
154 else
155 {
156 P(F("adding %s to working copy delete set\n") % path);
157 work.dels.insert(path);
158 rewrite_work = true;
159 }
160}
161
162void build_deletion(file_path const & path,
163 app_state & app,
164 work_set & work,
165 manifest_map & man,
166 bool & rewrite_work)
167{
168 deletion_builder build(app, work, man, rewrite_work);
169 walk_tree(path, build);
170}
171
172
173class rename_builder : public tree_walker
174{
175 file_path const & src;
176 file_path const & dst;
177 app_state & app;
178 work_set & work;
179 manifest_map & man;
180 bool & rewrite_work;
181public:
182 rename_builder(file_path const & s,
183 file_path const & d,
184 app_state & a,
185 work_set & w,
186 manifest_map & m,
187 bool & rw) :
188 src(s), dst(d),
189 app(a), work(w), man(m), rewrite_work(rw)
190 {}
191 file_path pathsub(file_path const & in);
192 virtual void visit_file(file_path const & path);
193};
194
195
196file_path rename_builder::pathsub(file_path const & in)
197{
198 fs::path sp = mkpath(src());
199 fs::path dp = mkpath(dst());
200 fs::path ip = mkpath(in());
201
202 fs::path::iterator i = ip.begin();
203 for (fs::path::iterator s = sp.begin();
204 s != sp.end(); ++s, ++i)
205 I(i != ip.end());
206
207 fs::path res = dp;
208
209 while (i != ip.end())
210 res /= *i++;
211
212 return file_path(res.string());
213}
214
215
216void rename_builder::visit_file(file_path const & path)
217{
218
219 if (book_keeping_file(path()))
220 {
221 P(F("skipping book-keeping file %s\n") % path);
222 return;
223 }
224
225 if (app.lua.hook_ignore_file(path))
226 {
227 P(F("skipping ignorable file %s\n") % path);
228 return;
229 }
230
231 N(work.dels.find(path) == work.dels.end(),
232 F("moving file %s, also scheduled for deletion") % path);
233
234 N(work.adds.find(path) == work.adds.end(),
235 F("moving file %s, also scheduled for addition") % path);
236
237 for (rename_set::const_iterator i = work.renames.begin();
238 i != work.renames.end(); ++i)
239 N(!(path == i->second),
240 F("renaming file %s, existing target of rename") % path);
241
242 if (work.renames.find(path) != work.renames.end())
243 {
244 P(F("skipping %s, already present in working copy rename set\n") % path);
245 return;
246 }
247
248 if (man.find(path) == man.end())
249 {
250 P(F("skipping %s, does not exist in manifest\n") % path);
251 return;
252 }
253
254 file_path targ = pathsub(path);
255 P(F("adding %s -> %s to working copy rename set\n") % path % targ);
256 work.renames.insert(make_pair(path, targ));
257 rewrite_work = true;
258}
259
260
261void build_rename(file_path const & src,
262 file_path const & dst,
263 app_state & app,
264 work_set & work,
265 manifest_map & man,
266 bool & rewrite_work)
267{
268 rename_builder build(src, dst, app, work, man, rewrite_work);
269 walk_tree(src, build);
270}
271
272
273struct add_to_work_set
274{
275 work_set & work;
276 explicit add_to_work_set(work_set & w) : work(w) {}
277 bool operator()(match_results<std::string::const_iterator, regex::alloc_type> const & res)
278 {
279 std::string action(res[1].first, res[1].second);
280 I(res.size() == 3 || res.size() == 4);
281 file_path path = file_path(std::string(res[2].first, res[2].second));
282 I(work.adds.find(path) == work.adds.end());
283 I(work.dels.find(path) == work.dels.end());
284 I(work.renames.find(path) == work.renames.end());
285
286 if (action == "add")
287 {
288N(res.size() == 3, F("extra junk on work entry for add of %s") % path);
289work.adds.insert(path);
290 }
291 else if (action == "drop")
292 {
293N(res.size() == 3, F("extra junk on work entry for drop of %s") % path);
294work.dels.insert(path);
295 }
296 else if (action == "rename")
297 {
298N(res.size() == 4, F("missing rename target for %s in work set") % path);
299file_path dst = file_path(std::string(res[3].first, res[3].second));
300
301for (path_set::const_iterator a = work.adds.begin();
302 a != work.adds.end(); ++a)
303 I(!(*a == dst));
304
305for (path_set::const_iterator d = work.dels.begin();
306 d != work.dels.end(); ++d)
307 I(!(*d == dst));
308
309for (rename_set::const_iterator r = work.renames.begin();
310 r != work.renames.end(); ++r)
311 I(!(r->second == dst));
312
313work.renames.insert(make_pair(path, dst));
314 }
315 else
316 throw oops("unknown action in work set: " + action);
317
318 return true;
319 }
320};
321
322void read_work_set(data const & dat,
323 work_set & work)
324{
325 regex expr("^(add|drop)\n ([^[:space:]].+)$");
326 regex_grep(add_to_work_set(work), dat(), expr, match_not_dot_newline);
327 regex expr2("^(rename)\n ([^[:space:]].+)\n ([^[:space:]].+)$");
328 regex_grep(add_to_work_set(work), dat(), expr2, match_not_dot_newline);
329}
330
331void write_work_set(data & dat,
332 work_set const & work)
333{
334 ostringstream tmp;
335 for (path_set::const_iterator i = work.dels.begin();
336 i != work.dels.end(); ++i)
337 tmp << "drop\n " << (*i) << endl;
338
339 for (path_set::const_iterator i = work.adds.begin();
340 i != work.adds.end(); ++i)
341 tmp << "add\n " << (*i) << endl;
342
343 for (rename_set::const_iterator i = work.renames.begin();
344 i != work.renames.end(); ++i)
345 tmp << "rename\n " << i->first << "\n " << i->second << endl;
346
347 dat = tmp.str();
348}
349
350void extract_path_set(manifest_map const & man,
351 path_set & paths)
352{
353 paths.clear();
354 for (manifest_map::const_iterator i = man.begin();
355 i != man.end(); ++i)
356 paths.insert(path_id_pair(*i).path());
357}
358
359void apply_work_set(work_set const & work,
360 path_set & paths)
361{
362 for (path_set::const_iterator i = work.dels.begin();
363 i != work.dels.end(); ++i)
364 {
365 I(paths.find(*i) != paths.end());
366 paths.erase(*i);
367 }
368
369 for (path_set::const_iterator i = work.adds.begin();
370 i != work.adds.end(); ++i)
371 {
372 I(paths.find(*i) == paths.end());
373 paths.insert(*i);
374 }
375
376 for (rename_set::const_iterator i = work.renames.begin();
377 i != work.renames.end(); ++i)
378 {
379 I(paths.find(i->first) != paths.end());
380 I(paths.find(i->second) == paths.end());
381 paths.erase(i->first);
382 paths.insert(i->second);
383 }
384
385}
386
387// options map file
388
389string const options_file_name("options");
390
391struct add_to_options_map
392{
393 options_map & options;
394 explicit add_to_options_map(options_map & m): options(m) {}
395 bool operator()(match_results<std::string::const_iterator, regex::alloc_type> const & res)
396 {
397 utf8 value;
398 std::string key(res[1].first, res[1].second);
399 value = std::string(res[2].first, res[2].second);
400 options[key] = value;
401 return true;
402 }
403};
404
405void get_options_path(local_path & o_path)
406{
407 o_path = (mkpath(book_keeping_dir) / mkpath(options_file_name)).string();
408 L(F("options path is %s\n") % o_path);
409}
410
411void read_options_map(data const & dat, options_map & options)
412{
413 regex expr("^([^[:space:]]+)[[:blank:]]+([^[:space:]]+)$");
414 regex_grep(add_to_options_map(options), dat(), expr, match_not_dot_newline);
415}
416
417void write_options_map(data & dat, options_map const & options)
418{
419 ostringstream tmp;
420 for (options_map::const_iterator i = options.begin();
421 i != options.end(); ++i)
422 tmp << i->first << " " << i->second << endl;
423 dat = tmp.str();
424}
425
426
427// attribute map file
428
429string const attr_file_name(".mt-attrs");
430
431struct add_to_attr_map
432{
433 attr_map & attr;
434 explicit add_to_attr_map(attr_map & m): attr(m) {}
435 bool operator()(match_results<std::string::const_iterator, regex::alloc_type> const & res)
436 {
437 std::string key(res[1].first, res[1].second);
438 std::string value(res[2].first, res[2].second);
439 std::string file(res[3].first, res[3].second);
440 attr[make_pair(file_path(file), key)] = value;
441 return true;
442 }
443};
444
445void get_attr_path(file_path & a_path)
446{
447 a_path = (mkpath(attr_file_name)).string();
448 L(F("attribute map path is %s\n") % a_path);
449}
450
451void read_attr_map(data const & dat, attr_map & attr)
452{
453 regex expr("^([^[:space:]]+) ([^[:space:]]+) ([^[:space:]].+)$");
454 regex_grep(add_to_attr_map(attr), dat(), expr, match_not_dot_newline);
455}
456
457void write_attr_map(data & dat, attr_map const & attr)
458{
459 ostringstream tmp;
460 for (attr_map::const_iterator i = attr.begin();
461 i != attr.end(); ++i)
462 tmp << i->first.second << " " // key
463<< i->second << " " // value
464<< i->first.first << endl; // file
465 dat = tmp.str();
466}
467
468
469void apply_attributes(app_state & app, attr_map const & attr)
470{
471 for (attr_map::const_iterator i = attr.begin();
472 i != attr.end(); ++i)
473 app.lua.hook_apply_attribute (i->first.second,
474 i->first.first,
475 i->second);
476}

Archive Download this file

Branches

Tags

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