# HG changeset patch # User Todd Larsen # Date 1211216462 0 # Node ID 636baa95715c5f6253ec51b4269de9d290a1079e # Parent 64b3e323210f8fc7974edad67561f88e6d32c280 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 diff -r 64b3e323210f -r 636baa95715c scripts/svn_helper.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" ', +] + + +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 diff -r 64b3e323210f -r 636baa95715c scripts/tests/svn_helper_test.py --- /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" ', +] + + +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'))