/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.py

  • Committer: Aaron Bentley
  • Date: 2006-09-28 13:48:10 UTC
  • mfrom: (2049 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2268.
  • Revision ID: abentley@panoramicfeedback.com-20060928134810-2c8ae086a4a70f43
Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
61
61
 
62
62
# TODO: If commit fails, leave the message in a file somewhere.
63
63
 
 
64
# TODO: Change the parameter 'rev_id' to 'revision_id' to be consistent with
 
65
# the rest of the code; add a deprecation of the old name.
64
66
 
65
67
import os
66
68
import re
69
71
 
70
72
from cStringIO import StringIO
71
73
 
 
74
from bzrlib import (
 
75
    errors,
 
76
    inventory,
 
77
    tree,
 
78
    )
72
79
import bzrlib.config
73
 
from bzrlib import errors, inventory
74
80
from bzrlib.errors import (BzrError, PointlessCommit,
75
81
                           ConflictsInTree,
76
82
                           StrictCommitFailed
245
251
            self._check_bound_branch()
246
252
 
247
253
            # check for out of date working trees
248
 
            # if we are bound, then self.branch is the master branch and this
249
 
            # test is thus all we need.
250
 
            if self.work_tree.last_revision() != self.master_branch.last_revision():
 
254
            try:
 
255
                first_tree_parent = self.work_tree.get_parent_ids()[0]
 
256
            except IndexError:
 
257
                # if there are no parents, treat our parent as 'None'
 
258
                # this is so that we still consier the master branch
 
259
                # - in a checkout scenario the tree may have no
 
260
                # parents but the branch may do.
 
261
                first_tree_parent = None
 
262
            master_last = self.master_branch.last_revision()
 
263
            if (master_last is not None and
 
264
                master_last != first_tree_parent):
251
265
                raise errors.OutOfDateTree(self.work_tree)
252
266
    
253
267
            if strict:
267
281
            self.work_inv = self.work_tree.inventory
268
282
            self.basis_tree = self.work_tree.basis_tree()
269
283
            self.basis_inv = self.basis_tree.inventory
 
284
            if specific_files is not None:
 
285
                # Ensure specified files are versioned
 
286
                # (We don't actually need the ids here)
 
287
                tree.find_ids_across_trees(specific_files, 
 
288
                                           [self.basis_tree, self.work_tree])
270
289
            # one to finish, one for rev and inventory, and one for each
271
290
            # inventory entry, and the same for the new inventory.
272
291
            # note that this estimate is too long when we do a partial tree
279
298
            if len(self.parents) > 1 and self.specific_files:
280
299
                raise NotImplementedError('selected-file commit of merges is not supported yet: files %r',
281
300
                        self.specific_files)
282
 
            self._check_parents_present()
 
301
            
283
302
            self.builder = self.branch.get_commit_builder(self.parents, 
284
303
                self.config, timestamp, timezone, committer, revprops, rev_id)
285
304
            
287
306
            self._populate_new_inv()
288
307
            self._report_deletes()
289
308
 
290
 
            if not (self.allow_pointless
291
 
                    or len(self.parents) > 1
292
 
                    or self.builder.new_inventory != self.basis_inv):
293
 
                raise PointlessCommit()
 
309
            self._check_pointless()
294
310
 
295
311
            self._emit_progress_update()
296
312
            # TODO: Now the new inventory is known, check for conflicts and
317
333
            # and now do the commit locally.
318
334
            self.branch.append_revision(self.rev_id)
319
335
 
320
 
            self.work_tree.set_pending_merges([])
321
 
            self.work_tree.set_last_revision(self.rev_id)
 
336
            rev_tree = self.builder.revision_tree()
 
337
            self.work_tree.set_parent_trees([(self.rev_id, rev_tree)])
322
338
            # now the work tree is up to date with the branch
323
339
            
324
340
            self.reporter.completed(self.branch.revno(), self.rev_id)
335
351
            self._cleanup()
336
352
        return self.rev_id
337
353
 
 
354
    def _any_real_changes(self):
 
355
        """Are there real changes between new_inventory and basis?
 
356
 
 
357
        For trees without rich roots, inv.root.revision changes every commit.
 
358
        But if that is the only change, we want to treat it as though there
 
359
        are *no* changes.
 
360
        """
 
361
        new_entries = self.builder.new_inventory.iter_entries()
 
362
        basis_entries = self.basis_inv.iter_entries()
 
363
        new_path, new_root_ie = new_entries.next()
 
364
        basis_path, basis_root_ie = basis_entries.next()
 
365
 
 
366
        # This is a copy of InventoryEntry.__eq__ only leaving out .revision
 
367
        def ie_equal_no_revision(this, other):
 
368
            return ((this.file_id == other.file_id)
 
369
                    and (this.name == other.name)
 
370
                    and (this.symlink_target == other.symlink_target)
 
371
                    and (this.text_sha1 == other.text_sha1)
 
372
                    and (this.text_size == other.text_size)
 
373
                    and (this.text_id == other.text_id)
 
374
                    and (this.parent_id == other.parent_id)
 
375
                    and (this.kind == other.kind)
 
376
                    and (this.executable == other.executable)
 
377
                    )
 
378
        if not ie_equal_no_revision(new_root_ie, basis_root_ie):
 
379
            return True
 
380
 
 
381
        for new_ie, basis_ie in zip(new_entries, basis_entries):
 
382
            if new_ie != basis_ie:
 
383
                return True
 
384
 
 
385
        # No actual changes present
 
386
        return False
 
387
 
 
388
    def _check_pointless(self):
 
389
        if self.allow_pointless:
 
390
            return
 
391
        # A merge with no effect on files
 
392
        if len(self.parents) > 1:
 
393
            return
 
394
        # Shortcut, if the number of entries changes, then we obviously have
 
395
        # a change
 
396
        if len(self.builder.new_inventory) != len(self.basis_inv):
 
397
            return
 
398
        # If length == 1, then we only have the root entry. Which means
 
399
        # that there is no real difference (only the root could be different)
 
400
        if (len(self.builder.new_inventory) != 1 and self._any_real_changes()):
 
401
            return
 
402
        raise PointlessCommit()
 
403
 
338
404
    def _check_bound_branch(self):
339
405
        """Check to see if the local branch is bound.
340
406
 
438
504
        self.parent_invs = []
439
505
        for revision in self.parents:
440
506
            if self.branch.repository.has_revision(revision):
 
507
                mutter('commit parent revision {%s}', revision)
441
508
                inventory = self.branch.repository.get_inventory(revision)
442
509
                self.parent_invs.append(inventory)
 
510
            else:
 
511
                mutter('commit parent ghost revision {%s}', revision)
443
512
 
444
 
    def _check_parents_present(self):
445
 
        for parent_id in self.parents:
446
 
            mutter('commit parent revision {%s}', parent_id)
447
 
            if not self.branch.repository.has_revision(parent_id):
448
 
                if parent_id == self.branch.last_revision():
449
 
                    warning("parent is missing %r", parent_id)
450
 
                    raise BzrCheckError("branch %s is missing revision {%s}"
451
 
                            % (self.branch, parent_id))
452
 
            
453
513
    def _remove_deleted(self):
454
514
        """Remove deleted files from the working inventories.
455
515
 
463
523
        """
464
524
        specific = self.specific_files
465
525
        deleted_ids = []
 
526
        deleted_paths = set()
466
527
        for path, ie in self.work_inv.iter_entries():
 
528
            if is_inside_any(deleted_paths, path):
 
529
                # The tree will delete the required ids recursively.
 
530
                continue
467
531
            if specific and not is_inside_any(specific, path):
468
532
                continue
469
533
            if not self.work_tree.has_filename(path):
 
534
                deleted_paths.add(path)
470
535
                self.reporter.missing(path)
471
 
                deleted_ids.append((path, ie.file_id))
472
 
        if deleted_ids:
473
 
            deleted_ids.sort(reverse=True)
474
 
            for path, file_id in deleted_ids:
475
 
                del self.work_inv[file_id]
476
 
            self.work_tree._write_inventory(self.work_inv)
 
536
                deleted_ids.append(ie.file_id)
 
537
        self.work_tree.unversion(deleted_ids)
477
538
 
478
539
    def _populate_new_inv(self):
479
540
        """Build revision inventory.
501
562
        for path, new_ie in entries:
502
563
            self._emit_progress_update()
503
564
            file_id = new_ie.file_id
504
 
            kind = self.work_tree.kind(file_id)
505
 
            if kind != new_ie.kind:
506
 
                new_ie = inventory.make_entry(kind, new_ie.name, 
507
 
                                              new_ie.parent_id, file_id)
 
565
            try:
 
566
                kind = self.work_tree.kind(file_id)
 
567
                if kind != new_ie.kind:
 
568
                    new_ie = inventory.make_entry(kind, new_ie.name, 
 
569
                                                  new_ie.parent_id, file_id)
 
570
            except errors.NoSuchFile:
 
571
                pass
508
572
            # mutter('check %s {%s}', path, file_id)
509
573
            if (not self.specific_files or 
510
574
                is_inside_or_parent_of_any(self.specific_files, path)):