monotone

monotone Mtn Source Tree

Root/src/revision.cc

1// Copyright (C) 2004 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#include "base.hh"
11#include "revision.hh"
12#include "roster.hh"
13
14#include "sanity.hh"
15#include "basic_io.hh"
16#include "transforms.hh"
17
18#include "safe_map.hh"
19#include <boost/shared_ptr.hpp>
20
21using std::make_pair;
22using std::map;
23using std::string;
24using boost::shared_ptr;
25
26void revision_t::check_sane() const
27{
28 E(!null_id(new_manifest), made_from, F("revision has no manifest id"));
29
30 if (edges.size() == 1)
31 {
32 // no particular checks to be done right now
33 }
34 else if (edges.size() == 2)
35 {
36 // merge nodes cannot have null revisions
37 for (edge_map::const_iterator i = edges.begin(); i != edges.end(); ++i)
38 E(!null_id(edge_old_revision(i)), made_from,
39 F("merge revision has a null parent"));
40 }
41 else
42 // revisions must always have either 1 or 2 edges
43 E(false, made_from, F("revision has %d edges, not 1 or 2") % edges.size());
44
45 // we used to also check that if there were multiple edges that had patches
46 // for the same file, then the new hashes on each edge matched each other.
47 // this is not ported over to roster-style revisions because it's an
48 // inadequate check, and the real check, that the new manifest id is correct
49 // (done in put_revision, for instance) covers this case automatically.
50}
51
52bool
53revision_t::is_merge_node() const
54{
55 return edges.size() > 1;
56}
57
58bool
59revision_t::is_nontrivial() const
60{
61 check_sane();
62 // merge revisions are never trivial, because even if the resulting node
63 // happens to be identical to both parents, the merge is still recording
64 // that fact.
65 if (is_merge_node())
66 return true;
67 else
68 return !edge_changes(edges.begin()).empty();
69}
70
71revision_t::revision_t(revision_t const & other)
72 : origin_aware(other)
73{
74 /* behave like normal constructor if other is empty */
75 made_for = made_for_nobody;
76 if (null_id(other.new_manifest) && other.edges.empty()) return;
77 other.check_sane();
78 new_manifest = other.new_manifest;
79 edges = other.edges;
80 made_for = other.made_for;
81}
82
83revision_t const &
84revision_t::operator=(revision_t const & other)
85{
86 other.check_sane();
87 new_manifest = other.new_manifest;
88 edges = other.edges;
89 made_for = other.made_for;
90 return *this;
91}
92
93void
94make_revision(revision_id const & old_rev_id,
95 roster_t const & old_roster,
96 roster_t const & new_roster,
97 revision_t & rev)
98{
99 shared_ptr<cset> cs(new cset());
100
101 rev.edges.clear();
102 make_cset(old_roster, new_roster, *cs);
103
104 calculate_ident(new_roster, rev.new_manifest);
105
106 if (global_sanity.debug_p())
107 L(FL("new manifest_id is %s")
108 % rev.new_manifest);
109
110 safe_insert(rev.edges, make_pair(old_rev_id, cs));
111 rev.made_for = made_for_database;
112}
113
114void
115make_revision(revision_id const & old_rev_id,
116 roster_t const & old_roster,
117 cset const & changes,
118 revision_t & rev)
119{
120 roster_t new_roster = old_roster;
121 {
122 temp_node_id_source nis;
123 editable_roster_base er(new_roster, nis);
124 changes.apply_to(er);
125 }
126
127 shared_ptr<cset> cs(new cset(changes));
128 rev.edges.clear();
129
130 calculate_ident(new_roster, rev.new_manifest);
131
132 if (global_sanity.debug_p())
133 L(FL("new manifest_id is %s")
134 % rev.new_manifest);
135
136 safe_insert(rev.edges, make_pair(old_rev_id, cs));
137 rev.made_for = made_for_database;
138}
139
140void
141make_revision(parent_map const & old_rosters,
142 roster_t const & new_roster,
143 revision_t & rev)
144{
145 edge_map edges;
146 for (parent_map::const_iterator i = old_rosters.begin();
147 i != old_rosters.end();
148 i++)
149 {
150 shared_ptr<cset> cs(new cset());
151 make_cset(parent_roster(i), new_roster, *cs);
152 safe_insert(edges, make_pair(parent_id(i), cs));
153 }
154
155 rev.edges = edges;
156 calculate_ident(new_roster, rev.new_manifest);
157
158 if (global_sanity.debug_p())
159 L(FL("new manifest_id is %s")
160 % rev.new_manifest);
161}
162
163static void
164recalculate_manifest_id_for_restricted_rev(parent_map const & old_rosters,
165 edge_map & edges,
166 revision_t & rev)
167{
168 // In order to get the correct manifest ID, recalculate the new roster
169 // using one of the restricted csets. It doesn't matter which of the
170 // parent roster/cset pairs we use for this; by construction, they must
171 // all produce the same result.
172 revision_id rid = parent_id(old_rosters.begin());
173 roster_t restricted_roster = *(safe_get(old_rosters, rid).first);
174
175 temp_node_id_source nis;
176 editable_roster_base er(restricted_roster, nis);
177 safe_get(edges, rid)->apply_to(er);
178
179 calculate_ident(restricted_roster, rev.new_manifest);
180 rev.edges = edges;
181
182 if (global_sanity.debug_p())
183 L(FL("new manifest_id is %s")
184 % rev.new_manifest);
185}
186
187void
188make_restricted_revision(parent_map const & old_rosters,
189 roster_t const & new_roster,
190 node_restriction const & mask,
191 revision_t & rev)
192{
193 edge_map edges;
194 for (parent_map::const_iterator i = old_rosters.begin();
195 i != old_rosters.end();
196 i++)
197 {
198 shared_ptr<cset> included(new cset());
199 roster_t restricted_roster;
200
201 make_restricted_roster(parent_roster(i), new_roster,
202 restricted_roster, mask);
203 make_cset(parent_roster(i), restricted_roster, *included);
204 safe_insert(edges, make_pair(parent_id(i), included));
205 }
206
207 recalculate_manifest_id_for_restricted_rev(old_rosters, edges, rev);
208}
209
210void
211make_restricted_revision(parent_map const & old_rosters,
212 roster_t const & new_roster,
213 node_restriction const & mask,
214 revision_t & rev,
215 cset & excluded,
216 utf8 const & cmd_name)
217{
218 edge_map edges;
219 bool no_excludes = true;
220 for (parent_map::const_iterator i = old_rosters.begin();
221 i != old_rosters.end();
222 i++)
223 {
224 shared_ptr<cset> included(new cset());
225 roster_t restricted_roster;
226
227 make_restricted_roster(parent_roster(i), new_roster,
228 restricted_roster, mask);
229 make_cset(parent_roster(i), restricted_roster, *included);
230 make_cset(restricted_roster, new_roster, excluded);
231 safe_insert(edges, make_pair(parent_id(i), included));
232 if (!excluded.empty())
233 no_excludes = false;
234 }
235
236 E(old_rosters.size() == 1 || no_excludes, origin::user,
237 F("the command '%s %s' cannot be restricted in a two-parent workspace")
238 % prog_name % cmd_name);
239
240 recalculate_manifest_id_for_restricted_rev(old_rosters, edges, rev);
241}
242
243// Workspace-only revisions, with fake rev.new_manifest and content
244// changes suppressed.
245void
246make_revision_for_workspace(revision_id const & old_rev_id,
247 cset const & changes,
248 revision_t & rev)
249{
250 MM(old_rev_id);
251 MM(changes);
252 MM(rev);
253 shared_ptr<cset> cs(new cset(changes));
254 cs->deltas_applied.clear();
255
256 rev.edges.clear();
257 safe_insert(rev.edges, make_pair(old_rev_id, cs));
258 rev.new_manifest = manifest_id(fake_id());
259 rev.made_for = made_for_workspace;
260}
261
262void
263make_revision_for_workspace(revision_id const & old_rev_id,
264 roster_t const & old_roster,
265 roster_t const & new_roster,
266 revision_t & rev)
267{
268 MM(old_rev_id);
269 MM(old_roster);
270 MM(new_roster);
271 MM(rev);
272 cset changes;
273 make_cset(old_roster, new_roster, changes);
274 make_revision_for_workspace(old_rev_id, changes, rev);
275}
276
277void
278make_revision_for_workspace(parent_map const & old_rosters,
279 roster_t const & new_roster,
280 revision_t & rev)
281{
282 edge_map edges;
283 for (parent_map::const_iterator i = old_rosters.begin();
284 i != old_rosters.end();
285 i++)
286 {
287 shared_ptr<cset> cs(new cset());
288 make_cset(parent_roster(i), new_roster, *cs);
289 cs->deltas_applied.clear();
290 safe_insert(edges, make_pair(parent_id(i), cs));
291 }
292
293 rev.edges = edges;
294 rev.new_manifest = manifest_id(fake_id());
295 rev.made_for = made_for_workspace;
296}
297
298// i/o stuff
299
300namespace
301{
302 namespace syms
303 {
304 symbol const format_version("format_version");
305 symbol const old_revision("old_revision");
306 symbol const new_manifest("new_manifest");
307 }
308}
309
310void
311print_edge(basic_io::printer & printer,
312 edge_entry const & e)
313{
314 basic_io::stanza st;
315 st.push_binary_pair(syms::old_revision, edge_old_revision(e).inner());
316 printer.print_stanza(st);
317 print_cset(printer, edge_changes(e));
318}
319
320static void
321print_insane_revision(basic_io::printer & printer,
322 revision_t const & rev)
323{
324
325 basic_io::stanza format_stanza;
326 format_stanza.push_str_pair(syms::format_version, "1");
327 printer.print_stanza(format_stanza);
328
329 basic_io::stanza manifest_stanza;
330 manifest_stanza.push_binary_pair(syms::new_manifest, rev.new_manifest.inner());
331 printer.print_stanza(manifest_stanza);
332
333 for (edge_map::const_iterator edge = rev.edges.begin();
334 edge != rev.edges.end(); ++edge)
335 print_edge(printer, *edge);
336}
337
338void
339print_revision(basic_io::printer & printer,
340 revision_t const & rev)
341{
342 rev.check_sane();
343 print_insane_revision(printer, rev);
344}
345
346
347void
348parse_edge(basic_io::parser & parser,
349 revision_t & rev)
350{
351 shared_ptr<cset> cs(new cset());
352 MM(*cs);
353 manifest_id old_man;
354 revision_id old_rev;
355 string tmp;
356
357 parser.esym(syms::old_revision);
358 parser.hex(tmp);
359 old_rev = decode_hexenc_as<revision_id>(tmp, parser.tok.in.made_from);
360
361 parse_cset(parser, *cs);
362
363 rev.edges.insert(make_pair(old_rev, cs));
364}
365
366
367void
368parse_revision(basic_io::parser & parser,
369 revision_t & rev)
370{
371 MM(rev);
372 rev.edges.clear();
373 rev.made_for = made_for_database;
374 rev.made_from = parser.tok.in.made_from;
375 string tmp;
376 parser.esym(syms::format_version);
377 parser.str(tmp);
378 E(tmp == "1", parser.tok.in.made_from,
379 F("encountered a revision with unknown format, version %s.\n"
380 "I only know how to understand the version 1 format.\n"
381 "A newer version of monotone is required to complete this operation")
382 % tmp);
383 parser.esym(syms::new_manifest);
384 parser.hex(tmp);
385 rev.new_manifest = decode_hexenc_as<manifest_id>(tmp, parser.tok.in.made_from);
386 while (parser.symp(syms::old_revision))
387 parse_edge(parser, rev);
388 rev.check_sane();
389}
390
391void
392read_revision(data const & dat,
393 revision_t & rev)
394{
395 MM(rev);
396 basic_io::input_source src(dat(), "revision");
397 src.made_from = dat.made_from;
398 basic_io::tokenizer tok(src);
399 basic_io::parser pars(tok);
400 parse_revision(pars, rev);
401 E(src.lookahead == EOF, rev.made_from,
402 F("failed to parse revision"));
403 rev.check_sane();
404}
405
406void
407read_revision(revision_data const & dat,
408 revision_t & rev)
409{
410 read_revision(dat.inner(), rev);
411 rev.check_sane();
412}
413
414static void write_insane_revision(revision_t const & rev,
415 data & dat)
416{
417 basic_io::printer pr;
418 print_insane_revision(pr, rev);
419 dat = data(pr.buf, origin::internal);
420}
421
422template <> void
423dump(revision_t const & rev, string & out)
424{
425 data dat;
426 write_insane_revision(rev, dat);
427 out = dat();
428}
429
430void
431write_revision(revision_t const & rev,
432 data & dat)
433{
434 rev.check_sane();
435 write_insane_revision(rev, dat);
436}
437
438void
439write_revision(revision_t const & rev,
440 revision_data & dat)
441{
442 data d;
443 write_revision(rev, d);
444 dat = revision_data(d);
445}
446
447void calculate_ident(revision_t const & cs,
448 revision_id & ident)
449{
450 data tmp;
451 id tid;
452 write_revision(cs, tmp);
453 calculate_ident(tmp, tid);
454 ident = revision_id(tid);
455}
456
457// Local Variables:
458// mode: C++
459// fill-column: 76
460// c-file-style: "gnu"
461// indent-tabs-mode: nil
462// End:
463// 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