Create a submit_buttons block in group edit profile template so that submit buttons can be customized. Replace submit_message usage with new notice block (still work in progress in Lookup User views). Add customized edit profile template for Sponsor with delete button (not used yet, upcoming commit). Add delete Sponsor request handler.
Patch by: Pawel Solyga
Review by: to-be-reviewed
#!/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
PYSVN_ALL_NODE_KINDS: all directory entry node_kinds supported by pysvn
PYSVN_FILE_DIR_NODE_KINDS: actual file and directory node_kinds
This module requires that the pysvn module be installed.
"""
__authors__ = [
# alphabetical order by last name, please
'"Todd Larsen" <tlarsen@google.com>',
]
import os
import pysvn
# top level script needs to use a relative import
import settings
#: 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])
# pysvn Client object initialized lazily the first time getPySvnClient()
# is called.
_client = None
def getPySvnClient():
"""Returns the module-global pysvn Client object (creating one if needed).
Lazily initializes a global pysvn Client object, returning the same one
once it exists.
"""
global _client
if not _client:
_client = pysvn.Client()
return _client
def formatDirPath(path):
"""Appends trailing separator to non-empty path if it is missing.
Args:
path: path string, which may be with or without a trailing separator,
or even empty or None
Returns:
path unchanged if path evaluates to False or already ends with a trailing
separator; otherwise, a / separator is appended
"""
if path and not path.endswith('/'):
path = path + '/'
return path
def formatDirPaths(*args):
"""Apply formatDirPath() to all supplied arguments, returning them in order.
"""
return tuple([formatDirPath(arg) for arg in args])
def getCanonicalSvnPath(path):
"""Returns the supplied svn repo path *without* the trailing / character.
Some pysvn methods raise exceptions if svn directory URLs end with a
trailing / ("non-canonical form") and some do not. Go figure...
"""
if path and path.endswith('/'):
path = path[:-1]
return path
def useLocalOsSep(path):
"""Return path with all / characters replaced with os.sep, to be OS-agnostic.
Args:
path: an SVN path (either working copy path or relative path, but not a
full repository URL) that uses the canonical / separators
"""
return path.replace('/', os.sep)
def getExpandedWorkingCopyPath(path, wc_root=None):
"""Returns expanded, local, native filesystem working copy path.
Args:
path: path to expand and convert to local filesystem directory separators
wc_root: if present, prepended to path first
"""
path = useLocalOsSep(path)
if wc_root:
# prepend (Windows-compatible) working copy root if one was supplied
path = os.path.join(useLocalOsSep(wc_root), path)
path = settings.getExpandedPath(path)
if not path.endswith(os.sep):
path = path + os.sep
return path
def encodeRevision(rev):
"""Encode supplied revision into a pysvn.Revision instance.
This function is currently very simplistic and does not produce all possible
types of pysvn.Revision object. See below for current limitations.
Args:
rev: integer revision number or None
Returns:
HEAD pysvn.Revision object if rev is None,
otherwise a pysvn.opt_revision_kind.number pysvn.Revision object created
using the supplied integer revision number
"""
if rev is None:
return pysvn.Revision(pysvn.opt_revision_kind.head)
return pysvn.Revision(pysvn.opt_revision_kind.number, int(rev))
def ls(repo_path, client=None, keep_kinds=PYSVN_FILE_DIR_NODE_KINDS, **kwargs):
"""Returns a list of (possibly recursive) svn repo directory entries.
Args:
repo_path: absolute svn repository path URL, including the server and
directory path within the repo
client: pysvn Client instance; default is None, which will use the pysvn
Client created by first call to getPySvnClient() (or create one if
necessary)
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.
"""
if not client:
client = getPySvnClient()
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 = formatDirPath(shortest_path)
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(repo_path, **kwargs):
"""Wrapper around ls() that only returns node_kind.dir entries.
"""
return ls(repo_path, keep_kinds=(pysvn.node_kind.dir,), **kwargs)
def lsFiles(repo_path, **kwargs):
"""Wrapper around ls() that only returns node_kind.files entries.
"""
return ls(repo_path, keep_kinds=(pysvn.node_kind.file,), **kwargs)
def exists(repo_path, client=None):
"""Returns True if repo_path exists in the svn repository."""
if not client:
client = getPySvnClient()
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
def branchItems(src, dest, items, rev=None, client=None):
"""Branch a list of items (files and/or directories).
Using the supplied pysvn client object, a list of items (expected to be
present in the src directory) is branched from the absolute svn repo src
path URL to the relative working client dest directory.
Args:
src: absolute svn repository source path URL, including the server and
directory path within the repo
dest: relative svn repository destination path in the current working copy
items: list of relative paths of items in src/ to branch to dest/ (no item
should begin with the / separator)
client: pysvn Client instance; default is None, which will use the pysvn
Client created by first call to getPySvnClient() (or create one if
necessary)
"""
if not client:
client = getPySvnClient()
src = formatDirPath(src)
dest = useLocalOsSep(formatDirPath(dest))
for item in items:
assert not item.startswith('/')
src_item = getCanonicalSvnPath(src + item)
# attempt to be compatible with Windows working copy paths
item = useLocalOsSep(item)
client.copy(src_item, dest + item, src_revision=encodeRevision(rev))
def branchDir(src, dest, client=None, rev=None):
"""Branch one directory to another.
Using the supplied pysvn client object, the absolute svn repo path URL src
directory is branched to the relative working client dest directory.
Args:
src: absolute svn repository source path URL, including the server and
directory path within the repo
dest: relative svn repository destination path in the current working copy
client: pysvn Client instance; default is None, which will use the pysvn
Client created by first call to getPySvnClient() (or create one if
necessary)
"""
if not client:
client = getPySvnClient()
src = getCanonicalSvnPath(src)
dest = useLocalOsSep(formatDirPath(dest))
client.copy(src, dest, src_revision=encodeRevision(rev))
def exportItems(src, dest, items, rev=None, client=None):
"""Export a list of items (files and/or directories).
Using the supplied pysvn client object, a list of items (expected to be
present in the src directory) is exported from the absolute svn repo src
path URL to the local filesystem directory.
Args:
src: absolute svn repository source path URL, including the server and
directory path within the repo
dest: local filesystem destination path
items: list of relative paths of items in src/ to export to dest/ (no item
should begin with the / separator)
client: pysvn Client instance; default is None, which will use the pysvn
Client created by first call to getPySvnClient() (or create one if
necessary)
"""
if not client:
client = getPySvnClient()
src = formatDirPath(src)
dest = useLocalOsSep(formatDirPath(dest))
for item in items:
assert not item.startswith('/')
src_item = getCanonicalSvnPath(src + item)
# attempt to be compatible with Windows local filesystem paths
dest_item = useLocalOsSep(getCanonicalSvnPath(dest + item))
client.export(src_item, dest_item, revision=encodeRevision(rev))
def exportDir(src, dest, client=None, rev=None):
"""Export one directory to another.
Using the supplied pysvn client object, the absolute svn repo path URL src
directory is exported to the the local filesystem directory.
Args:
src: absolute svn repository source path URL, including the server and
directory path within the repo
dest: local filesystem destination path
client: pysvn Client instance; default is None, which will use the pysvn
Client created by first call to getPySvnClient() (or create one if
necessary)
"""
if not client:
client = getPySvnClient()
src = getCanonicalSvnPath(src)
dest = useLocalOsSep(getCanonicalSvnPath(dest))
client.export(src, dest, revision=encodeRevision(rev))