05242db906ab9f3cbd612e10d497a7bf65bd8117
[be.git] / libbe / command / diff.py
1 # Copyright (C) 2005-2009 Aaron Bentley and Panometrics, Inc.
2 #                         Gianluca Montecchi <gian@grys.it>
3 #                         W. Trevor King <wking@drexel.edu>
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19 import libbe
20 import libbe.bug
21 import libbe.command
22 import libbe.command.util
23 import libbe.storage
24
25 import libbe.diff
26
27 class Diff (libbe.command.Command):
28     __doc__ = """Compare bug reports with older tree
29
30     >>> import sys
31     >>> import libbe.bugdir
32     >>> bd = libbe.bugdir.SimpleBugDir(memory=False)
33     >>> cmd = Subscribe()
34     >>> cmd._storage = bd.storage
35     >>> cmd._setup_io = lambda i_enc,o_enc : None
36     >>> cmd.stdout = sys.stdout
37
38     >>> original = bd.storage.commit('Original status')
39     >>> bug = bd.bug_from_uuid('a')
40     >>> bug.status = 'closed'
41     >>> changed = bd.vcs.commit('Closed bug a')
42     >>> if bd.vcs.versioned == True:
43     ...     ret = cmd.run(args=[original])
44     ... else:
45     ...     print 'Modified bugs:\\n  a:cm: Bug A\\n    Changed bug settings:\\n      status: open -> closed'
46     Modified bugs:
47       a:cm: Bug A
48         Changed bug settings:
49           status: open -> closed
50     >>> if bd.vcs.versioned == True:
51     ...     ret = cmd.run({'subscribe':'%(bugdir_id)s:mod', 'uuids':True}, [original])
52     ... else:
53     ...     print 'a'
54     a
55     >>> if bd.vcs.versioned == False:
56     ...     ret = cmd.run(args=[original])
57     ... else:
58     ...     raise libbe.command.UserError('This repository not revision-controlled.')
59     Traceback (most recent call last):
60       ...
61     UserError: This repository is not revision-controlled.
62     >>> bd.cleanup()
63     """ % {'bugdir_id':libbe.diff.BUGDIR_ID}
64     name = 'diff'
65
66     def __init__(self, *args, **kwargs):
67         libbe.command.Command.__init__(self, *args, **kwargs)
68         self.options.extend([
69                 libbe.command.Option(name='repo', short_name='r',
70                     help='Compare with repository in REPO instead'
71                          ' of the current repository.',
72                     arg=libbe.command.Argument(
73                         name='repo', metavar='REPO',
74                         completion_callback=libbe.command.util.complete_path)),
75                 libbe.command.Option(name='subscribe', short_name='s',
76                     help='Only print changes matching SUBSCRIPTION, '
77                     'subscription is a comma-separ\ated list of ID:TYPE '
78                     'tuples.  See `be subscribe --help` for descriptions '
79                     'of ID and TYPE.',
80                     arg=libbe.command.Argument(
81                         name='subscribe', metavar='SUBSCRIPTION')),
82                 libbe.command.Option(name='uuids', short_name='u',
83                     help='Only print the changed bug UUIDS.'),
84                 ])
85         self.args.extend([
86                 libbe.command.Argument(
87                     name='revision', metavar='REVISION', default=None,
88                     optional=True)
89                 ])
90
91     def _run(self, **params):
92         try:
93             subscriptions = libbe.diff.subscriptions_from_string(
94                 params['subscribe'])
95         except ValueError, e:
96             raise libbe.command.UserError(e.msg)
97         bugdir = self._get_bugdir()
98         if bugdir.storage.versioned == False:
99             raise libbe.command.UserError(
100                 'This repository is not revision-controlled.')
101         if params['repo'] == None:
102             if params['revision'] == None: # get the most recent revision
103                 params['revision'] = bugdir.storage.revision_id(-1)
104             old_bd = bugdir.duplicate_bugdir(params['revision']) # TODO
105         else:
106             old_storage = libbe.storage.get_storage(params['repo'])
107             old_storage.connect()
108             old_bd_current = bugdir.BugDir(old_storage, from_disk=True)
109             if params['revision'] == None: # use the current working state
110                 old_bd = old_bd_current
111             else:
112                 if old_bd_current.storage.versioned == False:
113                     raise libbe.command.UserError(
114                         '%s is not revision-controlled.'
115                         % storage.repo)
116                 old_bd = old_bd_current.duplicate_bugdir(revision) # TODO
117         d = libbe.diff.Diff(old_bd, bugir)
118         tree = d.report_tree(subscriptions)
119
120         if params['uuids'] == True:
121             uuids = []
122             bugs = tree.child_by_path('/bugs')
123             for bug_type in bugs:
124                 uuids.extend([bug.name for bug in bug_type])
125             print >> self.stdout, '\n'.join(uuids)
126         else :
127             rep = tree.report_string()
128             if rep != None:
129                 print >> self.stdout, rep
130         return 0
131
132     def _long_help(self):
133         return """
134 Uses the VCS to compare the current tree with a previous tree, and
135 prints a pretty report.  If REVISION is given, it is a specifier for
136 the particular previous tree to use.  Specifiers are specific to their
137 VCS.
138
139 For Arch your specifier must be a fully-qualified revision name.
140
141 Besides the standard summary output, you can use the options to output
142 UUIDS for the different categories.  This output can be used as the
143 input to 'be show' to get an understanding of the current status.
144 """