monotone

monotone Mtn Source Tree

Root/cmd_files.cc

1// Copyright (C) 2002 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 <iostream>
11
12#include "annotate.hh"
13#include "cmd.hh"
14#include "diff_patch.hh"
15#include "file_io.hh"
16#include "packet.hh"
17#include "simplestring_xform.hh"
18#include "transforms.hh"
19
20using std::cout;
21using std::ostream_iterator;
22using std::string;
23using std::vector;
24
25// fload, fmerge, and fdiff are simple commands for debugging the line
26// merger.
27
28CMD(fload, N_("debug"), "", N_("load file contents into db"), options::opts::none)
29{
30 data dat;
31 read_data_stdin(dat);
32
33 file_id f_id;
34 file_data f_data(dat);
35
36 calculate_ident (f_data, f_id);
37
38 packet_db_writer dbw(app);
39 dbw.consume_file_data(f_id, f_data);
40}
41
42CMD(fmerge, N_("debug"), N_("<parent> <left> <right>"),
43 N_("merge 3 files and output result"),
44 options::opts::none)
45{
46 if (args.size() != 3)
47 throw usage(name);
48
49 file_id
50 anc_id(idx(args, 0)()),
51 left_id(idx(args, 1)()),
52 right_id(idx(args, 2)());
53
54 file_data anc, left, right;
55
56 N(app.db.file_version_exists (anc_id),
57 F("ancestor file id does not exist"));
58
59 N(app.db.file_version_exists (left_id),
60 F("left file id does not exist"));
61
62 N(app.db.file_version_exists (right_id),
63 F("right file id does not exist"));
64
65 app.db.get_file_version(anc_id, anc);
66 app.db.get_file_version(left_id, left);
67 app.db.get_file_version(right_id, right);
68
69 vector<string> anc_lines, left_lines, right_lines, merged_lines;
70
71 split_into_lines(anc.inner()(), anc_lines);
72 split_into_lines(left.inner()(), left_lines);
73 split_into_lines(right.inner()(), right_lines);
74 N(merge3(anc_lines, left_lines, right_lines, merged_lines), F("merge failed"));
75 copy(merged_lines.begin(), merged_lines.end(), ostream_iterator<string>(cout, "\n"));
76
77}
78
79CMD(fdiff, N_("debug"), N_("SRCNAME DESTNAME SRCID DESTID"),
80 N_("diff 2 files and output result"),
81 options::opts::diff_options)
82{
83 if (args.size() != 4)
84 throw usage(name);
85
86 string const
87 & src_name = idx(args, 0)(),
88 & dst_name = idx(args, 1)();
89
90 file_id
91 src_id(idx(args, 2)()),
92 dst_id(idx(args, 3)());
93
94 file_data src, dst;
95
96 N(app.db.file_version_exists (src_id),
97 F("source file id does not exist"));
98
99 N(app.db.file_version_exists (dst_id),
100 F("destination file id does not exist"));
101
102 app.db.get_file_version(src_id, src);
103 app.db.get_file_version(dst_id, dst);
104
105 string pattern("");
106 if (!app.opts.no_show_encloser)
107 app.lua.hook_get_encloser_pattern(file_path_external(utf8(src_name)), pattern);
108
109 make_diff(src_name, dst_name,
110 src_id, dst_id,
111 src.inner(), dst.inner(),
112 cout, app.opts.diff_format, pattern);
113}
114
115CMD(annotate, N_("informative"), N_("PATH"),
116 N_("print annotated copy of the file from REVISION"),
117 options::opts::revision | options::opts::brief)
118{
119 revision_id rid;
120
121 if (app.opts.revision_selectors.size() == 0)
122 app.require_workspace();
123
124 if ((args.size() != 1) || (app.opts.revision_selectors.size() > 1))
125 throw usage(name);
126
127 file_path file = file_path_external(idx(args, 0));
128 split_path sp;
129 file.split(sp);
130
131 L(FL("annotate file '%s'") % file);
132
133 roster_t roster;
134 if (app.opts.revision_selectors.size() == 0)
135 {
136 // What this _should_ do is calculate the current workspace roster
137 // and/or revision and hand that to do_annotate. This should just
138 // work, no matter how many parents the workspace has. However,
139 // do_annotate currently expects to be given a file_t and revision_id
140 // corresponding to items already in the database. This is a minor
141 // bug in the one-parent case (it means annotate will not show you
142 // changes in the working copy) but is fatal in the two-parent case.
143 // Thus, what we do instead is get the parent rosters, refuse to
144 // proceed if there's more than one, and give do_annotate what it
145 // wants. See tests/two_parent_workspace_annotate.
146
147 revision_t rev;
148 app.work.get_work_rev(rev);
149 N(rev.edges.size() == 1,
150 F("with no revision selected, this command can only be used in "
151 "a single-parent workspace"));
152
153 rid = edge_old_revision(rev.edges.begin());
154
155 // this call will change to something else when the above bug is
156 // fixed, and so should not be merged with the identical call in
157 // the else branch.
158 app.db.get_roster(rid, roster);
159 }
160 else
161 {
162 complete(app, idx(app.opts.revision_selectors, 0)(), rid);
163 N(!null_id(rid),
164 F("no revision for file '%s' in database") % file);
165 N(app.db.revision_exists(rid),
166 F("no such revision '%s'") % rid);
167
168 app.db.get_roster(rid, roster);
169 }
170
171 // find the version of the file requested
172 N(roster.has_node(sp),
173 F("no such file '%s' in revision '%s'") % file % rid);
174 node_t node = roster.get_node(sp);
175 N(is_file_t(node),
176 F("'%s' in revision '%s' is not a file") % file % rid);
177
178 file_t file_node = downcast_to_file_t(node);
179 L(FL("annotate for file_id %s") % file_node->self);
180 do_annotate(app, file_node, rid, app.opts.brief);
181}
182
183CMD(identify, N_("debug"), N_("[PATH]"),
184 N_("calculate identity of PATH or stdin"),
185 options::opts::none)
186{
187 if (!(args.size() == 0 || args.size() == 1))
188 throw usage(name);
189
190 data dat;
191
192 if (args.size() == 1)
193 {
194 read_data_for_command_line(idx(args, 0), dat);
195 }
196 else
197 {
198 read_data_stdin(dat);
199 }
200
201 hexenc<id> ident;
202 calculate_ident(dat, ident);
203 cout << ident << '\n';
204}
205
206static void
207dump_file(std::ostream & output, app_state & app, file_id & ident)
208{
209 N(app.db.file_version_exists(ident),
210 F("no file version %s found in database") % ident);
211
212 file_data dat;
213 L(FL("dumping file %s") % ident);
214 app.db.get_file_version(ident, dat);
215 output.write(dat.inner()().data(), dat.inner()().size());
216}
217
218static void
219dump_file(std::ostream & output, app_state & app, revision_id rid, utf8 filename)
220{
221 N(app.db.revision_exists(rid),
222 F("no such revision '%s'") % rid);
223
224 // Paths are interpreted as standard external ones when we're in a
225 // workspace, but as project-rooted external ones otherwise.
226 file_path fp;
227 split_path sp;
228 fp = file_path_external(filename);
229 fp.split(sp);
230
231 roster_t roster;
232 marking_map marks;
233 app.db.get_roster(rid, roster, marks);
234 N(roster.has_node(sp),
235 F("no file '%s' found in revision '%s'") % fp % rid);
236
237 node_t node = roster.get_node(sp);
238 N((!null_node(node->self) && is_file_t(node)),
239 F("no file '%s' found in revision '%s'") % fp % rid);
240
241 file_t file_node = downcast_to_file_t(node);
242 dump_file(output, app, file_node->content);
243}
244
245CMD(cat, N_("informative"),
246 N_("FILENAME"),
247 N_("write file from database to stdout"),
248 options::opts::revision)
249{
250 if (args.size() != 1)
251 throw usage(name);
252
253 revision_id rid;
254 if (app.opts.revision_selectors.size() == 0)
255 {
256 app.require_workspace();
257
258 parent_map parents;
259 app.work.get_parent_rosters(parents);
260 N(parents.size() == 1,
261 F("this command can only be used in a single-parent workspace"));
262 rid = parent_id(parents.begin());
263 }
264 else
265 complete(app, idx(app.opts.revision_selectors, 0)(), rid);
266
267 dump_file(cout, app, rid, idx(args, 0));
268}
269
270// Name: get_file
271// Arguments:
272// 1: a file id
273// Added in: 1.0
274// Purpose: Prints the contents of the specified file.
275//
276// Output format: The file contents are output without modification.
277//
278// Error conditions: If the file id specified is unknown or invalid prints
279// an error message to stderr and exits with status 1.
280AUTOMATE(get_file, N_("FILEID"), options::opts::none)
281{
282 N(args.size() == 1,
283 F("wrong argument count"));
284
285 file_id ident(idx(args, 0)());
286 dump_file(output, app, ident);
287}
288
289// Name: get_fileof
290// Arguments:
291// 1: a filename
292//
293// Options:
294// r: a revision id
295//
296// Added in: 4.0
297// Purpose: Prints the contents of the specified file.
298//
299// Output format: The file contents are output without modification.
300//
301// Error conditions: If the file id specified is unknown or invalid prints
302// an error message to stderr and exits with status 1.
303AUTOMATE(get_file_of, N_("FILENAME"), options::opts::revision)
304{
305 N(args.size() == 1,
306 F("wrong argument count"));
307
308 revision_id rid;
309 if (app.opts.revision_selectors.size() == 0)
310 {
311 app.require_workspace();
312
313 parent_map parents;
314 app.work.get_parent_rosters(parents);
315 N(parents.size() == 1,
316 F("this command can only be used in a single-parent workspace"));
317 rid = parent_id(parents.begin());
318 }
319 else
320 complete(app, idx(app.opts.revision_selectors, 0)(), rid);
321
322 dump_file(output, app, rid, idx(args, 0));
323}
324
325// Local Variables:
326// mode: C++
327// fill-column: 76
328// c-file-style: "gnu"
329// indent-tabs-mode: nil
330// End:
331// 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