File: work.hh

package info (click to toggle)
monotone 0.48-3
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 20,096 kB
  • ctags: 8,077
  • sloc: cpp: 81,000; sh: 6,402; perl: 1,241; lisp: 1,045; makefile: 655; python: 566; sql: 112; ansic: 52
file content (317 lines) | stat: -rw-r--r-- 13,910 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
// Copyright (C) 2002 Graydon Hoare <graydon@pobox.com>
//
// This program is made available under the GNU GPL version 2.0 or
// greater. See the accompanying file COPYING for details.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE.

#ifndef __WORK_HH__
#define __WORK_HH__

#include <set>
#include "paths.hh"
#include "rev_types.hh"

class path_restriction;
class node_restriction;
struct content_merge_adaptor;
class lua_hooks;
class i18n_format;
struct options;
class app_state;

//
// this file defines structures to deal with the "workspace" of a tree
//
// at present the presence or absence of a workspace is intrinsically global
// state, because it affects things like file_path construction (over in
// paths.cc) and the current working directory.  also, there are a bunch of
// operations, mostly during program initialization, that are conditional on
// whether or not we are inside a workspace.  this has two visible
// consequences to this api: first, you cannot create more than one
// workspace object, and second, the workspace class has many class methods
// as well as many instance methods.  class methods can be used when you're
// not sure yet whether or not there is a workspace.  instance methods can
// only be used if there definitely is a workspace; the workspace object
// constructor will throw an E() if there isn't one.  (this can also be
// triggered by the class method require_workspace, for the sake of a few
// places that need to do that but not create the workspace object yet.)
//

//
// workspace book-keeping files are stored in a directory called _MTN, off
// the root of the workspace source tree (analogous to the CVS or .svn
// directories). there is no hierarchy of _MTN directories; only one exists,
// and it is always at the root. it contains the following files:
//

// _MTN/revision     -- this file can be thought of as an approximation to the
//                      revision that would be added to the database if one
//                      were to execute 'mtn commit' with the current set of
//                      changes.  it records the id of the revision that was
//                      checked out (the "parent revision") plus a cset
//                      describing pathname and attribute modifications
//                      relative to that revision.  if the workspace is the
//                      result of a merge, the revision will have more than
//                      one parent and thus more than one cset.  files
//                      changed solely in content do not appear in
//                      _MTN/revision; this is the major difference between
//                      the revision in this file and the revision that 'mtn
//                      commit' adds to the database.
// _MTN/options      -- the database, branch and key options currently in use
// _MTN/log          -- user edited log file
// _MTN/inodeprints  -- file fingerprint cache, see below
//
// as work proceeds, the files in the workspace either change their
// sha1 fingerprints from those listed in the revision's manifest, or else are
// added or deleted or renamed (and the paths of those changes recorded in
// '_MTN/revision').
//
// many operations need to work with a revision that accurately describes
// both pathname and content changes.  constructing this revision is the
// function of update_current_roster_from_filesystem().  this operation
// intrinsically requires reading every file in the workspace, which can be
// slow.  _MTN/inodeprints, if present, is used to speed up this process; it
// records information accessible via stat() that is expected to change
// whenever a file is modified.  this expectation is not true under all
// conditions, but works in practice (it is, for instance, the same
// expectation used by "make").  nonetheless, this mode is off by default.

bool directory_is_workspace(system_path const & dir);

namespace bisect
{
  enum type { start, good, bad, skipped, update };
  typedef std::pair<type, revision_id> entry;
};

struct workspace
{
  // This is a public flag because it's set from monotone.cc using a
  // function (find_and_go_to_workspace) which cannot presently be moved
  // from paths.cc.
  static bool found;
  // This is set to true when a workspace object was created and used
  // for a particular command
  static bool used;

private:
  // This is used by get_options and set_options. The branch option is set
  // to sticky (meaning it will be persisted in the workspace options) in
  // several cases:
  // - when update switches to a different branch
  // - when commit switches to a different branch
  // - when creating a new workspace
  // - when the given branch option is empty and the workspace branch option
  //   is not, to retain the previous workspace branch option
  static bool branch_is_sticky;

  // This is used by a lot of instance methods.
  lua_hooks & lua;

  // Give a nice error if the parent revisions aren't in the db
  void require_parents_in_db(database & db, revision_t const & rev);

  // Interfaces.
public:
  static void require_workspace();
  static void require_workspace(i18n_format const & explanation);

  static void create_workspace(options const & opts,
                               lua_hooks & lua,
                               system_path const & new_dir);

  // Constructor.  In normal usage, calling this transitions from the state
  // where there may or may not be a workspace to the state where there
  // definitely is.
  explicit workspace(app_state & app);
  explicit workspace(app_state & app, i18n_format const & explanation);
  explicit workspace(lua_hooks & lua, i18n_format const & explanation);

  // Methods for manipulating the workspace's content.
  void find_missing(roster_t const & new_roster_shape,
                    node_restriction const & mask,
                    std::set<file_path> & missing);

  void find_unknown_and_ignored(database & db,
                                path_restriction const & mask,
                                std::vector<file_path> const & roots,
                                std::set<file_path> & unknown,
                                std::set<file_path> & ignored);

  void perform_additions(database & db,
                         std::set<file_path> const & targets,
                         bool recursive = false,
                         bool respect_ignore = true);

  void perform_deletions(database & db,
                         std::set<file_path> const & targets,
                         bool recursive,
                         bool bookkeep_only);

  void perform_rename(database & db,
                      std::set<file_path> const & src_paths,
                      file_path const & dst_dir,
                      bool bookkeep_only);

