monotone

monotone Mtn Source Tree

Root/manifest.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 <string>
7#include <iterator>
8#include <sstream>
9#include <iostream>
10#include <algorithm>
11#include <iterator>
12
13#include <boost/filesystem/path.hpp>
14#include <boost/filesystem/operations.hpp>
15#include <boost/filesystem/convenience.hpp>
16
17#include "app_state.hh"
18#include "file_io.hh"
19#include "manifest.hh"
20#include "transforms.hh"
21#include "sanity.hh"
22#include "inodeprint.hh"
23#include "platform.hh"
24#include "constants.hh"
25
26// this file defines the class of manifest_map objects, and various comparison
27// and i/o functions on them. a manifest specifies exactly which versions
28// of each file reside at which path location in a given tree.
29
30using namespace std;
31
32// building manifest_maps
33
34class
35manifest_map_builder : public tree_walker
36{
37 app_state & app;
38 manifest_map & man;
39public:
40 manifest_map_builder(app_state & a, manifest_map & m);
41 virtual void visit_file(file_path const & path);
42};
43
44manifest_map_builder::manifest_map_builder(app_state & a, manifest_map & m)
45 : app(a), man(m)
46{
47}
48
49void
50manifest_map_builder::visit_file(file_path const & path)
51{
52 if (app.lua.hook_ignore_file(path))
53 return;
54 hexenc<id> ident;
55 L(F("scanning file %s\n") % path);
56 calculate_ident(path, ident, app.lua);
57 man.insert(manifest_entry(path, file_id(ident)));
58}
59
60void
61extract_path_set(manifest_map const & man, path_set & paths)
62{
63 paths.clear();
64 for (manifest_map::const_iterator i = man.begin();
65 i != man.end(); ++i)
66 paths.insert(manifest_entry_path(i));
67}
68
69inline static bool
70inodeprint_unchanged(inodeprint_map const & ipm, file_path const & path)
71{
72 inodeprint_map::const_iterator old_ip = ipm.find(path);
73 if (old_ip != ipm.end())
74 {
75 hexenc<inodeprint> ip;
76 if (inodeprint_file(path, ip) && ip == old_ip->second)
77 return true; // unchanged
78 else
79 return false; // changed or unavailable
80 }
81 else
82 return false; // unavailable
83}
84
85void
86classify_manifest_paths(app_state & app,
87 manifest_map const & man,
88 path_set & missing,
89 path_set & changed,
90 path_set & unchanged)
91{
92 inodeprint_map ipm;
93
94 if (in_inodeprints_mode())
95 {
96 data dat;
97 read_inodeprints(dat);
98 read_inodeprint_map(dat, ipm);
99 }
100
101 // this code is speed critical, hence the use of inode fingerprints so be
102 // careful when making changes in here and preferably do some timing tests
103
104 for (manifest_map::const_iterator i = man.begin(); i != man.end(); ++i)
105 {
106 if (app.restriction_includes(i->first))
107 {
108 // compute the current sha1 id for included files
109 // we might be able to avoid it, if we have an inode fingerprint...
110 if (inodeprint_unchanged(ipm, i->first))
111 {
112 // the inode fingerprint hasn't changed, so we assume the file
113 // hasn't either.
114 manifest_map::const_iterator k = man.find(i->first);
115 I(k != man.end());
116 unchanged.insert(i->first);
117 continue;
118 }
119
120 // ...ah, well, no good fingerprint, just check directly.
121 file_id ident;
122 if (ident_existing_file(i->first, ident, app.lua))
123 {
124 if (ident == i->second)
125 unchanged.insert(i->first);
126 else
127 changed.insert(i->first);
128 }
129 else
130 {
131 missing.insert(i->first);
132 }
133
134 }
135 else
136 {
137 // changes to excluded files are ignored
138 unchanged.insert(i->first);
139 }
140 }
141}
142
143void
144build_restricted_manifest_map(path_set const & paths,
145 manifest_map const & m_old,
146 manifest_map & m_new,
147 app_state & app)
148{
149 m_new.clear();
150 inodeprint_map ipm;
151
152 if (in_inodeprints_mode())
153 {
154 data dat;
155 read_inodeprints(dat);
156 read_inodeprint_map(dat, ipm);
157 }
158
159 size_t missing_files = 0;
160
161 // this code is speed critical, hence the use of inode fingerprints so be
162 // careful when making changes in here and preferably do some timing tests
163
164 for (path_set::const_iterator i = paths.begin(); i != paths.end(); ++i)
165 {
166 if (app.restriction_includes(*i))
167 {
168 // compute the current sha1 id for included files
169 // we might be able to avoid it, if we have an inode fingerprint...
170 if (inodeprint_unchanged(ipm, *i))
171 {
172 // the inode fingerprint hasn't changed, so we assume the file
173 // hasn't either.
174 manifest_map::const_iterator k = m_old.find(*i);
175 I(k != m_old.end());
176 m_new.insert(*k);
177 continue;
178 }
179
180 // ...ah, well, no good fingerprint, just check directly.
181 file_id ident;
182 if (ident_existing_file(*i, ident, app.lua))
183 {
184 m_new.insert(manifest_entry(*i, ident));
185 }
186 else
187 {
188 W(F("missing %s") % (*i));
189 missing_files++;
190 }
191 }
192 else
193 {
194 // copy the old manifest entry for excluded files
195 manifest_map::const_iterator old = m_old.find(*i);
196 if (old != m_old.end()) m_new.insert(*old);
197 }
198 }
199
200 N(missing_files == 0,
201 F("%d missing files\n"
202 "to restore consistency, on each missing file run either\n"
203 "'monotone drop FILE' to remove it permanently, or\n"
204 "'monotone revert FILE' to restore it\n")
205 % missing_files);
206
207}
208
209// reading manifest_maps
210
211void
212read_manifest_map(data const & dat,
213 manifest_map & man)
214{
215 std::string::size_type pos = 0;
216 while (pos != dat().size())
217 {
218 // whenever we get here, pos points to the beginning of a manifest
219 // line
220 // manifest file has 40 characters hash, then 2 characters space, then
221 // everything until next \n is filename.
222 std::string ident = dat().substr(pos, constants::idlen);
223 std::string::size_type file_name_begin = pos + constants::idlen + 2;
224 pos = dat().find('\n', file_name_begin);
225 std::string file_name;
226 if (pos == std::string::npos)
227 file_name = dat().substr(file_name_begin);
228 else
229 file_name = dat().substr(file_name_begin, pos - file_name_begin);
230 man.insert(manifest_entry(file_path_internal(file_name),
231 hexenc<id>(ident)));
232 // skip past the '\n'
233 ++pos;
234 }
235 return;
236}
237
238void
239read_manifest_map(manifest_data const & dat,
240 manifest_map & man)
241{
242 read_manifest_map(dat.inner(), man);
243}
244
245
246
247// writing manifest_maps
248
249std::ostream &
250operator<<(std::ostream & out, manifest_entry const & e)
251{
252 return (out << manifest_entry_id(e) << " " << manifest_entry_path(e) << "\n");
253}
254
255
256void
257write_manifest_map(manifest_map const & man,
258 manifest_data & dat)
259{
260 ostringstream sstr;
261 copy(man.begin(),
262 man.end(),
263 ostream_iterator<manifest_entry>(sstr));
264
265 dat = manifest_data(sstr.str());
266}
267
268void
269write_manifest_map(manifest_map const & man,
270 data & dat)
271{
272 ostringstream sstr;
273 for (manifest_map::const_iterator i = man.begin();
274 i != man.end(); ++i)
275 sstr << *i;
276 dat = sstr.str();
277}
278
279void
280dump(manifest_map const & man, std::string & out)
281{
282 data dat;
283 write_manifest_map(man, dat);
284 out = dat();
285}

Archive Download this file

Branches

Tags

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