monotone

monotone Mtn Source Tree

Root/automate.cc

1// copyright (C) 2004 nathaniel smith <njs@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 <iostream>
8#include <iterator>
9
10#include "vocab.hh"
11#include "app_state.hh"
12#include "commands.hh"
13#include "revision.hh"
14
15static std::string const interface_version = "0.1";
16
17// Name: interface_version
18// Arguments: none
19// Added in: 0.0
20// Purpose: Prints version of automation interface. Major number increments
21// whenever a backwards incompatible change is made; minor number increments
22// whenever any change is made (but is reset when major number increments).
23// Output format: "<decimal number>.<decimal number>\n". Always matches
24// "[0-9]+\.[0-9]+\n".
25// Error conditions: None.
26static void
27automate_interface_version(std::vector<utf8> args,
28 std::string const & help_name,
29 app_state & app,
30 std::ostream & output)
31{
32 if (args.size() != 0)
33 throw usage(help_name);
34
35 output << interface_version << std::endl;
36}
37
38// Name: heads
39// Arguments:
40// 1: a branch name
41// Added in: 0.0
42// Purpose: Prints the heads of the given branch.
43// Output format: A list of revision ids, in hexadecimal, each followed by a
44// newline. Revision ids are printed in alphabetically sorted order.
45// Error conditions: If the branch does not exist, prints nothing. (There are
46// no heads.)
47static void
48automate_heads(std::vector<utf8> args,
49 std::string const & help_name,
50 app_state & app,
51 std::ostream & output)
52{
53 if (args.size() != 1)
54 throw usage(help_name);
55
56 std::set<revision_id> heads;
57 get_branch_heads(idx(args, 0)(), app, heads);
58 for (std::set<revision_id>::const_iterator i = heads.begin(); i != heads.end(); ++i)
59 output << (*i).inner()() << std::endl;
60}
61
62// Name: descendents
63// Arguments:
64// 1 or more: revision ids
65// Added in: 0.1
66// Purpose: Prints the descendents (exclusive) of the given revisions
67// Output format: A list of revision ids, in hexadecimal, each followed by a
68// newline. Revision ids are printed in alphabetically sorted order.
69// Error conditions: If any of the revisions do not exist, prints nothing to
70// stdout, prints an error message to stderr, and exits with status 1.
71static void
72automate_descendents(std::vector<utf8> args,
73 std::string const & help_name,
74 app_state & app,
75 std::ostream & output)
76{
77 if (args.size() == 0)
78 throw usage(help_name);
79
80 std::set<revision_id> descendents;
81 std::vector<revision_id> frontier;
82 for (std::vector<utf8>::const_iterator i = args.begin(); i != args.end(); ++i)
83 {
84 revision_id rid((*i)());
85 N(app.db.revision_exists(rid), F("No such revision %s") % rid);
86 frontier.push_back(rid);
87 }
88 while (!frontier.empty())
89 {
90 revision_id rid = frontier.back();
91 frontier.pop_back();
92 std::set<revision_id> children;
93 app.db.get_revision_children(rid, children);
94 for (std::set<revision_id>::const_iterator i = children.begin();
95 i != children.end(); ++i)
96 {
97 if (descendents.find(*i) == descendents.end())
98 {
99 frontier.push_back(*i);
100 descendents.insert(*i);
101 }
102 }
103 }
104 for (std::set<revision_id>::const_iterator i = descendents.begin();
105 i != descendents.end(); ++i)
106 output << (*i).inner()() << std::endl;
107}
108
109// Name: erase_ancestors
110// Arguments:
111// 0 or more: revision ids
112// Added in: 0.1
113// Purpose: Prints all arguments, except those that are an ancestor of some
114// other argument. One way to think about this is that it prints the
115// minimal elements of the given set, under the ordering imposed by the
116// "child of" relation. Another way to think of it is if the arguments were
117// a branch, then we print the heads of that branch.
118// Output format: A list of revision ids, in hexadecimal, each followed by a
119// newline. Revision ids are printed in alphabetically sorted order.
120// Error conditions: If any of the revisions do not exist, prints nothing to
121// stdout, prints an error message to stderr, and exits with status 1.
122static void
123automate_erase_ancestors(std::vector<utf8> args,
124 std::string const & help_name,
125 app_state & app,
126 std::ostream & output)
127{
128 std::set<revision_id> revs;
129 for (std::vector<utf8>::const_iterator i = args.begin(); i != args.end(); ++i)
130 {
131 revision_id rid((*i)());
132 N(app.db.revision_exists(rid), F("No such revision %s") % rid);
133 revs.insert(rid);
134 }
135 erase_ancestors(revs, app);
136 for (std::set<revision_id>::const_iterator i = revs.begin(); i != revs.end(); ++i)
137 output << (*i).inner()() << std::endl;
138}
139
140// Name: toposort
141// Arguments:
142// 0 or more: revision ids
143// Added in: 0.1
144// Purpose: Prints all arguments, topologically sorted. I.e., if A is an
145// ancestor of B, then A will appear before B in the output list.
146// Output format: A list of revision ids, in hexadecimal, each followed by a
147// newline. Revisions are printed in topologically sorted order.
148// Error conditions: If any of the revisions do not exist, prints nothing to
149// stdout, prints an error message to stderr, and exits with status 1.
150static void
151automate_toposort(std::vector<utf8> args,
152 std::string const & help_name,
153 app_state & app,
154 std::ostream & output)
155{
156 std::set<revision_id> revs;
157 for (std::vector<utf8>::const_iterator i = args.begin(); i != args.end(); ++i)
158 {
159 revision_id rid((*i)());
160 N(app.db.revision_exists(rid), F("No such revision %s") % rid);
161 revs.insert(rid);
162 }
163 std::vector<revision_id> sorted;
164 toposort(revs, sorted, app);
165 for (std::vector<revision_id>::const_iterator i = sorted.begin();
166 i != sorted.end(); ++i)
167 output << (*i).inner()() << std::endl;
168}
169
170// Name: ancestry_difference
171// Arguments:
172// 1: a revision id
173// 0 or more further arguments: also revision ids
174// Added in: 0.1
175// Purpose: Prints all ancestors of the first revision A, that are not also
176// ancestors of the other revision ids, the "Bs". For purposes of this
177// command, "ancestor" is an inclusive term; that is, A is an ancestor of
178// one of the Bs, it will not be printed, but otherwise, it will be; and
179// none of the Bs will ever be printed. If A is a new revision, and Bs are
180// revisions that you have processed before, then this command tells you
181// which revisions are new since then.
182// Output format: A list of revision ids, in hexadecimal, each followed by a
183// newline. Revisions are printed in topologically sorted order.
184// Error conditions: If any of the revisions do not exist, prints nothing to
185// stdout, prints an error message to stderr, and exits with status 1.
186static void
187automate_ancestry_difference(std::vector<utf8> args,
188 std::string const & help_name,
189 app_state & app,
190 std::ostream & output)
191{
192 if (args.size() == 0)
193 throw usage(help_name);
194
195 revision_id a;
196 std::set<revision_id> bs;
197 std::vector<utf8>::const_iterator i = args.begin();
198 a = revision_id((*i)());
199 N(app.db.revision_exists(a), F("No such revision %s") % a);
200 for (++i; i != args.end(); ++i)
201 {
202 revision_id b((*i)());
203 N(app.db.revision_exists(b), F("No such revision %s") % b);
204 bs.insert(b);
205 }
206 std::set<revision_id> ancestors;
207 ancestry_difference(a, bs, ancestors, app);
208
209 std::vector<revision_id> sorted;
210 toposort(ancestors, sorted, app);
211 for (std::vector<revision_id>::const_iterator i = sorted.begin();
212 i != sorted.end(); ++i)
213 output << (*i).inner()() << std::endl;
214}
215
216// Name: leaves
217// Arguments:
218// None
219// Added in: 0.1
220// Purpose: Prints the leaves of the revision graph, i.e., all revisions that
221// have no children. This is similar, but not identical to the
222// functionality of 'heads', which prints every revision in a branch, that
223// has no descendents in that branch. If every revision in the database was
224// in the same branch, then they would be identical. Generally, every leaf
225// is the head of some branch, but not every branch head is a leaf.
226// Output format: A list of revision ids, in hexadecimal, each followed by a
227// newline. Revision ids are printed in alphabetically sorted order.
228// Error conditions: None.
229static void
230automate_leaves(std::vector<utf8> args,
231 std::string const & help_name,
232 app_state & app,
233 std::ostream & output)
234{
235 if (args.size() != 0)
236 throw usage(help_name);
237
238 // this might be more efficient in SQL, but for now who cares.
239 std::set<revision_id> leaves;
240 app.db.get_revision_ids(leaves);
241 std::multimap<revision_id, revision_id> graph;
242 app.db.get_revision_ancestry(graph);
243 for (std::multimap<revision_id, revision_id>::const_iterator i = graph.begin();
244 i != graph.end(); ++i)
245 leaves.erase(i->first);
246 for (std::set<revision_id>::const_iterator i = leaves.begin(); i != leaves.end(); ++i)
247 output << (*i).inner()() << std::endl;
248}
249
250void
251automate_command(utf8 cmd, std::vector<utf8> args,
252 std::string const & root_cmd_name,
253 app_state & app,
254 std::ostream & output)
255{
256 if (cmd() == "interface_version")
257 automate_interface_version(args, root_cmd_name, app, output);
258 else if (cmd() == "heads")
259 automate_heads(args, root_cmd_name, app, output);
260 else if (cmd() == "descendents")
261 automate_descendents(args, root_cmd_name, app, output);
262 else if (cmd() == "erase_ancestors")
263 automate_erase_ancestors(args, root_cmd_name, app, output);
264 else if (cmd() == "toposort")
265 automate_toposort(args, root_cmd_name, app, output);
266 else if (cmd() == "ancestry_difference")
267 automate_ancestry_difference(args, root_cmd_name, app, output);
268 else if (cmd() == "leaves")
269 automate_leaves(args, root_cmd_name, app, output);
270 else
271 throw usage(root_cmd_name);
272}

Archive Download this file

Branches

Tags

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