Helper module used by utility and tool scripts to access svn repositories.
authorTodd Larsen <tlarsen@google.com>
Mon, 19 May 2008 17:01:02 +0000
changeset 30 636baa95715c
parent 29 64b3e323210f
child 31 8b43c541afa7
Helper module used by utility and tool scripts to access svn repositories. Patch by: Todd Larsen Review by: Sverre Rabbelier Review issue: 105 Review URL: http://codereviews.googleopensourceprograms.com/105
scripts/svn_helper.py
scripts/tests/svn_helper_test.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/svn_helper.py	Mon May 19 17:01:02 2008 +0000
@@ -0,0 +1,139 @@
+#!/usr/bin/python2.5
+#
+# Copyright 2008 the Melange authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Helper functions that wrap the pysvn Python svn bindings.
+
+ls(): returns list of selected directory entries from an SVN repository
+lsDirs(): wrapper around ls() that only returns node_kind.dir entries
+lsFiles(): wrapper around ls() that only returns node_kind.files entries
+exists(): returns True if repo_path exists in the svn repository
+
+DEF_SVN_REPO: default HTTPS path to the SoC project SVN repo
+PYSVN_ALL_NODE_KINDS: all directory entry node_kinds supported by pysvn
+PYSVN_FILE_DIR_NODE_KINDS: actual file and directory node_kinds
+"""
+
+__authors__ = [
+  # alphabetical order by last name, please
+  '"Todd Larsen" <tlarsen@google.com>',
+]
+
+
+import pysvn
+
+
+#: default HTTPS path to the SoC project SVN repo
+DEF_SVN_REPO = 'https://soc.googlecode.com/svn/'
+
+#: all of the directory entry node_kinds supported py pysvn
+PYSVN_ALL_NODE_KINDS = set([pysvn.node_kind.none, pysvn.node_kind.dir,
+                            pysvn.node_kind.file, pysvn.node_kind.unknown])
+
+#: actual file and directory node_kinds (includes dir and file, but excludes
+#: the "non-file" none and unknown)
+PYSVN_FILE_DIR_NODE_KINDS = set([pysvn.node_kind.dir, pysvn.node_kind.file])
+
+
+def ls(client, repo_path, keep_kinds=PYSVN_FILE_DIR_NODE_KINDS, **kwargs):
+  """Returns a list of (possibly recursive) svn repo directory entries.
+
+  Args:
+    client: pysvn Client instance
+    repo_path: absolute svn repository path URL, including the server and
+      directory path within the repo
+    keep_kinds: types of directory entries to keep in the returned list; a
+      collection of pysvn.node_kind objects; default is
+      PYSVN_FILE_DIR_NODE_KINDS
+    **kwargs: keyword arguments passed on to Client.list(), including:
+      recurse: indicates if return results should include entries from
+        subdirectories of repo_path as well; default is False
+
+  Returns:
+    list of (Unicode, coming from pysvn) strings representing the entries
+    of types indicated by keep_kinds; strings are altered to match the
+    output of the actual 'svn ls' command: repo_path prefix is removed,
+    directories end with the / separator.
+  """
+  raw_entries = client.list(repo_path, **kwargs)
+  entries = []
+
+  # Find shortest repos_path that is a 'dir' entry; will be prefix of all
+  # other entries, since Client.list() always returns repo_path as one of
+  # the entries.  It is easier and more reliable to do this search than to
+  # try to manipulate repo_path into the prefix (since the user could supply
+  # any number of valid, but different, formats).
+  shortest_path = raw_entries[0][0].repos_path
+
+  for svn_list, _ in raw_entries:
+    if svn_list.kind == pysvn.node_kind.dir:
+      entry_path = svn_list.repos_path
+
+      if len(entry_path) < len(shortest_path):
+        shortest_path = entry_path
+
+  # normalize the path name of entry_prefix to include a trailing separator
+  entry_prefix = shortest_path
+
+  if not entry_prefix.endswith('/'):
+    entry_prefix = entry_prefix + '/'
+
+  for svn_list,_ in raw_entries:
+    # only include requested node kinds (dir, file, etc.)
+    if svn_list.kind not in keep_kinds:
+      continue
+
+    entry_path = svn_list.repos_path
+
+    # omit the repo_path directory entry itself (simiilar to omitting '.' as
+    # is done by the actual 'svn ls' command)
+    if entry_path == shortest_path:
+      continue
+
+    # all entry_paths except for the shortest should start with that
+    # shortest entry_prefix, so assert that and remove the prefix
+    assert entry_path.startswith(entry_prefix)
+    entry_path = entry_path[len(entry_prefix):]
+
+    # normalize directory entry_paths to include a trailing separator
+    if ((svn_list.kind == pysvn.node_kind.dir)
+        and (not entry_path.endswith('/'))):
+      entry_path = entry_path + '/'
+
+    entries.append(entry_path)
+
+  return entries
+
+
+def lsDirs(client, repo_path, **kwargs):
+  """Wrapper around ls() that only returns node_kind.dir entries.
+  """
+  return ls(client, repo_path, keep_kinds=(pysvn.node_kind.dir,), **kwargs)
+
+
+def lsFiles(client, repo_path, **kwargs):
+  """Wrapper around ls() that only returns node_kind.files entries.
+  """
+  return ls(client, repo_path, keep_kinds=(pysvn.node_kind.file,), **kwargs)
+
+
+def exists(client, repo_path):
+  """Returns True if repo_path exists in the svn repository."""
+  try:
+    raw_entries = client.list(repo_path)
+    return True
+  except pysvn._pysvn.ClientError:
+    # Client.list() raises an exception if the path is not present in the repo
+    return False
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/tests/svn_helper_test.py	Mon May 19 17:01:02 2008 +0000
@@ -0,0 +1,75 @@
+#!/usr/bin/python2.5
+#
+# Copyright 2008 the Melange authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Tests for the scripts.svn_helper module.
+
+For details on running the tests, see:
+  http://code.google.com/p/soc/wiki/TestingGuidelines#Running_the_smoke_tests
+"""
+
+__authors__ = [
+  # alphabetical order by last name, please
+  '"Todd Larsen" <tlarsen@google.com>',
+]
+
+
+import os
+import pysvn
+import sys
+import unittest
+
+from .. import svn_helper
+
+
+class SvnHelperTests(unittest.TestCase):
+  """pysvn wrapper tests for the svn_helper.py module.
+  """
+
+  def setUp(self):
+    self.client = pysvn.Client()
+
+  def testLsFiles(self):
+    """Test if lsFiles() contains only file entries, using the SoC SVN repo.
+    """
+    self.assert_(
+        'svn_helper_test.py' in svn_helper.lsFiles(
+            self.client, '%strunk/scripts/tests' % svn_helper.DEF_SVN_REPO))
+
+    self.assert_(
+        'tests/' not in svn_helper.lsFiles(
+            self.client, '%strunk/scripts' % svn_helper.DEF_SVN_REPO))
+
+  def testLsDirs(self):
+    """Test if lsDirs() contains only dir entries, using the SoC SVN repo.
+    """
+    self.assert_(
+        'tests/' in svn_helper.lsDirs(
+            self.client, '%strunk/scripts' % svn_helper.DEF_SVN_REPO))
+
+    self.assert_(
+        'svn_helper_test.py' not in svn_helper.lsDirs(
+            self.client, '%strunk/scripts' % svn_helper.DEF_SVN_REPO))
+
+  def testExists(self):
+    """Test if exists() works on the the SoC SVN repo.
+    """
+    self.assertEqual(
+        True, svn_helper.exists(self.client,
+                                svn_helper.DEF_SVN_REPO + 'trunk'))
+
+    self.assertEqual(
+        False, svn_helper.exists(self.client,
+                                 svn_helper.DEF_SVN_REPO + 'does_not_exist'))