1
# Copyright (C) 2005, 2006 Canonical Ltd
1
# Copyright (C) 2006, 2007, 2009, 2010, 2011 Canonical Ltd
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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17
"""Command which looks for unsigned commits by the current user, and signs them.
20
from __future__ import absolute_import
26
revision as _mod_revision,
19
28
from bzrlib.commands import Command
21
import bzrlib.errors as errors
23
29
from bzrlib.option import Option
30
from bzrlib.i18n import gettext, ngettext
26
33
class cmd_sign_my_commits(Command):
27
"""Sign all commits by a given committer.
34
__doc__ = """Sign all commits by a given committer.
29
36
If location is not specified the local tree is used.
30
37
If committer is not specified the default committer is used.
32
39
This does not sign commits that already have signatures.
41
# Note that this signs everything on the branch's ancestry
42
# (both mainline and merged), but not other revisions that may be in the
35
takes_options = [Option('dry-run'
36
, help='Don\'t actually sign anything, just print'
37
' the revisions that would be signed')
47
help='Don\'t actually sign anything, just print'
48
' the revisions that would be signed.'),
39
50
takes_args = ['location?', 'committer?']
41
52
def run(self, location=None, committer=None, dry_run=False):
42
53
if location is None:
43
from bzrlib.workingtree import WorkingTree
44
# Open the containing directory
45
wt = WorkingTree.open_containing('.')[0]
54
bzrdir = controldir.ControlDir.open_containing('.')[0]
48
56
# Passed in locations should be exact
49
from bzrlib.branch import Branch
50
b = Branch.open(location)
51
repo = getattr(b, 'repository', b)
53
config = bzrlib.config.BranchConfig(b)
57
bzrdir = controldir.ControlDir.open(location)
58
branch = bzrdir.open_branch()
59
repo = branch.repository
60
branch_config = branch.get_config_stack()
55
62
if committer is None:
56
committer = config.username()
58
gpg_strategy = bzrlib.gpg.GPGStrategy(config)
63
committer = branch_config.get('email')
64
gpg_strategy = gpg.GPGStrategy(branch_config)
61
# return in partial topological order for the sake of reproducibility
62
for rev_id in repo.all_revision_ids():
63
if repo.has_signature_for_revision_id(rev_id):
66
rev = repo.get_revision(rev_id)
67
if rev.committer != committer:
70
# We have a revision without a signature who has a
71
# matching committer, start signing
75
repo.sign_revision(rev_id, gpg_strategy)
76
print 'Signed %d revisions' % (count,)
69
graph = repo.get_graph()
70
repo.start_write_group()
72
for rev_id, parents in graph.iter_ancestry(
73
[branch.last_revision()]):
74
if _mod_revision.is_null(rev_id):
79
if repo.has_signature_for_revision_id(rev_id):
81
rev = repo.get_revision(rev_id)
82
if rev.committer != committer:
84
# We have a revision without a signature who has a
85
# matching committer, start signing
86
self.outf.write("%s\n" % rev_id)
89
repo.sign_revision(rev_id, gpg_strategy)
91
repo.abort_write_group()
94
repo.commit_write_group()
98
ngettext('Signed %d revision.\n', 'Signed %d revisions.\n', count) %
102
class cmd_verify_signatures(Command):
103
__doc__ = """Verify all commit signatures.
105
Verifies that all commits in the branch are signed by known GnuPG keys.
109
Option('acceptable-keys',
110
help='Comma separated list of GPG key patterns which are'
111
' acceptable for verification.',
117
takes_args = ['location?']
119
def run(self, acceptable_keys=None, revision=None, verbose=None,
121
bzrdir = controldir.ControlDir.open_containing(location)[0]
122
branch = bzrdir.open_branch()
123
repo = branch.repository
124
branch_config = branch.get_config_stack()
125
gpg_strategy = gpg.GPGStrategy(branch_config)
127
gpg_strategy.set_acceptable_keys(acceptable_keys)
130
self.outf.write(string + "\n")
131
def write_verbose(string):
132
self.outf.write(" " + string + "\n")
134
self.add_cleanup(repo.lock_read().unlock)
135
#get our list of revisions
137
if revision is not None:
138
if len(revision) == 1:
139
revno, rev_id = revision[0].in_history(branch)
140
revisions.append(rev_id)
141
elif len(revision) == 2:
142
from_revno, from_revid = revision[0].in_history(branch)
143
to_revno, to_revid = revision[1].in_history(branch)
145
to_revno = branch.revno()
146
if from_revno is None or to_revno is None:
147
raise errors.BzrCommandError(gettext(
148
'Cannot verify a range of non-revision-history revisions'))
149
for revno in range(from_revno, to_revno + 1):
150
revisions.append(branch.get_rev_id(revno))
152
#all revisions by default including merges
153
graph = repo.get_graph()
155
for rev_id, parents in graph.iter_ancestry(
156
[branch.last_revision()]):
157
if _mod_revision.is_null(rev_id):
162
revisions.append(rev_id)
163
count, result, all_verifiable =\
164
gpg.bulk_verify_signatures(repo, revisions, gpg_strategy)
166
write(gettext("All commits signed with verifiable keys"))
168
write(gpg.verbose_valid_message(result))
171
write(gpg.valid_commits_message(count))
173
for message in gpg.verbose_valid_message(result):
174
write_verbose(message)
175
write(gpg.expired_commit_message(count))
177
for message in gpg.verbose_expired_key_message(result, repo):
178
write_verbose(message)
179
write(gpg.unknown_key_message(count))
181
for message in gpg.verbose_missing_key_message(result):
182
write_verbose(message)
183
write(gpg.commit_not_valid_message(count))
185
for message in gpg.verbose_not_valid_message(result, repo):
186
write_verbose(message)
187
write(gpg.commit_not_signed_message(count))
189
for message in gpg.verbose_not_signed_message(result, repo):
190
write_verbose(message)