~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

Merge bzr.dev into cleanup resolving conflicts

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
    annotate,
26
26
    bencode,
27
27
    bzrdir,
 
28
    commit,
28
29
    delta,
29
30
    errors,
30
31
    inventory,
35
36
    )
36
37
""")
37
38
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
38
 
                           ReusingTransform, NotVersionedError, CantMoveRoot,
 
39
                           ReusingTransform, CantMoveRoot,
39
40
                           ExistingLimbo, ImmortalLimbo, NoFinalPath,
40
41
                           UnableCreateSymlink)
41
42
from bzrlib.filters import filtered_output_bytes, ContentFilterContext
915
916
        """
916
917
        return _PreviewTree(self)
917
918
 
918
 
    def commit(self, branch, message, merge_parents=None, strict=False):
 
919
    def commit(self, branch, message, merge_parents=None, strict=False,
 
920
               timestamp=None, timezone=None, committer=None, authors=None,
 
921
               revprops=None, revision_id=None):
919
922
        """Commit the result of this TreeTransform to a branch.
920
923
 
921
924
        :param branch: The branch to commit to.
922
925
        :param message: The message to attach to the commit.
923
 
        :param merge_parents: Additional parents specified by pending merges.
 
926
        :param merge_parents: Additional parent revision-ids specified by
 
927
            pending merges.
 
928
        :param strict: If True, abort the commit if there are unversioned
 
929
            files.
 
930
        :param timestamp: if not None, seconds-since-epoch for the time and
 
931
            date.  (May be a float.)
 
932
        :param timezone: Optional timezone for timestamp, as an offset in
 
933
            seconds.
 
934
        :param committer: Optional committer in email-id format.
 
935
            (e.g. "J Random Hacker <jrandom@example.com>")
 
936
        :param authors: Optional list of authors in email-id format.
 
937
        :param revprops: Optional dictionary of revision properties.
 
938
        :param revision_id: Optional revision id.  (Specifying a revision-id
 
939
            may reduce performance for some non-native formats.)
924
940
        :return: The revision_id of the revision committed.
925
941
        """
926
942
        self._check_malformed()
943
959
        if self._tree.get_revision_id() != last_rev_id:
944
960
            raise ValueError('TreeTransform not based on branch basis: %s' %
945
961
                             self._tree.get_revision_id())
946
 
        builder = branch.get_commit_builder(parent_ids)
 
962
        revprops = commit.Commit.update_revprops(revprops, branch, authors)
 
963
        builder = branch.get_commit_builder(parent_ids,
 
964
                                            timestamp=timestamp,
 
965
                                            timezone=timezone,
 
966
                                            committer=committer,
 
967
                                            revprops=revprops,
 
968
                                            revision_id=revision_id)
947
969
        preview = self.get_preview_tree()
948
970
        list(builder.record_iter_changes(preview, last_rev_id,
949
971
                                         self.iter_changes()))
1622
1644
                      or trans_id in self._new_parent):
1623
1645
                    try:
1624
1646
                        mover.rename(full_path, self._limbo_name(trans_id))
1625
 
                    except OSError, e:
 
1647
                    except errors.TransformRenameFailed, e:
1626
1648
                        if e.errno != errno.ENOENT:
1627
1649
                            raise
1628
1650
                    else:
1653
1675
                if trans_id in self._needs_rename:
1654
1676
                    try:
1655
1677
                        mover.rename(self._limbo_name(trans_id), full_path)
1656
 
                    except OSError, e:
 
1678
                    except errors.TransformRenameFailed, e:
1657
1679
                        # We may be renaming a dangling inventory id
1658
1680
                        if e.errno != errno.ENOENT:
1659
1681
                            raise
1757
1779
        parent_keys = [(file_id, self._file_revision(t, file_id)) for t in
1758
1780
                       self._iter_parent_trees()]
1759
1781
        vf.add_lines((file_id, tree_revision), parent_keys,
1760
 
                     self.get_file(file_id).readlines())
 
1782
                     self.get_file_lines(file_id))
1761
1783
        repo = self._get_repository()
1762
1784
        base_vf = repo.texts
1763
1785
        if base_vf not in vf.fallback_versionedfiles:
1785
1807
            executable = self.is_executable(file_id, path)
1786
1808
        return kind, executable, None
1787
1809
 
 
1810
    def is_locked(self):
 
1811
        return False
 
1812
 
1788
1813
    def lock_read(self):
1789
1814
        # Perhaps in theory, this should lock the TreeTransform?
1790
 
        pass
 
1815
        return self
1791
1816
 
