~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commit.py

  • Committer: Martin Pool
  • Date: 2010-02-25 06:17:27 UTC
  • mfrom: (5055 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5057.
  • Revision ID: mbp@sourcefrog.net-20100225061727-4sd9lt0qmdc6087t
merge news

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2010 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
49
49
# TODO: Change the parameter 'rev_id' to 'revision_id' to be consistent with
50
50
# the rest of the code; add a deprecation of the old name.
51
51
 
 
52
import os
 
53
import re
 
54
import sys
 
55
import time
 
56
 
 
57
from cStringIO import StringIO
 
58
 
52
59
from bzrlib import (
53
60
    debug,
54
61
    errors,
55
62
    revision,
56
63
    trace,
57
64
    tree,
58
 
    ui,
 
65
    xml_serializer,
59
66
    )
60
67
from bzrlib.branch import Branch
61
68
from bzrlib.cleanup import OperationWithCleanups
65
72
                           StrictCommitFailed
66
73
                           )
67
74
from bzrlib.osutils import (get_user_encoding,
68
 
                            is_inside_any,
 
75
                            kind_marker, isdir,isfile, is_inside_any,
 
76
                            is_inside_or_parent_of_any,
69
77
                            minimum_path_selection,
 
78
                            quotefn, sha_file, split_lines,
70
79
                            splitpath,
71
80
                            )
72
 
from bzrlib.trace import mutter, note, is_quiet
 
81
from bzrlib.testament import Testament
 
82
from bzrlib.trace import mutter, note, warning, is_quiet
73
83
from bzrlib.inventory import Inventory, InventoryEntry, make_entry
74
84
from bzrlib import symbol_versioning
 
85
from bzrlib.symbol_versioning import (deprecated_passed,
 
86
        deprecated_function,
 
87
        DEPRECATED_PARAMETER)
 
88
from bzrlib.workingtree import WorkingTree
75
89
from bzrlib.urlutils import unescape_for_display
 
90
import bzrlib.ui
76
91
 
77
92
 
78
93
class NullCommitReporter(object):
132
147
 
133
148
    def completed(self, revno, rev_id):
134
149
        self._note('Committed revision %d.', revno)
135
 
        # self._note goes to the console too; so while we want to log the
136
 
        # rev_id, we can't trivially only log it. (See bug 526425). Long
137
 
        # term we should rearrange the reporting structure, but for now
138
 
        # we just mutter seperately. We mutter the revid and revno together
139
 
        # so that concurrent bzr invocations won't lead to confusion.
140
 
        mutter('Committed revid %s as revno %d.', rev_id, revno)
141
150
 
142
151
    def deleted(self, path):
143
152
        self._note('deleted %s', path)
174
183
        self.reporter = reporter
175
184
        self.config = config
176
185
 
177
 
    @staticmethod
178
 
    def update_revprops(revprops, branch, authors=None, author=None,
179
 
                        local=False, possible_master_transports=None):
180
 
        if revprops is None:
181
 
            revprops = {}
182
 
        if possible_master_transports is None:
183
 
            possible_master_transports = []
184
 
        if not 'branch-nick' in revprops:
185
 
            revprops['branch-nick'] = branch._get_nick(
186
 
                local,
187
 
                possible_master_transports)
188
 
        if authors is not None:
189
 
            if author is not None:
190
 
                raise AssertionError('Specifying both author and authors '
191
 
                        'is not allowed. Specify just authors instead')
192
 
            if 'author' in revprops or 'authors' in revprops:
193
 
                # XXX: maybe we should just accept one of them?
194
 
                raise AssertionError('author property given twice')
195
 
            if authors:
196
 
                for individual in authors:
197
 
                    if '\n' in individual:
198
 
                        raise AssertionError('\\n is not a valid character '
199
 
                                'in an author identity')
200
 
                revprops['authors'] = '\n'.join(authors)
201
 
        if author is not None:
202
 
            symbol_versioning.warn('The parameter author was deprecated'
203
 
                   ' in version 1.13. Use authors instead',
204
 
                   DeprecationWarning)
205
 
            if 'author' in revprops or 'authors' in revprops:
206
 
                # XXX: maybe we should just accept one of them?
207
 
                raise AssertionError('author property given twice')
208
 
            if '\n' in author:
209
 
                raise AssertionError('\\n is not a valid character '
210
 
                        'in an author identity')
211
 
            revprops['authors'] = author
212
 
        return revprops
213
 
 
214
186
    def commit(self,
215
187
               message=None,
216
188
               timestamp=None,
229
201
               message_callback=None,
230
202
               recursive='down',
231
203
               exclude=None,
232
 
               possible_master_transports=None,
233
 
               lossy=False):
 
204
               possible_master_transports=None):
234
205
        """Commit working copy as a new revision.
235
206
 
236
207
        :param message: the commit message (it or message_callback is required)
263
234
        :param exclude: None or a list of relative paths to exclude from the
264
235
            commit. Pending changes to excluded files will be ignored by the
265
236
            commit.
266
 
        :param lossy: When committing to a foreign VCS, ignore any
267
 
            data that can not be natively represented.
268
237
        """
