summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Server/Plugins/Svn.py
diff options
context:
space:
mode:
authorChris St. Pierre <chris.a.st.pierre@gmail.com>2012-10-18 11:33:38 -0400
committerChris St. Pierre <chris.a.st.pierre@gmail.com>2012-10-30 09:11:53 -0400
commit63a5b62dba190007634e1e0f2f834057b63aeafd (patch)
treebeb6d51675d43fe8303aff62a3c9272e82e67520 /src/lib/Bcfg2/Server/Plugins/Svn.py
parent7b9987d1835ff422e21f0b2f36c93d956192bf4b (diff)
downloadbcfg2-63a5b62dba190007634e1e0f2f834057b63aeafd.tar.gz
bcfg2-63a5b62dba190007634e1e0f2f834057b63aeafd.tar.bz2
bcfg2-63a5b62dba190007634e1e0f2f834057b63aeafd.zip
added Git.Update RMI, ability to base bcfg2 VCS repo at a different directory than the repo root
Diffstat (limited to 'src/lib/Bcfg2/Server/Plugins/Svn.py')
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Svn.py133
1 files changed, 112 insertions, 21 deletions
diff --git a/src/lib/Bcfg2/Server/Plugins/Svn.py b/src/lib/Bcfg2/Server/Plugins/Svn.py
index 5bc9d6bbd..fda6b57b5 100644
--- a/src/lib/Bcfg2/Server/Plugins/Svn.py
+++ b/src/lib/Bcfg2/Server/Plugins/Svn.py
@@ -1,34 +1,125 @@
""" The Svn plugin provides a revision interface for Bcfg2 repos using
-svn. """
+Subversion. If PySvn libraries are installed, then it exposes two
+additional XML-RPC methods for committing data to the repository and
+updating the repository. """
-import pipes
-from subprocess import Popen, PIPE
+import sys
import Bcfg2.Server.Plugin
+try:
+ import pysvn
+ HAS_SVN = True
+except ImportError:
+ import pipes
+ from subprocess import Popen, PIPE
+ HAS_SVN = False
-class Svn(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.Version):
- """ The Svn plugin provides a revision interface for Bcfg2 repos
- using svn. """
+class Svn(Bcfg2.Server.Plugin.Version):
+ """Svn is a version plugin for dealing with Bcfg2 repos."""
__author__ = 'bcfg-dev@mcs.anl.gov'
- __vcs_metadata_path__ = ".svn"
+ if HAS_SVN:
+ __rmi__ = Bcfg2.Server.Plugin.Version.__rmi__ + ['Update', 'Commit']
+ else:
+ __vcs_metadata_path__ = ".svn"
def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.Version.__init__(self, datastore)
- self.logger.debug("Initialized svn plugin with svn directory %s" %
+ Bcfg2.Server.Plugin.Version.__init__(self, core, datastore)
+
+ self.revision = None
+ self.svn_root = None
+ if not HAS_SVN:
+ self.logger.debug("Svn: PySvn not found, using CLI interface to "
+ "SVN")
+ self.client = None
+ else:
+ self.client = pysvn.Client()
+
+ self.logger.debug("Initialized svn plugin with SVN directory %s" %
self.vcs_path)
def get_revision(self):
"""Read svn revision information for the Bcfg2 repository."""
+ msg = None
+ if HAS_SVN:
+ try:
+ info = self.client.info(self.vcs_root)
+ self.revision = info.revision
+ self.svn_root = info.url
+ return str(self.revision.number)
+ except pysvn.ClientError: # pylint: disable=E1101
+ msg = "Svn: Failed to get revision: %s" % sys.exc_info()[1]
+ else:
+ try:
+ data = Popen(("env LC_ALL=C svn info %s" %
+ pipes.quote(self.vcs_root)), shell=True,
+ stdout=PIPE).communicate()[0].split('\n')
+ return [line.split(': ')[1] for line in data \
+ if line[:9] == 'Revision:'][-1]
+ except IndexError:
+ msg = "Failed to read svn info"
+ self.logger.error('Ran command "svn info %s"' % self.vcs_root)
+ self.revision = None
+ self.logger.error(msg)
+ raise Bcfg2.Server.Plugin.PluginExecutionError(msg)
+
+ def Update(self):
+ '''Svn.Update() => True|False\nUpdate svn working copy\n'''
try:
- data = Popen(("env LC_ALL=C svn info %s" %
- pipes.quote(self.datastore)), shell=True,
- stdout=PIPE).communicate()[0].split('\n')
- return [line.split(': ')[1] for line in data \
- if line[:9] == 'Revision:'][-1]
- except IndexError:
- msg = "Failed to read svn info"
- self.logger.error(msg)
- self.logger.error('Ran command "svn info %s"' % self.datastore)
- raise Bcfg2.Server.Plugin.PluginExecutionError(msg)
+ old_revision = self.revision.number
+ self.revision = self.client.update(self.vcs_root, recurse=True)[0]
+ except pysvn.ClientError: # pylint: disable=E1101
+ err = sys.exc_info()[1]
+ # try to be smart about the error we got back
+ details = None
+ if "callback_ssl_server_trust_prompt" in str(err):
+ details = "SVN server certificate is not trusted"
+ elif "callback_get_login" in str(err):
+ details = "SVN credentials not cached"
+
+ if details is None:
+ self.logger.error("Svn: Failed to update server repository",
+ exc_info=1)
+ else:
+ self.logger.error("Svn: Failed to update server repository: "
+ "%s" % details)
+ return False
+
+ if old_revision == self.revision.number:
+ self.logger.debug("repository is current")
+ else:
+ self.logger.info("Updated %s from revision %s to %s" % \
+ (self.vcs_root, old_revision, self.revision.number))
+ return True
+
+ def Commit(self):
+ """Svn.Commit() => True|False\nCommit svn repository\n"""
+ # First try to update
+ if not self.Update():
+ self.logger.error("Failed to update svn repository, refusing to "
+ "commit changes")
+ return False
+
+ try:
+ self.revision = self.client.checkin([self.vcs_root],
+ 'Svn: autocommit',
+ recurse=True)
+ self.revision = self.client.update(self.vcs_root, recurse=True)[0]
+ self.logger.info("Svn: Commited changes. At %s" %
+ self.revision.number)
+ return True
+ except pysvn.ClientError: # pylint: disable=E1101
+ err = sys.exc_info()[1]
+ # try to be smart about the error we got back
+ details = None
+ if "callback_ssl_server_trust_prompt" in str(err):
+ details = "SVN server certificate is not trusted"
+ elif "callback_get_login" in str(err):
+ details = "SVN credentials not cached"
+
+ if details is None:
+ self.logger.error("Svn: Failed to commit changes",
+ exc_info=1)
+ else:
+ self.logger.error("Svn: Failed to commit changes: %s" %
+ details)
+ return False