changeset 1307:cdb1f1923a1a

Merge with stable.
author Augie Fackler <raf@durin42.com>
date Fri, 30 Jan 2015 13:47:27 -0500
parents 0326686199f5 (diff) b13f320ff4e3 (current diff)
children 78133c7ec2fc
files
diffstat 2 files changed, 73 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/hgsubversion/svnmeta.py
+++ b/hgsubversion/svnmeta.py
@@ -12,6 +12,7 @@ import util
 import maps
 import layouts
 import editor
+import svnwrap
 
 
 class SVNMeta(object):
@@ -40,6 +41,7 @@ class SVNMeta(object):
         self._branchmap = None
         self._tagmap = None
         self._filemap = None
+        self._layout = None
 
         # create .hg/svn folder if it doesn't exist
         if not os.path.isdir(self.metapath):
@@ -56,11 +58,12 @@ class SVNMeta(object):
         self._gen_cachedconfig('defaulthost', self.uuid)
         self._gen_cachedconfig('usebranchnames', True)
         self._gen_cachedconfig('defaultmessage', '')
+        self._gen_cachedconfig('branch', '')
+        self._gen_cachedconfig('layout', 'auto')
 
         # misc
         self.branches = util.load(self.branch_info_file) or {}
         self.prevbranches = dict(self.branches)
-        self._layout = layouts.detect.layout_from_file(self)
 
     def _get_cachedconfig(self, name, filename, configname, default, pre):
         """Return a cached value for a config option. If the cache is uninitialized
@@ -143,20 +146,71 @@ class SVNMeta(object):
                                                             filename))
         setattr(SVNMeta, name, prop)
 
+    def layout_from_subversion(self, svn, revision=None):
+        """ Guess what layout to use based on directories under the svn root.
+
+        This is intended for use during bootstrapping.  It guesses which
+        layout to use based on the presence or absence of the conventional
+        trunk, branches, tags dirs immediately under the path your are
+        cloning.
+
+        Additionally, this will write the layout in use to the ui object
+        passed, if any.
+
+        """
+
+        try:
+            rootlist = svn.list_dir('', revision=revision)
+        except svnwrap.SubversionException, e:
+            err = "%s (subversion error: %d)" % (e.args[0], e.args[1])
+            raise hgutil.Abort(err)
+        if sum(map(lambda x: x in rootlist, ('branches', 'tags', 'trunk'))):
+            layout = 'standard'
+        else:
+            layout = 'single'
+        self.ui.setconfig('hgsubversion', 'layout', layout)
+        return layout
+
+    def layout_from_commit(self, subdir, revpath, branch):
+        """ Guess what the layout is based existing commit info
+
+        Specifically, this compares the subdir for the repository and the
+        revpath as extracted from the convinfo in the commit.  If they
+        match, the layout is assumed to be single.  Otherwise, it tries
+        the available layouts and selects the first one that would
+        translate the given branch to the given revpath.
+
+        """
+
+        subdir = subdir or '/'
+        if subdir == revpath:
+            return 'single'
+
+        candidates = set()
+        for layout in layouts.NAME_TO_CLASS:
+            layoutobj = layouts.layout_from_name(layout, self)
+            try:
+                remotepath = layoutobj.remotepath(branch, subdir)
+            except KeyError:
+                continue
+            if  remotepath == revpath:
+                candidates.add(layout)
+
+        if len(candidates) == 1:
+            return candidates.pop()
+        elif candidates:
+            config_layout = layouts.detect.layout_from_config(self,
+                                                              allow_auto=True)
+            if config_layout in candidates:
+                return config_layout
+
+        return 'standard'
+
+
     @property
     def layout_file(self):
         return os.path.join(self.metapath, 'layout')
 
-    @property
-    def layout(self):
-        # this method can't determine the layout, but it needs to be
-        # resolved into something other than auto before this ever
-        # gets called
-        if not self._layout or self._layout == 'auto':
-            self._layout = layouts.detect.layout_from_config(self)
-            util.dump(self._layout, self.layout_file)
-        return self._layout
-
     @property
     def layoutobj(self):
         if not self._layoutobj:
--- a/hgsubversion/wrappers.py
+++ b/hgsubversion/wrappers.py
@@ -399,21 +399,17 @@ def pull(repo, source, heads=[], force=F
 
         stopat_rev = util.parse_revnum(svn, checkout)
 
-        layout = layouts.detect.layout_from_config(meta, allow_auto=True)
-        if layout == 'auto':
-            layout = layouts.detect.layout_from_subversion(svn,
-                                                           (stopat_rev or None),
-                                                           meta)
-            repo.ui.note('using %s layout\n' % layout)
-
-        branch = repo.ui.config('hgsubversion', 'branch')
-        if branch:
-            if layout != 'single':
+        if meta.layout == 'auto':
+            meta.layout = meta.layout_from_subversion(svn, (stopat_rev or None))
+            repo.ui.note('using %s layout\n' % meta.layout)
+
+        if meta.branch:
+            if meta.layout != 'single':
                 msg = ('branch cannot be specified for Subversion clones using '
                        'standard directory layout')
                 raise hgutil.Abort(msg)
 
-            meta.branchmap['default'] = branch
+            meta.branchmap['default'] = meta.branch
 
         ui = repo.ui
         start = meta.lastpulled
@@ -425,7 +421,7 @@ def pull(repo, source, heads=[], force=F
                                                           'startrev', 0))
 
             if start > 0:
-                if layout == 'standard':
+                if meta.layout == 'standard':
                     raise hgutil.Abort('non-zero start revisions are only '
                                        'supported for single-directory clones.')
                 ui.note('starting at revision %d; any prior will be ignored\n'