269
238
        operation = OperationWithCleanups(self._commit)
270
 
        self.revprops = revprops or {}
271
 
        # XXX: Can be set on __init__ or passed in - this is a bit ugly.
272
 
        self.config = config or self.config
273
239
        return operation.run(
274
240
               message=message,
275
241
               timestamp=timestamp,
280
246
               allow_pointless=allow_pointless,
281
247
               strict=strict,
282
248
               verbose=verbose,
 
249
               revprops=revprops,
283
250
               working_tree=working_tree,
284
251
               local=local,
285
252
               reporter=reporter,
 
253
               config=config,
286
254
               message_callback=message_callback,
287
255
               recursive=recursive,
288
256
               exclude=exclude,
289
 
               possible_master_transports=possible_master_transports,
290
 
               lossy=lossy)
 
257
               possible_master_transports=possible_master_transports)
291
258
 
292
259
    def _commit(self, operation, message, timestamp, timezone, committer,
293
 
            specific_files, rev_id, allow_pointless, strict, verbose,
294
 
            working_tree, local, reporter, message_callback, recursive,
295
 
            exclude, possible_master_transports, lossy):
 
260
            specific_files, rev_id, allow_pointless, strict, verbose, revprops,
 
261
            working_tree, local, reporter, config, message_callback, recursive,
 
262
            exclude, possible_master_transports):
296
263
        mutter('preparing to commit')
297
264
 
298
265
        if working_tree is None:
330
297
                minimum_path_selection(specific_files))
331
298
        else:
332
299
            self.specific_files = None
333
 
 
 
300
            
334
301
        self.allow_pointless = allow_pointless
 
302
        self.revprops = revprops
335
303
        self.message_callback = message_callback
336
304
        self.timestamp = timestamp
337
305
        self.timezone = timezone
350
318
            not self.branch.repository._format.supports_tree_reference and
351
319
            (self.branch.repository._format.fast_deltas or
352
320
             len(self.parents) < 2))
353
 
        self.pb = ui.ui_factory.nested_progress_bar()
 
321
        self.pb = bzrlib.ui.ui_factory.nested_progress_bar()
354
322
        operation.add_cleanup(self.pb.finished)
355
323
        self.basis_revid = self.work_tree.last_revision()
356
324
        self.basis_tree = self.work_tree.basis_tree()
384
352
        self.pb_stage_count = 0
385
353
        self.pb_stage_total = 5
386
354
        if self.bound_branch:
387
 
            # 2 extra stages: "Uploading data to master branch" and "Merging
388
 
            # tags to master branch"
389
 
            self.pb_stage_total += 2
 
355
            self.pb_stage_total += 1
390
356
        self.pb.show_pct = False
391
357
        self.pb.show_spinner = False
392
358
        self.pb.show_eta = False
404
370
 
405
371
        # Collect the changes
406
372
        self._set_progress_stage("Collecting changes", counter=True)
407
 
        self._lossy = lossy
408
373
        self.builder = self.branch.get_commit_builder(self.parents,
409
 
            self.config, timestamp, timezone, committer, self.revprops,
410
 
            rev_id, lossy=lossy)
411
 
        if not self.builder.supports_record_entry_contents and self.exclude:
412
 
            self.builder.abort()
413
 
            raise errors.ExcludesUnsupported(self.branch.repository)
 
374
            self.config, timestamp, timezone, committer, revprops, rev_id)
414
375
 
415
376
        try:
416
377
            self.builder.will_record_deletes()
455
416
            self._set_progress_stage("Uploading data to master branch")
456
417
            # 'commit' to the master first so a timeout here causes the
457
418
            # local branch to be out of date
458
 
            (new_revno, self.rev_id) = self.master_branch.import_last_revision_info_and_tags(
459
 
                self.branch, new_revno, self.rev_id, lossy=lossy)
460
 
            if lossy:
461
 
                self.branch.fetch(self.master_branch, self.rev_id)
 
419
            self.master_branch.import_last_revision_info(
 
420
                self.branch.repository, new_revno, self.rev_id)
462
421
 
463
422
        # and now do the commit locally.
464
423
        self.branch.set_last_revision_info(new_revno, self.rev_id)
465
424
 
466
 
        # Merge local tags to remote
467
 
        if self.bound_branch:
468
 
            self._set_progress_stage("Merging tags to master branch")
469
 
            tag_conflicts = self.branch.tags.merge_to(self.master_branch.tags)
470
 
            if tag_conflicts:
471
 
                warning_lines = ['    ' + name for name, _, _ in tag_conflicts]
472
 
                note("Conflicting tags in bound branch:\n" +
473
 
                    "\n".join(warning_lines))
474
 
 
475
425
        # Make the working tree be up to date with the branch. This
476
426
        # includes automatic changes scheduled to be made to the tree, such
477
427
        # as updating its basis and unversioning paths that were missing.