1792
1817
    def unlock(self):
1793
1818
        pass
2252
2277
    for num, _unused in enumerate(wt.all_file_ids()):
2253
2278
        if num > 0:  # more than just a root
2254
2279
            raise errors.WorkingTreeAlreadyPopulated(base=wt.basedir)
2255
 
    existing_files = set()
2256
 
    for dir, files in wt.walkdirs():
2257
 
        existing_files.update(f[0] for f in files)
2258
2280
    file_trans_id = {}
2259
2281
    top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2260
2282
    pp = ProgressPhase("Build phase", 2, top_pb)
2284
2306
                precomputed_delta = []
2285
2307
            else:
2286
2308
                precomputed_delta = None
 
2309
            # Check if tree inventory has content. If so, we populate
 
2310
            # existing_files with the directory content. If there are no
 
2311
            # entries we skip populating existing_files as its not used.
 
2312
            # This improves performance and unncessary work on large
 
2313
            # directory trees. (#501307)
 
2314
            if total > 0:
 
2315
                existing_files = set()
 
2316
                for dir, files in wt.walkdirs():
 
2317
                    existing_files.update(f[0] for f in files)
2287
2318
            for num, (tree_path, entry) in \
2288
2319
                enumerate(tree.inventory.iter_entries_by_dir()):
2289
2320
                pb.update("Building tree", num - len(deferred_contents), total)
2421
2452
    if entry.kind == "directory":
2422
2453
        return True
2423
2454
    if entry.kind == "file":
2424
 
        if tree.get_file(file_id).read() == file(target_path, 'rb').read():
2425
 
            return True
 
2455
        f = file(target_path, 'rb')
 
2456
        try:
 
2457
            if tree.get_file_text(file_id) == f.read():
 
2458
                return True
 
2459
        finally:
 
2460
            f.close()
2426
2461
    elif entry.kind == "symlink":
2427
2462
        if tree.get_symlink_target(file_id) == os.readlink(target_path):
2428
2463
            return True
2480
2515
        raise errors.BadFileKindError(name, kind)
2481
2516
 
2482
2517
 
2483
 
@deprecated_function(deprecated_in((1, 9, 0)))
2484
 
def create_by_entry(tt, entry, tree, trans_id, lines=None, mode_id=None):
2485
 
    """Create new file contents according to an inventory entry.
2486
 
 
2487
 
    DEPRECATED.  Use create_from_tree instead.
2488
 
    """
2489
 
    if entry.kind == "file":
2490
 
        if lines is None:
2491
 
            lines = tree.get_file(entry.file_id).readlines()
2492
 
        tt.create_file(lines, trans_id, mode_id=mode_id)
2493
 
    elif entry.kind == "symlink":
2494
 
        tt.create_symlink(tree.get_symlink_target(entry.file_id), trans_id)
2495
 
    elif entry.kind == "directory":
2496
 
        tt.create_directory(trans_id)
2497
 
 
2498
 
 
2499
2518
def create_from_tree(tt, trans_id, tree, file_id, bytes=None,
2500
2519
    filter_tree_path=None):
2501
2520
    """Create new file contents according to tree contents.
2884
2903
        self.pending_deletions = []
2885
2904
 
2886
2905
    def rename(self, from_, to):
2887
 
        """Rename a file from one path to another.  Functions like os.rename"""
 
2906
        """Rename a file from one path to another."""
2888
2907
        try:
2889
2908
            os.rename(from_, to)
2890
2909
        except OSError, e:
2891
2910
            if e.errno in (errno.EEXIST, errno.ENOTEMPTY):
2892
2911
                raise errors.FileExists(to, str(e))
2893
 
            raise
 
2912
            # normal OSError doesn't include filenames so it's hard to see where
 
2913
            # the problem is, see https://bugs.launchpad.net/bzr/+bug/491763
 
2914
            raise errors.TransformRenameFailed(from_, to, str(e), e.errno)
2894
2915
        self.past_renames.append((from_, to))
2895
2916
 
2896
2917
    def pre_delete(self, from_, to):
2906
2927
    def rollback(self):
2907
2928
        """Reverse all renames that have been performed"""
2908
2929
        for from_, to in reversed(self.past_renames):
2909
 
            os.rename(to, from_)
 
2930
            try:
 
2931
                os.rename(to, from_)
 
2932
            except OSError, e:
 
2933
                raise errors.TransformRenameFailed(to, from_, str(e), e.errno)                
2910
2934
        # after rollback, don't reuse _FileMover
2911
2935
        past_renames = None
2912
2936
        pending_deletions = None