/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5752.3.8 by John Arbash Meinel
Merge bzr.dev 5764 to resolve release-notes (aka NEWS) conflicts
1
# Copyright (C) 2006, 2007, 2009, 2010, 2011 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1185.78.6 by John Arbash Meinel
Adding sign-my-commits as a builtin, along with some simple tests.
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1185.78.6 by John Arbash Meinel
Adding sign-my-commits as a builtin, along with some simple tests.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1185.78.6 by John Arbash Meinel
Adding sign-my-commits as a builtin, along with some simple tests.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1732.2.3 by Martin Pool
sign-my-commits just signs revisions in the branch's ancestry.
16
1185.78.6 by John Arbash Meinel
Adding sign-my-commits as a builtin, along with some simple tests.
17
"""Command which looks for unsigned commits by the current user, and signs them.
18
"""
19
1996.3.14 by John Arbash Meinel
lazy_import osutils and sign_my_commits
20
from bzrlib.lazy_import import lazy_import
21
lazy_import(globals(), """
22
from bzrlib import (
5753.2.2 by Jelmer Vernooij
Remove some unnecessary imports, clean up lazy imports.
23
    bzrdir as _mod_bzrdir,
1996.3.14 by John Arbash Meinel
lazy_import osutils and sign_my_commits
24
    gpg,
25
    )
26
""")
1185.78.6 by John Arbash Meinel
Adding sign-my-commits as a builtin, along with some simple tests.
27
from bzrlib.commands import Command
28
from bzrlib.option import Option
5971.1.1 by Jonathan Riddell
add a verify command
29
from bzrlib.trace import note
5971.1.24 by Jonathan Riddell
fix translations for plural forms
30
from bzrlib.i18n import gettext, ngettext
1185.78.6 by John Arbash Meinel
Adding sign-my-commits as a builtin, along with some simple tests.
31
32
class cmd_sign_my_commits(Command):
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
33
    __doc__ = """Sign all commits by a given committer.
1185.78.6 by John Arbash Meinel
Adding sign-my-commits as a builtin, along with some simple tests.
34
35
    If location is not specified the local tree is used.
36
    If committer is not specified the default committer is used.
37
38
    This does not sign commits that already have signatures.
39
    """
1732.2.3 by Martin Pool
sign-my-commits just signs revisions in the branch's ancestry.
40
    # Note that this signs everything on the branch's ancestry
41
    # (both mainline and merged), but not other revisions that may be in the
42
    # repository
1185.78.6 by John Arbash Meinel
Adding sign-my-commits as a builtin, along with some simple tests.
43
2598.1.2 by Martin Pool
Also check that option help ends in a period, and fix those that don't
44
    takes_options = [
45
            Option('dry-run',
46
                   help='Don\'t actually sign anything, just print'
47
                        ' the revisions that would be signed.'),
48
            ]
1185.78.6 by John Arbash Meinel
Adding sign-my-commits as a builtin, along with some simple tests.
49
    takes_args = ['location?', 'committer?']
50
51
    def run(self, location=None, committer=None, dry_run=False):
52
        if location is None:
5753.2.2 by Jelmer Vernooij
Remove some unnecessary imports, clean up lazy imports.
53
            bzrdir = _mod_bzrdir.BzrDir.open_containing('.')[0]
1185.78.6 by John Arbash Meinel
Adding sign-my-commits as a builtin, along with some simple tests.
54
        else:
55
            # Passed in locations should be exact
5753.2.2 by Jelmer Vernooij
Remove some unnecessary imports, clean up lazy imports.
56
            bzrdir = _mod_bzrdir.BzrDir.open(location)
1732.2.3 by Martin Pool
sign-my-commits just signs revisions in the branch's ancestry.
57
        branch = bzrdir.open_branch()
58
        repo = branch.repository
1770.2.12 by Aaron Bentley
Merge bzr.dev
59
        branch_config = branch.get_config()
1185.78.6 by John Arbash Meinel
Adding sign-my-commits as a builtin, along with some simple tests.
60
61
        if committer is None:
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
62
            committer = branch_config.username()
63
        gpg_strategy = gpg.GPGStrategy(branch_config)
1185.78.6 by John Arbash Meinel
Adding sign-my-commits as a builtin, along with some simple tests.
64
65
        count = 0
1711.2.35 by John Arbash Meinel
sign-my-commits should take out a write lock.
66
        repo.lock_write()
67
        try:
3010.1.15 by Robert Collins
Manage write groups in sign_my_commits, for efficiency.
68
            repo.start_write_group()
69
            try:
70
                for rev_id in repo.get_ancestry(branch.last_revision())[1:]:
71
                    if repo.has_signature_for_revision_id(rev_id):
72
                        continue
73
                    rev = repo.get_revision(rev_id)
74
                    if rev.committer != committer:
75
                        continue
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
76
                    # We have a revision without a signature who has a
3010.1.15 by Robert Collins
Manage write groups in sign_my_commits, for efficiency.
77
                    # matching committer, start signing
