[Pysvnmanager-svn] SF.net SVN: pysvnmanager:[42] trunk/pysvnmanager
Status: Alpha
Brought to you by:
jiangx
From: <ji...@us...> - 2008-08-25 10:22:36
|
Revision: 42 http://pysvnmanager.svn.sourceforge.net/pysvnmanager/?rev=42&view=rev Author: jiangx Date: 2008-08-25 10:22:44 +0000 (Mon, 25 Aug 2008) Log Message: ----------- add model for svn plugins management. Modified Paths: -------------- trunk/pysvnmanager/model/repos.py trunk/pysvnmanager/tests/test_repos.py Added Paths: ----------- trunk/pysvnmanager/hooks/ trunk/pysvnmanager/hooks/__init__.py trunk/pysvnmanager/hooks/init/ trunk/pysvnmanager/hooks/init/__init__.py trunk/pysvnmanager/hooks/plugins/ trunk/pysvnmanager/hooks/plugins/CaseInsensitive.py trunk/pysvnmanager/hooks/plugins/EolStyleCheck.py trunk/pysvnmanager/hooks/plugins/__init__.py trunk/pysvnmanager/model/hooks.py Added: trunk/pysvnmanager/hooks/__init__.py =================================================================== --- trunk/pysvnmanager/hooks/__init__.py (rev 0) +++ trunk/pysvnmanager/hooks/__init__.py 2008-08-25 10:22:44 UTC (rev 42) @@ -0,0 +1,4 @@ +__all__ = ["init", "plugins"] + +import init +import plugins Added: trunk/pysvnmanager/hooks/init/__init__.py =================================================================== --- trunk/pysvnmanager/hooks/init/__init__.py (rev 0) +++ trunk/pysvnmanager/hooks/init/__init__.py 2008-08-25 10:22:44 UTC (rev 42) @@ -0,0 +1,11 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os + +svn_hooks_init_dict = { '1.4': 'hook1.4', + '1.5': 'hook1.5', + 'default': 'hook1.5', + } + +svn_hooks_init_base = os.path.dirname(os.path.abspath(__file__)) Added: trunk/pysvnmanager/hooks/plugins/CaseInsensitive.py =================================================================== --- trunk/pysvnmanager/hooks/plugins/CaseInsensitive.py (rev 0) +++ trunk/pysvnmanager/hooks/plugins/CaseInsensitive.py 2008-08-25 10:22:44 UTC (rev 42) @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pysvnmanager.hooks.plugins import PluginBase + +class CaseInsensitive(PluginBase): + name = "check case insensitive" + description = "A pre-commit hook to detect case-insensitive filename clashes." + option = "case_insensitive" + value = "yes" + + def is_set(self): + return self.get_config(self.option) == self.value + + def show(self): + return self.description + + def show_form(self): + return self.description + + def delete_plugin(self): + self.del_config(self.option) + self.write() + + def set_plugin(self, form=None): + self.set_config(self.option, self.value) + self.write() + +def execute(repospath=""): + """ + Generate and return a hooks plugin object + + @param request: repos full path + @rtype: Plugin + @return: Plugin object + """ + return CaseInsensitive(repospath) \ No newline at end of file Added: trunk/pysvnmanager/hooks/plugins/EolStyleCheck.py =================================================================== --- trunk/pysvnmanager/hooks/plugins/EolStyleCheck.py (rev 0) +++ trunk/pysvnmanager/hooks/plugins/EolStyleCheck.py 2008-08-25 10:22:44 UTC (rev 42) @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pysvnmanager.hooks.plugins import PluginBase + +class EolStyleCheck(PluginBase): + name = "mime-type and eol-style check" + description = "New file must provide svn:eol-style if not binary file." + option = "check_eol_style" + value = "yes" + + def is_set(self): + return self.get_config(self.option) == self.value + + def show(self): + return self.description + + def show_form(self): + return self.description + + def delete_plugin(self): + self.del_config(self.option) + self.write() + + def set_plugin(self, form=None): + self.set_config(self.option, self.value) + self.write() + +def execute(repospath=""): + """ + Generate and return a hooks plugin object + + @param request: repos full path + @rtype: Plugin + @return: Plugin object + """ + return EolStyleCheck(repospath) \ No newline at end of file Added: trunk/pysvnmanager/hooks/plugins/__init__.py =================================================================== --- trunk/pysvnmanager/hooks/plugins/__init__.py (rev 0) +++ trunk/pysvnmanager/hooks/plugins/__init__.py 2008-08-25 10:22:44 UTC (rev 42) @@ -0,0 +1,102 @@ +# create a list of extension actions from the package directory +import ConfigParser +import os + +def getPackageModules(packagefile): + """ Return a list of modules for a package, omitting any modules + starting with an underscore. + """ + import os, re + + packagedir = os.path.dirname(packagefile) + pyre = re.compile(r"^([^_].*)\.py$") + dirlist = os.listdir(packagedir) + + matches = [pyre.match(fn) for fn in dirlist] + modules = [match.group(1) for match in matches if match] + + modules.sort() + return modules + + +def getHandler(name, function="execute"): + """ return a handler function for a given action or None """ + if function: + fromlist = [function] + else: + fromlist = [] + moduleName = 'pysvnmanager.hooks.plugins.' + name + module = __import__(moduleName, globals(), {}, fromlist) + + if function: + # module has the obj for module <moduleName> + return getattr(module, function) + else: + # module now has the toplevel module of <moduleName> (see __import__ docs!) + components = moduleName.split('.') + for comp in components[1:]: + module = getattr(module, comp) + return module + + +class PluginBase(object): + """ Base class for hook plugins + """ + name = "" + description = "" + + def __init__(self, repospath): + self.__repospath = repospath + if not os.path.exists(self.__repospath): + raise Exception, "repos '%s' not exist!" % os.path.basename(self.__repospath) + self.__configfile = "%s/conf/hooks.ini" % self.__repospath + self.cp = ConfigParser.ConfigParser() + self.__read_config() + + def __read_config(self): + if os.path.exists(self.__configfile): + self.cp.read(self.__configfile) + else: + self.cp.add_section('main') + + def write(self): + fp = open(self.__configfile, 'w') + self.cp.write(fp) + + def get_config(self, option, default="", section='main'): + if not self.cp.has_section(section): + self.cp.add_section(section) + if self.cp.has_option(section, option): + result = self.cp.get(section, option) + else: + result = default + return result + + def set_config(self, option, value="", section='main'): + if not self.cp.has_section(section): + self.cp.add_section(section) + self.cp.set(section, option, value) + + def del_config(self, option, section='main'): + if self.cp.has_section(section): + self.cp.remove_option(section, option) + if not self.cp.options(section): + self.cp.remove_section(section) + + def is_set(self): + raise Exception, "Not implement." + + def show(self): + return self.description + + def show_form(self): + return self.description + + def delete_plugin(self): + raise Exception, "Not implement." + + def set_plugin(self, form=None): + raise Exception, "Not implement." + + +modules = getPackageModules(__file__) Added: trunk/pysvnmanager/model/hooks.py =================================================================== --- trunk/pysvnmanager/model/hooks.py (rev 0) +++ trunk/pysvnmanager/model/hooks.py 2008-08-25 10:22:44 UTC (rev 42) @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Subversion repos hooks plugin. + +Basic classes used for Subversion hooks management. +""" + +import re +import sys +import os +import StringIO +import logging +log = logging.getLogger(__name__) + +from pylons import config +config_path = config["here"] + '/config' +if config_path not in sys.path: + sys.path.insert(0, config_path) +from localconfig import LocalConfig as cfg + +sys.path.insert(0,os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) +from pysvnmanager.hooks import plugins +from pysvnmanager.model import repos + +# i18n works only as pysvnmanager (a pylons app) model. +if config.get('package') and not config.has_key('unittest'): + from pylons.i18n import _ +else: + def _(message): return message + +#reload(sys) # in Python2.5, method sys.setdefaultencoding + #will be delete after initialize. we need reload it. +#sys.setdefaultencoding('utf-8') + +class Hooks: + + def __init__(self, repos_path): + self.__repos_path = os.path.abspath(repos_path) + self.__repos_root = os.path.dirname(self.__repos_path) + self.__repos_name = os.path.basename(self.__repos_path) + self.repos = repos.Repos(self.__repos_root) + assert self.repos.is_svn_repos(self.__repos_name) + + self.plugins = {} + self.pluginnames = plugins.modules + for m in self.pluginnames: + self.plugins[m] = plugins.getHandler(m)(self.__repos_path) + + def __get_applied_plugins(self): + return [m for m in self.pluginnames if self.plugins[m].is_set()] + + applied_plugins = property(__get_applied_plugins) + + def __get_unapplied_plugins(self): + return [m for m in self.pluginnames if not self.plugins[m].is_set()] + + unapplied_plugins = property(__get_unapplied_plugins) + + def __get_repos_root(self): + return self.__repos_root + + repos_root = property(__get_repos_root) + + def __get_repos_name(self): + return self.__repos_name + + repos_name = property(__get_repos_name) + + def __get_repos_path(self): + return self.__repos_path + + repos_path = property(__get_repos_path) + + + +if __name__ == '__main__': + import doctest + doctest.testmod() Modified: trunk/pysvnmanager/model/repos.py =================================================================== --- trunk/pysvnmanager/model/repos.py 2008-08-25 10:19:22 UTC (rev 41) +++ trunk/pysvnmanager/model/repos.py 2008-08-25 10:22:44 UTC (rev 42) @@ -1,9 +1,9 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -"""Subversion authz config file management. +"""Subversion repos management. -Basic classes used for Subversion authz management. +Basic classes used for Subversion repository add/remove. """ import re @@ -13,8 +13,16 @@ import logging log = logging.getLogger(__name__) +from pylons import config +config_path = config["here"] + '/config' +if config_path not in sys.path: + sys.path.insert(0, config_path) +from localconfig import LocalConfig as cfg + +sys.path.insert(0,os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) +from pysvnmanager import hooks + # i18n works only as pysvnmanager (a pylons app) model. -from pylons import config if config.get('package') and not config.has_key('unittest'): from pylons.i18n import _ else: @@ -59,8 +67,28 @@ self.hooks_init(repos_name) def hooks_init(self, repos_name): - version = self.svnversion() - repos_path = "%(root)s/%(entry)s" % { "root": self.repos_root, "entry": repos_name} + import distutils.version as dv + version = '.'.join(self.svnversion()) + matched = 'default' + for ver in sorted(hooks.init.svn_hooks_init_dict.keys(), + cmp = lambda x,y: cmp(dv.LooseVersion(x), dv.LooseVersion(y)), + reverse=True): + if dv.LooseVersion(version) >= dv.LooseVersion(ver): + matched = ver + break + + #log.debug('Hooks version matched: %s' % matched) + #log.debug('svn_hooks_init_base: %s' % hooks.init.svn_hooks_init_base) + + # copy hook-scripts from matched hooks templates directory. + src = hooks.init.svn_hooks_init_base + '/' + hooks.init.svn_hooks_init_dict[matched] + dest = "%(root)s/%(entry)s/hooks" % { "root": self.repos_root, "entry": repos_name} + + log.debug('Now copy hooks from \n\t%s to \n\t%s' % (src, dest)) + import shutil + shutil.rmtree(dest) + shutil.copytree(src, dest, symlinks=True) + def svnversion(self): cmd = 'LC_ALL=C svn --version' @@ -93,12 +121,13 @@ return False def delete(self, repos_name): - if self.is_blank_svn_repos(repos_name): - repos_path = "%(root)s/%(entry)s" % { "root": self.repos_root, "entry": repos_name} - from svn import repos as _repos - _repos.delete(repos_path) - else: - raise Exception, _("Repos %s is not a blank repository.") % repos_name + repos_path = "%(root)s/%(entry)s" % { "root": self.repos_root, "entry": repos_name} + if os.path.exists(repos_path): + if self.is_blank_svn_repos(repos_name): + from svn import repos as _repos + _repos.delete(repos_path) + else: + raise Exception, _("Repos %s is not a blank repository.") % repos_name if __name__ == '__main__': Modified: trunk/pysvnmanager/tests/test_repos.py =================================================================== --- trunk/pysvnmanager/tests/test_repos.py 2008-08-25 10:19:22 UTC (rev 41) +++ trunk/pysvnmanager/tests/test_repos.py 2008-08-25 10:22:44 UTC (rev 42) @@ -8,14 +8,17 @@ from pysvnmanager.tests import * from pysvnmanager import model from pysvnmanager.model import repos +from pysvnmanager.model import hooks +from pysvnmanager.hooks import plugins + import StringIO from pprint import pprint class TestRepos(TestController): def __init__(self, *args): - repos_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + '/svnroot' - self.repos = repos.Repos(repos_root) + self.repos_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + '/svnroot' + self.repos = repos.Repos(self.repos_root) super(TestRepos, self).__init__(*args) def setUp(self): @@ -26,27 +29,89 @@ #print '+'*40, 'teardown' pass - def testReposRoot(self): - repos.Repos('/tmp') - self.assertRaises(Exception, repos.Repos, '/tmp/svnroot.noexists') - - def testReposlist(self): - self.assert_(sorted(self.repos.repos_list) == ['repos1', 'repos2'], u','.join(self.repos.repos_list).encode('utf-8')) - def testReposCreate(self): self.assertRaises(Exception, self.repos.create, 'repos1') + self.repos.delete('repos3') self.repos.create('repos3') self.assert_(sorted(self.repos.repos_list) == ['repos1', 'repos2', 'repos3'], self.repos.repos_list) - self.repos.delete('repos3') def testReposDelete(self): self.assertRaises(Exception, self.repos.delete, 'repos1') + def testReposRoot(self): + repos.Repos('/tmp') + self.assertRaises(Exception, repos.Repos, '/tmp/svnroot.noexists') + + def testReposlist(self): + self.assert_(sorted(self.repos.repos_list) == ['repos1', 'repos2', 'repos3'], u','.join(self.repos.repos_list).encode('utf-8')) + def testSvnVersion(self): svnversion = self.repos.svnversion() self.assert_(svnversion[0]!='', svnversion[0]) self.assert_(svnversion[1]!='', svnversion[1]) + +class TestReposPlugin(TestController): + def __init__(self, *args): + self.repos_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + '/svnroot' + super(TestReposPlugin, self).__init__(*args) + + def setUp(self): + #print '+'*40, 'setup' + pass + + def tearDown(self): + #print '+'*40, 'teardown' + pass + + def testPluginList(self): + self.assert_(plugins.modules==['CaseInsensitive', 'EolStyleCheck'], plugins.modules) + + def testPluginImport(self): + self.assertRaises(Exception, plugins.getHandler("CaseInsensitive"), "") + module_ci = plugins.getHandler("CaseInsensitive")(self.repos_root + '/repos1') + self.assert_(module_ci.name=="check case insensitive", module_ci.name) + self.assert_(module_ci.description!="", module_ci.description) + + def testPluginSetting(self): + m = plugins.getHandler("CaseInsensitive")(self.repos_root + '/repos1') + self.assert_(m.is_set()==False) + m.set_plugin() + self.assert_(m.is_set()==True) + m.delete_plugin() + self.assert_(m.is_set()==False) + + def testHooks(self): + # self.repos_root is not a repository. + self.assertRaises(AssertionError, hooks.Hooks, self.repos_root) + + myhooks = hooks.Hooks(self.repos_root + '/repos1') + self.assert_(myhooks.pluginnames==['CaseInsensitive', 'EolStyleCheck'], myhooks.pluginnames) + self.assert_(myhooks.unapplied_plugins==['CaseInsensitive', 'EolStyleCheck'], myhooks.unapplied_plugins) + + m = myhooks.plugins['CaseInsensitive'] + self.assert_(m.name=="check case insensitive", m.name) + self.assert_(m.description!="", m.description) + + def testHooksSetting(self): + myhooks = hooks.Hooks(self.repos_root + '/repos1') + + m = myhooks.plugins['CaseInsensitive'] + self.assert_(m.is_set()==False) + self.assert_(myhooks.applied_plugins==[], myhooks.applied_plugins) + self.assert_(myhooks.unapplied_plugins==['CaseInsensitive', 'EolStyleCheck'], myhooks.unapplied_plugins) + + m.set_plugin() + self.assert_(m.is_set()==True) + self.assert_(myhooks.applied_plugins==['CaseInsensitive'], myhooks.applied_plugins) + self.assert_(myhooks.unapplied_plugins==['EolStyleCheck'], myhooks.unapplied_plugins) + + m.delete_plugin() + self.assert_(m.is_set()==False) + self.assert_(myhooks.applied_plugins==[], myhooks.applied_plugins) + self.assert_(myhooks.unapplied_plugins==['CaseInsensitive', 'EolStyleCheck'], myhooks.unapplied_plugins) + + if __name__ == '__main__': import unittest unittest.main() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |