1 | #ifndef __WORK_HH__␊ |
2 | #define __WORK_HH__␊ |
3 | ␊ |
4 | // Copyright (C) 2002 Graydon Hoare <graydon@pobox.com>␊ |
5 | //␊ |
6 | // This program is made available under the GNU GPL version 2.0 or␊ |
7 | // greater. See the accompanying file COPYING for details.␊ |
8 | //␊ |
9 | // This program is distributed WITHOUT ANY WARRANTY; without even the␊ |
10 | // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR␊ |
11 | // PURPOSE.␊ |
12 | ␊ |
13 | #include <set>␊ |
14 | #include "paths.hh"␊ |
15 | #include "rev_types.hh"␊ |
16 | ␊ |
17 | class path_restriction;␊ |
18 | class node_restriction;␊ |
19 | struct content_merge_adaptor;␊ |
20 | class lua_hooks;␊ |
21 | class i18n_format;␊ |
22 | struct options;␊ |
23 | class app_state;␊ |
24 | ␊ |
25 | //␊ |
26 | // this file defines structures to deal with the "workspace" of a tree␊ |
27 | //␊ |
28 | // at present the presence or absence of a workspace is intrinsically global␊ |
29 | // state, because it affects things like file_path construction (over in␊ |
30 | // paths.cc) and the current working directory. also, there are a bunch of␊ |
31 | // operations, mostly during program initialization, that are conditional on␊ |
32 | // whether or not we are inside a workspace. this has two visible␊ |
33 | // consequences to this api: first, you cannot create more than one␊ |
34 | // workspace object, and second, the workspace class has many class methods␊ |
35 | // as well as many instance methods. class methods can be used when you're␊ |
36 | // not sure yet whether or not there is a workspace. instance methods can␊ |
37 | // only be used if there definitely is a workspace; the workspace object␊ |
38 | // constructor will throw an N() if there isn't one. (this can also be␊ |
39 | // triggered by the class method require_workspace, for the sake of a few␊ |
40 | // places that need to do that but not create the workspace object yet.)␊ |
41 | //␊ |
42 | ␊ |
43 | //␊ |
44 | // workspace book-keeping files are stored in a directory called _MTN, off␊ |
45 | // the root of the workspace source tree (analogous to the CVS or .svn␊ |
46 | // directories). there is no hierarchy of _MTN directories; only one exists,␊ |
47 | // and it is always at the root. it contains the following files:␊ |
48 | //␊ |
49 | ␊ |
50 | // _MTN/revision -- this file can be thought of as an approximation to the␊ |
51 | // revision that would be added to the database if one␊ |
52 | // were to execute 'mtn commit' with the current set of␊ |
53 | // changes. it records the id of the revision that was␊ |
54 | // checked out (the "parent revision") plus a cset␊ |
55 | // describing pathname and attribute modifications␊ |
56 | // relative to that revision. if the workspace is the␊ |
57 | // result of a merge, the revision will have more than␊ |
58 | // one parent and thus more than one cset. files␊ |
59 | // changed solely in content do not appear in␊ |
60 | // _MTN/revision; this is the major difference between␊ |
61 | // the revision in this file and the revision that 'mtn␊ |
62 | // commit' adds to the database.␊ |
63 | // _MTN/options -- the database, branch and key options currently in use␊ |
64 | // _MTN/log -- user edited log file␊ |
65 | // _MTN/inodeprints -- file fingerprint cache, see below␊ |
66 | //␊ |
67 | // as work proceeds, the files in the workspace either change their␊ |
68 | // sha1 fingerprints from those listed in the revision's manifest, or else are␊ |
69 | // added or deleted or renamed (and the paths of those changes recorded in␊ |
70 | // '_MTN/revision').␊ |
71 | //␊ |
72 | // many operations need to work with a revision that accurately describes␊ |
73 | // both pathname and content changes. constructing this revision is the␊ |
74 | // function of update_current_roster_from_filesystem(). this operation␊ |
75 | // intrinsically requires reading every file in the workspace, which can be␊ |
76 | // slow. _MTN/inodeprints, if present, is used to speed up this process; it␊ |
77 | // records information accessible via stat() that is expected to change␊ |
78 | // whenever a file is modified. this expectation is not true under all␊ |
79 | // conditions, but works in practice (it is, for instance, the same␊ |
80 | // expectation used by "make"). nonetheless, this mode is off by default.␊ |
81 | ␊ |
82 | bool directory_is_workspace(system_path const & dir);␊ |
83 | ␊ |
84 | struct workspace␊ |
85 | {␊ |
86 | // This is a public flag because it's set from monotone.cc using a␊ |
87 | // function (find_and_go_to_workspace) which cannot presently be moved␊ |
88 | // from paths.cc.␊ |
89 | static bool found;␊ |
90 | ␊ |
91 | private:␊ |
92 | // This is used by get_ws_options and set_ws_options.␊ |
93 | static bool branch_is_sticky;␊ |
94 | ␊ |
95 | // This is used by a lot of instance methods.␊ |
96 | lua_hooks & lua;␊ |
97 | ␊ |
98 | // Interfaces.␊ |
99 | public:␊ |
100 | static void require_workspace();␊ |
101 | static void require_workspace(i18n_format const & explanation);␊ |
102 | ␊ |
103 | static void create_workspace(options const & opts,␊ |
104 | lua_hooks & lua,␊ |
105 | system_path const & new_dir);␊ |
106 | ␊ |
107 | // Constructor. In normal usage, calling this transitions from the state␊ |
108 | // where there may or may not be a workspace to the state where there␊ |
109 | // definitely is.␊ |
110 | explicit workspace(app_state & app, bool writeback_options = true);␊ |
111 | explicit workspace(app_state & app, i18n_format const & explanation,␊ |
112 | bool writeback_options = true);␊ |
113 | explicit workspace(options const & opts, lua_hooks & lua,␊ |
114 | i18n_format const & explanation, bool writeback_options = true);␊ |
115 | ␊ |
116 | // Methods for manipulating the workspace's content.␊ |
117 | void find_missing(roster_t const & new_roster_shape,␊ |
118 | node_restriction const & mask,␊ |
119 | std::set<file_path> & missing);␊ |
120 | ␊ |
121 | void find_unknown_and_ignored(database & db,␊ |
122 | path_restriction const & mask,␊ |
123 | std::vector<file_path> const & roots,␊ |
124 | std::set<file_path> & unknown,␊ |
125 | std::set<file_path> & ignored);␊ |
126 | ␊ |
127 | void perform_additions(database & db,␊ |
128 | std::set<file_path> const & targets,␊ |
129 | bool recursive = false,␊ |
130 | bool respect_ignore = true);␊ |
131 | ␊ |
132 | void perform_deletions(database & db,␊ |
133 | std::set<file_path> const & targets,␊ |
134 | ␉␉␉ bool recursive, ␊ |
135 | bool bookkeep_only);␊ |
136 | ␊ |
137 | void perform_rename(database & db,␊ |
138 | std::set<file_path> const & src_paths,␊ |
139 | file_path const & dst_dir,␊ |
140 | bool bookkeep_only);␊ |
141 | ␊ |
142 | void perform_pivot_root(database & db,␊ |
143 | file_path const & new_root,␊ |
144 | file_path const & put_old,␊ |
145 | bool bookkeep_only);␊ |
146 | ␊ |
147 | void perform_content_update(database & db,␊ |
148 | cset const & cs,␊ |
149 | content_merge_adaptor const & ca,␊ |
150 | bool messages = true);␊ |
151 | ␊ |
152 | void update_any_attrs(database & db);␊ |
153 | void init_attributes(file_path const & path, editable_roster_base & er);␊ |
154 | ␊ |
155 | bool has_changes(database & db);␊ |
156 | ␊ |
157 | // write out a new (partial) revision describing the current workspace;␊ |
158 | // the important pieces of this are the base revision id and the "shape"␊ |
159 | // changeset (representing tree rearrangements).␊ |
160 | void put_work_rev(revision_t const & rev);␊ |
161 | ␊ |
162 | // read the (partial) revision describing the current workspace.␊ |
163 | void get_work_rev(revision_t & rev);␊ |
164 | ␊ |
165 | // convenience wrappers around the above functions.␊ |
166 | ␊ |
167 | // This returns the current roster, except it does not bother updating the␊ |
168 | // hashes in that roster -- the "shape" is correct, all files and dirs␊ |
169 | // exist and under the correct names -- but do not trust file content␊ |
170 | // hashes. If you need the current roster with correct file content␊ |
171 | // hashes, call update_current_roster_from_filesystem on the result of␊ |
172 | // this function. Under almost all conditions, NIS should be a␊ |
173 | // temp_node_id_source.␊ |
174 | void get_current_roster_shape(database & db, node_id_source & nis,␊ |
175 | roster_t & ros);␊ |
176 | ␊ |
177 | // This returns a map whose keys are revision_ids and whose values are␊ |
178 | // rosters, there being one such pair for each parent of the current␊ |
179 | // revision.␊ |
180 | void get_parent_rosters(database & db, parent_map & parents);␊ |
181 | ␊ |
182 | // This updates the file-content hashes in ROSTER, which is assumed to be␊ |
183 | // the "current" roster returned by one of the above get_*_roster_shape␊ |
184 | // functions. If a node_restriction is provided, only the files matching␊ |
185 | // the restriction have their hashes updated.␊ |
186 | void update_current_roster_from_filesystem(roster_t & ros);␊ |
187 | void update_current_roster_from_filesystem(roster_t & ros,␊ |
188 | node_restriction const & mask);␊ |
189 | ␊ |
190 | ␊ |
191 | // the "user log" is a file the user can edit as they program to record␊ |
192 | // changes they make to their source code. Upon commit the file is read␊ |
193 | // and passed to the edit_comment lua hook. If the commit is a success,␊ |
194 | // the user log is then blanked. If the commit does not succeed, no␊ |
195 | // change is made to the user log file.␊ |
196 | ␊ |
197 | void read_user_log(utf8 & dat);␊ |
198 | void write_user_log(utf8 const & dat);␊ |
199 | void blank_user_log();␊ |
200 | bool has_contents_user_log();␊ |
201 | ␊ |
202 | // the "options map" is another administrative file, stored in␊ |
203 | // _MTN/options. it keeps a list of name/value pairs which are considered␊ |
204 | // "persistent options", associated with a particular workspace and␊ |
205 | // implied unless overridden on the command line.␊ |
206 | static void get_ws_options(options & opts);␊ |
207 | static void get_database_option(system_path const & workspace_root,␊ |
208 | system_path & database_option);␊ |
209 | static void set_ws_options(options const & opts, bool branch_is_sticky);␊ |
210 | static void print_ws_option(utf8 const & opt, std::ostream & output);␊ |
211 | ␊ |
212 | // the "workspace format version" is a nonnegative integer value, stored␊ |
213 | // in _MTN/format as an unadorned decimal number. at any given time␊ |
214 | // monotone supports actual use of only one workspace format.␊ |
215 | // check_ws_format throws an error if the workspace exists but its format␊ |
216 | // number is not equal to the currently supported format number. it is␊ |
217 | // automatically called for all commands defined with CMD() (not␊ |
218 | // CMD_NO_WORKSPACE()). migrate_ws_format is called only on explicit user␊ |
219 | // request (mtn ws migrate) and will convert a workspace from any older␊ |
220 | // format to the new one. finally, write_ws_format is called only when a␊ |
221 | // workspace is created, and simply writes the current workspace format␊ |
222 | // number to _MTN/format. unlike most routines in this class, these␊ |
223 | // functions are defined in their own file, work_migration.cc.␊ |
224 | static void check_ws_format();␊ |
225 | static void write_ws_format();␊ |
226 | void migrate_ws_format();␊ |
227 | ␊ |
228 | // the "local dump file' is a debugging file, stored in _MTN/debug. if we␊ |
229 | // crash, we save some debugging information here.␊ |
230 | ␊ |
231 | static void get_local_dump_path(bookkeeping_path & d_path);␊ |
232 | ␊ |
233 | // the 'inodeprints file' contains inode fingerprints␊ |
234 | ␊ |
235 | bool in_inodeprints_mode();␊ |
236 | void read_inodeprints(data & dat);␊ |
237 | void write_inodeprints(data const & dat);␊ |
238 | ␊ |
239 | void enable_inodeprints();␊ |
240 | void maybe_update_inodeprints(database &);␊ |
241 | ␊ |
242 | // the 'ignore file', .mtn-ignore in the root of the workspace, contains a␊ |
243 | // set of regular expressions that match pathnames. any file or directory␊ |
244 | // that exists, is unknown, and matches one of these regexps is treated as␊ |
245 | // if it did not exist, instead of being an unknown file.␊ |
246 | bool ignore_file(file_path const & path);␊ |
247 | };␊ |
248 | ␊ |
249 | // Local Variables:␊ |
250 | // mode: C++␊ |
251 | // fill-column: 76␊ |
252 | // c-file-style: "gnu"␊ |
253 | // indent-tabs-mode: nil␊ |
254 | // End:␊ |
255 | // vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:␊ |
256 | ␊ |
257 | #endif // __WORK_HH__␊ |
258 | ␊ |