78
                    print rev_id
79
                    count += 1
80
                    if not dry_run:
81
                        repo.sign_revision(rev_id, gpg_strategy)
82
            except:
83
                repo.abort_write_group()
84
                raise
85
            else:
86
                repo.commit_write_group()
1711.2.35 by John Arbash Meinel
sign-my-commits should take out a write lock.
87
        finally:
88
            repo.unlock()
1185.78.6 by John Arbash Meinel
Adding sign-my-commits as a builtin, along with some simple tests.
89
        print 'Signed %d revisions' % (count,)
90
91
5971.1.1 by Jonathan Riddell
add a verify command
92
class cmd_verify(Command):
5971.1.3 by Jonathan Riddell
tidying up
93
    __doc__ = """Verify all commit signatures.
94
95
    Verifies that all commits in the branch are signed by known GnuPG keys.
5971.1.1 by Jonathan Riddell
add a verify command
96
    """
5971.1.3 by Jonathan Riddell
tidying up
97
5971.1.12 by Jonathan Riddell
add acceptable-keys option
98
    takes_options = [
99
            Option('acceptable-keys',
100
                   help='Comma separated list of GPG key patterns which are'
101
                        ' acceptable for verification.',
102
                   short_name='k',
103
                   type=str,),
5971.1.17 by Jonathan Riddell
add verbose option
104
            'revision', 
105
            'verbose',
5971.1.15 by Jonathan Riddell
add a revision argument to bzr verify
106
          ]
5971.1.12 by Jonathan Riddell
add acceptable-keys option
107
5971.1.17 by Jonathan Riddell
add verbose option
108
    def run(self, acceptable_keys=None, revision=None, verbose=None):
5971.1.3 by Jonathan Riddell
tidying up
109
        bzrdir = _mod_bzrdir.BzrDir.open_containing('.')[0]
5971.1.1 by Jonathan Riddell
add a verify command
110
        branch = bzrdir.open_branch()
111
        repo = branch.repository
112
        branch_config = branch.get_config()
113
114
        gpg_strategy = gpg.GPGStrategy(branch_config)
5971.1.12 by Jonathan Riddell
add acceptable-keys option
115
        if acceptable_keys is not None:
116
            gpg_strategy.set_acceptable_keys(acceptable_keys)
5971.1.1 by Jonathan Riddell
add a verify command
117
118
        count = {gpg.SIGNATURE_VALID: 0,
119
                 gpg.SIGNATURE_KEY_MISSING: 0,
120
                 gpg.SIGNATURE_NOT_VALID: 0,
121
                 gpg.SIGNATURE_NOT_SIGNED: 0}
122
        result = []
5971.1.15 by Jonathan Riddell
add a revision argument to bzr verify
123
        revisions = []
124
        if revision is not None:
125
            if len(revision) == 1:
126
                revno, rev_id = revision[0].in_history(branch)
127
                revisions.append(rev_id)
128
            elif len(revision) == 2:
129
                from_revno, from_revid = revision[0].in_history(branch)
130
                to_revno, to_revid = revision[1].in_history(branch)
131
                if to_revid is None:
132
                    to_revno = branch.revno()
133
                if from_revno is None or to_revno is None:
134
                    raise errors.BzrCommandError('Cannot verify a range of \
135
                                                non-revision-history revisions')
136
                for revno in range(from_revno, to_revno + 1):
137
                    revisions.append(branch.get_rev_id(revno))
138
        else:
5971.1.16 by Jonathan Riddell
tidying
139
            #all revisions by default including merges
5971.1.15 by Jonathan Riddell
add a revision argument to bzr verify
140
            revisions = repo.get_ancestry(branch.last_revision())[1:]
141
        for rev_id in revisions:
5971.1.22 by Jonathan Riddell
fix tests
142
            verification_result, uid = repo.verify_revision(rev_id,gpg_strategy)
5971.1.18 by Jonathan Riddell
add email to verbose output
143
            result.append([rev_id, verification_result, uid])
5971.1.3 by Jonathan Riddell
tidying up
144
            count[verification_result] += 1
5971.1.2 by Jonathan Riddell
give result to user
145
146
        if count[gpg.SIGNATURE_VALID] > 0 and \
147
           count[gpg.SIGNATURE_KEY_MISSING] == 0 and \
148
           count[gpg.SIGNATURE_NOT_VALID] == 0 and \
149
           count[gpg.SIGNATURE_NOT_SIGNED] == 0:
5971.1.19 by Jonathan Riddell
i18n
150
               note(gettext("All commits signed with verifiable keys"))
5971.1.17 by Jonathan Riddell
add verbose option
151
               if verbose:
5971.1.25 by Jonathan Riddell
Add _print_verbose_valid_message()
152
                   self._print_verbose_valid_message(result)
5971.1.2 by Jonathan Riddell
give result to user
153
               return 0
154
        else:
5971.1.19 by Jonathan Riddell
i18n
155
            note(gettext("{0} commits with valid signatures").format(
5971.1.2 by Jonathan Riddell
give result to user
156
                                        count[gpg.SIGNATURE_VALID]))
5971.1.20 by Jonathan Riddell
add verbose for bad signatures too
157
            if verbose:
5971.1.25 by Jonathan Riddell
Add _print_verbose_valid_message()
158
               self._print_verbose_valid_message(result)
5971.1.20 by Jonathan Riddell
add verbose for bad signatures too
159
            #TODO verbose for the other types too
5971.1.24 by Jonathan Riddell
fix translations for plural forms
160
            note(ngettext("{0} commit with unknown key",
161
                          "{0} commits with unknown keys",
162
                          count[gpg.SIGNATURE_KEY_MISSING]).format(
5971.1.2 by Jonathan Riddell
give result to user
163
                                        count[gpg.SIGNATURE_KEY_MISSING]))
5971.1.27 by Jonathan Riddell
verbose info for unknown keys
164
            if verbose:
165
               self._print_verbose_missing_key_message(result)
5971.1.24 by Jonathan Riddell
fix translations for plural forms
166
            note(ngettext("{0} commit not valid",
167
                          "{0} commits not valid",
168
                          count[gpg.SIGNATURE_NOT_VALID]).format(
5971.1.2 by Jonathan Riddell
give result to user
169
                                        count[gpg.SIGNATURE_NOT_VALID]))
5971.1.29 by Jonathan Riddell
verbose for invalid signatures
170
            if verbose:
171
               self._print_verbose_not_valid(result, repo)
5971.1.24 by Jonathan Riddell
fix translations for plural forms
172
            note(ngettext("{0} commit not signed",
173
                          "{0} commits not signed",
174
                          count[gpg.SIGNATURE_NOT_SIGNED]).format(
5971.1.2 by Jonathan Riddell
give result to user
175
                                        count[gpg.SIGNATURE_NOT_SIGNED]))
5971.1.28 by Jonathan Riddell
verbose for not signed
176
            if verbose:
177
               self._print_verbose_not_signed(result, repo)
5971.1.2 by Jonathan Riddell
give result to user
178
            return 1
5971.1.25 by Jonathan Riddell
Add _print_verbose_valid_message()
179
5971.1.29 by Jonathan Riddell
verbose for invalid signatures
180
    def _print_verbose_not_valid(self, result, repo):
181
        """takes a verify result and prints out not signed commit info"""
182
        signers = {}
183
        for rev_id, validity, empty in result:
184
            if validity == gpg.SIGNATURE_NOT_VALID:
185
                revision = repo.get_revision(rev_id)
186
                authors = ', '.join(revision.get_apparent_authors())
187
                signers.setdefault(authors, 0)
188
                signers[authors] += 1
189
        for authors, number in signers.items():
190
            note(gettext(ngettext("  {0} commit by author {1}", 
191
                                "  {0} commits by author {1}",
192
                            number)).format(number, authors))
193
5971.1.28 by Jonathan Riddell
verbose for not signed
194
    def _print_verbose_not_signed(self, result, repo):
195
        """takes a verify result and prints out not signed commit info"""
196
        signers = {}
197
        for rev_id, validity, empty in result:
198
            if validity == gpg.SIGNATURE_KEY_MISSING:
199
                revision = repo.get_revision(rev_id)
200
                authors = ', '.join(revision.get_apparent_authors())
201
                signers.setdefault(authors, 0)
202
                signers[authors] += 1
203
        for authors, number in signers.items():
204
            note(gettext(ngettext("  {0} commit by author {1}", 
205
                                "  {0} commits by author {1}",
206
                            number)).format(number, authors))
207
5971.1.27 by Jonathan Riddell
verbose info for unknown keys
208
    def _print_verbose_missing_key_message(self, result):
209
        """takes a verify result and prints out missing key info"""
210
        signers = {}
211
        for rev_id, validity, fingerprint in result:
212
            if validity == gpg.SIGNATURE_KEY_MISSING:
213
                signers.setdefault(fingerprint, 0)
214
                signers[fingerprint] += 1
215
        for fingerprint, number in signers.items():
216
            note(gettext(ngettext("  Unknown key {0} signed {1} commit", 
217
                                "  Unknown key {0} signed {1} commits",
218
                            number)).format(fingerprint, number))
219
5971.1.25 by Jonathan Riddell
Add _print_verbose_valid_message()
220
    def _print_verbose_valid_message(self, result):
5971.1.26 by Jonathan Riddell
Add _print_verbose_valid_message() doc
221
        """takes a verify result and prints out number of signed commits"""
5971.1.25 by Jonathan Riddell
Add _print_verbose_valid_message()
222
        signers = {}
223
        for rev_id, validity, uid in result:
224
            if validity == gpg.SIGNATURE_VALID:
225
                signers.setdefault(uid, 0)
226
                signers[uid] += 1
227
        for uid, number in signers.items():
228
            note(gettext(ngettext("  {0} signed {1} commit", 
229
                                "  {0} signed {1} commits",
230
                            number)).format(uid, number))
231