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 "or to handle all at once, simple 'monotone drop --missing'\n"
206 "or 'monotone revert --missing'")
207 % missing_files);
208
209}
210
211// reading manifest_maps
212
213void
214read_manifest_map(data const & dat,
215 manifest_map & man)
216{
217 std::string::size_type pos = 0;
218 while (pos != dat().size())
219 {
220 // whenever we get here, pos points to the beginning of a manifest
221 // line
222 // manifest file has 40 characters hash, then 2 characters space, then
223 // everything until next \n is filename.
224 std::string ident = dat().substr(pos, constants::idlen);
225 std::string::size_type file_name_begin = pos + constants::idlen + 2;
226 pos = dat().find('\n', file_name_begin);
227 std::string file_name;
228 if (pos == std::string::npos)
229 file_name = dat().substr(file_name_begin);
230 else
231 file_name = dat().substr(file_name_begin, pos - file_name_begin);
232 man.insert(manifest_entry(file_path_internal(file_name),
233 hexenc<id>(ident)));
234 // skip past the '\n'
235 ++pos;
236 }
237 return;
238}
239
240void
241read_manifest_map(manifest_data const & dat,
242 manifest_map & man)
243{
244 read_manifest_map(dat.inner(), man);
245}
246
247
248
249// writing manifest_maps
250
251std::ostream &
252operator<<(std::ostream & out, manifest_entry const & e)
253{
254 return (out << manifest_entry_id(e) << " " << manifest_entry_path(e) << "\n");
255}
256
257
258void
259write_manifest_map(manifest_map const & man,
260 manifest_data & dat)
261{
262 ostringstream sstr;
263 copy(man.begin(),
264 man.end(),
265 ostream_iterator<manifest_entry>(sstr));
266
267 dat = manifest_data(sstr.str());
268}
269
270void
271write_manifest_map(manifest_map const & man,
272 data & dat)
273{
274 ostringstream sstr;
275 for (manifest_map::const_iterator i = man.begin();
276 i != man.end(); ++i)
277 sstr << *i;
278 dat = sstr.str();
279}
280
281void
282dump(manifest_map const & man, std::string & out)
283{
284 data dat;
285 write_manifest_map(man, dat);
286 out = dat();
287}

Archive Download this file

Branches

Tags

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