  void perform_pivot_root(database & db,
                          file_path const & new_root,
                          file_path const & put_old,
                          bool bookkeep_only,
                          bool move_conflicting_paths);

  void perform_content_update(roster_t const & old_roster,
                              roster_t const & new_roster,
                              cset const & cs,
                              content_merge_adaptor const & ca,
                              bool const messages = true,
                              bool const move_conflicting_paths = false);

  void init_attributes(file_path const & path, editable_roster_base & er);

  bool has_changes(database & db);

  // write out a new (partial) revision describing the current workspace;
  // the important pieces of this are the base revision id and the "shape"
  // changeset (representing tree rearrangements).
  void put_work_rev(revision_t const & rev);

  // read the (partial) revision describing the current workspace.
  void get_work_rev(revision_t & rev);

  // read the revision id that was the parent of this workspace before
  // the last update occured. this is used for the u: (update) selector
  void get_update_id(revision_id & update_id);

  // write the revision id that was the parent of this workspace before
  // update completes. this is used for the u: (update) selector
  void put_update_id(revision_id const & update_id);

  // convenience wrappers around the above functions.

  // This returns the current roster, except it does not bother updating the
  // hashes in that roster -- the "shape" is correct, all files and dirs
  // exist and under the correct names -- but do not trust file content
  // hashes.  If you need the current roster with correct file content
  // hashes, call update_current_roster_from_filesystem on the result of
  // this function.  Under almost all conditions, NIS should be a
  // temp_node_id_source.
  void get_current_roster_shape(database & db, node_id_source & nis,
                                roster_t & ros);

  // This returns a map whose keys are revision_ids and whose values are
  // rosters, there being one such pair for each parent of the current
  // revision.
  void get_parent_rosters(database & db, parent_map & parents);

  // This updates the file-content hashes in ROSTER, which is assumed to be
  // the "current" roster returned by one of the above get_*_roster_shape
  // functions.  If a node_restriction is provided, only the files matching
  // the restriction have their hashes updated.
  void update_current_roster_from_filesystem(roster_t & ros);
  void update_current_roster_from_filesystem(roster_t & ros,
                                             node_restriction const & mask);


  // the "user log" is a file the user can edit as they program to record
  // changes they make to their source code. Upon commit the file is read
  // and passed to the edit_comment lua hook. If the commit is a success,
  // the user log is then blanked. If the commit does not succeed, no
  // change is made to the user log file.

  void read_user_log(utf8 & dat);
  void write_user_log(utf8 const & dat);
  void blank_user_log();
  bool has_contents_user_log();

  // The full commit text from the edit_comment lua hook is saved before
  // attempting to extract the various Author: Date: Branch: and Changelog:
  // values from it in case these values don't appear where they are
  // expected. Once all the values have been extracted the backup file is
  // removed.

  void load_commit_text(utf8 & dat);
  void save_commit_text(utf8 const & dat);
  void clear_commit_text();

  // the "options map" is another administrative file, stored in
  // _MTN/options. it keeps a list of name/value pairs which are considered
  // "persistent options", associated with a particular workspace and
  // implied unless overridden on the command line.
  static void get_options(options & opts);
  // like above, just that it reads the options from the given workspace,
  // not the one we found earlier
  static void get_options(system_path const & workspace_root,
                          options & opts);
  static void set_options(options const & opts,
                          lua_hooks & lua,
                          bool branch_is_sticky = false);
  static void maybe_set_options(options const & opts, lua_hooks & lua);
  static void print_option(utf8 const & opt, std::ostream & output);

  // the "bisect" infromation file is a file that records current status
  // information for the bisect search.

  void get_bisect_info(std::vector<bisect::entry> & bisect);
  void put_bisect_info(std::vector<bisect::entry> const & bisect);
  void remove_bisect_info();

  // the "workspace format version" is a nonnegative integer value, stored
  // in _MTN/format as an unadorned decimal number.  at any given time
  // monotone supports actual use of only one workspace format.
  // check_format throws an error if the workspace exists but its format
  // number is not equal to the currently supported format number.  it is
  // automatically called for all commands defined with CMD() (not
  // CMD_NO_WORKSPACE()).  migrate_format is called only on explicit user
  // request (mtn ws migrate) and will convert a workspace from any older
  // format to the new one.  finally, write_format is called only when a
  // workspace is created, and simply writes the current workspace format
  // number to _MTN/format.  unlike most routines in this class, these
  // functions are defined in their own file, work_migration.cc.
  static void check_format();
  static void write_format();
  void migrate_format();

  // the "local dump file' is a debugging file, stored in _MTN/debug.  if we
  // crash, we save some debugging information here.

  static void get_local_dump_path(bookkeeping_path & d_path);

  // the 'inodeprints file' contains inode fingerprints

  bool in_inodeprints_mode();
  void read_inodeprints(data & dat);
  void write_inodeprints(data const & dat);

  void enable_inodeprints();
  void maybe_update_inodeprints(database &);

  // the 'ignore file', .mtn-ignore in the root of the workspace, contains a
  // set of regular expressions that match pathnames.  any file or directory
  // that exists, is unknown, and matches one of these regexps is treated as
  // if it did not exist, instead of being an unknown file.
  bool ignore_file(file_path const & path);
};

// This object turns the workspace ignore_file method into a path predicate,
// suitable for passing to restriction constructors (for instance).
struct ignored_file : public path_predicate<file_path>
{
  ignored_file(workspace & work) : work(work) {}
  bool operator()(file_path const &) const;

private:
  workspace & work;
};

#endif // __WORK_HH__

// Local Variables:
// mode: C++
// fill-column: 76
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: