/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/commit_signature_commands.py

  • Committer: Jonathan Riddell
  • Date: 2011-06-22 13:53:20 UTC
  • mto: This revision was merged to the branch mainline in revision 6003.
  • Revision ID: jriddell@canonical.com-20110622135320-ct7e52dz851m1ird
more tests for new config options

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007, 2009, 2010 Canonical Ltd
 
1
# Copyright (C) 2006, 2007, 2009, 2010, 2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
20
20
from bzrlib.lazy_import import lazy_import
21
21
lazy_import(globals(), """
22
22
from bzrlib import (
23
 
    config,
 
23
    bzrdir as _mod_bzrdir,
 
24
    errors,
24
25
    gpg,
 
26
    revision as _mod_revision,
25
27
    )
26
 
from bzrlib.bzrdir import BzrDir
27
28
""")
28
29
from bzrlib.commands import Command
29
30
from bzrlib.option import Option
30
 
 
 
31
from bzrlib.trace import note
 
32
from bzrlib.i18n import gettext, ngettext
31
33
 
32
34
class cmd_sign_my_commits(Command):
33
35
    __doc__ = """Sign all commits by a given committer.
50
52
 
51
53
    def run(self, location=None, committer=None, dry_run=False):
52
54
        if location is None:
53
 
            bzrdir = BzrDir.open_containing('.')[0]
 
55
            bzrdir = _mod_bzrdir.BzrDir.open_containing('.')[0]
54
56
        else:
55
57
            # Passed in locations should be exact
56
 
            bzrdir = BzrDir.open(location)
 
58
            bzrdir = _mod_bzrdir.BzrDir.open(location)
57
59
        branch = bzrdir.open_branch()
58
60
        repo = branch.repository
59
61
        branch_config = branch.get_config()
65
67
        count = 0
66
68
        repo.lock_write()
67
69
        try:
 
70
            graph = repo.get_graph()
68
71
            repo.start_write_group()
69
72
            try:
70
 
                for rev_id in repo.get_ancestry(branch.last_revision())[1:]:
 
73
                for rev_id, parents in graph.iter_ancestry(
 
74
                        [branch.last_revision()]):
 
75
                    if _mod_revision.is_null(rev_id):
 
76
                        continue
 
77
                    if parents is None:
 
78
                        # Ignore ghosts
 
79
                        continue
71
80
                    if repo.has_signature_for_revision_id(rev_id):
72
81
                        continue
73
82
                    rev = repo.get_revision(rev_id)
89
98
        print 'Signed %d revisions' % (count,)
90
99
 
91
100
 
 
101
class cmd_verify_signatures(Command):
 
102
    __doc__ = """Verify all commit signatures.
 
103
 
 
104
    Verifies that all commits in the branch are signed by known GnuPG keys.
 
105
    """
 
106
 
 
107
    takes_options = [
 
108
            Option('acceptable-keys',
 
109
                   help='Comma separated list of GPG key patterns which are'
 
110
                        ' acceptable for verification.',
 
111
                   short_name='k',
 
112
                   type=str,),
 
113
            'revision', 
 
114
            'verbose',
 
115
            'directory',
 
116
          ]
 
117
 
 
118
    def run(self, acceptable_keys=None, revision=None, verbose=None,
 
119
                                                            directory=u'.'):
 
120
        bzrdir = _mod_bzrdir.BzrDir.open_containing(directory)[0]
 
121
        branch = bzrdir.open_branch()
 
122
        repo = branch.repository
 
123
        branch_config = branch.get_config()
 
124
        gpg_strategy = gpg.GPGStrategy(branch_config)
 
125
 
 
126
        acceptable_keys_config = branch_config.acceptable_keys()
 
127
        try:
 
128
            acceptable_keys_config = str(acceptable_keys_config)
 
129
        except UnicodeEncodeError:
 
130
            raise errors.BzrCommandError('Only ASCII permitted in option names')
 
131
 
 
132
        if acceptable_keys_config is not None:
 
133
            gpg_strategy.set_acceptable_keys(acceptable_keys_config)
 
134
        if acceptable_keys is not None: #command line overrides config
 
135
            gpg_strategy.set_acceptable_keys(acceptable_keys)
 
136
 
 
137
        count = {gpg.SIGNATURE_VALID: 0,
 
138
                 gpg.SIGNATURE_KEY_MISSING: 0,
 
139
                 gpg.SIGNATURE_NOT_VALID: 0,
 
140
                 gpg.SIGNATURE_NOT_SIGNED: 0}
 
141
        result = []
 
142
        revisions = []
 
143
 
 
144
        if revision is not None:
 
145
            if len(revision) == 1:
 
146
                revno, rev_id = revision[0].in_history(branch)
 
147
                revisions.append(rev_id)
 
148
            elif len(revision) == 2:
 
149
                from_revno, from_revid = revision[0].in_history(branch)
 
150
                to_revno, to_revid = revision[1].in_history(branch)
 
151
                if to_revid is None:
 
152
                    to_revno = branch.revno()
 
153
                if from_revno is None or to_revno is None:
 
154
                    raise errors.BzrCommandError('Cannot verify a range of '\
 
155
                                               'non-revision-history revisions')
 
156
                for revno in range(from_revno, to_revno + 1):
 
157
                    revisions.append(branch.get_rev_id(revno))
 
158
        else:
 
159
            #all revisions by default including merges
 
160
            graph = repo.get_graph()
 
161
            revisions = []
 
162
            repo.lock_read()
 
163
            for rev_id, parents in graph.iter_ancestry(
 
164
                    [branch.last_revision()]):
 
165
                if _mod_revision.is_null(rev_id):
 
166
                    continue
 
167
                if parents is None:
 
168
                    # Ignore ghosts
 
169
                    continue
 
170
                revisions.append(rev_id)
 
171
            repo.unlock()
 
172
        for rev_id in revisions:
 
173
            verification_result, uid = repo.verify_revision(rev_id,gpg_strategy)
 
174
            result.append([rev_id, verification_result, uid])
 
175
            count[verification_result] += 1
 
176
 
 
177
        if count[gpg.SIGNATURE_VALID] > 0 and \
 
178
           count[gpg.SIGNATURE_KEY_MISSING] == 0 and \
 
179
           count[gpg.SIGNATURE_NOT_VALID] == 0 and \
 
180
           count[gpg.SIGNATURE_NOT_SIGNED] == 0:
 
181
               note(gettext("All commits signed with verifiable keys"))
 
182
               if verbose:
 
183
                   self._print_verbose_valid_message(result)
 
184
               return 0
 
185
        else:
 
186
            note(gettext("{0} commits with valid signatures").format(
 
187
                                        count[gpg.SIGNATURE_VALID]))
 
188
            if verbose:
 
189
               self._print_verbose_valid_message(result)
 
190
            #TODO verbose for the other types too
 
191
            note(ngettext("{0} commit with unknown key",
 
192
                          "{0} commits with unknown keys",
 
193
                          count[gpg.SIGNATURE_KEY_MISSING]).format(
 
194
                                        count[gpg.SIGNATURE_KEY_MISSING]))
 
195
            if verbose:
 
196
               self._print_verbose_missing_key_message(result)
 
197
            note(ngettext("{0} commit not valid",
 
198
                          "{0} commits not valid",
 
199
                          count[gpg.SIGNATURE_NOT_VALID]).format(
 
200
                                        count[gpg.SIGNATURE_NOT_VALID]))
 
201
            if verbose:
 
202
               self._print_verbose_not_valid(result, repo)
 
203
            note(ngettext("{0} commit not signed",
 
204
                          "{0} commits not signed",
 
205
                          count[gpg.SIGNATURE_NOT_SIGNED]).format(
 
206
                                        count[gpg.SIGNATURE_NOT_SIGNED]))
 
207
            if verbose:
 
208
               self._print_verbose_not_signed(result, repo)
 
209
            return 1
 
210
 
 
211
    def _print_verbose_not_valid(self, result, repo):
 
212
        """takes a verify result and prints out not signed commit info"""
 
213
        signers = {}
 
214
        for rev_id, validity, empty in result:
 
215
            if validity == gpg.SIGNATURE_NOT_VALID:
 
216
                revision = repo.get_revision(rev_id)
 
217
                authors = ', '.join(revision.get_apparent_authors())
 
218
                signers.setdefault(authors, 0)
 
219
                signers[authors] += 1
 
220
        for authors, number in signers.items():
 
221
            note(gettext(ngettext("  {0} commit by author {1}", 
 
222
                                "  {0} commits by author {1}",
 
223
                            number)).format(number, authors))
 
224
 
 
225
    def _print_verbose_not_signed(self, result, repo):
 
226
        """takes a verify result and prints out not signed commit info"""
 
227
        signers = {}
 
228
        for rev_id, validity, empty in result:
 
229
            if validity == gpg.SIGNATURE_KEY_MISSING:
 
230
                revision = repo.get_revision(rev_id)
 
231
                authors = ', '.join(revision.get_apparent_authors())
 
232
                signers.setdefault(authors, 0)
 
233
                signers[authors] += 1
 
234
        for authors, number in signers.items():
 
235
            note(gettext(ngettext("  {0} commit by author {1}", 
 
236
                                "  {0} commits by author {1}",
 
237
                            number)).format(number, authors))
 
238
 
 
239
    def _print_verbose_missing_key_message(self, result):
 
240
        """takes a verify result and prints out missing key info"""
 
241
        signers = {}
 
242
        for rev_id, validity, fingerprint in result:
 
243
            if validity == gpg.SIGNATURE_KEY_MISSING:
 
244
                signers.setdefault(fingerprint, 0)
 
245
                signers[fingerprint] += 1
 
246
        for fingerprint, number in signers.items():
 
247
            note(gettext(ngettext("  Unknown key {0} signed {1} commit", 
 
248
                                "  Unknown key {0} signed {1} commits",
 
249
                            number)).format(fingerprint, number))
 
250
 
 
251
    def _print_verbose_valid_message(self, result):
 
252
        """takes a verify result and prints out number of signed commits"""
 
253
        signers = {}
 
254
        for rev_id, validity, uid in result:
 
255
            if validity == gpg.SIGNATURE_VALID:
 
256
                signers.setdefault(uid, 0)
 
257
                signers[uid] += 1
 
258
        for uid, number in signers.items():
 
259
            note(gettext(ngettext("  {0} signed {1} commit", 
 
260
                                "  {0} signed {1} commits",
 
261
                            number)).format(uid, number))