1731.1.5
by Aaron Bentley
Restore test_patches_data |
1 |
# Copyright (C) 2004 Aaron Bentley
|
2 |
# <aaron.bentley@utoronto.ca>
|
|
3 |
#
|
|
4 |
# This program is free software; you can redistribute it and/or modify
|
|
5 |
# it under the terms of the GNU General Public License as published by
|
|
6 |
# the Free Software Foundation; either version 2 of the License, or
|
|
7 |
# (at your option) any later version.
|
|
8 |
#
|
|
9 |
# This program is distributed in the hope that it will be useful,
|
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12 |
# GNU General Public License for more details.
|
|
13 |
#
|
|
14 |
# You should have received a copy of the GNU General Public License
|
|
15 |
# along with this program; if not, write to the Free Software
|
|
4183.7.1
by Sabin Iacob
update FSF mailing address |
16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
1731.1.5
by Aaron Bentley
Restore test_patches_data |
17 |
|
18 |
import sys |
|
19 |
import arch |
|
20 |
import arch.util |
|
21 |
import arch.arch |
|
22 |
||
23 |
import pylon.errors |
|
24 |
from pylon.errors import * |
|
25 |
from pylon import errors |
|
26 |
from pylon import util |
|
27 |
from pylon import arch_core |
|
28 |
from pylon import arch_compound |
|
29 |
from pylon import ancillary |
|
30 |
from pylon import misc |
|
31 |
from pylon import paths |
|
32 |
||
33 |
import abacmds |
|
34 |
import cmdutil |
|
35 |
import shutil |
|
36 |
import os |
|
37 |
import options |
|
38 |
import time |
|
39 |
import cmd |
|
40 |
import readline |
|
41 |
import re |
|
42 |
import string |
|
43 |
import terminal |
|
44 |
import email |
|
45 |
import smtplib |
|
46 |
import textwrap |
|
47 |
||
48 |
__docformat__ = "restructuredtext" |
|
49 |
__doc__ = "Implementation of user (sub) commands" |
|
50 |
commands = {} |
|
51 |
||
52 |
def find_command(cmd): |
|
53 |
"""
|
|
54 |
Return an instance of a command type. Return None if the type isn't
|
|
55 |
registered.
|
|
56 |
||
57 |
:param cmd: the name of the command to look for
|
|
58 |
:type cmd: the type of the command
|
|
59 |
"""
|
|
60 |
if commands.has_key(cmd): |
|
61 |
return commands[cmd]() |
|
62 |
else: |
|
63 |
return None |
|
64 |
||
65 |
class BaseCommand: |
|
66 |
def __call__(self, cmdline): |
|
67 |
try: |
|
68 |
self.do_command(cmdline.split()) |
|
69 |
except cmdutil.GetHelp, e: |
|
70 |
self.help() |
|
71 |
except Exception, e: |
|
72 |
print e |
|
73 |
||
74 |
def get_completer(index): |
|
75 |
return None |
|
76 |
||
77 |
def complete(self, args, text): |
|
78 |
"""
|
|
79 |
Returns a list of possible completions for the given text.
|
|
80 |
||
81 |
:param args: The complete list of arguments
|
|
82 |
:type args: List of str
|
|
83 |
:param text: text to complete (may be shorter than args[-1])
|
|
84 |
:type text: str
|
|
85 |
:rtype: list of str
|
|
86 |
"""
|
|
87 |
matches = [] |
|
88 |
candidates = None |
|
89 |
||
90 |
if len(args) > 0: |
|
91 |
realtext = args[-1] |
|
92 |
else: |
|
93 |
realtext = "" |
|
94 |
||
95 |
try: |
|
96 |
parser=self.get_parser() |
|
97 |
if realtext.startswith('-'): |
|
98 |
candidates = parser.iter_options() |
|
99 |
else: |
|
100 |
(options, parsed_args) = parser.parse_args(args) |
|
101 |
||
102 |
if len (parsed_args) > 0: |
|
103 |
candidates = self.get_completer(parsed_args[-1], len(parsed_args) -1) |
|
104 |
else: |
|
105 |
candidates = self.get_completer("", 0) |
|
106 |
except: |
|
107 |
pass
|
|
108 |
if candidates is None: |
|
109 |
return
|
|
110 |
for candidate in candidates: |
|
111 |
candidate = str(candidate) |
|
112 |
if candidate.startswith(realtext): |
|
113 |
matches.append(candidate[len(realtext)- len(text):]) |
|
114 |
return matches |
|
115 |
||
116 |
||
117 |
class Help(BaseCommand): |
|
118 |
"""
|
|
119 |
Lists commands, prints help messages.
|
|
120 |
"""
|
|
121 |
def __init__(self): |
|
122 |
self.description="Prints help mesages" |
|
123 |
self.parser = None |
|
124 |
||
125 |
def do_command(self, cmdargs): |
|
126 |
"""
|
|
127 |
Prints a help message.
|
|
128 |
"""
|
|
129 |
options, args = self.get_parser().parse_args(cmdargs) |
|
130 |
if len(args) > 1: |
|
131 |
raise cmdutil.GetHelp |
|
132 |
||
133 |
if options.native or options.suggestions or options.external: |
|
134 |
native = options.native |
|
135 |
suggestions = options.suggestions |
|
136 |
external = options.external |
|
137 |
else: |
|
138 |
native = True |
|
139 |
suggestions = False |
|
140 |
external = True |
|
141 |
||
142 |
if len(args) == 0: |
|
143 |
self.list_commands(native, suggestions, external) |
|
144 |
return
|
|
145 |
elif len(args) == 1: |
|
146 |
command_help(args[0]) |
|
147 |
return
|
|
148 |
||
149 |
def help(self): |
|
150 |
self.get_parser().print_help() |
|
151 |
print """ |
|
152 |
If no command is specified, commands are listed. If a command is
|
|
153 |
specified, help for that command is listed.
|
|
154 |
"""
|
|
155 |
||
156 |
def get_parser(self): |
|
157 |
"""
|
|
158 |
Returns the options parser to use for the "revision" command.
|
|
159 |
||
160 |
:rtype: cmdutil.CmdOptionParser
|
|
161 |
"""
|
|
162 |
if self.parser is not None: |
|
163 |
return self.parser |
|
164 |
parser=cmdutil.CmdOptionParser("fai help [command]") |
|
165 |
parser.add_option("-n", "--native", action="store_true", |
|
166 |
dest="native", help="Show native commands") |
|
167 |
parser.add_option("-e", "--external", action="store_true", |
|
168 |
dest="external", help="Show external commands") |
|
169 |
parser.add_option("-s", "--suggest", action="store_true", |
|
170 |
dest="suggestions", help="Show suggestions") |
|
171 |
self.parser = parser |
|
172 |
return parser |
|
173 |
||
174 |
def list_commands(self, native=True, suggest=False, external=True): |
|
175 |
"""
|
|
176 |
Lists supported commands.
|
|
177 |
||
178 |
:param native: list native, python-based commands
|
|
179 |
:type native: bool
|
|
180 |
:param external: list external aba-style commands
|
|
181 |
:type external: bool
|
|
182 |
"""
|
|
183 |
if native: |
|
184 |
print "Native Fai commands" |
|
185 |
keys=commands.keys() |
|
186 |
keys.sort() |
|
187 |
for k in keys: |
|
188 |
space="" |
|
189 |
for i in range(28-len(k)): |
|
190 |
space+=" " |
|
191 |
print space+k+" : "+commands[k]().description |
|
192 |
print
|
|
193 |
if suggest: |
|
194 |
print "Unavailable commands and suggested alternatives" |
|
195 |
key_list = suggestions.keys() |
|
196 |
key_list.sort() |
|
197 |
for key in key_list: |
|
198 |
print "%28s : %s" % (key, suggestions[key]) |
|
199 |
print
|
|
200 |
if external: |
|
201 |
fake_aba = abacmds.AbaCmds() |
|
202 |
if (fake_aba.abadir == ""): |
|
203 |
return
|
|
204 |
print "External commands" |
|
205 |
fake_aba.list_commands() |
|
206 |
print
|
|
207 |
if not suggest: |
|
208 |
print "Use help --suggest to list alternatives to tla and aba"\ |
|
209 |
" commands."
|
|
210 |
if options.tla_fallthrough and (native or external): |
|
211 |
print "Fai also supports tla commands." |
|
212 |
||
213 |
def command_help(cmd): |
|
214 |
"""
|
|
215 |
Prints help for a command.
|
|
216 |
||
217 |
:param cmd: The name of the command to print help for
|
|
218 |
:type cmd: str
|
|
219 |
"""
|
|
220 |
fake_aba = abacmds.AbaCmds() |
|
221 |
cmdobj = find_command(cmd) |
|
222 |
if cmdobj != None: |
|
223 |
cmdobj.help() |
|
224 |
elif suggestions.has_key(cmd): |
|
225 |
print "Not available\n" + suggestions[cmd] |
|
226 |
else: |
|
227 |
abacmd = fake_aba.is_command(cmd) |
|
228 |
if abacmd: |
|
229 |
abacmd.help() |
|
230 |
else: |
|
231 |
print "No help is available for \""+cmd+"\". Maybe try \"tla "+cmd+" -H\"?" |
|
232 |
||
233 |
||
234 |
||
235 |
class Changes(BaseCommand): |
|
236 |
"""
|
|
237 |
the "changes" command: lists differences between trees/revisions:
|
|
238 |
"""
|
|
239 |
||
240 |
def __init__(self): |
|
241 |
self.description="Lists what files have changed in the project tree" |
|
242 |
||
243 |
def get_completer(self, arg, index): |
|
244 |
if index > 1: |
|
245 |
return None |
|
246 |
try: |
|
247 |
tree = arch.tree_root() |
|
248 |
except: |
|
249 |
tree = None |
|
250 |
return cmdutil.iter_revision_completions(arg, tree) |
|
251 |
||
252 |
def parse_commandline(self, cmdline): |
|
253 |
"""
|
|
254 |
Parse commandline arguments. Raises cmdutil.GetHelp if help is needed.
|
|
255 |
|
|
256 |
:param cmdline: A list of arguments to parse
|
|
257 |
:rtype: (options, Revision, Revision/WorkingTree)
|
|
258 |
"""
|
|
259 |
parser=self.get_parser() |
|
260 |
(options, args) = parser.parse_args(cmdline) |
|
261 |
if len(args) > 2: |
|
262 |
raise cmdutil.GetHelp |
|
263 |
||
264 |
tree=arch.tree_root() |
|
265 |
if len(args) == 0: |
|
266 |
a_spec = ancillary.comp_revision(tree) |
|
267 |
else: |
|
268 |
a_spec = cmdutil.determine_revision_tree(tree, args[0]) |
|
269 |
cmdutil.ensure_archive_registered(a_spec.archive) |
|
270 |
if len(args) == 2: |
|
271 |
b_spec = cmdutil.determine_revision_tree(tree, args[1]) |
|
272 |
cmdutil.ensure_archive_registered(b_spec.archive) |
|
273 |
else: |
|
274 |
b_spec=tree |
|
275 |
return options, a_spec, b_spec |
|
276 |
||
277 |
def do_command(self, cmdargs): |
|
278 |
"""
|
|
279 |
Master function that perfoms the "changes" command.
|
|
280 |
"""
|
|
281 |
try: |
|
282 |
options, a_spec, b_spec = self.parse_commandline(cmdargs); |
|
283 |
except cmdutil.CantDetermineRevision, e: |
|
284 |
print e |
|
285 |
return
|
|
286 |
except arch.errors.TreeRootError, e: |
|
287 |
print e |
|
288 |
return
|
|
289 |
if options.changeset: |
|
290 |
changeset=options.changeset |
|
291 |
tmpdir = None |
|
292 |
else: |
|
293 |
tmpdir=util.tmpdir() |
|
294 |
changeset=tmpdir+"/changeset" |
|
295 |
try: |
|
296 |
delta=arch.iter_delta(a_spec, b_spec, changeset) |
|
297 |
try: |
|
298 |
for line in delta: |
|
299 |
if cmdutil.chattermatch(line, "changeset:"): |
|
300 |
pass
|
|
301 |
else: |
|
302 |
cmdutil.colorize(line, options.suppress_chatter) |
|
303 |
except arch.util.ExecProblem, e: |
|
304 |
if e.proc.error and e.proc.error.startswith( |
|
305 |
"missing explicit id for file"): |
|
306 |
raise MissingID(e) |
|
307 |
else: |
|
308 |
raise
|
|
309 |
status=delta.status |
|
310 |
if status > 1: |
|
311 |
return
|
|
312 |
if (options.perform_diff): |
|
313 |
chan = arch_compound.ChangesetMunger(changeset) |
|
314 |
chan.read_indices() |
|
315 |
if options.diffopts is not None: |
|
316 |
if isinstance(b_spec, arch.Revision): |
|
317 |
b_dir = b_spec.library_find() |
|
318 |
else: |
|
319 |
b_dir = b_spec |
|
320 |
a_dir = a_spec.library_find() |
|
321 |
diffopts = options.diffopts.split() |
|
322 |
cmdutil.show_custom_diffs(chan, diffopts, a_dir, b_dir) |
|
323 |
else: |
|
324 |
cmdutil.show_diffs(delta.changeset) |
|
325 |
finally: |
|
326 |
if tmpdir and (os.access(tmpdir, os.X_OK)): |
|
327 |
shutil.rmtree(tmpdir) |
|
328 |
||
329 |
def get_parser(self): |
|
330 |
"""
|
|
331 |
Returns the options parser to use for the "changes" command.
|
|
332 |
||
333 |
:rtype: cmdutil.CmdOptionParser
|
|
334 |
"""
|
|
335 |
parser=cmdutil.CmdOptionParser("fai changes [options] [revision]" |
|
336 |
" [revision]") |
|
337 |
parser.add_option("-d", "--diff", action="store_true", |
|
338 |
dest="perform_diff", default=False, |
|
339 |
help="Show diffs in summary") |
|
340 |
parser.add_option("-c", "--changeset", dest="changeset", |
|
341 |
help="Store a changeset in the given directory", |
|
342 |
metavar="DIRECTORY") |
|
343 |
parser.add_option("-s", "--silent", action="store_true", |
|
344 |
dest="suppress_chatter", default=False, |
|
345 |
help="Suppress chatter messages") |
|
346 |
parser.add_option("--diffopts", dest="diffopts", |
|
347 |
help="Use the specified diff options", |
|
348 |
metavar="OPTIONS") |
|
349 |
||
350 |
return parser |
|
351 |
||
352 |
def help(self, parser=None): |
|
353 |
"""
|
|
354 |
Prints a help message.
|
|
355 |
||
356 |
:param parser: If supplied, the parser to use for generating help. If \
|
|
357 |
not supplied, it is retrieved.
|
|
358 |
:type parser: cmdutil.CmdOptionParser
|
|
359 |
"""
|
|
360 |
if parser is None: |
|
361 |
parser=self.get_parser() |
|
362 |
parser.print_help() |
|
363 |
print """ |
|
364 |
Performs source-tree comparisons
|
|
365 |
||
366 |
If no revision is specified, the current project tree is compared to the
|
|
367 |
last-committed revision. If one revision is specified, the current project
|
|
368 |
tree is compared to that revision. If two revisions are specified, they are
|
|
369 |
compared to each other.
|
|
370 |
"""
|
|
371 |
help_tree_spec() |
|
372 |
return
|
|
373 |
||
374 |
||
375 |
class ApplyChanges(BaseCommand): |
|
376 |
"""
|
|
377 |
Apply differences between two revisions to a tree
|
|
378 |
"""
|
|
379 |
||
380 |
def __init__(self): |
|
381 |
self.description="Applies changes to a project tree" |
|
382 |
||
383 |
def get_completer(self, arg, index): |
|
384 |
if index > 1: |
|
385 |
return None |
|
386 |
try: |
|
387 |
tree = arch.tree_root() |
|
388 |
except: |
|
389 |
tree = None |
|
390 |
return cmdutil.iter_revision_completions(arg, tree) |
|
391 |
||
392 |
def parse_commandline(self, cmdline, tree): |
|
393 |
"""
|
|
394 |
Parse commandline arguments. Raises cmdutil.GetHelp if help is needed.
|
|
395 |
|
|
396 |
:param cmdline: A list of arguments to parse
|
|
397 |
:rtype: (options, Revision, Revision/WorkingTree)
|
|
398 |
"""
|
|
399 |
parser=self.get_parser() |
|
400 |
(options, args) = parser.parse_args(cmdline) |
|
401 |
if len(args) != 2: |
|
402 |
raise cmdutil.GetHelp |
|
403 |
||
404 |
a_spec = cmdutil.determine_revision_tree(tree, args[0]) |
|
405 |
cmdutil.ensure_archive_registered(a_spec.archive) |
|
406 |
b_spec = cmdutil.determine_revision_tree(tree, args[1]) |
|
407 |
cmdutil.ensure_archive_registered(b_spec.archive) |
|
408 |
return options, a_spec, b_spec |
|
409 |
||
410 |
def do_command(self, cmdargs): |
|
411 |
"""
|
|
412 |
Master function that performs "apply-changes".
|
|
413 |
"""
|
|
414 |
try: |
|
415 |
tree = arch.tree_root() |
|
416 |
options, a_spec, b_spec = self.parse_commandline(cmdargs, tree); |
|
417 |
except cmdutil.CantDetermineRevision, e: |
|
418 |
print e |
|
419 |
return
|
|
420 |
except arch.errors.TreeRootError, e: |
|
421 |
print e |
|
422 |
return
|
|
423 |
delta=cmdutil.apply_delta(a_spec, b_spec, tree) |
|
424 |
for line in cmdutil.iter_apply_delta_filter(delta): |
|
425 |
cmdutil.colorize(line, options.suppress_chatter) |
|
426 |
||
427 |
def get_parser(self): |
|
428 |
"""
|
|
429 |
Returns the options parser to use for the "apply-changes" command.
|
|
430 |
||
431 |
:rtype: cmdutil.CmdOptionParser
|
|
432 |
"""
|
|
433 |
parser=cmdutil.CmdOptionParser("fai apply-changes [options] revision" |
|
434 |
" revision") |
|
435 |
parser.add_option("-d", "--diff", action="store_true", |
|
436 |
dest="perform_diff", default=False, |
|
437 |
help="Show diffs in summary") |
|
438 |
parser.add_option("-c", "--changeset", dest="changeset", |
|
439 |
help="Store a changeset in the given directory", |
|
440 |
metavar="DIRECTORY") |
|
441 |
parser.add_option("-s", "--silent", action="store_true", |
|
442 |
dest="suppress_chatter", default=False, |
|
443 |
help="Suppress chatter messages") |
|
444 |
return parser |
|
445 |
||
446 |
def help(self, parser=None): |
|
447 |
"""
|
|
448 |
Prints a help message.
|
|
449 |
||
450 |
:param parser: If supplied, the parser to use for generating help. If \
|
|
451 |
not supplied, it is retrieved.
|
|
452 |
:type parser: cmdutil.CmdOptionParser
|
|
453 |
"""
|
|
454 |
if parser is None: |
|
455 |
parser=self.get_parser() |
|
456 |
parser.print_help() |
|
457 |
print """ |
|
458 |
Applies changes to a project tree
|
|
459 |
||
460 |
Compares two revisions and applies the difference between them to the current
|
|
461 |
tree.
|
|
462 |
"""
|
|
463 |
help_tree_spec() |
|
464 |
return
|
|
465 |
||
466 |
class Update(BaseCommand): |
|
467 |
"""
|
|
468 |
Updates a project tree to a given revision, preserving un-committed hanges.
|
|
469 |
"""
|
|
470 |
||
471 |
def __init__(self): |
|
472 |
self.description="Apply the latest changes to the current directory" |
|
473 |
||
474 |
def get_completer(self, arg, index): |
|
475 |
if index > 0: |
|
476 |
return None |
|
477 |
try: |
|
478 |
tree = arch.tree_root() |
|
479 |
except: |
|
480 |
tree = None |
|
481 |
return cmdutil.iter_revision_completions(arg, tree) |
|
482 |
||
483 |
def parse_commandline(self, cmdline, tree): |
|
484 |
"""
|
|
485 |
Parse commandline arguments. Raises cmdutil.GetHelp if help is needed.
|
|
486 |
|
|
487 |
:param cmdline: A list of arguments to parse
|
|
488 |
:rtype: (options, Revision, Revision/WorkingTree)
|
|
489 |
"""
|
|
490 |
parser=self.get_parser() |
|
491 |
(options, args) = parser.parse_args(cmdline) |
|
492 |
if len(args) > 2: |
|
493 |
raise cmdutil.GetHelp |
|
494 |
||
495 |
spec=None |
|
496 |
if len(args)>0: |
|
497 |
spec=args[0] |
|
498 |
revision=cmdutil.determine_revision_arch(tree, spec) |
|
499 |
cmdutil.ensure_archive_registered(revision.archive) |
|
500 |
||
501 |
mirror_source = cmdutil.get_mirror_source(revision.archive) |
|
502 |
if mirror_source != None: |
|
503 |
if cmdutil.prompt("Mirror update"): |
|
504 |
cmd=cmdutil.mirror_archive(mirror_source, |
|
505 |
revision.archive, arch.NameParser(revision).get_package_version()) |
|
506 |
for line in arch.chatter_classifier(cmd): |
|
507 |
cmdutil.colorize(line, options.suppress_chatter) |
|
508 |
||
509 |
revision=cmdutil.determine_revision_arch(tree, spec) |
|
510 |
||
511 |
return options, revision |
|
512 |
||
513 |
def do_command(self, cmdargs): |
|
514 |
"""
|
|
515 |
Master function that perfoms the "update" command.
|
|
516 |
"""
|
|
517 |
tree=arch.tree_root() |
|
518 |
try: |
|
519 |
options, to_revision = self.parse_commandline(cmdargs, tree); |
|
520 |
except cmdutil.CantDetermineRevision, e: |
|
521 |
print e |
|
522 |
return
|
|
523 |
except arch.errors.TreeRootError, e: |
|
524 |
print e |
|
525 |
return
|
|
526 |
from_revision = arch_compound.tree_latest(tree) |
|
527 |
if from_revision==to_revision: |
|
528 |
print "Tree is already up to date with:\n"+str(to_revision)+"." |
|
529 |
return
|
|
530 |
cmdutil.ensure_archive_registered(from_revision.archive) |
|
531 |
cmd=cmdutil.apply_delta(from_revision, to_revision, tree, |
|
532 |
options.patch_forward) |
|
533 |
for line in cmdutil.iter_apply_delta_filter(cmd): |
|
534 |
cmdutil.colorize(line) |
|
535 |
if to_revision.version != tree.tree_version: |
|
536 |
if cmdutil.prompt("Update version"): |
|
537 |
tree.tree_version = to_revision.version |
|
538 |
||
539 |
def get_parser(self): |
|
540 |
"""
|
|
541 |
Returns the options parser to use for the "update" command.
|
|
542 |
||
543 |
:rtype: cmdutil.CmdOptionParser
|
|
544 |
"""
|
|
545 |
parser=cmdutil.CmdOptionParser("fai update [options]" |
|
546 |
" [revision/version]") |
|
547 |
parser.add_option("-f", "--forward", action="store_true", |
|
548 |
dest="patch_forward", default=False, |
|
549 |
help="pass the --forward option to 'patch'") |
|
550 |
parser.add_option("-s", "--silent", action="store_true", |
|
551 |
dest="suppress_chatter", default=False, |
|
552 |
help="Suppress chatter messages") |
|
553 |
return parser |
|
554 |
||
555 |
def help(self, parser=None): |
|
556 |
"""
|
|
557 |
Prints a help message.
|
|
558 |
||
559 |
:param parser: If supplied, the parser to use for generating help. If \
|
|
560 |
not supplied, it is retrieved.
|
|
561 |
:type parser: cmdutil.CmdOptionParser
|
|
562 |
"""
|
|
563 |
if parser is None: |
|
564 |
parser=self.get_parser() |
|
565 |
parser.print_help() |
|
566 |
print """ |
|
567 |
Updates a working tree to the current archive revision
|
|
568 |
||
569 |
If a revision or version is specified, that is used instead
|
|
570 |
"""
|
|
571 |
help_tree_spec() |
|
572 |
return
|
|
573 |
||
574 |
||
575 |
class Commit(BaseCommand): |
|
576 |
"""
|
|
577 |
Create a revision based on the changes in the current tree.
|
|
578 |
"""
|
|
579 |
||
580 |
def __init__(self): |
|
581 |
self.description="Write local changes to the archive" |
|
582 |
||
583 |
def get_completer(self, arg, index): |
|
584 |
if arg is None: |
|
585 |
arg = "" |
|
586 |
return iter_modified_file_completions(arch.tree_root(), arg) |
|
587 |
# return iter_source_file_completions(arch.tree_root(), arg)
|
|
588 |
||
589 |
def parse_commandline(self, cmdline, tree): |
|
590 |
"""
|
|
591 |
Parse commandline arguments. Raise cmtutil.GetHelp if help is needed.
|
|
592 |
|
|
593 |
:param cmdline: A list of arguments to parse
|
|
594 |
:rtype: (options, Revision, Revision/WorkingTree)
|
|
595 |
"""
|
|
596 |
parser=self.get_parser() |
|
597 |
(options, args) = parser.parse_args(cmdline) |
|
598 |
||
599 |
if len(args) == 0: |
|
600 |
args = None |
|
601 |
if options.version is None: |
|
602 |
return options, tree.tree_version, args |
|
603 |
||
604 |
revision=cmdutil.determine_revision_arch(tree, options.version) |
|
605 |
return options, revision.get_version(), args |
|
606 |
||
607 |
def do_command(self, cmdargs): |
|
608 |
"""
|
|
609 |
Master function that perfoms the "commit" command.
|
|
610 |
"""
|
|
611 |
tree=arch.tree_root() |
|
612 |
options, version, files = self.parse_commandline(cmdargs, tree) |
|
613 |
ancestor = None |
|
614 |
if options.__dict__.has_key("base") and options.base: |
|
615 |
base = cmdutil.determine_revision_tree(tree, options.base) |
|
616 |
ancestor = base |
|
617 |
else: |
|
618 |
base = ancillary.submit_revision(tree) |
|
619 |
ancestor = base |
|
620 |
if ancestor is None: |
|
621 |
ancestor = arch_compound.tree_latest(tree, version) |
|
622 |
||
623 |
writeversion=version |
|
624 |
archive=version.archive |
|
625 |
source=cmdutil.get_mirror_source(archive) |
|
626 |
allow_old=False |
|
627 |
writethrough="implicit" |
|
628 |
||
629 |
if source!=None: |
|
630 |
if writethrough=="explicit" and \ |
|
631 |
cmdutil.prompt("Writethrough"): |
|
632 |
writeversion=arch.Version(str(source)+"/"+str(version.get_nonarch())) |
|
633 |
elif writethrough=="none": |
|
634 |
raise CommitToMirror(archive) |
|
635 |
||
636 |
elif archive.is_mirror: |
|
637 |
raise CommitToMirror(archive) |
|
638 |
||
639 |
try: |
|
640 |
last_revision=tree.iter_logs(version, True).next().revision |
|
641 |
except StopIteration, e: |
|
642 |
last_revision = None |
|
643 |
if ancestor is None: |
|
644 |
if cmdutil.prompt("Import from commit"): |
|
645 |
return do_import(version) |
|
646 |
else: |
|
647 |
raise NoVersionLogs(version) |
|
648 |
try: |
|
649 |
arch_last_revision = version.iter_revisions(True).next() |
|
650 |
except StopIteration, e: |
|
651 |
arch_last_revision = None |
|
652 |
||
653 |
if last_revision != arch_last_revision: |
|
654 |
print "Tree is not up to date with %s" % str(version) |
|
655 |
if not cmdutil.prompt("Out of date"): |
|
656 |
raise OutOfDate |
|
657 |
else: |
|
658 |
allow_old=True |
|
659 |
||
660 |
try: |
|
661 |
if not cmdutil.has_changed(ancestor): |
|
662 |
if not cmdutil.prompt("Empty commit"): |
|
663 |
raise EmptyCommit |
|
664 |
except arch.util.ExecProblem, e: |
|
665 |
if e.proc.error and e.proc.error.startswith( |
|
666 |
"missing explicit id for file"): |
|
667 |
raise MissingID(e) |
|
668 |
else: |
|
669 |
raise
|
|
670 |
log = tree.log_message(create=False, version=version) |
|
671 |
if log is None: |
|
672 |
try: |
|
673 |
if cmdutil.prompt("Create log"): |
|
674 |
edit_log(tree, version) |
|
675 |
||
676 |
except cmdutil.NoEditorSpecified, e: |
|
677 |
raise CommandFailed(e) |
|
678 |
log = tree.log_message(create=False, version=version) |
|
679 |
if log is None: |
|
680 |
raise NoLogMessage |
|
681 |
if log["Summary"] is None or len(log["Summary"].strip()) == 0: |
|
682 |
if not cmdutil.prompt("Omit log summary"): |
|
683 |
raise errors.NoLogSummary |
|
684 |
try: |
|
685 |
for line in tree.iter_commit(version, seal=options.seal_version, |
|
686 |
base=base, out_of_date_ok=allow_old, file_list=files): |
|
687 |
cmdutil.colorize(line, options.suppress_chatter) |
|
688 |
||
689 |
except arch.util.ExecProblem, e: |
|
690 |
if e.proc.error and e.proc.error.startswith( |
|
691 |
"These files violate naming conventions:"): |
|
692 |
raise LintFailure(e.proc.error) |
|
693 |
else: |
|
694 |
raise
|
|
695 |
||
696 |
def get_parser(self): |
|
697 |
"""
|
|
698 |
Returns the options parser to use for the "commit" command.
|
|
699 |
||
700 |
:rtype: cmdutil.CmdOptionParser
|
|
701 |
"""
|
|
702 |
||
703 |
parser=cmdutil.CmdOptionParser("fai commit [options] [file1]" |
|
704 |
" [file2...]") |
|
705 |
parser.add_option("--seal", action="store_true", |
|
706 |
dest="seal_version", default=False, |
|
707 |
help="seal this version") |
|
708 |
parser.add_option("-v", "--version", dest="version", |
|
709 |
help="Use the specified version", |
|
710 |
metavar="VERSION") |
|
711 |
parser.add_option("-s", "--silent", action="store_true", |
|
712 |
dest="suppress_chatter", default=False, |
|
713 |
help="Suppress chatter messages") |
|
714 |
if cmdutil.supports_switch("commit", "--base"): |
|
715 |
parser.add_option("--base", dest="base", help="", |
|
716 |
metavar="REVISION") |
|
717 |
return parser |
|
718 |
||
719 |
def help(self, parser=None): |
|
720 |
"""
|
|
721 |
Prints a help message.
|
|
722 |
||
723 |
:param parser: If supplied, the parser to use for generating help. If \
|
|
724 |
not supplied, it is retrieved.
|
|
725 |
:type parser: cmdutil.CmdOptionParser
|
|
726 |
"""
|
|
727 |
if parser is None: |
|
728 |
parser=self.get_parser() |
|
729 |
parser.print_help() |
|
730 |
print """ |
|
731 |
Updates a working tree to the current archive revision
|
|
732 |
||
733 |
If a version is specified, that is used instead
|
|
734 |
"""
|
|
735 |
# help_tree_spec()
|
|
736 |
return
|
|
737 |
||
738 |
||
739 |
||
740 |
class CatLog(BaseCommand): |
|
741 |
"""
|
|
742 |
Print the log of a given file (from current tree)
|
|
743 |
"""
|
|
744 |
def __init__(self): |
|
745 |
self.description="Prints the patch log for a revision" |
|
746 |
||
747 |
def get_completer(self, arg, index): |
|
748 |
if index > 0: |
|
749 |
return None |
|
750 |
try: |
|
751 |
tree = arch.tree_root() |
|
752 |
except: |
|
753 |
tree = None |
|
754 |
return cmdutil.iter_revision_completions(arg, tree) |
|
755 |
||
756 |
def do_command(self, cmdargs): |
|
757 |
"""
|
|
758 |
Master function that perfoms the "cat-log" command.
|
|
759 |
"""
|
|
760 |
parser=self.get_parser() |
|
761 |
(options, args) = parser.parse_args(cmdargs) |
|
762 |
try: |
|
763 |
tree = arch.tree_root() |
|
764 |
except arch.errors.TreeRootError, e: |
|
765 |
tree = None |
|
766 |
spec=None |
|
767 |
if len(args) > 0: |
|
768 |
spec=args[0] |
|
769 |
if len(args) > 1: |
|
770 |
raise cmdutil.GetHelp() |
|
771 |
try: |
|
772 |
if tree: |
|
773 |
revision = cmdutil.determine_revision_tree(tree, spec) |
|
774 |
else: |
|
775 |
revision = cmdutil.determine_revision_arch(tree, spec) |
|
776 |
except cmdutil.CantDetermineRevision, e: |
|
777 |
raise CommandFailedWrapper(e) |
|
778 |
log = None |
|
779 |
||
780 |
use_tree = (options.source == "tree" or \ |
|
781 |
(options.source == "any" and tree)) |
|
782 |
use_arch = (options.source == "archive" or options.source == "any") |
|
783 |
||
784 |
log = None |
|
785 |
if use_tree: |
|
786 |
for log in tree.iter_logs(revision.get_version()): |
|
787 |
if log.revision == revision: |
|
788 |
break
|
|
789 |
else: |
|
790 |
log = None |
|
791 |
if log is None and use_arch: |
|
792 |
cmdutil.ensure_revision_exists(revision) |
|
793 |
log = arch.Patchlog(revision) |
|
794 |
if log is not None: |
|
795 |
for item in log.items(): |
|
796 |
print "%s: %s" % item |
|
797 |
print log.description |
|
798 |
||
799 |
def get_parser(self): |
|
800 |
"""
|
|
801 |
Returns the options parser to use for the "cat-log" command.
|
|
802 |
||
803 |
:rtype: cmdutil.CmdOptionParser
|
|
804 |
"""
|
|
805 |
parser=cmdutil.CmdOptionParser("fai cat-log [revision]") |
|
806 |
parser.add_option("--archive", action="store_const", dest="source", |
|
807 |
const="archive", default="any", |
|
808 |
help="Always get the log from the archive") |
|
809 |
parser.add_option("--tree", action="store_const", dest="source", |
|
810 |
const="tree", help="Always get the log from the tree") |
|
811 |
return parser |
|
812 |
||
813 |
def help(self, parser=None): |
|
814 |
"""
|
|
815 |
Prints a help message.
|
|
816 |
||
817 |
:param parser: If supplied, the parser to use for generating help. If \
|
|
818 |
not supplied, it is retrieved.
|
|
819 |
:type parser: cmdutil.CmdOptionParser
|
|
820 |
"""
|
|
821 |
if parser==None: |
|
822 |
parser=self.get_parser() |
|
823 |
parser.print_help() |
|
824 |
print """ |
|
825 |
Prints the log for the specified revision
|
|
826 |
"""
|
|
827 |
help_tree_spec() |
|
828 |
return
|
|
829 |
||
830 |
class Revert(BaseCommand): |
|
831 |
""" Reverts a tree (or aspects of it) to a revision
|
|
832 |
"""
|
|
833 |
def __init__(self): |
|
834 |
self.description="Reverts a tree (or aspects of it) to a revision " |
|
835 |
||
836 |
def get_completer(self, arg, index): |
|
837 |
if index > 0: |
|
838 |
return None |
|
839 |
try: |
|
840 |
tree = arch.tree_root() |
|
841 |
except: |
|
842 |
tree = None |
|
843 |
return iter_modified_file_completions(tree, arg) |
|
844 |
||
845 |
def do_command(self, cmdargs): |
|
846 |
"""
|
|
847 |
Master function that perfoms the "revert" command.
|
|
848 |
"""
|
|
849 |
parser=self.get_parser() |
|
850 |
(options, args) = parser.parse_args(cmdargs) |
|
851 |
try: |
|
852 |
tree = arch.tree_root() |
|
853 |
except arch.errors.TreeRootError, e: |
|
854 |
raise CommandFailed(e) |
|
855 |
spec=None |
|
856 |
if options.revision is not None: |
|
857 |
spec=options.revision |
|
858 |
try: |
|
859 |
if spec is not None: |
|
860 |
revision = cmdutil.determine_revision_tree(tree, spec) |
|
861 |
else: |
|
862 |
revision = ancillary.comp_revision(tree) |
|
863 |
except cmdutil.CantDetermineRevision, e: |
|
864 |
raise CommandFailedWrapper(e) |
|
865 |
munger = None |
|
866 |
||
867 |
if options.file_contents or options.file_perms or options.deletions\ |
|
868 |
or options.additions or options.renames or options.hunk_prompt: |
|
869 |
munger = arch_compound.MungeOpts() |
|
870 |
munger.set_hunk_prompt(cmdutil.colorize, cmdutil.user_hunk_confirm, |
|
871 |
options.hunk_prompt) |
|
872 |
||
873 |
if len(args) > 0 or options.logs or options.pattern_files or \ |
|
874 |
options.control: |
|
875 |
if munger is None: |
|
876 |
munger = cmdutil.arch_compound.MungeOpts(True) |
|
877 |
munger.all_types(True) |
|
878 |
if len(args) > 0: |
|
879 |
t_cwd = arch_compound.tree_cwd(tree) |
|
880 |
for name in args: |
|
881 |
if len(t_cwd) > 0: |
|
882 |
t_cwd += "/" |
|
883 |
name = "./" + t_cwd + name |
|
884 |
munger.add_keep_file(name); |
|
885 |
||
886 |
if options.file_perms: |
|
887 |
munger.file_perms = True |
|
888 |
if options.file_contents: |
|
889 |
munger.file_contents = True |
|
890 |
if options.deletions: |
|
891 |
munger.deletions = True |
|
892 |
if options.additions: |
|
893 |
munger.additions = True |
|
894 |
if options.renames: |
|
895 |
munger.renames = True |
|
896 |
if options.logs: |
|
897 |
munger.add_keep_pattern('^\./\{arch\}/[^=].*') |
|
898 |
if options.control: |
|
899 |
munger.add_keep_pattern("/\.arch-ids|^\./\{arch\}|"\ |
|
900 |
"/\.arch-inventory$") |
|
901 |
if options.pattern_files: |
|
902 |
munger.add_keep_pattern(options.pattern_files) |
|
903 |
||
904 |
for line in arch_compound.revert(tree, revision, munger, |
|
905 |
not options.no_output): |
|
906 |
cmdutil.colorize(line) |
|
907 |
||
908 |
||
909 |
def get_parser(self): |
|
910 |
"""
|
|
911 |
Returns the options parser to use for the "cat-log" command.
|
|
912 |
||
913 |
:rtype: cmdutil.CmdOptionParser
|
|
914 |
"""
|
|
915 |
parser=cmdutil.CmdOptionParser("fai revert [options] [FILE...]") |
|
916 |
parser.add_option("", "--contents", action="store_true", |
|
917 |
dest="file_contents", |
|
918 |
help="Revert file content changes") |
|
919 |
parser.add_option("", "--permissions", action="store_true", |
|
920 |
dest="file_perms", |
|
921 |
help="Revert file permissions changes") |
|
922 |
parser.add_option("", "--deletions", action="store_true", |
|
923 |
dest="deletions", |
|
924 |
help="Restore deleted files") |
|
925 |
parser.add_option("", "--additions", action="store_true", |
|
926 |
dest="additions", |
|
927 |
help="Remove added files") |
|
928 |
parser.add_option("", "--renames", action="store_true", |
|
929 |
dest="renames", |
|
930 |
help="Revert file names") |
|
931 |
parser.add_option("--hunks", action="store_true", |
|
932 |
dest="hunk_prompt", default=False, |
|
933 |
help="Prompt which hunks to revert") |
|
934 |
parser.add_option("--pattern-files", dest="pattern_files", |
|
935 |
help="Revert files that match this pattern", |
|
936 |
metavar="REGEX") |
|
937 |
parser.add_option("--logs", action="store_true", |
|
938 |
dest="logs", default=False, |
|
939 |
help="Revert only logs") |
|
940 |
parser.add_option("--control-files", action="store_true", |
|
941 |
dest="control", default=False, |
|
942 |
help="Revert logs and other control files") |
|
943 |
parser.add_option("-n", "--no-output", action="store_true", |
|
944 |
dest="no_output", |
|
945 |
help="Don't keep an undo changeset") |
|
946 |
parser.add_option("--revision", dest="revision", |
|
947 |
help="Revert to the specified revision", |
|
948 |
metavar="REVISION") |
|
949 |
return parser |
|
950 |
||
951 |
def help(self, parser=None): |
|
952 |
"""
|
|
953 |
Prints a help message.
|
|
954 |
||
955 |
:param parser: If supplied, the parser to use for generating help. If \
|
|
956 |
not supplied, it is retrieved.
|
|
957 |
:type parser: cmdutil.CmdOptionParser
|
|
958 |
"""
|
|
959 |
if parser==None: |
|
960 |
parser=self.get_parser() |
|
961 |
parser.print_help() |
|
962 |
print """ |
|
963 |
Reverts changes in the current working tree. If no flags are specified, all
|
|
964 |
types of changes are reverted. Otherwise, only selected types of changes are
|
|
965 |
reverted.
|
|
966 |
||
967 |
If a revision is specified on the commandline, differences between the current
|
|
968 |
tree and that revision are reverted. If a version is specified, the current
|
|
969 |
tree is used to determine the revision.
|
|
970 |
||
971 |
If files are specified, only those files listed will have any changes applied.
|
|
972 |
To specify a renamed file, you can use either the old or new name. (or both!)
|
|
973 |
||
974 |
Unless "-n" is specified, reversions can be undone with "redo".
|
|
975 |
"""
|
|
976 |
return
|
|
977 |
||
978 |
class Revision(BaseCommand): |
|
979 |
"""
|
|
980 |
Print a revision name based on a revision specifier
|
|
981 |
"""
|
|
982 |
def __init__(self): |
|
983 |
self.description="Prints the name of a revision" |
|
984 |
||
985 |
def get_completer(self, arg, index): |
|
986 |
if index > 0: |
|
987 |
return None |
|
988 |
try: |
|
989 |
tree = arch.tree_root() |
|
990 |
except: |
|
991 |
tree = None |
|
992 |
return cmdutil.iter_revision_completions(arg, tree) |
|
993 |
||
994 |
def do_command(self, cmdargs): |
|
995 |
"""
|
|
996 |
Master function that perfoms the "revision" command.
|
|
997 |
"""
|
|
998 |
parser=self.get_parser() |
|
999 |
(options, args) = parser.parse_args(cmdargs) |
|
1000 |
||
1001 |
try: |
|
1002 |
tree = arch.tree_root() |
|
1003 |
except arch.errors.TreeRootError: |
|
1004 |
tree = None |
|
1005 |
||
1006 |
spec=None |
|
1007 |
if len(args) > 0: |
|
1008 |
spec=args[0] |
|
1009 |
if len(args) > 1: |
|
1010 |
raise cmdutil.GetHelp |
|
1011 |
try: |
|
1012 |
if tree: |
|
1013 |
revision = cmdutil.determine_revision_tree(tree, spec) |
|
1014 |
else: |
|
1015 |
revision = cmdutil.determine_revision_arch(tree, spec) |
|
1016 |
except cmdutil.CantDetermineRevision, e: |
|
1017 |
print str(e) |
|
1018 |
return
|
|
1019 |
print options.display(revision) |
|
1020 |
||
1021 |
def get_parser(self): |
|
1022 |
"""
|
|
1023 |
Returns the options parser to use for the "revision" command.
|
|
1024 |
||
1025 |
:rtype: cmdutil.CmdOptionParser
|
|
1026 |
"""
|
|
1027 |
parser=cmdutil.CmdOptionParser("fai revision [revision]") |
|
1028 |
parser.add_option("", "--location", action="store_const", |
|
1029 |
const=paths.determine_path, dest="display", |
|
1030 |
help="Show location instead of name", default=str) |
|
1031 |
parser.add_option("--import", action="store_const", |
|
1032 |
const=paths.determine_import_path, dest="display", |
|
1033 |
help="Show location of import file") |
|
1034 |
parser.add_option("--log", action="store_const", |
|
1035 |
const=paths.determine_log_path, dest="display", |
|
1036 |
help="Show location of log file") |
|
1037 |
parser.add_option("--patch", action="store_const", |
|
1038 |
dest="display", const=paths.determine_patch_path, |
|
1039 |
help="Show location of patchfile") |
|
1040 |
parser.add_option("--continuation", action="store_const", |
|
1041 |
const=paths.determine_continuation_path, |
|
1042 |
dest="display", |
|
1043 |
help="Show location of continuation file") |
|
1044 |
parser.add_option("--cacherev", action="store_const", |
|
1045 |
const=paths.determine_cacherev_path, dest="display", |
|
1046 |
help="Show location of cacherev file") |
|
1047 |
return parser |
|
1048 |
||
1049 |
def help(self, parser=None): |
|
1050 |
"""
|
|
1051 |
Prints a help message.
|
|
1052 |
||
1053 |
:param parser: If supplied, the parser to use for generating help. If \
|
|
1054 |
not supplied, it is retrieved.
|
|
1055 |
:type parser: cmdutil.CmdOptionParser
|
|
1056 |
"""
|
|
1057 |
if parser==None: |
|
1058 |
parser=self.get_parser() |
|
1059 |
parser.print_help() |
|
1060 |
print """ |
|
1061 |
Expands aliases and prints the name of the specified revision. Instead of
|
|
1062 |
the name, several options can be used to print locations. If more than one is
|
|
1063 |
specified, the last one is used.
|
|
1064 |
"""
|
|
1065 |
help_tree_spec() |
|
1066 |
return
|
|
1067 |
||
1068 |
class Revisions(BaseCommand): |
|
1069 |
"""
|
|
1070 |
Print a revision name based on a revision specifier
|
|
1071 |
"""
|
|
1072 |
def __init__(self): |
|
1073 |
self.description="Lists revisions" |
|
1074 |
self.cl_revisions = [] |
|
1075 |
||
1076 |
def do_command(self, cmdargs): |
|
1077 |
"""
|
|
1078 |
Master function that perfoms the "revision" command.
|
|
1079 |
"""
|
|
1080 |
(options, args) = self.get_parser().parse_args(cmdargs) |
|
1081 |
if len(args) > 1: |
|
1082 |
raise cmdutil.GetHelp |
|
1083 |
try: |
|
1084 |
self.tree = arch.tree_root() |
|
1085 |
except arch.errors.TreeRootError: |
|
1086 |
self.tree = None |
|
1087 |
if options.type == "default": |
|
1088 |
options.type = "archive" |
|
1089 |
try: |
|
1090 |
iter = cmdutil.revision_iterator(self.tree, options.type, args, |
|
1091 |
options.reverse, options.modified, |
|
1092 |
options.shallow) |
|
1093 |
except cmdutil.CantDetermineRevision, e: |
|
1094 |
raise CommandFailedWrapper(e) |
|
1095 |
except cmdutil.CantDetermineVersion, e: |
|
1096 |
raise CommandFailedWrapper(e) |
|
1097 |
if options.skip is not None: |
|
1098 |
iter = cmdutil.iter_skip(iter, int(options.skip)) |
|
1099 |
||
1100 |
try: |
|
1101 |
for revision in iter: |
|
1102 |
log = None |
|
1103 |
if isinstance(revision, arch.Patchlog): |
|
1104 |
log = revision |
|
1105 |
revision=revision.revision |
|
1106 |
out = options.display(revision) |
|
1107 |
if out is not None: |
|
1108 |
print out |
|
1109 |
if log is None and (options.summary or options.creator or |
|
1110 |
options.date or options.merges): |
|
1111 |
log = revision.patchlog |
|
1112 |
if options.creator: |
|
1113 |
print " %s" % log.creator |
|
1114 |
if options.date: |
|
1115 |
print " %s" % time.strftime('%Y-%m-%d %H:%M:%S %Z', log.date) |
|
1116 |
if options.summary: |
|
1117 |
print " %s" % log.summary |
|
1118 |
if options.merges: |
|
1119 |
showed_title = False |
|
1120 |
for revision in log.merged_patches: |
|
1121 |
if not showed_title: |
|
1122 |
print " Merged:" |
|
1123 |
showed_title = True |
|
1124 |
print " %s" % revision |
|
1125 |
if len(self.cl_revisions) > 0: |
|
1126 |
print pylon.changelog_for_merge(self.cl_revisions) |
|
1127 |
except pylon.errors.TreeRootNone: |
|
1128 |
raise CommandFailedWrapper( |
|
1129 |
Exception("This option can only be used in a project tree.")) |
|
1130 |
||
1131 |
def changelog_append(self, revision): |
|
1132 |
if isinstance(revision, arch.Revision): |
|
1133 |
revision=arch.Patchlog(revision) |
|
1134 |
self.cl_revisions.append(revision) |
|
1135 |
||
1136 |
def get_parser(self): |
|
1137 |
"""
|
|
1138 |
Returns the options parser to use for the "revision" command.
|
|
1139 |
||
1140 |
:rtype: cmdutil.CmdOptionParser
|
|
1141 |
"""
|
|
1142 |
parser=cmdutil.CmdOptionParser("fai revisions [version/revision]") |
|
1143 |
select = cmdutil.OptionGroup(parser, "Selection options", |
|
1144 |
"Control which revisions are listed. These options"
|
|
1145 |
" are mutually exclusive. If more than one is"
|
|
1146 |
" specified, the last is used.") |
|
1147 |
||
1148 |
cmdutil.add_revision_iter_options(select) |
|
1149 |
parser.add_option("", "--skip", dest="skip", |
|
1150 |
help="Skip revisions. Positive numbers skip from " |
|
1151 |
"beginning, negative skip from end.", |
|
1152 |
metavar="NUMBER") |
|
1153 |
||
1154 |
parser.add_option_group(select) |
|
1155 |
||
1156 |
format = cmdutil.OptionGroup(parser, "Revision format options", |
|
1157 |
"These control the appearance of listed revisions") |
|
1158 |
format.add_option("", "--location", action="store_const", |
|
1159 |
const=paths.determine_path, dest="display", |
|
1160 |
help="Show location instead of name", default=str) |
|
1161 |
format.add_option("--import", action="store_const", |
|
1162 |
const=paths.determine_import_path, dest="display", |
|
1163 |
help="Show location of import file") |
|
1164 |
format.add_option("--log", action="store_const", |
|
1165 |
const=paths.determine_log_path, dest="display", |
|
1166 |
help="Show location of log file") |
|
1167 |
format.add_option("--patch", action="store_const", |
|
1168 |
dest="display", const=paths.determine_patch_path, |
|
1169 |
help="Show location of patchfile") |
|
1170 |
format.add_option("--continuation", action="store_const", |
|
1171 |
const=paths.determine_continuation_path, |
|
1172 |
dest="display", |
|
1173 |
help="Show location of continuation file") |
|
1174 |
format.add_option("--cacherev", action="store_const", |
|
1175 |
const=paths.determine_cacherev_path, dest="display", |
|
1176 |
help="Show location of cacherev file") |
|
1177 |
format.add_option("--changelog", action="store_const", |
|
1178 |
const=self.changelog_append, dest="display", |
|
1179 |
help="Show location of cacherev file") |
|
1180 |
parser.add_option_group(format) |
|
1181 |
display = cmdutil.OptionGroup(parser, "Display format options", |
|
1182 |
"These control the display of data") |
|
1183 |
display.add_option("-r", "--reverse", action="store_true", |
|
1184 |
dest="reverse", help="Sort from newest to oldest") |
|
1185 |
display.add_option("-s", "--summary", action="store_true", |
|
1186 |
dest="summary", help="Show patchlog summary") |
|
1187 |
display.add_option("-D", "--date", action="store_true", |
|
1188 |
dest="date", help="Show patchlog date") |
|
1189 |
display.add_option("-c", "--creator", action="store_true", |
|
1190 |
dest="creator", help="Show the id that committed the" |
|
1191 |
" revision") |
|
1192 |
display.add_option("-m", "--merges", action="store_true", |
|
1193 |
dest="merges", help="Show the revisions that were" |
|
1194 |
" merged") |
|
1195 |
parser.add_option_group(display) |
|
1196 |
return parser |
|
1197 |
def help(self, parser=None): |
|
1198 |
"""Attempt to explain the revisions command
|
|
1199 |
|
|
1200 |
:param parser: If supplied, used to determine options
|
|
1201 |
"""
|
|
1202 |
if parser==None: |
|
1203 |
parser=self.get_parser() |
|
1204 |
parser.print_help() |
|
1205 |
print """List revisions. |
|
1206 |
"""
|
|
1207 |
help_tree_spec() |
|
1208 |
||
1209 |
||
1210 |
class Get(BaseCommand): |
|
1211 |
"""
|
|
1212 |
Retrieve a revision from the archive
|
|
1213 |
"""
|
|
1214 |
def __init__(self): |
|
1215 |
self.description="Retrieve a revision from the archive" |
|
1216 |
self.parser=self.get_parser() |
|
1217 |
||
1218 |
||
1219 |
def get_completer(self, arg, index): |
|
1220 |
if index > 0: |
|
1221 |
return None |
|
1222 |
try: |
|
1223 |
tree = arch.tree_root() |
|
1224 |
except: |
|
1225 |
tree = None |
|
1226 |
return cmdutil.iter_revision_completions(arg, tree) |
|
1227 |
||
1228 |
||
1229 |
def do_command(self, cmdargs): |
|
1230 |
"""
|
|
1231 |
Master function that perfoms the "get" command.
|
|
1232 |
"""
|
|
1233 |
(options, args) = self.parser.parse_args(cmdargs) |
|
1234 |
if len(args) < 1: |
|
1235 |
return self.help() |
|
1236 |
try: |
|
1237 |
tree = arch.tree_root() |
|
1238 |
except arch.errors.TreeRootError: |
|
1239 |
tree = None |
|
1240 |
||
1241 |
arch_loc = None |
|
1242 |
try: |
|
1243 |
revision, arch_loc = paths.full_path_decode(args[0]) |
|
1244 |
except Exception, e: |
|
1245 |
revision = cmdutil.determine_revision_arch(tree, args[0], |
|
1246 |
check_existence=False, allow_package=True) |
|
1247 |
if len(args) > 1: |
|
1248 |
directory = args[1] |
|
1249 |
else: |
|
1250 |
directory = str(revision.nonarch) |
|
1251 |
if os.path.exists(directory): |
|
1252 |
raise DirectoryExists(directory) |
|
1253 |
cmdutil.ensure_archive_registered(revision.archive, arch_loc) |
|
1254 |
try: |
|
1255 |
cmdutil.ensure_revision_exists(revision) |
|
1256 |
except cmdutil.NoSuchRevision, e: |
|
1257 |
raise CommandFailedWrapper(e) |
|
1258 |
||
1259 |
link = cmdutil.prompt ("get link") |
|
1260 |
for line in cmdutil.iter_get(revision, directory, link, |
|
1261 |
options.no_pristine, |
|
1262 |
options.no_greedy_add): |
|
1263 |
cmdutil.colorize(line) |
|
1264 |
||
1265 |
def get_parser(self): |
|
1266 |
"""
|
|
1267 |
Returns the options parser to use for the "get" command.
|
|
1268 |
||
1269 |
:rtype: cmdutil.CmdOptionParser
|
|
1270 |
"""
|
|
1271 |
parser=cmdutil.CmdOptionParser("fai get revision [dir]") |
|
1272 |
parser.add_option("--no-pristine", action="store_true", |
|
1273 |
dest="no_pristine", |
|
1274 |
help="Do not make pristine copy for reference") |
|
1275 |
parser.add_option("--no-greedy-add", action="store_true", |
|
1276 |
dest="no_greedy_add", |
|
1277 |
help="Never add to greedy libraries") |
|
1278 |
||
1279 |
return parser |
|
1280 |
||
1281 |
def help(self, parser=None): |
|
1282 |
"""
|
|
1283 |
Prints a help message.
|
|
1284 |
||
1285 |
:param parser: If supplied, the parser to use for generating help. If \
|
|
1286 |
not supplied, it is retrieved.
|
|
1287 |
:type parser: cmdutil.CmdOptionParser
|
|
1288 |
"""
|
|
1289 |
if parser==None: |
|
1290 |
parser=self.get_parser() |
|
1291 |
parser.print_help() |
|
1292 |
print """ |
|
1293 |
Expands aliases and constructs a project tree for a revision. If the optional
|
|
1294 |
"dir" argument is provided, the project tree will be stored in this directory.
|
|
1295 |
"""
|
|
1296 |
help_tree_spec() |
|
1297 |
return
|
|
1298 |
||
1299 |
class PromptCmd(cmd.Cmd): |
|
1300 |
def __init__(self): |
|
1301 |
cmd.Cmd.__init__(self) |
|
1302 |
self.prompt = "Fai> " |
|
1303 |
try: |
|
1304 |
self.tree = arch.tree_root() |
|
1305 |
except: |
|
1306 |
self.tree = None |
|
1307 |
self.set_title() |
|
1308 |
self.set_prompt() |
|
1309 |
self.fake_aba = abacmds.AbaCmds() |
|
1310 |
self.identchars += '-' |
|
1311 |
self.history_file = os.path.expanduser("~/.fai-history") |
|
1312 |
readline.set_completer_delims(string.whitespace) |
|
1313 |
if os.access(self.history_file, os.R_OK) and \ |
|
1314 |
os.path.isfile(self.history_file): |
|
1315 |
readline.read_history_file(self.history_file) |
|
1316 |
self.cwd = os.getcwd() |
|
1317 |
||
1318 |
def write_history(self): |
|
1319 |
readline.write_history_file(self.history_file) |
|
1320 |
||
1321 |
def do_quit(self, args): |
|
1322 |
self.write_history() |
|
1323 |
sys.exit(0) |
|
1324 |
||
1325 |
def do_exit(self, args): |
|
1326 |
self.do_quit(args) |
|
1327 |
||
1328 |
def do_EOF(self, args): |
|
1329 |
print
|
|
1330 |
self.do_quit(args) |
|
1331 |
||
1332 |
def postcmd(self, line, bar): |
|
1333 |
self.set_title() |
|
1334 |
self.set_prompt() |
|
1335 |
||
1336 |
def set_prompt(self): |
|
1337 |
if self.tree is not None: |
|
1338 |
try: |
|
1339 |
prompt = pylon.alias_or_version(self.tree.tree_version, |
|
1340 |
self.tree, |
|
1341 |
full=False) |
|
1342 |
if prompt is not None: |
|
1343 |
prompt = " " + prompt |
|
1344 |
except: |
|
1345 |
prompt = "" |
|
1346 |
else: |
|
1347 |
prompt = "" |
|
1348 |
self.prompt = "Fai%s> " % prompt |
|
1349 |
||
1350 |
def set_title(self, command=None): |
|
1351 |
try: |
|
1352 |
version = pylon.alias_or_version(self.tree.tree_version, self.tree, |
|
1353 |
full=False) |
|
1354 |
except: |
|
1355 |
version = "[no version]" |
|
1356 |
if command is None: |
|
1357 |
command = "" |
|
1358 |
sys.stdout.write(terminal.term_title("Fai %s %s" % (command, version))) |
|
1359 |
||
1360 |
def do_cd(self, line): |
|
1361 |
if line == "": |
|
1362 |
line = "~" |
|
1363 |
line = os.path.expanduser(line) |
|
1364 |
if os.path.isabs(line): |
|
1365 |
newcwd = line |
|
1366 |
else: |
|
1367 |
newcwd = self.cwd+'/'+line |
|
1368 |
newcwd = os.path.normpath(newcwd) |
|
1369 |
try: |
|
1370 |
os.chdir(newcwd) |
|
1371 |
self.cwd = newcwd |
|
1372 |
except Exception, e: |
|
1373 |
print e |
|
1374 |
try: |
|
1375 |
self.tree = arch.tree_root() |
|
1376 |
except: |
|
1377 |
self.tree = None |
|
1378 |
||
1379 |
def do_help(self, line): |
|
1380 |
Help()(line) |
|
1381 |
||
1382 |
def default(self, line): |
|
1383 |
args = line.split() |
|
1384 |
if find_command(args[0]): |
|
1385 |
try: |
|
1386 |
find_command(args[0]).do_command(args[1:]) |
|
1387 |
except cmdutil.BadCommandOption, e: |
|
1388 |
print e |
|
1389 |
except cmdutil.GetHelp, e: |
|
1390 |
find_command(args[0]).help() |
|
1391 |
except CommandFailed, e: |
|
1392 |
print e |
|
1393 |
except arch.errors.ArchiveNotRegistered, e: |
|
1394 |
print e |
|
1395 |
except KeyboardInterrupt, e: |
|
1396 |
print "Interrupted" |
|
1397 |
except arch.util.ExecProblem, e: |
|
1398 |
print e.proc.error.rstrip('\n') |
|
1399 |
except cmdutil.CantDetermineVersion, e: |
|
1400 |
print e |
|
1401 |
except cmdutil.CantDetermineRevision, e: |
|
1402 |
print e |
|
1403 |
except Exception, e: |
|
1404 |
print "Unhandled error:\n%s" % errors.exception_str(e) |
|
1405 |
||
1406 |
elif suggestions.has_key(args[0]): |
|
1407 |
print suggestions[args[0]] |
|
1408 |
||
1409 |
elif self.fake_aba.is_command(args[0]): |
|
1410 |
tree = None |
|
1411 |
try: |
|
1412 |
tree = arch.tree_root() |
|
1413 |
except arch.errors.TreeRootError: |
|
1414 |
pass
|
|
1415 |
cmd = self.fake_aba.is_command(args[0]) |
|
1416 |
try: |
|
1417 |
cmd.run(cmdutil.expand_prefix_alias(args[1:], tree)) |
|
1418 |
except KeyboardInterrupt, e: |
|
1419 |
print "Interrupted" |
|
1420 |
||
1421 |
elif options.tla_fallthrough and args[0] != "rm" and \ |
|
1422 |
cmdutil.is_tla_command(args[0]): |
|
1423 |
try: |
|
1424 |
tree = None |
|
1425 |
try: |
|
1426 |
tree = arch.tree_root() |
|
1427 |
except arch.errors.TreeRootError: |
|
1428 |
pass
|
|
1429 |
args = cmdutil.expand_prefix_alias(args, tree) |
|
1430 |
arch.util.exec_safe('tla', args, stderr=sys.stderr, |
|
1431 |
expected=(0, 1)) |
|
1432 |
except arch.util.ExecProblem, e: |
|
1433 |
pass
|
|
1434 |
except KeyboardInterrupt, e: |
|
1435 |
print "Interrupted" |
|
1436 |
else: |
|
1437 |
try: |
|
1438 |
try: |
|
1439 |
tree = arch.tree_root() |
|
1440 |
except arch.errors.TreeRootError: |
|
1441 |
tree = None |
|
1442 |
args=line.split() |
|
1443 |
os.system(" ".join(cmdutil.expand_prefix_alias(args, tree))) |
|
1444 |
except KeyboardInterrupt, e: |
|
1445 |
print "Interrupted" |
|
1446 |
||
1447 |
def completenames(self, text, line, begidx, endidx): |
|
1448 |
completions = [] |
|
1449 |
iter = iter_command_names(self.fake_aba) |
|
1450 |
try: |
|
1451 |
if len(line) > 0: |
|
1452 |
arg = line.split()[-1] |
|
1453 |
else: |
|
1454 |
arg = "" |
|
1455 |
iter = cmdutil.iter_munged_completions(iter, arg, text) |
|
1456 |
except Exception, e: |
|
1457 |
print e |
|
1458 |
return list(iter) |
|
1459 |
||
1460 |
def completedefault(self, text, line, begidx, endidx): |
|
1461 |
"""Perform completion for native commands.
|
|
1462 |
|
|
1463 |
:param text: The text to complete
|
|
1464 |
:type text: str
|
|
1465 |
:param line: The entire line to complete
|
|
1466 |
:type line: str
|
|
1467 |
:param begidx: The start of the text in the line
|
|
1468 |
:type begidx: int
|
|
1469 |
:param endidx: The end of the text in the line
|
|
1470 |
:type endidx: int
|
|
1471 |
"""
|
|
1472 |
try: |
|
1473 |
(cmd, args, foo) = self.parseline(line) |
|
1474 |
command_obj=find_command(cmd) |
|
1475 |
if command_obj is not None: |
|
1476 |
return command_obj.complete(args.split(), text) |
|
1477 |
elif not self.fake_aba.is_command(cmd) and \ |
|
1478 |
cmdutil.is_tla_command(cmd): |
|
1479 |
iter = cmdutil.iter_supported_switches(cmd) |
|
1480 |
if len(args) > 0: |
|
1481 |
arg = args.split()[-1] |
|
1482 |
else: |
|
1483 |
arg = "" |
|
1484 |
if arg.startswith("-"): |
|
1485 |
return list(cmdutil.iter_munged_completions(iter, arg, |
|
1486 |
text)) |
|
1487 |
else: |
|
1488 |
return list(cmdutil.iter_munged_completions( |
|
1489 |
cmdutil.iter_file_completions(arg), arg, text)) |
|
1490 |
||
1491 |
||
1492 |
elif cmd == "cd": |
|
1493 |
if len(args) > 0: |
|
1494 |
arg = args.split()[-1] |
|
1495 |
else: |
|
1496 |
arg = "" |
|
1497 |
iter = cmdutil.iter_dir_completions(arg) |
|
1498 |
iter = cmdutil.iter_munged_completions(iter, arg, text) |
|
1499 |
return list(iter) |
|
1500 |
elif len(args)>0: |
|
1501 |
arg = args.split()[-1] |
|
1502 |
iter = cmdutil.iter_file_completions(arg) |
|
1503 |
return list(cmdutil.iter_munged_completions(iter, arg, text)) |
|
1504 |
else: |
|
1505 |
return self.completenames(text, line, begidx, endidx) |
|
1506 |
except Exception, e: |
|
1507 |
print e |
|
1508 |
||
1509 |
||
1510 |
def iter_command_names(fake_aba): |
|
1511 |
for entry in cmdutil.iter_combine([commands.iterkeys(), |
|
1512 |
fake_aba.get_commands(), |
|
1513 |
cmdutil.iter_tla_commands(False)]): |
|
1514 |
if not suggestions.has_key(str(entry)): |
|
1515 |
yield entry |
|
1516 |
||
1517 |
||
1518 |
def iter_source_file_completions(tree, arg): |
|
1519 |
treepath = arch_compound.tree_cwd(tree) |
|
1520 |
if len(treepath) > 0: |
|
1521 |
dirs = [treepath] |
|
1522 |
else: |
|
1523 |
dirs = None |
|
1524 |
for file in tree.iter_inventory(dirs, source=True, both=True): |
|
1525 |
file = file_completion_match(file, treepath, arg) |
|
1526 |
if file is not None: |
|
1527 |
yield file |
|
1528 |
||
1529 |
||
1530 |
def iter_untagged(tree, dirs): |
|
1531 |
for file in arch_core.iter_inventory_filter(tree, dirs, tagged=False, |
|
1532 |
categories=arch_core.non_root, |
|
1533 |
control_files=True): |
|
1534 |
yield file.name |
|
1535 |
||
1536 |
||
1537 |
def iter_untagged_completions(tree, arg): |
|
1538 |
"""Generate an iterator for all visible untagged files that match arg.
|
|
1539 |
||
1540 |
:param tree: The tree to look for untagged files in
|
|
1541 |
:type tree: `arch.WorkingTree`
|
|
1542 |
:param arg: The argument to match
|
|
1543 |
:type arg: str
|
|
1544 |
:return: An iterator of all matching untagged files
|
|
1545 |
:rtype: iterator of str
|
|
1546 |
"""
|
|
1547 |
treepath = arch_compound.tree_cwd(tree) |
|
1548 |
if len(treepath) > 0: |
|
1549 |
dirs = [treepath] |
|
1550 |
else: |
|
1551 |
dirs = None |
|
1552 |
||
1553 |
for file in iter_untagged(tree, dirs): |
|
1554 |
file = file_completion_match(file, treepath, arg) |
|
1555 |
if file is not None: |
|
1556 |
yield file |
|
1557 |
||
1558 |
||
1559 |
def file_completion_match(file, treepath, arg): |
|
1560 |
"""Determines whether a file within an arch tree matches the argument.
|
|
1561 |
||
1562 |
:param file: The rooted filename
|
|
1563 |
:type file: str
|
|
1564 |
:param treepath: The path to the cwd within the tree
|
|
1565 |
:type treepath: str
|
|
1566 |
:param arg: The prefix to match
|
|
1567 |
:return: The completion name, or None if not a match
|
|
1568 |
:rtype: str
|
|
1569 |
"""
|
|
1570 |
if not file.startswith(treepath): |
|
1571 |
return None |
|
1572 |
if treepath != "": |
|
1573 |
file = file[len(treepath)+1:] |
|
1574 |
||
1575 |
if not file.startswith(arg): |
|
1576 |
return None |
|
1577 |
if os.path.isdir(file): |
|
1578 |
file += '/' |
|
1579 |
return file |
|
1580 |
||
1581 |
def iter_modified_file_completions(tree, arg): |
|
1582 |
"""Returns a list of modified files that match the specified prefix.
|
|
1583 |
||
1584 |
:param tree: The current tree
|
|
1585 |
:type tree: `arch.WorkingTree`
|
|
1586 |
:param arg: The prefix to match
|
|
1587 |
:type arg: str
|
|
1588 |
"""
|
|
1589 |
treepath = arch_compound.tree_cwd(tree) |
|
1590 |
tmpdir = util.tmpdir() |
|
1591 |
changeset = tmpdir+"/changeset" |
|
1592 |
completions = [] |
|
1593 |
revision = cmdutil.determine_revision_tree(tree) |
|
1594 |
for line in arch.iter_delta(revision, tree, changeset): |
|
1595 |
if isinstance(line, arch.FileModification): |
|
1596 |
file = file_completion_match(line.name[1:], treepath, arg) |
|
1597 |
if file is not None: |
|
1598 |
completions.append(file) |
|
1599 |
shutil.rmtree(tmpdir) |
|
1600 |
return completions |
|
1601 |
||
1602 |
class Shell(BaseCommand): |
|
1603 |
def __init__(self): |
|
1604 |
self.description = "Runs Fai as a shell" |
|
1605 |
||
1606 |
def do_command(self, cmdargs): |
|
1607 |
if len(cmdargs)!=0: |
|
1608 |
raise cmdutil.GetHelp |
|
1609 |
prompt = PromptCmd() |
|
1610 |
try: |
|
1611 |
prompt.cmdloop() |
|
1612 |
finally: |
|
1613 |
prompt.write_history() |
|
1614 |
||
1615 |
class AddID(BaseCommand): |
|
1616 |
"""
|
|
1617 |
Adds an inventory id for the given file
|
|
1618 |
"""
|
|
1619 |
def __init__(self): |
|
1620 |
self.description="Add an inventory id for a given file" |
|
1621 |
||
1622 |
def get_completer(self, arg, index): |
|
1623 |
tree = arch.tree_root() |
|
1624 |
return iter_untagged_completions(tree, arg) |
|
1625 |
||
1626 |
def do_command(self, cmdargs): |
|
1627 |
"""
|
|
1628 |
Master function that perfoms the "revision" command.
|
|
1629 |
"""
|
|
1630 |
parser=self.get_parser() |
|
1631 |
(options, args) = parser.parse_args(cmdargs) |
|
1632 |
||
1633 |
try: |
|
1634 |
tree = arch.tree_root() |
|
1635 |
except arch.errors.TreeRootError, e: |
|
1636 |
raise pylon.errors.CommandFailedWrapper(e) |
|
1637 |
||
1638 |
||
1639 |
if (len(args) == 0) == (options.untagged == False): |
|
1640 |
raise cmdutil.GetHelp |
|
1641 |
||
1642 |
#if options.id and len(args) != 1:
|
|
1643 |
# print "If --id is specified, only one file can be named."
|
|
1644 |
# return
|
|
1645 |
||
1646 |
method = tree.tagging_method |
|
1647 |
||
1648 |
if options.id_type == "tagline": |
|
1649 |
if method != "tagline": |
|
1650 |
if not cmdutil.prompt("Tagline in other tree"): |
|
1651 |
if method == "explicit" or method == "implicit": |
|
1652 |
options.id_type == method |
|
1653 |
else: |
|
1654 |
print "add-id not supported for \"%s\" tagging method"\ |
|
1655 |
% method |
|
1656 |
return
|
|
1657 |
||
1658 |
elif options.id_type == "implicit": |
|
1659 |
if method != "implicit": |
|
1660 |
if not cmdutil.prompt("Implicit in other tree"): |
|
1661 |
if method == "explicit" or method == "tagline": |
|
1662 |
options.id_type == method |
|
1663 |
else: |
|
1664 |
print "add-id not supported for \"%s\" tagging method"\ |
|
1665 |
% method |
|
1666 |
return
|
|
1667 |
elif options.id_type == "explicit": |
|
1668 |
if method != "tagline" and method != explicit: |
|
1669 |
if not prompt("Explicit in other tree"): |
|
1670 |
print "add-id not supported for \"%s\" tagging method" % \ |
|
1671 |
method
|
|
1672 |
return
|
|
1673 |
||
1674 |
if options.id_type == "auto": |
|
1675 |
if method != "tagline" and method != "explicit" \ |
|
1676 |
and method !="implicit": |
|
1677 |
print "add-id not supported for \"%s\" tagging method" % method |
|
1678 |
return
|
|
1679 |
else: |
|
1680 |
options.id_type = method |
|
1681 |
if options.untagged: |
|
1682 |
args = None |
|
1683 |
self.add_ids(tree, options.id_type, args) |
|
1684 |
||
1685 |
def add_ids(self, tree, id_type, files=()): |
|
1686 |
"""Add inventory ids to files.
|
|
1687 |
|
|
1688 |
:param tree: the tree the files are in
|
|
1689 |
:type tree: `arch.WorkingTree`
|
|
1690 |
:param id_type: the type of id to add: "explicit" or "tagline"
|
|
1691 |
:type id_type: str
|
|
1692 |
:param files: The list of files to add. If None do all untagged.
|
|
1693 |
:type files: tuple of str
|
|
1694 |
"""
|
|
1695 |
||
1696 |
untagged = (files is None) |
|
1697 |
if untagged: |
|
1698 |
files = list(iter_untagged(tree, None)) |
|
1699 |
previous_files = [] |
|
1700 |
while len(files) > 0: |
|
1701 |
previous_files.extend(files) |
|
1702 |
if id_type == "explicit": |
|
1703 |
cmdutil.add_id(files) |
|
1704 |
elif id_type == "tagline" or id_type == "implicit": |
|
1705 |
for file in files: |
|
1706 |
try: |
|
1707 |
implicit = (id_type == "implicit") |
|
1708 |
cmdutil.add_tagline_or_explicit_id(file, False, |
|
1709 |
implicit) |
|
1710 |
except cmdutil.AlreadyTagged: |
|
1711 |
print "\"%s\" already has a tagline." % file |
|
1712 |
except cmdutil.NoCommentSyntax: |
|
1713 |
pass
|
|
1714 |
#do inventory after tagging until no untagged files are encountered
|
|
1715 |
if untagged: |
|
1716 |
files = [] |
|
1717 |
for file in iter_untagged(tree, None): |
|
1718 |
if not file in previous_files: |
|
1719 |
files.append(file) |
|
1720 |
||
1721 |
else: |
|
1722 |
break
|
|
1723 |
||
1724 |
def get_parser(self): |
|
1725 |
"""
|
|
1726 |
Returns the options parser to use for the "revision" command.
|
|
1727 |
||
1728 |
:rtype: cmdutil.CmdOptionParser
|
|
1729 |
"""
|
|
1730 |
parser=cmdutil.CmdOptionParser("fai add-id file1 [file2] [file3]...") |
|
1731 |
# ddaa suggests removing this to promote GUIDs. Let's see who squalks.
|
|
1732 |
# parser.add_option("-i", "--id", dest="id",
|
|
1733 |
# help="Specify id for a single file", default=None)
|
|
1734 |
parser.add_option("--tltl", action="store_true", |
|
1735 |
dest="lord_style", help="Use Tom Lord's style of id.") |
|
1736 |
parser.add_option("--explicit", action="store_const", |
|
1737 |
const="explicit", dest="id_type", |
|
1738 |
help="Use an explicit id", default="auto") |
|
1739 |
parser.add_option("--tagline", action="store_const", |
|
1740 |
const="tagline", dest="id_type", |
|
1741 |
help="Use a tagline id") |
|
1742 |
parser.add_option("--implicit", action="store_const", |
|
1743 |
const="implicit", dest="id_type", |
|
1744 |
help="Use an implicit id (deprecated)") |
|
1745 |
parser.add_option("--untagged", action="store_true", |
|
1746 |
dest="untagged", default=False, |
|
1747 |
help="tag all untagged files") |
|
1748 |
return parser |
|
1749 |
||
1750 |
def help(self, parser=None): |
|
1751 |
"""
|
|
1752 |
Prints a help message.
|
|
1753 |
||
1754 |
:param parser: If supplied, the parser to use for generating help. If \
|
|
1755 |
not supplied, it is retrieved.
|
|
1756 |
:type parser: cmdutil.CmdOptionParser
|
|
1757 |
"""
|
|
1758 |
if parser==None: |
|
1759 |
parser=self.get_parser() |
|
1760 |
parser.print_help() |
|
1761 |
print """ |
|
1762 |
Adds an inventory to the specified file(s) and directories. If --untagged is
|
|
1763 |
specified, adds inventory to all untagged files and directories.
|
|
1764 |
"""
|
|
1765 |
return
|
|
1766 |
||
1767 |
||
1768 |
class Merge(BaseCommand): |
|
1769 |
"""
|
|
1770 |
Merges changes from other versions into the current tree
|
|
1771 |
"""
|
|
1772 |
def __init__(self): |
|
1773 |
self.description="Merges changes from other versions" |
|
1774 |
try: |
|
1775 |
self.tree = arch.tree_root() |
|
1776 |
except: |
|
1777 |
self.tree = None |
|
1778 |
||
1779 |
||
1780 |
def get_completer(self, arg, index): |
|
1781 |
if self.tree is None: |
|
1782 |
raise arch.errors.TreeRootError |
|
1783 |
return cmdutil.merge_completions(self.tree, arg, index) |
|
1784 |
||
1785 |
def do_command(self, cmdargs): |
|
1786 |
"""
|
|
1787 |
Master function that perfoms the "merge" command.
|
|
1788 |
"""
|
|
1789 |
parser=self.get_parser() |
|
1790 |
(options, args) = parser.parse_args(cmdargs) |
|
1791 |
if options.diff3: |
|
1792 |
action="star-merge" |
|
1793 |
else: |
|
1794 |
action = options.action |
|
1795 |
||
1796 |
if self.tree is None: |
|
1797 |
raise arch.errors.TreeRootError(os.getcwd()) |
|
1798 |
if cmdutil.has_changed(ancillary.comp_revision(self.tree)): |
|
1799 |
raise UncommittedChanges(self.tree) |
|
1800 |
||
1801 |
if len(args) > 0: |
|
1802 |
revisions = [] |
|
1803 |
for arg in args: |
|
1804 |
revisions.append(cmdutil.determine_revision_arch(self.tree, |
|
1805 |
arg)) |
|
1806 |
source = "from commandline" |
|
1807 |
else: |
|
1808 |
revisions = ancillary.iter_partner_revisions(self.tree, |
|
1809 |
self.tree.tree_version) |
|
1810 |
source = "from partner version" |
|
1811 |
revisions = misc.rewind_iterator(revisions) |
|
1812 |
try: |
|
1813 |
revisions.next() |
|
1814 |
revisions.rewind() |
|
1815 |
except StopIteration, e: |
|
1816 |
revision = cmdutil.tag_cur(self.tree) |
|
1817 |
if revision is None: |
|
1818 |
raise CantDetermineRevision("", "No version specified, no " |
|
1819 |
"partner-versions, and no tag"
|
|
1820 |
" source") |
|
1821 |
revisions = [revision] |
|
1822 |
source = "from tag source" |
|
1823 |
for revision in revisions: |
|
1824 |
cmdutil.ensure_archive_registered(revision.archive) |
|
1825 |
cmdutil.colorize(arch.Chatter("* Merging %s [%s]" % |
|
1826 |
(revision, source))) |
|
1827 |
if action=="native-merge" or action=="update": |
|
1828 |
if self.native_merge(revision, action) == 0: |
|
1829 |
continue
|
|
1830 |
elif action=="star-merge": |
|
1831 |
try: |
|
1832 |
self.star_merge(revision, options.diff3) |
|
1833 |
except errors.MergeProblem, e: |
|
1834 |
break
|
|
1835 |
if cmdutil.has_changed(self.tree.tree_version): |
|
1836 |
break
|
|
1837 |
||
1838 |
def star_merge(self, revision, diff3): |
|
1839 |
"""Perform a star-merge on the current tree.
|
|
1840 |
|
|
1841 |
:param revision: The revision to use for the merge
|
|
1842 |
:type revision: `arch.Revision`
|
|
1843 |
:param diff3: If true, do a diff3 merge
|
|
1844 |
:type diff3: bool
|
|
1845 |
"""
|
|
1846 |
try: |
|
1847 |
for line in self.tree.iter_star_merge(revision, diff3=diff3): |
|
1848 |
cmdutil.colorize(line) |
|
1849 |
except arch.util.ExecProblem, e: |
|
1850 |
if e.proc.status is not None and e.proc.status == 1: |
|
1851 |
if e.proc.error: |
|
1852 |
print e.proc.error |
|
1853 |
raise MergeProblem |
|
1854 |
else: |
|
1855 |
raise
|
|
1856 |
||
1857 |
def native_merge(self, other_revision, action): |
|
1858 |
"""Perform a native-merge on the current tree.
|
|
1859 |
|
|
1860 |
:param other_revision: The revision to use for the merge
|
|
1861 |
:type other_revision: `arch.Revision`
|
|
1862 |
:return: 0 if the merge was skipped, 1 if it was applied
|
|
1863 |
"""
|
|
1864 |
other_tree = arch_compound.find_or_make_local_revision(other_revision) |
|
1865 |
try: |
|
1866 |
if action == "native-merge": |
|
1867 |
ancestor = arch_compound.merge_ancestor2(self.tree, other_tree, |
|
1868 |
other_revision) |
|
1869 |
elif action == "update": |
|
1870 |
ancestor = arch_compound.tree_latest(self.tree, |
|
1871 |
other_revision.version) |
|
1872 |
except CantDetermineRevision, e: |
|
1873 |
raise CommandFailedWrapper(e) |
|
1874 |
cmdutil.colorize(arch.Chatter("* Found common ancestor %s" % ancestor)) |
|
1875 |
if (ancestor == other_revision): |
|
1876 |
cmdutil.colorize(arch.Chatter("* Skipping redundant merge" |
|
1877 |
% ancestor)) |
|
1878 |
return 0 |
|
1879 |
delta = cmdutil.apply_delta(ancestor, other_tree, self.tree) |
|
1880 |
for line in cmdutil.iter_apply_delta_filter(delta): |
|
1881 |
cmdutil.colorize(line) |
|
1882 |
return 1 |
|
1883 |
||
1884 |
||
1885 |
||
1886 |
def get_parser(self): |
|
1887 |
"""
|
|
1888 |
Returns the options parser to use for the "merge" command.
|
|
1889 |
||
1890 |
:rtype: cmdutil.CmdOptionParser
|
|
1891 |
"""
|
|
1892 |
parser=cmdutil.CmdOptionParser("fai merge [VERSION]") |
|
1893 |
parser.add_option("-s", "--star-merge", action="store_const", |
|
1894 |
dest="action", help="Use star-merge", |
|
1895 |
const="star-merge", default="native-merge") |
|
1896 |
parser.add_option("--update", action="store_const", |
|
1897 |
dest="action", help="Use update picker", |
|
1898 |
const="update") |
|
1899 |
parser.add_option("--diff3", action="store_true", |
|
1900 |
dest="diff3", |
|
1901 |
help="Use diff3 for merge (implies star-merge)") |
|
1902 |
return parser |
|
1903 |
||
1904 |
def help(self, parser=None): |
|
1905 |
"""
|
|
1906 |
Prints a help message.
|
|
1907 |
||
1908 |
:param parser: If supplied, the parser to use for generating help. If \
|
|
1909 |
not supplied, it is retrieved.
|
|
1910 |
:type parser: cmdutil.CmdOptionParser
|
|
1911 |
"""
|
|
1912 |
if parser==None: |
|
1913 |
parser=self.get_parser() |
|
1914 |
parser.print_help() |
|
1915 |
print """ |
|
1916 |
Performs a merge operation using the specified version.
|
|
1917 |
"""
|
|
1918 |
return
|
|
1919 |
||
1920 |
class ELog(BaseCommand): |
|
1921 |
"""
|
|
1922 |
Produces a raw patchlog and invokes the user's editor
|
|
1923 |
"""
|
|
1924 |
def __init__(self): |
|
1925 |
self.description="Edit a patchlog to commit" |
|
1926 |
try: |
|
1927 |
self.tree = arch.tree_root() |
|
1928 |
except: |
|
1929 |
self.tree = None |
|
1930 |
||
1931 |
||
1932 |
def do_command(self, cmdargs): |
|
1933 |
"""
|
|
1934 |
Master function that perfoms the "elog" command.
|
|
1935 |
"""
|
|
1936 |
parser=self.get_parser() |
|
1937 |
(options, args) = parser.parse_args(cmdargs) |
|
1938 |
if self.tree is None: |
|
1939 |
raise arch.errors.TreeRootError |
|
1940 |
||
1941 |
try: |
|
1942 |
edit_log(self.tree, self.tree.tree_version) |
|
1943 |
except pylon.errors.NoEditorSpecified, e: |
|
1944 |
raise pylon.errors.CommandFailedWrapper(e) |
|
1945 |
||
1946 |
def get_parser(self): |
|
1947 |
"""
|
|
1948 |
Returns the options parser to use for the "merge" command.
|
|
1949 |
||
1950 |
:rtype: cmdutil.CmdOptionParser
|
|
1951 |
"""
|
|
1952 |
parser=cmdutil.CmdOptionParser("fai elog") |
|
1953 |
return parser |
|
1954 |
||
1955 |
||
1956 |
def help(self, parser=None): |
|
1957 |
"""
|
|
1958 |
Invokes $EDITOR to produce a log for committing.
|
|
1959 |
||
1960 |
:param parser: If supplied, the parser to use for generating help. If \
|
|
1961 |
not supplied, it is retrieved.
|
|
1962 |
:type parser: cmdutil.CmdOptionParser
|
|
1963 |
"""
|
|
1964 |
if parser==None: |
|
1965 |
parser=self.get_parser() |
|
1966 |
parser.print_help() |
|
1967 |
print """ |
|
1968 |
Invokes $EDITOR to produce a log for committing.
|
|
1969 |
"""
|
|
1970 |
return
|
|
1971 |
||
1972 |
def edit_log(tree, version): |
|
1973 |
"""Makes and edits the log for a tree. Does all kinds of fancy things
|
|
1974 |
like log templates and merge summaries and log-for-merge
|
|
1975 |
|
|
1976 |
:param tree: The tree to edit the log for
|
|
1977 |
:type tree: `arch.WorkingTree`
|
|
1978 |
"""
|
|
1979 |
#ensure we have an editor before preparing the log
|
|
1980 |
cmdutil.find_editor() |
|
1981 |
log = tree.log_message(create=False, version=version) |
|
1982 |
log_is_new = False |
|
1983 |
if log is None or cmdutil.prompt("Overwrite log"): |
|
1984 |
if log is not None: |
|
1985 |
os.remove(log.name) |
|
1986 |
log = tree.log_message(create=True, version=version) |
|
1987 |
log_is_new = True |
|
1988 |
tmplog = log.name |
|
1989 |
template = pylon.log_template_path(tree) |
|
1990 |
if template: |
|
1991 |
shutil.copyfile(template, tmplog) |
|
1992 |
comp_version = ancillary.comp_revision(tree).version |
|
1993 |
new_merges = cmdutil.iter_new_merges(tree, comp_version) |
|
1994 |
new_merges = cmdutil.direct_merges(new_merges) |
|
1995 |
log["Summary"] = pylon.merge_summary(new_merges, |
|
1996 |
version) |
|
1997 |
if len(new_merges) > 0: |
|
1998 |
if cmdutil.prompt("Log for merge"): |
|
1999 |
if cmdutil.prompt("changelog for merge"): |
|
2000 |
mergestuff = "Patches applied:\n" |
|
2001 |
mergestuff += pylon.changelog_for_merge(new_merges) |
|
2002 |
else: |
|
2003 |
mergestuff = cmdutil.log_for_merge(tree, comp_version) |
|
2004 |
log.description += mergestuff |
|
2005 |
log.save() |
|
2006 |
try: |
|
2007 |
cmdutil.invoke_editor(log.name) |
|
2008 |
except: |
|
2009 |
if log_is_new: |
|
2010 |
os.remove(log.name) |
|
2011 |
raise
|
|
2012 |
||
2013 |
||
2014 |
class MirrorArchive(BaseCommand): |
|
2015 |
"""
|
|
2016 |
Updates a mirror from an archive
|
|
2017 |
"""
|
|
2018 |
def __init__(self): |
|
2019 |
self.description="Update a mirror from an archive" |
|
2020 |
||
2021 |
def do_command(self, cmdargs): |
|
2022 |
"""
|
|
2023 |
Master function that perfoms the "revision" command.
|
|
2024 |
"""
|
|
2025 |
||
2026 |
parser=self.get_parser() |
|
2027 |
(options, args) = parser.parse_args(cmdargs) |
|
2028 |
if len(args) > 1: |
|
2029 |
raise GetHelp |
|
2030 |
try: |
|
2031 |
tree = arch.tree_root() |
|
2032 |
except: |
|
2033 |
tree = None |
|
2034 |
||
2035 |
if len(args) == 0: |
|
2036 |
if tree is not None: |
|
2037 |
name = tree.tree_version() |
|
2038 |
else: |
|
2039 |
name = cmdutil.expand_alias(args[0], tree) |
|
2040 |
name = arch.NameParser(name) |
|
2041 |
||
2042 |
to_arch = name.get_archive() |
|
2043 |
from_arch = cmdutil.get_mirror_source(arch.Archive(to_arch)) |
|
2044 |
limit = name.get_nonarch() |
|
2045 |
||
2046 |
iter = arch_core.mirror_archive(from_arch,to_arch, limit) |
|
2047 |
for line in arch.chatter_classifier(iter): |
|
2048 |
cmdutil.colorize(line) |
|
2049 |
||
2050 |
def get_parser(self): |
|
2051 |
"""
|
|
2052 |
Returns the options parser to use for the "revision" command.
|
|
2053 |
||
2054 |
:rtype: cmdutil.CmdOptionParser
|
|
2055 |
"""
|
|
2056 |
parser=cmdutil.CmdOptionParser("fai mirror-archive ARCHIVE") |
|
2057 |
return parser |
|
2058 |
||
2059 |
def help(self, parser=None): |
|
2060 |
"""
|
|
2061 |
Prints a help message.
|
|
2062 |
||
2063 |
:param parser: If supplied, the parser to use for generating help. If \
|
|
2064 |
not supplied, it is retrieved.
|
|
2065 |
:type parser: cmdutil.CmdOptionParser
|
|
2066 |
"""
|
|
2067 |
if parser==None: |
|
2068 |
parser=self.get_parser() |
|
2069 |
parser.print_help() |
|
2070 |
print """ |
|
2071 |
Updates a mirror from an archive. If a branch, package, or version is
|
|
2072 |
supplied, only changes under it are mirrored.
|
|
2073 |
"""
|
|
2074 |
return
|
|
2075 |
||
2076 |
def help_tree_spec(): |
|
2077 |
print """Specifying revisions (default: tree) |
|
2078 |
Revisions may be specified by alias, revision, version or patchlevel.
|
|
2079 |
Revisions or versions may be fully qualified. Unqualified revisions, versions,
|
|
2080 |
or patchlevels use the archive of the current project tree. Versions will
|
|
2081 |
use the latest patchlevel in the tree. Patchlevels will use the current tree-
|
|
2082 |
version.
|
|
2083 |
||
2084 |
Use "alias" to list available (user and automatic) aliases."""
|
|
2085 |
||
2086 |
auto_alias = [ |
|
2087 |
"acur", |
|
2088 |
"The latest revision in the archive of the tree-version. You can specify \ |
|
2089 |
a different version like so: acur:foo--bar--0 (aliases can be used)", |
|
2090 |
"tcur", |
|
2091 |
"""(tree current) The latest revision in the tree of the tree-version. \
|
|
2092 |
You can specify a different version like so: tcur:foo--bar--0 (aliases can be \
|
|
2093 |
used).""", |
|
2094 |
"tprev" , |
|
2095 |
"""(tree previous) The previous revision in the tree of the tree-version. To \
|
|
2096 |
specify an older revision, use a number, e.g. "tprev:4" """, |
|
2097 |
"tanc" , |
|
2098 |
"""(tree ancestor) The ancestor revision of the tree To specify an older \
|
|
2099 |
revision, use a number, e.g. "tanc:4".""", |
|
2100 |
"tdate" , |
|
2101 |
"""(tree date) The latest revision from a given date, e.g. "tdate:July 6".""", |
|
2102 |
"tmod" , |
|
2103 |
""" (tree modified) The latest revision to modify a given file, e.g. \
|
|
2104 |
"tmod:engine.cpp" or "tmod:engine.cpp:16".""", |
|
2105 |
"ttag" , |
|
2106 |
"""(tree tag) The revision that was tagged into the current tree revision, \
|
|
2107 |
according to the tree""", |
|
2108 |
"tagcur", |
|
2109 |
"""(tag current) The latest revision of the version that the current tree \
|
|
2110 |
was tagged from.""", |
|
2111 |
"mergeanc" , |
|
2112 |
"""The common ancestor of the current tree and the specified revision. \
|
|
2113 |
Defaults to the first partner-version's latest revision or to tagcur.""", |
|
2114 |
]
|
|
2115 |
||
2116 |
||
2117 |
def is_auto_alias(name): |
|
2118 |
"""Determine whether a name is an auto alias name
|
|
2119 |
||
2120 |
:param name: the name to check
|
|
2121 |
:type name: str
|
|
2122 |
:return: True if the name is an auto alias, false if not
|
|
2123 |
:rtype: bool
|
|
2124 |
"""
|
|
2125 |
return name in [f for (f, v) in pylon.util.iter_pairs(auto_alias)] |
|
2126 |
||
2127 |
||
2128 |
def display_def(iter, wrap = 80): |
|
2129 |
"""Display a list of definitions
|
|
2130 |
||
2131 |
:param iter: iter of name, definition pairs
|
|
2132 |
:type iter: iter of (str, str)
|
|
2133 |
:param wrap: The width for text wrapping
|
|
2134 |
:type wrap: int
|
|
2135 |
"""
|
|
2136 |
vals = list(iter) |
|
2137 |
maxlen = 0 |
|
2138 |
for (key, value) in vals: |
|
2139 |
if len(key) > maxlen: |
|
2140 |
maxlen = len(key) |
|
2141 |
for (key, value) in vals: |
|
2142 |
tw=textwrap.TextWrapper(width=wrap, |
|
2143 |
initial_indent=key.rjust(maxlen)+" : ", |
|
2144 |
subsequent_indent="".rjust(maxlen+3)) |
|
2145 |
print tw.fill(value) |
|
2146 |
||
2147 |
||
2148 |
def help_aliases(tree): |
|
2149 |
print """Auto-generated aliases""" |
|
2150 |
display_def(pylon.util.iter_pairs(auto_alias)) |
|
2151 |
print "User aliases" |
|
2152 |
display_def(ancillary.iter_all_alias(tree)) |
|
2153 |
||
2154 |
class Inventory(BaseCommand): |
|
2155 |
"""List the status of files in the tree"""
|
|
2156 |
def __init__(self): |
|
2157 |
self.description=self.__doc__ |
|
2158 |
||
2159 |
def do_command(self, cmdargs): |
|
2160 |
"""
|
|
2161 |
Master function that perfoms the "revision" command.
|
|
2162 |
"""
|
|
2163 |
||
2164 |
parser=self.get_parser() |
|
2165 |
(options, args) = parser.parse_args(cmdargs) |
|
2166 |
tree = arch.tree_root() |
|
2167 |
categories = [] |
|
2168 |
||
2169 |
if (options.source): |
|
2170 |
categories.append(arch_core.SourceFile) |
|
2171 |
if (options.precious): |
|
2172 |
categories.append(arch_core.PreciousFile) |
|
2173 |
if (options.backup): |
|
2174 |
categories.append(arch_core.BackupFile) |
|
2175 |
if (options.junk): |
|
2176 |
categories.append(arch_core.JunkFile) |
|
2177 |
||
2178 |
if len(categories) == 1: |
|
2179 |
show_leading = False |
|
2180 |
else: |
|
2181 |
show_leading = True |
|
2182 |
||
2183 |
if len(categories) == 0: |
|
2184 |
categories = None |
|
2185 |
||
2186 |
if options.untagged: |
|
2187 |
categories = arch_core.non_root |
|
2188 |
show_leading = False |
|
2189 |
tagged = False |
|
2190 |
else: |
|
2191 |
tagged = None |
|
2192 |
||
2193 |
for file in arch_core.iter_inventory_filter(tree, None, |
|
2194 |
control_files=options.control_files, |
|
2195 |
categories = categories, tagged=tagged): |
|
2196 |
print arch_core.file_line(file, |
|
2197 |
category = show_leading, |
|
2198 |
untagged = show_leading, |
|
2199 |
id = options.ids) |
|
2200 |
||
2201 |
def get_parser(self): |
|
2202 |
"""
|
|
2203 |
Returns the options parser to use for the "revision" command.
|
|
2204 |
||
2205 |
:rtype: cmdutil.CmdOptionParser
|
|
2206 |
"""
|
|
2207 |
parser=cmdutil.CmdOptionParser("fai inventory [options]") |
|
2208 |
parser.add_option("--ids", action="store_true", dest="ids", |
|
2209 |
help="Show file ids") |
|
2210 |
parser.add_option("--control", action="store_true", |
|
2211 |
dest="control_files", help="include control files") |
|
2212 |
parser.add_option("--source", action="store_true", dest="source", |
|
2213 |
help="List source files") |
|
2214 |
parser.add_option("--backup", action="store_true", dest="backup", |
|
2215 |
help="List backup files") |
|
2216 |
parser.add_option("--precious", action="store_true", dest="precious", |
|
2217 |
help="List precious files") |
|
2218 |
parser.add_option("--junk", action="store_true", dest="junk", |
|
2219 |
help="List junk files") |
|
2220 |
parser.add_option("--unrecognized", action="store_true", |
|
2221 |
dest="unrecognized", help="List unrecognized files") |
|
2222 |
parser.add_option("--untagged", action="store_true", |
|
2223 |
dest="untagged", help="List only untagged files") |
|
2224 |
return parser |
|
2225 |
||
2226 |
def help(self, parser=None): |
|
2227 |
"""
|
|
2228 |
Prints a help message.
|
|
2229 |
||
2230 |
:param parser: If supplied, the parser to use for generating help. If \
|
|
2231 |
not supplied, it is retrieved.
|
|
2232 |
:type parser: cmdutil.CmdOptionParser
|
|
2233 |
"""
|
|
2234 |
if parser==None: |
|
2235 |
parser=self.get_parser() |
|
2236 |
parser.print_help() |
|
2237 |
print """ |
|
2238 |
Lists the status of files in the archive:
|
|
2239 |
S source
|
|
2240 |
P precious
|
|
2241 |
B backup
|
|
2242 |
J junk
|
|
2243 |
U unrecognized
|
|
2244 |
T tree root
|
|
2245 |
? untagged-source
|
|
2246 |
Leading letter are not displayed if only one kind of file is shown
|
|
2247 |
"""
|
|
2248 |
return
|
|
2249 |
||
2250 |
||
2251 |
class Alias(BaseCommand): |
|
2252 |
"""List or adjust aliases"""
|
|
2253 |
def __init__(self): |
|
2254 |
self.description=self.__doc__ |
|
2255 |
||
2256 |
def get_completer(self, arg, index): |
|
2257 |
if index > 2: |
|
2258 |
return () |
|
2259 |
try: |
|
2260 |
self.tree = arch.tree_root() |
|
2261 |
except: |
|
2262 |
self.tree = None |
|
2263 |
||
2264 |
if index == 0: |
|
2265 |
return [part[0]+" " for part in ancillary.iter_all_alias(self.tree)] |
|
2266 |
elif index == 1: |
|
2267 |
return cmdutil.iter_revision_completions(arg, self.tree) |
|
2268 |
||
2269 |
||
2270 |
def do_command(self, cmdargs): |
|
2271 |
"""
|
|
2272 |
Master function that perfoms the "revision" command.
|
|
2273 |
"""
|
|
2274 |
||
2275 |
parser=self.get_parser() |
|
2276 |
(options, args) = parser.parse_args(cmdargs) |
|
2277 |
try: |
|
2278 |
self.tree = arch.tree_root() |
|
2279 |
except: |
|
2280 |
self.tree = None |
|
2281 |
||
2282 |
||
2283 |
try: |
|
2284 |
options.action(args, options) |
|
2285 |
except cmdutil.ForbiddenAliasSyntax, e: |
|
2286 |
raise CommandFailedWrapper(e) |
|
2287 |
||
2288 |
def no_prefix(self, alias): |
|
2289 |
if alias.startswith("^"): |
|
2290 |
alias = alias[1:] |
|
2291 |
return alias |
|
2292 |
||
2293 |
def arg_dispatch(self, args, options): |
|
2294 |
"""Add, modify, or list aliases, depending on number of arguments
|
|
2295 |
||
2296 |
:param args: The list of commandline arguments
|
|
2297 |
:type args: list of str
|
|
2298 |
:param options: The commandline options
|
|
2299 |
"""
|
|
2300 |
if len(args) == 0: |
|
2301 |
help_aliases(self.tree) |
|
2302 |
return
|
|
2303 |
else: |
|
2304 |
alias = self.no_prefix(args[0]) |
|
2305 |
if len(args) == 1: |
|
2306 |
self.print_alias(alias) |
|
2307 |
elif (len(args)) == 2: |
|
2308 |
self.add(alias, args[1], options) |
|
2309 |
else: |
|
2310 |
raise cmdutil.GetHelp |
|
2311 |
||
2312 |
def print_alias(self, alias): |
|
2313 |
answer = None |
|
2314 |
if is_auto_alias(alias): |
|
2315 |
raise pylon.errors.IsAutoAlias(alias, "\"%s\" is an auto alias." |
|
2316 |
" Use \"revision\" to expand auto aliases." % alias) |
|
2317 |
for pair in ancillary.iter_all_alias(self.tree): |
|
2318 |
if pair[0] == alias: |
|
2319 |
answer = pair[1] |
|
2320 |
if answer is not None: |
|
2321 |
print answer |
|
2322 |
else: |
|
2323 |
print "The alias %s is not assigned." % alias |
|
2324 |
||
2325 |
def add(self, alias, expansion, options): |
|
2326 |
"""Add or modify aliases
|
|
2327 |
||
2328 |
:param alias: The alias name to create/modify
|
|
2329 |
:type alias: str
|
|
2330 |
:param expansion: The expansion to assign to the alias name
|
|
2331 |
:type expansion: str
|
|
2332 |
:param options: The commandline options
|
|
2333 |
"""
|
|
2334 |
if is_auto_alias(alias): |
|
2335 |
raise IsAutoAlias(alias) |
|
2336 |
newlist = "" |
|
2337 |
written = False |
|
2338 |
new_line = "%s=%s\n" % (alias, cmdutil.expand_alias(expansion, |
|
2339 |
self.tree)) |
|
2340 |
ancillary.check_alias(new_line.rstrip("\n"), [alias, expansion]) |
|
2341 |
||
2342 |
for pair in self.get_iterator(options): |
|
2343 |
if pair[0] != alias: |
|
2344 |
newlist+="%s=%s\n" % (pair[0], pair[1]) |
|
2345 |
elif not written: |
|
2346 |
newlist+=new_line |
|
2347 |
written = True |
|
2348 |
if not written: |
|
2349 |
newlist+=new_line |
|
2350 |
self.write_aliases(newlist, options) |
|
2351 |
||
2352 |
def delete(self, args, options): |
|
2353 |
"""Delete the specified alias
|
|
2354 |
||
2355 |
:param args: The list of arguments
|
|
2356 |
:type args: list of str
|
|
2357 |
:param options: The commandline options
|
|
2358 |
"""
|
|
2359 |
deleted = False |
|
2360 |
if len(args) != 1: |
|
2361 |
raise cmdutil.GetHelp |
|
2362 |
alias = self.no_prefix(args[0]) |
|
2363 |
if is_auto_alias(alias): |
|
2364 |
raise IsAutoAlias(alias) |
|
2365 |
newlist = "" |
|
2366 |
for pair in self.get_iterator(options): |
|
2367 |
if pair[0] != alias: |
|
2368 |
newlist+="%s=%s\n" % (pair[0], pair[1]) |
|
2369 |
else: |
|
2370 |
deleted = True |
|
2371 |
if not deleted: |
|
2372 |
raise errors.NoSuchAlias(alias) |
|
2373 |
self.write_aliases(newlist, options) |
|
2374 |
||
2375 |
def get_alias_file(self, options): |
|
2376 |
"""Return the name of the alias file to use
|
|
2377 |
||
2378 |
:param options: The commandline options
|
|
2379 |
"""
|
|
2380 |
if options.tree: |
|
2381 |
if self.tree is None: |
|
2382 |
self.tree == arch.tree_root() |
|
2383 |
return str(self.tree)+"/{arch}/+aliases" |
|
2384 |
else: |
|
2385 |
return "~/.aba/aliases" |
|
2386 |
||
2387 |
def get_iterator(self, options): |
|
2388 |
"""Return the alias iterator to use
|
|
2389 |
||
2390 |
:param options: The commandline options
|
|
2391 |
"""
|
|
2392 |
return ancillary.iter_alias(self.get_alias_file(options)) |
|
2393 |
||
2394 |
def write_aliases(self, newlist, options): |
|
2395 |
"""Safely rewrite the alias file
|
|
2396 |
:param newlist: The new list of aliases
|
|
2397 |
:type newlist: str
|
|
2398 |
:param options: The commandline options
|
|
2399 |
"""
|
|
2400 |
filename = os.path.expanduser(self.get_alias_file(options)) |
|
2401 |
file = util.NewFileVersion(filename) |
|
2402 |
file.write(newlist) |
|
2403 |
file.commit() |
|
2404 |
||
2405 |
||
2406 |
def get_parser(self): |
|
2407 |
"""
|
|
2408 |
Returns the options parser to use for the "alias" command.
|
|
2409 |
||
2410 |
:rtype: cmdutil.CmdOptionParser
|
|
2411 |
"""
|
|
2412 |
parser=cmdutil.CmdOptionParser("fai alias [ALIAS] [NAME]") |
|
2413 |
parser.add_option("-d", "--delete", action="store_const", dest="action", |
|
2414 |
const=self.delete, default=self.arg_dispatch, |
|
2415 |
help="Delete an alias") |
|
2416 |
parser.add_option("--tree", action="store_true", dest="tree", |
|
2417 |
help="Create a per-tree alias", default=False) |
|
2418 |
return parser |
|
2419 |
||
2420 |
def help(self, parser=None): |
|
2421 |
"""
|
|
2422 |
Prints a help message.
|
|
2423 |
||
2424 |
:param parser: If supplied, the parser to use for generating help. If \
|
|
2425 |
not supplied, it is retrieved.
|
|
2426 |
:type parser: cmdutil.CmdOptionParser
|
|
2427 |
"""
|
|
2428 |
if parser==None: |
|
2429 |
parser=self.get_parser() |
|
2430 |
parser.print_help() |
|
2431 |
print """ |
|
2432 |
Lists current aliases or modifies the list of aliases.
|
|
2433 |
||
2434 |
If no arguments are supplied, aliases will be listed. If two arguments are
|
|
2435 |
supplied, the specified alias will be created or modified. If -d or --delete
|
|
2436 |
is supplied, the specified alias will be deleted.
|
|
2437 |
||
2438 |
You can create aliases that refer to any fully-qualified part of the
|
|
2439 |
Arch namespace, e.g.
|
|
2440 |
archive,
|
|
2441 |
archive/category,
|
|
2442 |
archive/category--branch,
|
|
2443 |
archive/category--branch--version (my favourite)
|
|
2444 |
archive/category--branch--version--patchlevel
|
|
2445 |
||
2446 |
Aliases can be used automatically by native commands. To use them
|
|
2447 |
with external or tla commands, prefix them with ^ (you can do this
|
|
2448 |
with native commands, too).
|
|
2449 |
"""
|
|
2450 |
||
2451 |
||
2452 |
class RequestMerge(BaseCommand): |
|
2453 |
"""Submit a merge request to Bug Goo"""
|
|
2454 |
def __init__(self): |
|
2455 |
self.description=self.__doc__ |
|
2456 |
||
2457 |
def do_command(self, cmdargs): |
|
2458 |
"""Submit a merge request
|
|
2459 |
||
2460 |
:param cmdargs: The commandline arguments
|
|
2461 |
:type cmdargs: list of str
|
|
2462 |
"""
|
|
2463 |
parser = self.get_parser() |
|
2464 |
(options, args) = parser.parse_args(cmdargs) |
|
2465 |
try: |
|
2466 |
cmdutil.find_editor() |
|
2467 |
except pylon.errors.NoEditorSpecified, e: |
|
2468 |
raise pylon.errors.CommandFailedWrapper(e) |
|
2469 |
try: |
|
2470 |
self.tree=arch.tree_root() |
|
2471 |
except: |
|
2472 |
self.tree=None |
|
2473 |
base, revisions = self.revision_specs(args) |
|
2474 |
message = self.make_headers(base, revisions) |
|
2475 |
message += self.make_summary(revisions) |
|
2476 |
path = self.edit_message(message) |
|
2477 |
message = self.tidy_message(path) |
|
2478 |
if cmdutil.prompt("Send merge"): |
|
2479 |
self.send_message(message) |
|
2480 |
print "Merge request sent" |
|
2481 |
||
2482 |
def make_headers(self, base, revisions): |
|
2483 |
"""Produce email and Bug Goo header strings
|
|
2484 |
||
2485 |
:param base: The base revision to apply merges to
|
|
2486 |
:type base: `arch.Revision`
|
|
2487 |
:param revisions: The revisions to replay into the base
|
|
2488 |
:type revisions: list of `arch.Patchlog`
|
|
2489 |
:return: The headers
|
|
2490 |
:rtype: str
|
|
2491 |
"""
|
|
2492 |
headers = "To: gnu-arch-users@gnu.org\n" |
|
2493 |
headers += "From: %s\n" % options.fromaddr |
|
2494 |
if len(revisions) == 1: |
|
2495 |
headers += "Subject: [MERGE REQUEST] %s\n" % revisions[0].summary |
|
2496 |
else: |
|
2497 |
headers += "Subject: [MERGE REQUEST]\n" |
|
2498 |
headers += "\n" |
|
2499 |
headers += "Base-Revision: %s\n" % base |
|
2500 |
for revision in revisions: |
|
2501 |
headers += "Revision: %s\n" % revision.revision |
|
2502 |
headers += "Bug: \n\n" |
|
2503 |
return headers |
|
2504 |
||
2505 |
def make_summary(self, logs): |
|
2506 |
"""Generate a summary of merges
|
|
2507 |
||
2508 |
:param logs: the patchlogs that were directly added by the merges
|
|
2509 |
:type logs: list of `arch.Patchlog`
|
|
2510 |
:return: the summary
|
|
2511 |
:rtype: str
|
|
2512 |
"""
|
|
2513 |
summary = "" |
|
2514 |
for log in logs: |
|
2515 |
summary+=str(log.revision)+"\n" |
|
2516 |
summary+=log.summary+"\n" |
|
2517 |
if log.description.strip(): |
|
2518 |
summary+=log.description.strip('\n')+"\n\n" |
|
2519 |
return summary |
|
2520 |
||
2521 |
def revision_specs(self, args): |
|
2522 |
"""Determine the base and merge revisions from tree and arguments.
|
|
2523 |
||
2524 |
:param args: The parsed arguments
|
|
2525 |
:type args: list of str
|
|
2526 |
:return: The base revision and merge revisions
|
|
2527 |
:rtype: `arch.Revision`, list of `arch.Patchlog`
|
|
2528 |
"""
|
|
2529 |
if len(args) > 0: |
|
2530 |
target_revision = cmdutil.determine_revision_arch(self.tree, |
|
2531 |
args[0]) |
|
2532 |
else: |
|
2533 |
target_revision = arch_compound.tree_latest(self.tree) |
|
2534 |
if len(args) > 1: |
|
2535 |
merges = [ arch.Patchlog(cmdutil.determine_revision_arch( |
|
2536 |
self.tree, f)) for f in args[1:] ] |
|
2537 |
else: |
|
2538 |
if self.tree is None: |
|
2539 |
raise CantDetermineRevision("", "Not in a project tree") |
|
2540 |
merge_iter = cmdutil.iter_new_merges(self.tree, |
|
2541 |
target_revision.version, |
|
2542 |
False) |
|
2543 |
merges = [f for f in cmdutil.direct_merges(merge_iter)] |
|
2544 |
return (target_revision, merges) |
|
2545 |
||
2546 |
def edit_message(self, message): |
|
2547 |
"""Edit an email message in the user's standard editor
|
|
2548 |
||
2549 |
:param message: The message to edit
|
|
2550 |
:type message: str
|
|
2551 |
:return: the path of the edited message
|
|
2552 |
:rtype: str
|
|
2553 |
"""
|
|
2554 |
if self.tree is None: |
|
2555 |
path = os.get_cwd() |
|
2556 |
else: |
|
2557 |
path = self.tree |
|
2558 |
path += "/,merge-request" |
|
2559 |
file = open(path, 'w') |
|
2560 |
file.write(message) |
|
2561 |
file.flush() |
|
2562 |
cmdutil.invoke_editor(path) |
|
2563 |
return path |
|
2564 |
||
2565 |
def tidy_message(self, path): |
|
2566 |
"""Validate and clean up message.
|
|
2567 |
||
2568 |
:param path: The path to the message to clean up
|
|
2569 |
:type path: str
|
|
2570 |
:return: The parsed message
|
|
2571 |
:rtype: `email.Message`
|
|
2572 |
"""
|
|
2573 |
mail = email.message_from_file(open(path)) |
|
2574 |
if mail["Subject"].strip() == "[MERGE REQUEST]": |
|
2575 |
raise BlandSubject |
|
2576 |
||
2577 |
request = email.message_from_string(mail.get_payload()) |
|
2578 |
if request.has_key("Bug"): |
|
2579 |
if request["Bug"].strip()=="": |
|
2580 |
del request["Bug"] |
|
2581 |
mail.set_payload(request.as_string()) |
|
2582 |
return mail |
|
2583 |
||
2584 |
def send_message(self, message): |
|
2585 |
"""Send a message, using its headers to address it.
|
|
2586 |
||
2587 |
:param message: The message to send
|
|
2588 |
:type message: `email.Message`"""
|
|
2589 |
server = smtplib.SMTP("localhost") |
|
2590 |
server.sendmail(message['From'], message['To'], message.as_string()) |
|
2591 |
server.quit() |
|
2592 |
||
2593 |
def help(self, parser=None): |
|
2594 |
"""Print a usage message
|
|
2595 |
||
2596 |
:param parser: The options parser to use
|
|
2597 |
:type parser: `cmdutil.CmdOptionParser`
|
|
2598 |
"""
|
|
2599 |
if parser is None: |
|
2600 |
parser = self.get_parser() |
|
2601 |
parser.print_help() |
|
2602 |
print """ |
|
2603 |
Sends a merge request formatted for Bug Goo. Intended use: get the tree
|
|
2604 |
you'd like to merge into. Apply the merges you want. Invoke request-merge.
|
|
2605 |
The merge request will open in your $EDITOR.
|
|
2606 |
||
2607 |
When no TARGET is specified, it uses the current tree revision. When
|
|
2608 |
no MERGE is specified, it uses the direct merges (as in "revisions
|
|
2609 |
--direct-merges"). But you can specify just the TARGET, or all the MERGE
|
|
2610 |
revisions.
|
|
2611 |
"""
|
|
2612 |
||
2613 |
def get_parser(self): |
|
2614 |
"""Produce a commandline parser for this command.
|
|
2615 |
||
2616 |
:rtype: `cmdutil.CmdOptionParser`
|
|
2617 |
"""
|
|
2618 |
parser=cmdutil.CmdOptionParser("request-merge [TARGET] [MERGE1...]") |
|
2619 |
return parser |
|
2620 |
||
2621 |
commands = { |
|
2622 |
'changes' : Changes, |
|
2623 |
'help' : Help, |
|
2624 |
'update': Update, |
|
2625 |
'apply-changes':ApplyChanges, |
|
2626 |
'cat-log': CatLog, |
|
2627 |
'commit': Commit, |
|
2628 |
'revision': Revision, |
|
2629 |
'revisions': Revisions, |
|
2630 |
'get': Get, |
|
2631 |
'revert': Revert, |
|
2632 |
'shell': Shell, |
|
2633 |
'add-id': AddID, |
|
2634 |
'merge': Merge, |
|
2635 |
'elog': ELog, |
|
2636 |
'mirror-archive': MirrorArchive, |
|
2637 |
'ninventory': Inventory, |
|
2638 |
'alias' : Alias, |
|
2639 |
'request-merge': RequestMerge, |
|
2640 |
}
|
|
2641 |
||
2642 |
def my_import(mod_name): |
|
2643 |
module = __import__(mod_name) |
|
2644 |
components = mod_name.split('.') |
|
2645 |
for comp in components[1:]: |
|
2646 |
module = getattr(module, comp) |
|
2647 |
return module |
|
2648 |
||
2649 |
def plugin(mod_name): |
|
2650 |
module = my_import(mod_name) |
|
2651 |
module.add_command(commands) |
|
2652 |
||
2653 |
for file in os.listdir(sys.path[0]+"/command"): |
|
2654 |
if len(file) > 3 and file[-3:] == ".py" and file != "__init__.py": |
|
2655 |
plugin("command."+file[:-3]) |
|
2656 |
||
2657 |
suggestions = { |
|
2658 |
'apply-delta' : "Try \"apply-changes\".", |
|
2659 |
'delta' : "To compare two revisions, use \"changes\".", |
|
2660 |
'diff-rev' : "To compare two revisions, use \"changes\".", |
|
2661 |
'undo' : "To undo local changes, use \"revert\".", |
|
2662 |
'undelete' : "To undo only deletions, use \"revert --deletions\"", |
|
2663 |
'missing-from' : "Try \"revisions --missing-from\".", |
|
2664 |
'missing' : "Try \"revisions --missing\".", |
|
2665 |
'missing-merge' : "Try \"revisions --partner-missing\".", |
|
2666 |
'new-merges' : "Try \"revisions --new-merges\".", |
|
2667 |
'cachedrevs' : "Try \"revisions --cacherevs\". (no 'd')", |
|
2668 |
'logs' : "Try \"revisions --logs\"", |
|
2669 |
'tree-source' : "Use the \"^ttag\" alias (\"revision ^ttag\")", |
|
2670 |
'latest-revision' : "Use the \"^acur\" alias (\"revision ^acur\")", |
|
2671 |
'change-version' : "Try \"update REVISION\"", |
|
2672 |
'tree-revision' : "Use the \"^tcur\" alias (\"revision ^tcur\")", |
|
2673 |
'rev-depends' : "Use revisions --dependencies", |
|
2674 |
'auto-get' : "Plain get will do archive lookups", |
|
2675 |
'tagline' : "Use add-id. It uses taglines in tagline trees", |
|
2676 |
'emlog' : "Use elog. It automatically adds log-for-merge text, if any", |
|
2677 |
'library-revisions' : "Use revisions --library", |
|
2678 |
'file-revert' : "Use revert FILE", |
|
2679 |
'join-branch' : "Use replay --logs-only" |
|
2680 |
}
|
|
2681 |
# arch-tag: 19d5739d-3708-486c-93ba-deecc3027fc7
|