More fixes, cache revmeta data.
authorJelmer Vernooij <jelmer@samba.org>
Fri, 29 Aug 2008 23:55:41 +0000 (01:55 +0200)
committerJelmer Vernooij <jelmer@samba.org>
Fri, 29 Aug 2008 23:55:41 +0000 (01:55 +0200)
12 files changed:
NEWS
TODO
__init__.py
commit.py
logwalker.py
mapping.py
mapping4.py
repository.py
revids.py
tags.py
transport.py
upgrade.py

diff --git a/NEWS b/NEWS
index bc58fc320a8373393aa8c2674cc1ac3c6411a76e..67e38aa0e291748e7afd5de103b18eb939c7fcaf 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,16 @@ bzr-svn-0.5                    UNRELEASED
 
 bzr-svn 0.4.12 UNRELEASED
 
+
+  CHANGES
+
+   * Implement set-revprops command.
+
+  FEATURES
+
+   * Add bzr:skip revision property to allow skipping 
+     more detailed analysis of revisions not created by bzr.
+
   BUG FIXES
 
    * Cope with svn+ prefix when setting tags. (#261748)
@@ -10,6 +20,8 @@ bzr-svn 0.4.12        UNRELEASED
 
    * Fix compatibility with Bazaar 1.7.
 
+   * Set bzr signature revision property during commit if possible.
+
 bzr-svn 0.4.11 2008-08-26
 
 bzr-svn 0.4.11~rc2     2008-08-26
diff --git a/TODO b/TODO
index 605a3ef486d84409bab54c41c2b3da84e69c70c3..4581037e76dd36eb43ab137c97168734fd824016 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,8 +1,11 @@
 mappingv4:
  - refuse to set fileprops on repository on which revprops have been set
- - skip looking for fileprops if revprops have been found in earlier revisions
+ - skip looking for fileprops if revprops have been found in earlier revisions \
+   AND server supports revprops AND mapping.supports_custom_revprops()
  - implement layout functions, including command
  - integrate svn-set-revprops into svn-upgrade ?
+ - add options in commit for create_root, create_prefix
+  - if create_root=False: skip _check_dirs_exist
 
 todo:
 - generate deltas rather than fulltexts when creating file id maps
@@ -32,7 +35,6 @@ pushmerge:
  - Run all tests against repository with revprop changing allowed and without
 - Needs upgrade command that can use legacy file properties and set revprops
 - Support disabling legacy file property support somehow
-- remove set revision properties settings
 
 for other things to do, see:
 
index 35503aef66e6fe91229e6991ae0afd172adaab93..4ae53e98969c7570a3dff3b372d0e98f53a48d9d 100644 (file)
@@ -515,6 +515,8 @@ class cmd_svn_set_revprops(Command):
         from bzrlib.plugins.svn.upgrade import set_revprops
         from bzrlib.plugins.svn.mapping import get_default_mapping
         repos = Repository.open(location) 
+        if not repos.transport.has_capability("commit-revprops"):
+            raise BzrCommandError("Please upgrade the Subversion server to 1.5 or higher.")
         if mapping is None:
             mapping = get_default_mapping()
         new_mapping = mapping.from_repository(repos)
index dbdaf6ac029a080cc9f12edefbd91f2822503743..d5778e3540410198446606ebda63e41169246a36 100644 (file)
--- a/commit.py
+++ b/commit.py
@@ -190,7 +190,10 @@ class SvnCommitBuilder(RootCommitBuilder):
         else:
             self._base_branch_props = lazy_dict({}, self.repository.branchprop_list.get_properties, self.base_path, self.base_revnum)
         self.supports_custom_revprops = self.repository.transport.has_capability("commit-revprops")
-        if self.supports_custom_revprops:
+        if self.supports_custom_revprops is None and self.base_mapping.supports_custom_revprops() and self.repository.seen_bzr_revprops():
+            raise BzrError("Please upgrade your Subversion client libraries to 1.5 or higher to be able to commit with Subversion mapping %s" % self.base_mapping.name)
+
+        if self.supports_custom_revprops == True:
             self._svn_revprops = {}
             if opt_signature is not None:
                 self._svn_revprops[mapping.SVN_REVPROP_BZR_SIGNATURE] = opt_signature
index abaed04bc7aa3c41a39c1f061f2d8fce1fc93232..1093c4fa993bc11ad3bdaea56a02eaccdf639fab 100644 (file)
@@ -587,6 +587,9 @@ class LogWalker(object):
 
     def changes_path(self, path, revnum):
         return self._get_revision_paths(revnum).has_key(path)
+
+    def get_change(self, path, revnum):
+        return self._get_revision_paths(revnum).get(path)
         
     def find_children(self, path, revnum):
         """Find all children of path in revnum.
index 1887e0a7e90b6e3a62274a0f4bd3741c63e5f448..d39e9305bc8ff49c05b6a5ea74aeb902ab8e5dd6 100644 (file)
@@ -283,11 +283,7 @@ class BzrSvnMapping(foreign.VcsMapping):
 
     @classmethod
     def supports_custom_revprops(cls):
-        """Whether this mapping can be used with custom revision properties."""
-        return False
-
-    def is_bzr_revision(self, revprops, fileprops):
-        """Whether this is a revision that was pushed by Bazaar."""
+        """Whether this mapping will primarily use custom revision properties."""
         return False
 
     @classmethod
@@ -580,9 +576,6 @@ class BzrSvnMappingFileProps(object):
     def export_message(self, message, revprops, fileprops):
         fileprops[SVN_PROP_BZR_LOG] = message.encode("utf-8")
 
-    def is_bzr_revision(self, revprops, fileprops):
-        return fileprops.has_key(SVN_PROP_BZR_REVISION_ID+self.name)
-
     def get_revision_id(self, branch_path, revprops, fileprops):
         # Lookup the revision from the bzr:revision-id-vX property
         text = fileprops.get(SVN_PROP_BZR_REVISION_ID+self.name, None)
@@ -640,15 +633,8 @@ class BzrSvnMappingRevProps(object):
             return []
         return svn_revprops.get(SVN_REVPROP_BZR_MERGE, "").splitlines()
 
-    def is_bzr_revision(self, revprops, fileprops):
-        if revprops.has_key(SVN_REVPROP_BZR_MAPPING_VERSION):
-            return True
-        if revprops.has_key(SVN_REVPROP_BZR_SKIP):
-            return False
-        return None
-
     def get_revision_id(self, branch_path, revprops, fileprops):
-        if not self.is_bzr_revision(revprops, fileprops):
+        if not is_bzr_revision_revprops(revprops):
             return (None, None)
         if revprops[SVN_REVPROP_BZR_ROOT] == branch_path:
             revid = revprops[SVN_REVPROP_BZR_REVISION_ID]
@@ -749,3 +735,15 @@ def find_mapping(revprops, fileprops):
             return parse_mapping_name(k[len(SVN_PROP_BZR_REVISION_ID):])
     return None
 
+def is_bzr_revision_revprops(revprops):
+    if revprops.has_key(SVN_REVPROP_BZR_MAPPING_VERSION):
+        return True
+    if revprops.has_key(SVN_REVPROP_BZR_SKIP):
+        return False
+    return None
+
+def is_bzr_revision_fileprops(fileprops):
+    for k in fileprops:
+        if k.startswith(SVN_PROP_BZR_REVISION_ID):
+            return True
+    return None
index 31025a893ef523f3ddcf46f5138de3fe5286f3f4..aa6d62ce10f7bbc0ba65d536629bff2187907215 100644 (file)
@@ -48,13 +48,6 @@ class BzrSvnMappingv4(mapping.BzrSvnMapping):
     def supports_custom_revprops():
         return True
 
-    def is_bzr_revision(self, revprops, fileprops):
-        """Whether this is a revision that was pushed by Bazaar."""
-        is_revprop_rev = self.revprops.is_bzr_revision(revprops, fileprops)
-        if is_revprop_rev is not None:
-            return is_revprop_rev
-        return self.fileprops.is_bzr_revision(revprops, fileprops)
-
     @classmethod
     def revision_id_bzr_to_foreign(cls, revid):
         assert isinstance(revid, str)
index 5c3779300be3c28f3bbaaee3d44c6e6cd160cd87..3460e1e77392ff1cbddbb07c20d28b5243b78fe6 100644 (file)
@@ -41,6 +41,7 @@ from bzrlib.plugins.svn.core import SubversionException
 from bzrlib.plugins.svn.mapping import (SVN_REVPROP_BZR_SIGNATURE,
                      BzrSvnMapping,
                      get_default_mapping, 
+                     is_bzr_revision_revprops, is_bzr_revision_fileprops,
                      parse_svn_dateprop)
 from bzrlib.plugins.svn.parents import DiskCachingParentsProvider
 from bzrlib.plugins.svn.revids import CachingRevidMap, RevidMap
@@ -80,8 +81,19 @@ class RevisionMetadata(object):
             lhs_parent = self.repository.lhs_revision_parent(self.branch_path, self.revnum, mapping)
         return lhs_parent
 
-    def is_bzr_revision(self, mapping):
-        return mapping.is_bzr_revision(self.revprops, self.fileprops)
+    def is_bzr_revision(self):
+        # If the server already sent us all revprops, look at those first
+        if self.repository.transport.has_capability("log-revprops"):
+            order = [lambda: is_bzr_revision_revprops(self.revprops),
+                     lambda: is_bzr_revision_fileprops(self.fileprops)]
+        else:
+            order = [lambda: is_bzr_revision_fileprops(self.fileprops),
+                     lambda: is_bzr_revision_revprops(self.revprops)]
+        for fn in order:
+            ret = fn()
+            if ret is not None:
+                return ret
+        return None
 
     def get_rhs_parents(self, mapping):
         extra_rhs_parents = mapping.get_rhs_parents(self.branch_path, self.revprops, self.fileprops)
@@ -89,7 +101,7 @@ class RevisionMetadata(object):
         if extra_rhs_parents != ():
             return extra_rhs_parents
 
-        if self.is_bzr_revision(mapping):
+        if self.is_bzr_revision():
             return ()
 
         (prev_path, prev_revnum) = self.repository._log.get_previous(self.branch_path, 
@@ -219,6 +231,7 @@ class SvnRepository(Repository):
         self._hinted_branch_path = branch_path
         self._real_parents_provider = self
         self._cached_tags = {}
+        self._revmeta_cache = {}
 
         cache = self.get_config().get_use_cache()
 
@@ -449,7 +462,7 @@ class SvnRepository(Repository):
                                 svn_fileprops = {}
                             else:
                                 svn_fileprops = self.branchprop_list.get_changed_properties(bp, revnum)
-                            yield RevisionMetadata(self, bp, paths, revnum, revprops, svn_fileprops)
+                            yield self._revmeta(bp, paths, revnum, revprops, svn_fileprops)
 
     def all_revision_ids(self, layout=None, mapping=None):
         if mapping is None:
@@ -571,9 +584,7 @@ class SvnRepository(Repository):
             except NoSuchRevision:
                 continue
 
-            svn_fileprops = self.branchprop_list.get_changed_properties(branch, revnum)
-            svn_revprops = self._log.revprop_list(revnum)
-            revmeta = RevisionMetadata(self, branch, None, revnum, svn_revprops, svn_fileprops)
+            revmeta = self._revmeta(branch, None, revnum)
 
             parent_map[revision_id] = revmeta.get_parent_ids(mapping)
         return parent_map
@@ -597,6 +608,19 @@ class SvnRepository(Repository):
             if revid is not None:
                 yield revid
 
+    def _revmeta(self, path, changes, revnum, revprops=None, fileprops=None):
+        if (path, revnum) in self._revmeta_cache:
+            return self._revmeta_cache[path,revnum]
+
+        if revprops is None:
+            revprops = self._log.revprop_list(revnum)
+        if fileprops is None:
+            fileprops = self.branchprop_list.get_changed_properties(path, revnum)
+
+        revmeta = RevisionMetadata(self, path, changes, revnum, revprops, fileprops)
+        self._revmeta_cache[path,revnum] = revmeta
+        return revmeta
+
     def get_revision(self, revision_id):
         """See Repository.get_revision."""
         if not revision_id or not isinstance(revision_id, str):
@@ -604,10 +628,7 @@ class SvnRepository(Repository):
 
         (path, revnum, mapping) = self.lookup_revision_id(revision_id)
         
-        svn_revprops = self._log.revprop_list(revnum)
-        svn_fileprops = self.branchprop_list.get_changed_properties(path, revnum)
-
-        revmeta = RevisionMetadata(self, path, None, revnum, svn_revprops, svn_fileprops)
+        revmeta = self._revmeta(path, None, revnum)
 
         return revmeta.get_revision(mapping)
 
@@ -726,6 +747,16 @@ class SvnRepository(Repository):
             else:
                 bp = next[0]
 
+    def seen_bzr_revprops(self):
+        """Check whether bzr-specific custom revision properties are present on this 
+        repository.
+
+        """
+        for revmeta in self._log.iter_all_changes():
+            if revmeta.is_bzr_revision():
+                return True
+        return False
+
     def iter_reverse_branch_changes(self, branch_path, from_revnum, to_revnum, 
                                     mapping=None, pb=None, limit=0):
         """Return all the changes that happened in a branch 
@@ -741,7 +772,7 @@ class SvnRepository(Repository):
             else:
                 svn_fileprops = self.branchprop_list.get_changed_properties(bp, revnum)
 
-            yield RevisionMetadata(self, bp, paths, revnum, revprops, svn_fileprops)
+            yield self._revmeta(bp, paths, revnum, revprops, svn_fileprops)
 
     def get_config(self):
         return SvnRepositoryConfig(self.uuid)
index 18269e862e713c1f38fa7d4f1552c9488e092443..068deed7dd9af87d8b6c65e36cbd72bc8452d9a6 100644 (file)
--- a/revids.py
+++ b/revids.py
@@ -63,7 +63,7 @@ class RevidMap(object):
         for entry_revid, branch, revno, mapping in self.discover_revids(layout, 0, self.repos.get_latest_revnum(), project):
             if revid == entry_revid:
                 (bp, revnum, mapping_name) = self.bisect_revid_revnum(revid, branch, 0, revno)
-                return (bp, revnum, parse_mapping_name(mapping_name))
+                return (bp, revnum, mapping_name)
         raise NoSuchRevision(self, revid)
 
     def discover_revids(self, layout, from_revnum, to_revnum, project=None):
diff --git a/tags.py b/tags.py
index bd6a2b34838838c1d26568ff30575d7abe6dd393..8225a3c312c199d1cff20d92245c906cb7803506 100644 (file)
--- a/tags.py
+++ b/tags.py
@@ -18,7 +18,7 @@ from bzrlib.errors import NoSuchRevision, NoSuchTag
 from bzrlib.tag import BasicTags
 from bzrlib.trace import mutter
 
-from bzrlib.plugins.svn import commit, core, properties
+from bzrlib.plugins.svn import commit, core, mapping, properties
 
 class SubversionTags(BasicTags):
     def __init__(self, branch):
index 8a98f50747061afa22b664a4ffb402b99a4bde35..9055fb0641add159788443d443113ff3db354790 100644 (file)
@@ -426,7 +426,7 @@ class SvnRaTransport(Transport):
             try:
                 self.capabilities[cap] = conn.has_capability(cap)
             except NotImplementedError:
-                self.capabilities[cap] = False # Assume the worst
+                self.capabilities[cap] = None # None for unknown
             return self.capabilities[cap]
         finally:
             self.add_connection(conn)
index da753de0a66f09318c246d01383a1b9ab9c5f7d0..890eef5fba793ba58ddfaeea123cb34729015bef 100644 (file)
@@ -252,9 +252,10 @@ def set_revprops(repository, new_mapping, from_revnum=0, to_revnum=None):
                 continue
             assert old_mapping.supports_custom_revprops() or bp is not None
             new_revprops = dict(revprops.items())
-            revmeta = RevisionMetadata(repository, bp, changes, revnum, revprops, fileprops)
+            revmeta = repository._revmeta(bp, changes, revnum, revprops, fileprops)
             rev = revmeta.get_revision(old_mapping)
             revno = graph.find_distance_to_null(rev.revision_id, [])
+            assert bp is not None
             new_mapping.export_revision(bp, rev.timestamp, rev.timezone, rev.committer, rev.properties, rev.revision_id, revno, rev.parent_ids, new_revprops, None)
             new_mapping.export_fileid_map(old_mapping.import_fileid_map(revprops, fileprops), 
                 new_revprops, None)
@@ -262,7 +263,7 @@ def set_revprops(repository, new_mapping, from_revnum=0, to_revnum=None):
                 new_revprops, None)
             if rev.message != mapping.parse_svn_log(revprops.get(properties.PROP_REVISION_LOG)):
                 new_mapping.export_message(rev.message, new_revprops, None)
-            changed_revprops = dict(filter(lambda (k,v): revprops.get(k) != v, new_revprops.items()))
+            changed_revprops = dict(filter(lambda (k,v): k not in revprops or revprops[k] != v, new_revprops.items()))
             if logcache is not None:
                 logcache.drop_revprops(revnum)
             for k, v in changed_revprops.items():