Mercurial > hgweb.cgi > hwm
changeset 65:d20e6d543ee8
Fixed displayed PEP 8 warnings.
author | John Schneiderman |
---|---|
date | Fri, 19 Feb 2016 18:45:37 +0100 |
parents | 4f295ab3a0b7 |
children | 28249d6ea0ef |
files | HgWebManager.kdev4 INSTALL MANIFEST.in README data/ignores.xml doc/CREDITS doc/ChangeLog doc/TODO setup.cfg setup.py src/__init__.py src/_app_info.py src/config.py src/enum.py src/hwm.py src/ignorepo.py src/manager.py src/manrepo.py src/manrepolock.py |
diffstat | 19 files changed, 1413 insertions(+), 1274 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HgWebManager.kdev4 Fri Feb 19 18:45:37 2016 +0100 @@ -0,0 +1,3 @@ +[Project] +Manager=KDevGenericManager +Name=HgWebManager
--- a/INSTALL Tue Apr 07 20:03:21 2015 +0200 +++ b/INSTALL Fri Feb 19 18:45:37 2016 +0100 @@ -1,7 +1,7 @@ ******************************************************************************** *** This file is part of HgWeb Manager. *** *** *** -*** Copyright (C) 2014 - 2015 *** +*** Copyright (C) 2014 - 2016 *** *** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** *** *** *** This program is free software: you can redistribute it and/or modify it ***
--- a/MANIFEST.in Tue Apr 07 20:03:21 2015 +0200 +++ b/MANIFEST.in Fri Feb 19 18:45:37 2016 +0100 @@ -1,7 +1,7 @@ #******************************************************************************* #** This file is part of HgWeb Manager. *** #** *** -#** Copyright (C) 2014 - 2015 *** +#** Copyright (C) 2014 - 2016 *** #** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** #** *** #** This program is free software: you can redistribute it and/or modify it ***
--- a/README Tue Apr 07 20:03:21 2015 +0200 +++ b/README Fri Feb 19 18:45:37 2016 +0100 @@ -1,7 +1,7 @@ ******************************************************************************** *** This file is part of HgWeb Manager. *** *** *** -*** Copyright (C) 2014 - 2015 *** +*** Copyright (C) 2014 - 2016 *** *** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** *** *** *** This program is free software: you can redistribute it and/or modify it *** @@ -27,7 +27,7 @@ Development website: http://www.codegnu.org BUILD ENVIRONMENT -HgWebManager is developed on Mageia 4 using just the standard development +HgWebManager is developed on Mageia 5 using just the standard development libraries, mercurial, and python. In addition, testing on Microsoft Windows Server 2008.
--- a/data/ignores.xml Tue Apr 07 20:03:21 2015 +0200 +++ b/data/ignores.xml Fri Feb 19 18:45:37 2016 +0100 @@ -2,7 +2,7 @@ <!--**************************************************************************** *** This file is part of HgWeb Manager. *** *** *** -*** Copyright (C) 2014 - 2015 *** +*** Copyright (C) 2014 - 2016 *** *** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** *** *** *** This program is free software: you can redistribute it and/or modify it ***
--- a/doc/CREDITS Tue Apr 07 20:03:21 2015 +0200 +++ b/doc/CREDITS Fri Feb 19 18:45:37 2016 +0100 @@ -1,7 +1,7 @@ ******************************************************************************** *** This file is part of HgWeb Manager. *** *** *** -*** Copyright (C) 2014 - 2015 *** +*** Copyright (C) 2014 - 2016 *** *** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** *** *** *** This program is free software: you can redistribute it and/or modify it ***
--- a/doc/ChangeLog Tue Apr 07 20:03:21 2015 +0200 +++ b/doc/ChangeLog Fri Feb 19 18:45:37 2016 +0100 @@ -1,7 +1,7 @@ ******************************************************************************** *** This file is part of HgWeb Manager. *** *** *** -*** Copyright (C) 2014 - 2015 *** +*** Copyright (C) 2014 - 2016 *** *** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** *** *** *** This program is free software: you can redistribute it and/or modify it *** @@ -17,8 +17,9 @@ *** You should have received a copy of the GNU Affero General Public License*** *** along with this program. If not, see <http://www.gnu.org/licenses/>. *** ******************************************************************************** -2015-XX-XX John Schneiderman <Licensing _AT_ CodeGNU _DOT_ com> 0.5.0 +2016-XX-XX John Schneiderman <Licensing _AT_ CodeGNU _DOT_ com> 0.5.0 - Split configuration file into logical sections. +- Brought into PEP 8 compliance. 2015-03-28 John Schneiderman <Licensing _AT_ CodeGNU _DOT_ com> 0.4.0 - Ability to add a plug-in to a managed repository. - Ability to remove a plug-in from a managed repository.
--- a/doc/TODO Tue Apr 07 20:03:21 2015 +0200 +++ b/doc/TODO Fri Feb 19 18:45:37 2016 +0100 @@ -1,7 +1,7 @@ ******************************************************************************** *** This file is part of HgWeb Manager. *** *** *** -*** Copyright (C) 2014 - 2015 *** +*** Copyright (C) 2014 - 2016 *** *** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** *** *** *** This program is free software: you can redistribute it and/or modify it *** @@ -29,9 +29,6 @@ *** *** - Installation tutorial. - User tutorials. -- Manager functions should take both an output and error device instead of defaulting to std. -- Manager should handle the HgWeb configuration file settings. - * Create a separate manager for the HgWeb configuration file. - Manager should provide a REST API for repository management. - Manager should have an API key per user permission values. -- Prevent a push that would create multiple heads +- Add support for integrating with Mercurial-Server, http://www.lshift.net/work/open-source/mercurial-server/
--- a/setup.cfg Tue Apr 07 20:03:21 2015 +0200 +++ b/setup.cfg Fri Feb 19 18:45:37 2016 +0100 @@ -2,7 +2,7 @@ #******************************************************************************* #** This file is part of HgWeb Manager. *** #** *** -#** Copyright (C) 2014 - 2015 *** +#** Copyright (C) 2014 - 2016 *** #** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** #** *** #** This program is free software: you can redistribute it and/or modify it ***
--- a/setup.py Tue Apr 07 20:03:21 2015 +0200 +++ b/setup.py Fri Feb 19 18:45:37 2016 +0100 @@ -1,24 +1,25 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -'''***************************************************************************** -*** This file is part of HgWeb Manager. *** -*** *** -*** Copyright (C) 2014 - 2015 *** -*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** -*** *** -*** This program is free software: you can redistribute it and/or modify it *** -*** under the terms of the GNU Affero General Public License as published *** -*** by the Free Software Foundation, either version 3 of the License, or *** -*** (at your option) any later version. *** -*** *** -*** This program is distributed in the hope that it will be useful, but *** -*** WITHOUT ANY WARRANTY; without even the implied warranty of *** -*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** -*** See the GNU Affero General Public License for more details. *** -*** *** -*** You should have received a copy of the GNU Affero General Public License*** -*** along with this program. If not, see <http://www.gnu.org/licenses/>. *** -*****************************************************************************''' +'''**************************************************************************** +*** This file is part of HgWeb Manager. *** +*** *** +*** Copyright (C) 2014 - 2016 *** +*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** +*** *** +*** This program is free software: you can redistribute it and/or modify *** +*** it under the terms of the GNU Affero General Public License as *** +*** published by the Free Software Foundation, either version 3 of the *** +*** License, or (at your option) any later version. *** +*** *** +*** This program is distributed in the hope that it will be useful, but *** +*** WITHOUT ANY WARRANTY; without even the implied warranty of *** +*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** +*** See the GNU Affero General Public License for more details. *** +*** *** +*** You should have received a copy of the GNU Affero General Public *** +*** License along with this program. If not, *** +*** see <http://www.gnu.org/licenses/>. *** +****************************************************************************''' from distutils.core import setup @@ -28,58 +29,59 @@ from _app_info import VERSION, DESCRIPTION, LONG_DESCRIPTION, SHORT_NAME required = \ - [ - 'mercurial', - 'mercurial.hg', - 'mercurial.ui', - 'mercurial.error', - 'mercurial.hgweb' - ] + [ + 'mercurial', + 'mercurial.hg', + 'mercurial.ui', + 'mercurial.error', + 'mercurial.hgweb' + ] # Basic package setup information setup( - name=SHORT_NAME, - version=VERSION, - description=DESCRIPTION, - long_description=LONG_DESCRIPTION, - author='CodeGNU Solutions', - author_email='Licensing@CodeGNU.com', - url='http://www.codegnu.com', - download_url="http://www.codegnu.com/files/hwm-{0}.tar.gz".format(VERSION), - license='AGPLv3+', - packages=['HgWebManager'], - package_dir={'HgWebManager': 'src'}, - provides=['HgWebManager'], - requires=required, - platforms=[ - 'GNU/Linux', - 'POSIX', - 'Mac OS', - 'Windows' - ], - classifiers=[ - 'Development Status :: 3 - Alpha', - 'Environment :: Console', - 'Environment :: Web Environment', - 'Intended Audience :: Developers', - 'Intended Audience :: System Administrators', - 'Intended Audience :: Information Technology', - 'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)', - 'Natural Language :: English', - 'Operating System :: MacOS', - 'Operating System :: Microsoft :: Windows', - 'Operating System :: POSIX :: Linux', - 'Programming Language :: Python :: 2.7', - 'Topic :: Internet :: WWW/HTTP :: Site Management', - 'Topic :: Software Development :: Version Control', - 'Topic :: System :: Systems Administration' - ], - data_files=[ - ( - "share/" + SHORT_NAME, - [ - 'ignores.xml' - ] - ), - ], + name=SHORT_NAME, + version=VERSION, + description=DESCRIPTION, + long_description=LONG_DESCRIPTION, + author='CodeGNU Solutions', + author_email='Licensing@CodeGNU.com', + url='http://www.codegnu.com', + download_url="http://www.codegnu.com/files/hwm-{0}.tar.gz".format(VERSION), + license='AGPLv3+', + packages=['HgWebManager'], + package_dir={'HgWebManager': 'src'}, + provides=['HgWebManager'], + requires=required, + platforms=[ + 'GNU/Linux', + 'POSIX', + 'Mac OS', + 'Windows' + ], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Console', + 'Environment :: Web Environment', + 'Intended Audience :: Developers', + 'Intended Audience :: System Administrators', + 'Intended Audience :: Information Technology', + 'License :: OSI Approved :: GNU Affero General Public License ' + 'v3 or later (AGPLv3+)', + 'Natural Language :: English', + 'Operating System :: MacOS', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 2.7', + 'Topic :: Internet :: WWW/HTTP :: Site Management', + 'Topic :: Software Development :: Version Control', + 'Topic :: System :: Systems Administration' + ], + data_files=[ + ( + "share/" + SHORT_NAME, + [ + 'ignores.xml' + ] + ), + ], )
--- a/src/__init__.py Tue Apr 07 20:03:21 2015 +0200 +++ b/src/__init__.py Fri Feb 19 18:45:37 2016 +0100 @@ -1,20 +1,21 @@ # -*- coding: utf-8 -*- -'''***************************************************************************** -*** This file is part of HgWeb Manager. *** -*** *** -*** Copyright (C) 2014 - 2015 *** -*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** -*** *** -*** This program is free software: you can redistribute it and/or modify it *** -*** under the terms of the GNU Affero General Public License as published *** -*** by the Free Software Foundation, either version 3 of the License, or *** -*** (at your option) any later version. *** -*** *** -*** This program is distributed in the hope that it will be useful, but *** -*** WITHOUT ANY WARRANTY; without even the implied warranty of *** -*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** -*** See the GNU Affero General Public License for more details. *** -*** *** -*** You should have received a copy of the GNU Affero General Public License*** -*** along with this program. If not, see <http://www.gnu.org/licenses/>. *** -*****************************************************************************''' +'''**************************************************************************** +*** This file is part of HgWeb Manager. *** +*** *** +*** Copyright (C) 2014 - 2016 *** +*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** +*** *** +*** This program is free software: you can redistribute it and/or modify *** +*** it under the terms of the GNU Affero General Public License as *** +*** published by the Free Software Foundation, either version 3 of the *** +*** License, or (at your option) any later version. *** +*** *** +*** This program is distributed in the hope that it will be useful, but *** +*** WITHOUT ANY WARRANTY; without even the implied warranty of *** +*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** +*** See the GNU Affero General Public License for more details. *** +*** *** +*** You should have received a copy of the GNU Affero General Public *** +*** License along with this program. If not, *** +*** see <http://www.gnu.org/licenses/>. *** +****************************************************************************'''
--- a/src/_app_info.py Tue Apr 07 20:03:21 2015 +0200 +++ b/src/_app_info.py Fri Feb 19 18:45:37 2016 +0100 @@ -1,23 +1,24 @@ # -*- coding: utf-8 -*- -'''***************************************************************************** -*** This file is part of HgWeb Manager. *** -*** *** -*** Copyright (C) 2014 - 2015 *** -*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** -*** *** -*** This program is free software: you can redistribute it and/or modify it *** -*** under the terms of the GNU Affero General Public License as published *** -*** by the Free Software Foundation, either version 3 of the License, or *** -*** (at your option) any later version. *** -*** *** -*** This program is distributed in the hope that it will be useful, but *** -*** WITHOUT ANY WARRANTY; without even the implied warranty of *** -*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** -*** See the GNU Affero General Public License for more details. *** -*** *** -*** You should have received a copy of the GNU Affero General Public License*** -*** along with this program. If not, see <http://www.gnu.org/licenses/>. *** -*****************************************************************************''' +'''**************************************************************************** +*** This file is part of HgWeb Manager. *** +*** *** +*** Copyright (C) 2014 - 2016 *** +*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** +*** *** +*** This program is free software: you can redistribute it and/or modify *** +*** it under the terms of the GNU Affero General Public License as *** +*** published by the Free Software Foundation, either version 3 of the *** +*** License, or (at your option) any later version. *** +*** *** +*** This program is distributed in the hope that it will be useful, but *** +*** WITHOUT ANY WARRANTY; without even the implied warranty of *** +*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** +*** See the GNU Affero General Public License for more details. *** +*** *** +*** You should have received a copy of the GNU Affero General Public *** +*** License along with this program. If not, *** +*** see <http://www.gnu.org/licenses/>. *** +****************************************************************************''' # The shortened name of the application @@ -27,13 +28,14 @@ LONG_NAME = 'HgWeb Manager' # The current version of the application -VERSION = '0.4.0' +VERSION = '0.5.0' # The current copyright years. -YEARS = '2014 - 2015' +YEARS = '2014 - 2016' # A short description of the application DESCRIPTION = 'Manages HgWeb Repositories' # A long description of the application -LONG_DESCRIPTION = 'An application to simplify the management of repositories shared through the Mercurial web publishing method.' +LONG_DESCRIPTION = 'An application to simplify the management of ' \ + 'repositories shared through the Mercurial web publishing method.'
--- a/src/config.py Tue Apr 07 20:03:21 2015 +0200 +++ b/src/config.py Fri Feb 19 18:45:37 2016 +0100 @@ -1,116 +1,121 @@ # -*- coding: utf-8 -*- -'''***************************************************************************** -*** This file is part of HgWeb Manager. *** -*** *** -*** Copyright (C) 2014 - 2015 *** -*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** -*** *** -*** This program is free software: you can redistribute it and/or modify it *** -*** under the terms of the GNU Affero General Public License as published *** -*** by the Free Software Foundation, either version 3 of the License, or *** -*** (at your option) any later version. *** -*** *** -*** This program is distributed in the hope that it will be useful, but *** -*** WITHOUT ANY WARRANTY; without even the implied warranty of *** -*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** -*** See the GNU Affero General Public License for more details. *** -*** *** -*** You should have received a copy of the GNU Affero General Public License*** -*** along with this program. If not, see <http://www.gnu.org/licenses/>. *** -*****************************************************************************''' +'''**************************************************************************** +*** This file is part of HgWeb Manager. *** +*** *** +*** Copyright (C) 2014 - 2016 *** +*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** +*** *** +*** This program is free software: you can redistribute it and/or modify *** +*** it under the terms of the GNU Affero General Public License as *** +*** published by the Free Software Foundation, either version 3 of the *** +*** License, or (at your option) any later version. *** +*** *** +*** This program is distributed in the hope that it will be useful, but *** +*** WITHOUT ANY WARRANTY; without even the implied warranty of *** +*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** +*** See the GNU Affero General Public License for more details. *** +*** *** +*** You should have received a copy of the GNU Affero General Public *** +*** License along with this program. If not, *** +*** see <http://www.gnu.org/licenses/>. *** +****************************************************************************''' class Manager(object): - """ Manages the configurations for HgWebManager """ + """ Manages the configurations for HgWebManager """ - # The configuration file parser. - __parser = None + # The configuration file parser. + __parser = None - # The absolute directory path and file name of the hg command. - __hgCommand = None + # The absolute directory path and file name of the hg command. + __hgCommand = None - @property - def HgCommand(self): - """ Gets the command for executing mercurial. """ - return self.__hgCommand + @property + def HgCommand(self): + """ Gets the command for executing mercurial. """ + return self.__hgCommand + + # The absolute directory path to the managed HgWeb repositories. + __repositoryPath = None - # The absolute directory path to the managed HgWeb repositories. - __repositoryPath = None + @property + def RepositoryPath(self): + """ Gets the directory path to the managed repositories. """ + return self.__repositoryPath - @property - def RepositoryPath(self): - """ Gets the directory path to the managed repositories. """ - return self.__repositoryPath + # The absolute directory path to the HgWeb web-server site. + __hgWebPath = None - # The absolute directory path to the HgWeb web-server site. - __hgWebPath = None + @property + def HgWebPath(self): + """ Gets the directory path to the repository web-server site. """ + return self.__hgWebPath - @property - def HgWebPath(self): - """ Gets the directory path to the repository web-server site. """ - return self.__hgWebPath - - # The directory path for HWM data. - __dataPath = None + # The directory path for HWM data. + __dataPath = None - @property - def DataPath(self): - """ Gets the directory path to the HWM data directory. """ - return self.__dataPath + @property + def DataPath(self): + """ Gets the directory path to the HWM data directory. """ + return self.__dataPath + + # The user-name of the Mercurial web-manager. + __hgUser = None - # The user-name of the Mercurial web-manager. - __hgUser = None + @property + def HgUser(self): + """ Gets the user-name of the web-manager. """ + return self.__hgUser - @property - def HgUser(self): - """ Gets the user-name of the web-manager. """ - return self.__hgUser + def __init__(self, path=['/etc/hwm.ini', '~/.hwm/hwm.ini', './hwm.ini']): + """ Loads the settings values stored in the configuration file. - def __init__(self, path=['/etc/hwm.ini', '~/.hwm/hwm.ini', './hwm.ini']): - """ Loads the settings values stored in the configuration file. - - @param[in] path The path and file name of the configuration file. + @param[in] path The path and file name of the configuration file. - @throws ValueError When the configuration file cannot be found. - @throw RuntimeError When the configuration file is missing required - entries. - """ - from ConfigParser import SafeConfigParser + @throws ValueError When the configuration file cannot be found. + @throw RuntimeError When the configuration file is missing + required entries. + """ + from ConfigParser import SafeConfigParser - self.__parser = SafeConfigParser() - if not self.__parser.read(path): - raise ValueError("Failed to find configuration file.") + self.__parser = SafeConfigParser() + if not self.__parser.read(path): + raise ValueError("Failed to find configuration file.") - if self.__parser.has_section('Mercurial'): - if self.__parser.has_option('Mercurial', 'Command'): - self.__hgCommand = self.__parser.get('Mercurial', 'Command') - else: - self.__hgCommand = '/usr/bin/hg' - else: - self.__hgCommand = '/usr/bin/hg' + if self.__parser.has_section('Mercurial'): + if self.__parser.has_option('Mercurial', 'Command'): + self.__hgCommand = self.__parser.get('Mercurial', 'Command') + else: + self.__hgCommand = '/usr/bin/hg' + else: + self.__hgCommand = '/usr/bin/hg' - if self.__parser.has_section('HgWeb'): - if self.__parser.has_option('HgWeb', 'Base'): - self.__repositoryPath = self.__parser.get('HgWeb', 'Base') - else: - raise RuntimeError('Failed to locate the HgWeb-Base entry') + if self.__parser.has_section('HgWeb'): + if self.__parser.has_option('HgWeb', 'Base'): + self.__repositoryPath = self.__parser.get('HgWeb', 'Base') + else: + raise RuntimeError('Failed to locate the HgWeb-Base entry') - if self.__parser.has_option('HgWeb', 'Server'): - self.__hgWebPath = self.__parser.get('HgWeb', 'Server') - else: - raise RuntimeError('Failed to locate the HgWeb-Server entry') - else: - raise RuntimeError('Failed to locate the HgWeb configuration section') + if self.__parser.has_option('HgWeb', 'Server'): + self.__hgWebPath = self.__parser.get('HgWeb', 'Server') + else: + raise RuntimeError('Failed to locate the HgWeb-Server entry') + else: + raise RuntimeError( + 'Failed to locate the HgWeb configuration section' + ) - if self.__parser.has_section('HWM'): - if self.__parser.has_option('HWM', 'Data'): - self.__dataPath = self.__parser.get('HWM', 'Data') - else: - self.__dataPath = '/usr/share/hwm' + if self.__parser.has_section('HWM'): + if self.__parser.has_option('HWM', 'Data'): + self.__dataPath = self.__parser.get('HWM', 'Data') + else: + self.__dataPath = '/usr/share/hwm' - if self.__parser.has_option('HWM', 'Manager'): - self.__hgUser = self.__parser.get('HWM', 'Manager') - else: - raise RuntimeError('Failed to locate the HWM-Manager entry') - else: - raise RuntimeError('Failed to locate the HWM configuration section') + if self.__parser.has_option('HWM', 'Manager'): + self.__hgUser = self.__parser.get('HWM', 'Manager') + else: + raise RuntimeError('Failed to locate the HWM-Manager entry') + else: + raise RuntimeError( + 'Failed to locate the HWM configuration section' + )
--- a/src/enum.py Tue Apr 07 20:03:21 2015 +0200 +++ b/src/enum.py Fri Feb 19 18:45:37 2016 +0100 @@ -1,34 +1,35 @@ # -*- coding: utf-8 -*- -'''***************************************************************************** -*** This file is part of HgWeb Manager. *** -*** *** -*** Copyright (C) 2014 - 2015 *** -*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** -*** *** -*** This program is free software: you can redistribute it and/or modify it *** -*** under the terms of the GNU Affero General Public License as published *** -*** by the Free Software Foundation, either version 3 of the License, or *** -*** (at your option) any later version. *** -*** *** -*** This program is distributed in the hope that it will be useful, but *** -*** WITHOUT ANY WARRANTY; without even the implied warranty of *** -*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** -*** See the GNU Affero General Public License for more details. *** -*** *** -*** You should have received a copy of the GNU Affero General Public License*** -*** along with this program. If not, see <http://www.gnu.org/licenses/>. *** -*****************************************************************************''' +'''**************************************************************************** +*** This file is part of HgWeb Manager. *** +*** *** +*** Copyright (C) 2014 - 2016 *** +*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** +*** *** +*** This program is free software: you can redistribute it and/or modify *** +*** it under the terms of the GNU Affero General Public License as *** +*** published by the Free Software Foundation, either version 3 of the *** +*** License, or (at your option) any later version. *** +*** *** +*** This program is distributed in the hope that it will be useful, but *** +*** WITHOUT ANY WARRANTY; without even the implied warranty of *** +*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** +*** See the GNU Affero General Public License for more details. *** +*** *** +*** You should have received a copy of the GNU Affero General Public *** +*** License along with this program. If not, *** +*** see <http://www.gnu.org/licenses/>. *** +****************************************************************************''' def create(*sequential, **named): - """ Creates a type which mimics the behaviour of an enumeration. + """ Creates a type which mimics the behaviour of an enumeration. - @param[in] sequential - @param[in] named + @param[in] sequential + @param[in] named - @return An object which contains the supplied enumerated values. - """ - enums = dict(zip(sequential, range(len(sequential))), **named) - reverse = dict((value, key) for key, value in enums.iteritems()) - enums['reverse_mapping'] = reverse - return type('Enum', (), enums) + @return An object which contains the supplied enumerated values. + """ + enums = dict(zip(sequential, range(len(sequential))), **named) + reverse = dict((value, key) for key, value in enums.iteritems()) + enums['reverse_mapping'] = reverse + return type('Enum', (), enums)
--- a/src/hwm.py Tue Apr 07 20:03:21 2015 +0200 +++ b/src/hwm.py Fri Feb 19 18:45:37 2016 +0100 @@ -1,160 +1,201 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -'''***************************************************************************** -*** This file is part of HgWeb Manager. *** -*** *** -*** Copyright (C) 2014 - 2015 *** -*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** -*** *** -*** This program is free software: you can redistribute it and/or modify it *** -*** under the terms of the GNU Affero General Public License as published *** -*** by the Free Software Foundation, either version 3 of the License, or *** -*** (at your option) any later version. *** -*** *** -*** This program is distributed in the hope that it will be useful, but *** -*** WITHOUT ANY WARRANTY; without even the implied warranty of *** -*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** -*** See the GNU Affero General Public License for more details. *** -*** *** -*** You should have received a copy of the GNU Affero General Public License*** -*** along with this program. If not, see <http://www.gnu.org/licenses/>. *** -*****************************************************************************''' +'''**************************************************************************** +*** This file is part of HgWeb Manager. *** +*** *** +*** Copyright (C) 2014 - 2016 *** +*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** +*** *** +*** This program is free software: you can redistribute it and/or modify *** +*** it under the terms of the GNU Affero General Public License as *** +*** published by the Free Software Foundation, either version 3 of the *** +*** License, or (at your option) any later version. *** +*** *** +*** This program is distributed in the hope that it will be useful, but *** +*** WITHOUT ANY WARRANTY; without even the implied warranty of *** +*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** +*** See the GNU Affero General Public License for more details. *** +*** *** +*** You should have received a copy of the GNU Affero General Public *** +*** License along with this program. If not, *** +*** see <http://www.gnu.org/licenses/>. *** +****************************************************************************''' def is_hgWeb_user(expectedHgUser): - """ Determines if the current running user is the expected HgWeb user. + """ Determines if the current running user is the expected HgWeb user. - @param[in] str expectedHgUser The expected user-name for the Mercurial - web-manager. + @param[in] str expectedHgUser The expected user-name for the Mercurial + web-manager. - @return Gives true when the user is the expected HgWeb user, false - else-wise. - """ - import getpass + @return Gives true when the user is the expected HgWeb user, false + else-wise. + """ + import getpass - # FIXME: This isn't a secure check as it is based upon the environmental variable. - if expectedHgUser == getpass.getuser(): - return True - else: - return False + # FIXME: This isn't a secure check as it is based upon the + # environmental variable. + if expectedHgUser == getpass.getuser(): + return True + else: + return False def __extract_values(args): - """ Pulls the creation arguments out of the command-line. The returned - object is filled with the repository details when it exists and any of the - detail values supplied on the command-line will replace the one found in - the repository details. + """ Pulls the creation arguments out of the command-line. The returned + object is filled with the repository details when it exists and any of the + detail values supplied on the command-line will replace the one found in + the repository details. - @param[in] args The command-line argument processor containing the - creation argument values. + @param[in] args The command-line argument processor containing the + creation argument values. - @return A managed repository object. - """ - import manrepo + @return A managed repository object. + """ + import manrepo - managed = None - if args.rename: - original = manrepo.Repository(args.storage) - managed = manrepo.Repository(args.rename) - managed.DisplayName = original.DisplayName - managed.Description = original.Description - managed.Contact = original.Contact - elif args.storage: - managed = manrepo.Repository(args.storage) - else: - raise ValueError("Missing repository storage name.") + managed = None + if args.rename: + original = manrepo.Repository(args.storage) + managed = manrepo.Repository(args.rename) + managed.DisplayName = original.DisplayName + managed.Description = original.Description + managed.Contact = original.Contact + elif args.storage: + managed = manrepo.Repository(args.storage) + else: + raise ValueError("Missing repository storage name.") - if args.name: - managed.DisplayName = args.name + if args.name: + managed.DisplayName = args.name - if args.description: - managed.Description = args.description + if args.description: + managed.Description = args.description - if args.contact: - managed.Contact = args.contact + if args.contact: + managed.Contact = args.contact - return managed + return managed if __name__ == '__main__': - import _app_info - import sys + import _app_info + import sys - try: - # Display license - print "%s %s Copyright (C) %s CodeGNU Solutions" % \ - (_app_info.LONG_NAME, _app_info.VERSION, _app_info.YEARS) - print "%s comes with ABSOLUTELY NO WARRANTY;" % (_app_info.SHORT_NAME) - print 'This is free software, and you are welcome to redistribute it' - print 'under certain conditions; see the LICENSE file for details,' - print 'or the Free Software Foundation\'s AGPL.\n' + try: + # Display license + print "%s %s Copyright (C) %s CodeGNU Solutions" % \ + (_app_info.LONG_NAME, _app_info.VERSION, _app_info.YEARS) + print "%s comes with ABSOLUTELY NO WARRANTY;" % (_app_info.SHORT_NAME) + print 'This is free software, and you are welcome to redistribute it' + print 'under certain conditions; see the LICENSE file for details,' + print 'or the Free Software Foundation\'s AGPL.\n' - from manager import settings - import argparse - import manager + from manager import settings + import argparse + import manager - if not is_hgWeb_user(settings.HgUser): - print >>sys.stderr, 'Must execute as the Mercurial Web manager.' - exit(1) + if not is_hgWeb_user(settings.HgUser): + print >>sys.stderr, 'Must execute as the Mercurial Web manager.' + exit(1) - parser = argparse.ArgumentParser(description=_app_info.DESCRIPTION) - parser.add_argument('-l', '--list', action='store_true', help='Outputs a list of all the managed repositories.') - - plgInGrp = parser.add_argument_group('Manage Plug-Ins', 'Options that operate upon a managed repository\'s plug-ins.') - plgInGrp.add_argument('-p', '--plugin', action='store', nargs=1, type=str, default=None, help='The name of a plug-in for a repository.') - plgInGrp.add_argument('-e', '--enable', action='store_true', help='Enable a plug-in in a repository.') - plgInGrp.add_argument('-f', '--script-path', action='store', nargs='?', type=str, default=None, help='The path to the plug-in script.') - plgInGrp.add_argument('-x', '--disable', action='store_true', help='Disable a plug-in in a repository.') - plgInGrp.add_argument('-s', '--setting', action='store', nargs=2, type=str, default=None, help='Sets a setting name/value pair for a plug-in.') + parser = argparse.ArgumentParser(description=_app_info.DESCRIPTION) + parser.add_argument('-l', '--list', action='store_true', + help='Outputs a list of all the managed ' + 'repositories.') - manGrp = parser.add_argument_group('Manage Repositories', 'Options that operate upon managed repositories.') - manGrp.add_argument('storage', action='store', nargs='?', help='The storage-name of the repository to perform an action upon.') - manGrp.add_argument('-a', '--action', action='store', nargs=1, type=str, choices=['c', 'create', 'm', 'modify', 'd', 'delete', 'r', 'register'], help='Performs an action upon a managed repository.') - manGrp.add_argument('-i', '--ignore', action='store', nargs='+', default=None, help='The groups to place in an ignore file.') - manGrp.add_argument('-k', '--skip-common', action='store_true', help='The common ignore group is not added by default.') - manGrp.add_argument('-n', '--name', action='store', nargs='?', default=None, help='The display name of the repository.') - manGrp.add_argument('-d', '--description', action='store', nargs='?', default=None, help='The description of the repository.') - manGrp.add_argument('-c', '--contact', action='store', nargs='?', default=None, help='The contact point of a repository.') - manGrp.add_argument('-r', '--rename', action='store', nargs='?', default=None, help='The new storage-name for a repository.') + plgInGrp = parser.add_argument_group('Manage Plug-Ins', + 'Options that operate upon a ' + 'managed repository\'s plug-ins.') + plgInGrp.add_argument('-p', '--plugin', action='store', nargs=1, + type=str, default=None, + help='The name of a plug-in for a repository.') + plgInGrp.add_argument('-e', '--enable', action='store_true', + help='Enable a plug-in in a repository.') + plgInGrp.add_argument('-f', '--script-path', action='store', nargs='?', + type=str, default=None, + help='The path to the plug-in script.') + plgInGrp.add_argument('-x', '--disable', action='store_true', + help='Disable a plug-in in a repository.') + plgInGrp.add_argument('-s', '--setting', action='store', nargs=2, + type=str, default=None, + help='Sets a setting name/value pair ' + 'for a plug-in.') - # Examine the supplied arguments and perform requested actions. - args = parser.parse_args() - repo = __extract_values(args) + manGrp = parser.add_argument_group('Manage Repositories', + 'Options that operate upon ' + 'managed repositories.') + manGrp.add_argument('storage', action='store', nargs='?', + help='The storage-name of the repository to ' + 'perform an action upon.') + manGrp.add_argument('-a', '--action', action='store', nargs=1, + type=str, choices=['c', 'create', 'm', 'modify', + 'd', 'delete', 'r', 'register'], + help='Performs an action upon a managed ' + 'repository.') + manGrp.add_argument('-i', '--ignore', action='store', nargs='+', + default=None, + help='The groups to place in an ignore file.') + manGrp.add_argument('-k', '--skip-common', action='store_true', + help='The common ignore group is not added ' + 'by default.') + manGrp.add_argument('-n', '--name', action='store', nargs='?', + default=None, + help='The display name of the repository.') + manGrp.add_argument('-d', '--description', action='store', nargs='?', + default=None, + help='The description of the repository.') + manGrp.add_argument('-c', '--contact', action='store', nargs='?', + default=None, + help='The contact point of a repository.') + manGrp.add_argument('-r', '--rename', action='store', nargs='?', + default=None, + help='The new storage-name for a repository.') + + # Examine the supplied arguments and perform requested actions. + args = parser.parse_args() + repo = __extract_values(args) - if args.list: - manager.list() - elif args.plugin is not None: - if args.enable: - manager.plugInEnable(repo, args.plugin[0], args.script_path) - elif args.disable: - manager.plugInDisable(repo, args.plugin[0]) - elif args.setting is not None: - if len(args.setting[1]) > 0: - manager.setPlugInSetting(repo, args.plugin[0], args.setting[0], args.setting[1]) - else: - manager.setPlugInSetting(repo, args.plugin[0], args.setting[0], None) - else: - print >>sys.stderr, "Failure determine requested plug-in '%s' option." % args.plugin[0] - exit(1) - elif args.action is None: - print >>sys.stderr, "No repository operation argument supplied." - exit(1) - elif ('create' == args.action[0]) or ('c' == args.action[0]): - manager.create(repo, args.ignore, args.skip_common) - elif ('modify' == args.action[0]) or ('m' == args.action[0]): - manager.modify(repo, args.storage, args.ignore, args.skip_common) - elif ('delete' == args.action[0]) or ('d' == args.action[0]): - manager.delete(repo) - elif ('register' == args.action[0]) or ('r' == args.action[0]): - manager.register(repo) - else: - print >>sys.stderr, "Unknown repository action supplied '%s'." % args.action[0] - exit(1) - exit(0) - except (ValueError, RuntimeError) as error: - print >>sys.stderr, "Execution Failed: %s" % error - exit(2) - except Exception as error: - import traceback + if args.list: + manager.list() + elif args.plugin is not None: + if args.enable: + manager.plugInEnable(repo, args.plugin[0], args.script_path) + elif args.disable: + manager.plugInDisable(repo, args.plugin[0]) + elif args.setting is not None: + if len(args.setting[1]) > 0: + manager.setPlugInSetting(repo, args.plugin[0], + args.setting[0], args.setting[1]) + else: + manager.setPlugInSetting(repo, args.plugin[0], + args.setting[0], None) + else: + print >>sys.stderr, \ + "Failure determine requested plug-in '%s' option." % \ + args.plugin[0] + exit(1) + elif args.action is None: + print >>sys.stderr, "No repository operation argument supplied." + exit(1) + elif ('create' == args.action[0]) or ('c' == args.action[0]): + manager.create(repo, args.ignore, args.skip_common) + elif ('modify' == args.action[0]) or ('m' == args.action[0]): + manager.modify(repo, args.storage, args.ignore, args.skip_common) + elif ('delete' == args.action[0]) or ('d' == args.action[0]): + manager.delete(repo) + elif ('register' == args.action[0]) or ('r' == args.action[0]): + manager.register(repo) + else: + print >>sys.stderr, \ + "Unknown repository action supplied '%s'." % args.action[0] + exit(1) + exit(0) + except (ValueError, RuntimeError) as error: + print >>sys.stderr, "Execution Failed: %s" % error + exit(2) + except Exception as error: + import traceback - print >>sys.stderr, "Unexpected error: %s\n" % error, '-' * 60, '\n', traceback.format_exc(), '-' * 60 - exit(3) + print >>sys.stderr, "Unexpected error: %s\n" % error, '-' * 60, '\n', + traceback.format_exc(), '-' * 60 + exit(3)
--- a/src/ignorepo.py Tue Apr 07 20:03:21 2015 +0200 +++ b/src/ignorepo.py Fri Feb 19 18:45:37 2016 +0100 @@ -1,23 +1,24 @@ # -*- coding: utf-8 -*- -'''***************************************************************************** -*** This file is part of HgWeb Manager. *** -*** *** -*** Copyright (C) 2014 - 2015 *** -*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** -*** *** -*** This program is free software: you can redistribute it and/or modify it *** -*** under the terms of the GNU Affero General Public License as published *** -*** by the Free Software Foundation, either version 3 of the License, or *** -*** (at your option) any later version. *** -*** *** -*** This program is distributed in the hope that it will be useful, but *** -*** WITHOUT ANY WARRANTY; without even the implied warranty of *** -*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** -*** See the GNU Affero General Public License for more details. *** -*** *** -*** You should have received a copy of the GNU Affero General Public License*** -*** along with this program. If not, see <http://www.gnu.org/licenses/>. *** -*****************************************************************************''' +'''**************************************************************************** +*** This file is part of HgWeb Manager. *** +*** *** +*** Copyright (C) 2014 - 2016 *** +*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** +*** *** +*** This program is free software: you can redistribute it and/or modify *** +*** it under the terms of the GNU Affero General Public License as *** +*** published by the Free Software Foundation, either version 3 of the *** +*** License, or (at your option) any later version. *** +*** *** +*** This program is distributed in the hope that it will be useful, but *** +*** WITHOUT ANY WARRANTY; without even the implied warranty of *** +*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** +*** See the GNU Affero General Public License for more details. *** +*** *** +*** You should have received a copy of the GNU Affero General Public *** +*** License along with this program. If not, *** +*** see <http://www.gnu.org/licenses/>. *** +****************************************************************************''' import enum @@ -27,106 +28,105 @@ def ignore_syntax_name(mapFilterType): - """ Provides the mapping between an enumerated filter type and the - Mercurial ignore section header. + """ Provides the mapping between an enumerated filter type and the + Mercurial ignore section header. - @param[in] mapFilterType Is the enumerated value to map. + @param[in] mapFilterType Is the enumerated value to map. - @throws ValueError When an invalid filtering type is supplied. + @throws ValueError When an invalid filtering type is supplied. - @return The string value of the supplied enumerated value. - """ - if FilterType.Glob == mapFilterType: - return 'glob' - elif FilterType.RegularExpression == mapFilterType: - return 'regexp' - else: - raise ValueError("Unknown filter type supplied, '%s'." % mapFilterType) + @return The string value of the supplied enumerated value. + """ + if FilterType.Glob == mapFilterType: + return 'glob' + elif FilterType.RegularExpression == mapFilterType: + return 'regexp' + else: + raise ValueError("Unknown filter type supplied, '%s'." % mapFilterType) class Pattern(object): - """ Describes the properties of an entry in a Mercurial ignore file. """ + """ Describes the properties of an entry in a Mercurial ignore file. """ - # A short entry describing the purpose of the ignore entry. - __description = None - # The type of ignore entry used by Mercurial. - __filter = None - # The ignore expression to provide for an ignore file. - __value = None + # A short entry describing the purpose of the ignore entry. + __description = None + # The type of ignore entry used by Mercurial. + __filter = None + # The ignore expression to provide for an ignore file. + __value = None - @property - def Description(self): - """ A short entry describing the purpose of the ignore entry when - provided, else gives miscellaneous. - """ - if self.__description: - return self.__description - else: - return 'Miscellaneous' + @property + def Description(self): + """ A short entry describing the purpose of the ignore entry when + provided, else gives miscellaneous. + """ + if self.__description: + return self.__description + else: + return 'Miscellaneous' - @property - def Filter(self): - """ The type of ignore entry used by Mercurial. """ - return self.__filter + @property + def Filter(self): + """ The type of ignore entry used by Mercurial. """ + return self.__filter - @property - def Value(self): - """ The ignore expression to provide for an ignore file. """ - return self.__value + @property + def Value(self): + """ The ignore expression to provide for an ignore file. """ + return self.__value - def __init__(self, desc, fil, val): - """ Initialises the object with the values supplied. + def __init__(self, desc, fil, val): + """ Initialises the object with the values supplied. - @param[in] desc The description of the ignore entry. - @param[in] fil The type of ignore filtering. - @param[in] val The ignore expression. + @param[in] desc The description of the ignore entry. + @param[in] fil The type of ignore filtering. + @param[in] val The ignore expression. - @throws ValueError When the supplied ignore filter is invalid. - """ - self.__description = desc.strip() - if fil == 'glob': - self.__filter = FilterType.Glob - elif fil == 'regex': - self.__filter = FilterType.RegularExpression - else: - raise ValueError("Invalid filter type '%s' supplied" % fil) - self.__value = val.strip() + @throws ValueError When the supplied ignore filter is invalid. + """ + self.__description = desc.strip() + if fil == 'glob': + self.__filter = FilterType.Glob + elif fil == 'regex': + self.__filter = FilterType.RegularExpression + else: + raise ValueError("Invalid filter type '%s' supplied" % fil) + self.__value = val.strip() def extract(ignoreFile): - """ Parses an XML file for ignore file patterns. Generates a dictionary - object whose key is the name of the group for a collection of ignore - patterns. The value in each dictionary is an array of all the ignore - pattern objects within that group. Upon any parsing error, no ignore - patterns are supplied. + """ Parses an XML file for ignore file patterns. Generates a dictionary + object whose key is the name of the group for a collection of ignore + patterns. The value in each dictionary is an array of all the ignore + pattern objects within that group. Upon any parsing error, no ignore + patterns are supplied. - @param[in] ignoreFile The directory path and file name to an XML file - that contains the ignore patterns to extract. + @param[in] ignoreFile The directory path and file name to an XML file + that contains the ignore patterns to extract. - @throw ValueError When the name of a group is reused - in the XML file. + @throw ValueError When the name of a group is reused in the XML file. + @throw RuntimeError When the XML file cannot be parsed. - @throw When the XML file cannot be parsed. + @return The extracted grouped ignore patterns. + """ + from xml.dom import minidom + from xml.parsers.expat import ExpatError - @return The extracted grouped ignore patterns. - """ - from xml.dom import minidom - from xml.parsers.expat import ExpatError - - ignores = {} - try: - xmlIgnore = minidom.parse(ignoreFile) - except ExpatError as error: - raise RuntimeError(error) - for group in xmlIgnore.getElementsByTagName('ignores')[0].getElementsByTagName('group'): - groupName = group.getAttribute('name') - if groupName in ignores: - raise ValueError("The group '%s' was already defined." % groupName) - else: - ignores[groupName] = [] - for pattern in group.getElementsByTagName('pattern'): - ignores[groupName].append(Pattern( - pattern.getAttribute('description'), - pattern.getAttribute('type'), - pattern.firstChild.nodeValue)) - return ignores + ignores = {} + try: + xmlIgnore = minidom.parse(ignoreFile) + except ExpatError as error: + raise RuntimeError(error) + for group in xmlIgnore.getElementsByTagName( + 'ignores')[0].getElementsByTagName('group'): + groupName = group.getAttribute('name') + if groupName in ignores: + raise ValueError("The group '%s' was already defined." % groupName) + else: + ignores[groupName] = [] + for pattern in group.getElementsByTagName('pattern'): + ignores[groupName].append(Pattern( + pattern.getAttribute('description'), + pattern.getAttribute('type'), + pattern.firstChild.nodeValue)) + return ignores
--- a/src/manager.py Tue Apr 07 20:03:21 2015 +0200 +++ b/src/manager.py Fri Feb 19 18:45:37 2016 +0100 @@ -1,23 +1,24 @@ # -*- coding: utf-8 -*- -'''***************************************************************************** -*** This file is part of HgWeb Manager. *** -*** *** -*** Copyright (C) 2014 - 2015 *** -*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** -*** *** -*** This program is free software: you can redistribute it and/or modify it *** -*** under the terms of the GNU Affero General Public License as published *** -*** by the Free Software Foundation, either version 3 of the License, or *** -*** (at your option) any later version. *** -*** *** -*** This program is distributed in the hope that it will be useful, but *** -*** WITHOUT ANY WARRANTY; without even the implied warranty of *** -*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** -*** See the GNU Affero General Public License for more details. *** -*** *** -*** You should have received a copy of the GNU Affero General Public License*** -*** along with this program. If not, see <http://www.gnu.org/licenses/>. *** -*****************************************************************************''' +'''**************************************************************************** +*** This file is part of HgWeb Manager. *** +*** *** +*** Copyright (C) 2014 - 2016 *** +*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** +*** *** +*** This program is free software: you can redistribute it and/or modify *** +*** it under the terms of the GNU Affero General Public License as *** +*** published by the Free Software Foundation, either version 3 of the *** +*** License, or (at your option) any later version. *** +*** *** +*** This program is distributed in the hope that it will be useful, but *** +*** WITHOUT ANY WARRANTY; without even the implied warranty of *** +*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** +*** See the GNU Affero General Public License for more details. *** +*** *** +*** You should have received a copy of the GNU Affero General Public *** +*** License along with this program. If not, *** +*** see <http://www.gnu.org/licenses/>. *** +****************************************************************************''' from manrepolock import RepositoryManagerLock import config @@ -27,548 +28,611 @@ def plugInEnable(repository, plugInName, scriptFile): - """ Enables a plug-in to a managed repository. + """ Enables a plug-in to a managed repository. - @pre The repository must already exist. + @pre The repository must already exist. - @param[in] repository The targeted repository to add a plug-in to. - @param[in] plugInName The name of the plug-in to add. - @param[in] scriptFile The file path location of the plug-in script. + @param[in] repository The targeted repository to add a plug-in to. + @param[in] plugInName The name of the plug-in to add. + @param[in] scriptFile The file path location of the plug-in script. - @post The managed repository has it's configuration file changed which - enables the supplied plug-in. + @post The managed repository has it's configuration file changed which + enables the supplied plug-in. - @throws ValueError When the repository storage name does not exist. - """ - from manrepo import RepositoryPlugin + @throws ValueError When the repository storage name does not exist. + """ + from manrepo import RepositoryPlugin - with RepositoryManagerLock(): - print "\tEnable plug-in %s for %s" % (plugInName, repository.StorageName) - if not __doesRepositoryStorageNameExist(repository): - raise ValueError("The repository '%s' does not exist." % repository.StorageName) + with RepositoryManagerLock(): + print "\tEnable plug-in %s for %s" % (plugInName, + repository.StorageName) + if not __doesRepositoryStorageNameExist(repository): + raise ValueError("The repository '%s' does not exist." % + repository.StorageName) - print 'Creating plug-in information ...' - plugIn = RepositoryPlugin(plugInName, scriptFile) - repository.addPlugIn(plugIn) - __writeRepositoryDetails(repository) + print 'Creating plug-in information ...' + plugIn = RepositoryPlugin(plugInName, scriptFile) + repository.addPlugIn(plugIn) + __writeRepositoryDetails(repository) def plugInDisable(repository, named): - """ Disables a plug-in to a managed repository. + """ Disables a plug-in to a managed repository. - @pre The repository must already exist. + @pre The repository must already exist. - @param[in] repository The targeted repository to remove a plug-in from. - @param[in] named The name of the plug-in to remove. + @param[in] repository The targeted repository to remove a plug-in + from. + @param[in] named The name of the plug-in to remove. - @post The managed repository has it's configuration file changed which - disables the supplied plug-in. + @post The managed repository has it's configuration file changed which + disables the supplied plug-in. - @throws ValueError When the repository storage name does not exist. - """ - with RepositoryManagerLock(): - print "\tDisable plug-in %s for %s" % (named, repository.StorageName) - if not __doesRepositoryStorageNameExist(repository): - raise ValueError("The repository '%s' does not exist." % repository.StorageName) + @throws ValueError When the repository storage name does not exist. + """ + with RepositoryManagerLock(): + print "\tDisable plug-in %s for %s" % (named, repository.StorageName) + if not __doesRepositoryStorageNameExist(repository): + raise ValueError("The repository '%s' does not exist." % + repository.StorageName) - print 'Removing plug-in information ...' - repository.removePlugIn(named) - __writeRepositoryDetails(repository) + print 'Removing plug-in information ...' + repository.removePlugIn(named) + __writeRepositoryDetails(repository) def setPlugInSetting(repository, plugIn, named, value): - with RepositoryManagerLock(): - print "\t Setting repository %s's '%s' plug-in setting '%s' to %s" % (repository.StorageName, plugIn, named, value) - if not __doesRepositoryStorageNameExist(repository): - raise ValueError("The repository '%s' does not exist." % repository.StorageName) + with RepositoryManagerLock(): + print "\t Setting repository %s's '%s' plug-in setting '%s' to %s" % ( + repository.StorageName, plugIn, named, value) + if not __doesRepositoryStorageNameExist(repository): + raise ValueError("The repository '%s' does not exist." % + repository.StorageName) - print 'Modifying plug-in setting ...' - repository.setSetting(plugIn, named, value) - __writeRepositoryDetails(repository) + print 'Modifying plug-in setting ...' + repository.setSetting(plugIn, named, value) + __writeRepositoryDetails(repository) def create(repository, ignoreGroups, skipCommon): - """ Creates a new repository under HgWeb. + """ Creates a new repository under HgWeb. - @pre The repository to create cannot already exist. + @pre The repository to create cannot already exist. - @param[in] repository The targeted repository to create. - @param[in] ignoreGroups The list of all ignore groups to add. - @param[in] skipCommon A flag that when true indicates the common group - should not be added by default. + @param[in] repository The targeted repository to create. + @param[in] ignoreGroups The list of all ignore groups to add. + @param[in] skipCommon A flag that when true indicates the common + group should not be added by default. - @post The file system now contains a new directory in the repository path - that is the newly generated repository. The new repository is registered - in HgWeb to display and is secured to prevent accidental modification. + @post The file system now contains a new directory in the repository path + that is the newly generated repository. The new repository is registered + in HgWeb to display and is secured to prevent accidental modification. - @throws ValueError When the repository storage or display name exists. - @throws RuntimeError When the new repository creation encounters an - error. - """ - import os - import shutil - import stat + @throws ValueError When the repository storage or display name + exists. + @throws RuntimeError When the new repository creation encounters an + error. + """ + import os + import shutil + import stat - with RepositoryManagerLock(): - print "\tAdding repository: %s" % repository.StorageName - if __doesRepositoryStorageNameExist(repository): - raise ValueError("The repository storage name '%s' already exists." % repository.StorageName) + with RepositoryManagerLock(): + print "\tAdding repository: %s" % repository.StorageName + if __doesRepositoryStorageNameExist(repository): + raise ValueError("The repository storage name '%s' already exists." + % repository.StorageName) - if __doesRepositoryDisplayNameExist(repository): - raise ValueError("The display name '%s' already exists." % repository.DisplayName) + if __doesRepositoryDisplayNameExist(repository): + raise ValueError("The display name '%s' already exists." % + repository.DisplayName) - try: - __addRepository(repository) - __create_ignores(repository, ignoreGroups, skipCommon) - except RuntimeError: - __removeRepository(repository) - pass + try: + __addRepository(repository) + __create_ignores(repository, ignoreGroups, skipCommon) + except RuntimeError: + __removeRepository(repository) + pass - try: - __writeRepositoryDetails(repository) - __registerRepository(repository) - except RuntimeError: - os.chmod(os.path.join(settings.RepositoryPath, repository.StorageName, '.hg', "hgrc"), stat.S_IWRITE) - shutil.rmtree(settings.RepositoryPath + os.sep + repository.StorageName) - pass + try: + __writeRepositoryDetails(repository) + __registerRepository(repository) + except RuntimeError: + os.chmod(os.path.join(settings.RepositoryPath, + repository.StorageName, '.hg', "hgrc"), + stat.S_IWRITE) + shutil.rmtree(settings.RepositoryPath + os.sep + + repository.StorageName) + pass def register(repository): - """ Connects an existing repository to the mercurial web registry. + """ Connects an existing repository to the mercurial web registry. - @pre The repository to register must already exist. + @pre The repository to register must already exist. - @param[in] repository The targeted repository to register. + @param[in] repository The targeted repository to register. - @post The new repository is registered in HgWeb to display and is - secured to prevent accidental modification. + @post The new repository is registered in HgWeb to display and is + secured to prevent accidental modification. - @throws ValueError When the repository storage or display name does not - exist. - @throws RuntimeError When the new repository registration encounters an - error. - """ - with RepositoryManagerLock(): - print "\tRegistering the repository: %s" % repository.StorageName - if __doesRepositoryStorageNameExist(repository): - __registerRepository(repository) - else: - raise ValueError("The repository '%s' does not exists." % repository.StorageName) + @throws ValueError When the repository storage or display name does + not exist. + @throws RuntimeError When the new repository registration encounters an + error. + """ + with RepositoryManagerLock(): + print "\tRegistering the repository: %s" % repository.StorageName + if __doesRepositoryStorageNameExist(repository): + __registerRepository(repository) + else: + raise ValueError("The repository '%s' does not exists." % + repository.StorageName) def modify(newRepository, currentStorageName, ignoreGroups, skipCommon): - """ Changes an existing repository in HgWeb. + """ Changes an existing repository in HgWeb. - @pre The repository to modify must already exist. + @pre The repository to modify must already exist. - @param[in] newRepository The new values for the repository to - modify. - @param[in] currentStorageName The current storage name of the - repository to modify. - @param[in] ignoreGroups The list of all ignore groups to add. - @param[in] skipCommon A flag that when true indicates the - common group should not be added by - default. + @param[in] newRepository The new values for the repository to + modify. + @param[in] currentStorageName The current storage name of the + repository to modify. + @param[in] ignoreGroups The list of all ignore groups to add. + @param[in] skipCommon A flag that when true indicates the + common group should not be added by + default. - @post The repository is changed with the requested modifications. + @post The repository is changed with the requested modifications. + + @throws ValueError When the repository storage name does not exist. + @throws RuntimeError When the new repository modification encounters an + error. + """ + from manrepo import Repository - @throws ValueError When the repository storage name does not exist. - @throws RuntimeError When the new repository modification encounters an - error. - """ - from manrepo import Repository + with RepositoryManagerLock(): + print "\tModifying repository: %s" % currentStorageName + oldRepository = Repository(currentStorageName) - with RepositoryManagerLock(): - print "\tModifying repository: %s" % currentStorageName - oldRepository = Repository(currentStorageName) - - if not __doesRepositoryStorageNameExist(oldRepository): - raise ValueError("The repository '%s' was not found." % oldRepository.StorageName) + if not __doesRepositoryStorageNameExist(oldRepository): + raise ValueError("The repository '%s' was not found." % + oldRepository.StorageName) - __unregisterRepository(oldRepository) - - if __doesRepositoryDisplayNameExist(newRepository): - __registerRepository(oldRepository) - raise ValueError("The display name '%s' already exists." % newRepository.DisplayName) + __unregisterRepository(oldRepository) - # Update renamed repositories - if not oldRepository == newRepository: - try: - __renameStorage(oldRepository, newRepository.StorageName) - except RuntimeError: - __registerRepository(oldRepository) - pass + if __doesRepositoryDisplayNameExist(newRepository): + __registerRepository(oldRepository) + raise ValueError("The display name '%s' already exists." % + newRepository.DisplayName) - # Fill out the details of about the new repository. - try: - __writeRepositoryDetails(newRepository) - # Update ignore file if requested. - if ignoreGroups is not None: - __create_ignores(newRepository, ignoreGroups, skipCommon) - except RuntimeError: - __registerRepository(oldRepository) - print "Successfully rolled backed action(s)." - pass + # Update renamed repositories + if not oldRepository == newRepository: + try: + __renameStorage(oldRepository, newRepository.StorageName) + except RuntimeError: + __registerRepository(oldRepository) + pass - # Add the new repository to the web registry. - __registerRepository(newRepository) + # Fill out the details of about the new repository. + try: + __writeRepositoryDetails(newRepository) + # Update ignore file if requested. + if ignoreGroups is not None: + __create_ignores(newRepository, ignoreGroups, skipCommon) + except RuntimeError: + __registerRepository(oldRepository) + print "Successfully rolled backed action(s)." + pass + + # Add the new repository to the web registry. + __registerRepository(newRepository) def delete(repository): - """ Removes an existing repository. + """ Removes an existing repository. - @pre The repository to remove must already exist. + @pre The repository to remove must already exist. - @param[in] repository The targeted repository to delete. + @param[in] repository The targeted repository to delete. - @post The file system no longer contains a directory in the repository - path that is the supplied repository. The repository is no longer - registered in HgWeb. + @post The file system no longer contains a directory in the repository + path that is the supplied repository. The repository is no longer + registered in HgWeb. - @throws ValueError When the repository storage name does not exist. - """ - with RepositoryManagerLock(): - if not __doesRepositoryStorageNameExist(repository): - raise ValueError("The repository %s was not found." % repository.StorageName) + @throws ValueError When the repository storage name does not exist. + """ + with RepositoryManagerLock(): + if not __doesRepositoryStorageNameExist(repository): + raise ValueError("The repository %s was not found." % + repository.StorageName) - print "\tRemoving repository: %s" % repository.StorageName - __unregisterRepository(repository) - __removeRepository(repository) + print "\tRemoving repository: %s" % repository.StorageName + __unregisterRepository(repository) + __removeRepository(repository) def list(): - """ Outputs a listing of all the known managed repositories """ - import manrepo + """ Outputs a listing of all the known managed repositories """ + import manrepo - print "Managed Repositories:" - repoCol = manrepo.ManagedCollection() - for repo in repoCol.Repositories: - print "\t%s (%s)" % (repo.StorageName, repo.DisplayName) + print "Managed Repositories:" + repoCol = manrepo.ManagedCollection() + for repo in repoCol.Repositories: + print "\t%s (%s)" % (repo.StorageName, repo.DisplayName) -# Functions For Fulfilling Repository Management ### +# Functions For Fulfilling Repository Management ### def __create_ignores(repo, ignoreGroups, skipCommon): - """ Generates and commits an ignore file to an existing repository. + """ Generates and commits an ignore file to an existing repository. - @pre The repository to create an ignore file must already exist. The list - of ignore patterns to use is expected to be in an XML file named - "ignores.xml" and be in the hwm-ignore schema. + @pre The repository to create an ignore file must already exist. The list + of ignore patterns to use is expected to be in an XML file named + "ignores.xml" and be in the hwm-ignore schema. - @param[in] repo The targeted repository for the ignore file. - @param[in] ignoreGroups The list of all ignore groups to add. - @param[in] skipCommon A flag that when true indicates the common group - should not be added by default. + @param[in] repo The targeted repository for the ignore file. + @param[in] ignoreGroups The list of all ignore groups to add. + @param[in] skipCommon A flag that when true indicates the common + group should not be added by default. - @post The managed repository now has an ignore file committed by the - HgWeb manager. + @post The managed repository now has an ignore file committed by the + HgWeb manager. - @throws RuntimeError When the list of ignores does not have a group. - """ - import os - import ignorepo + @throws RuntimeError When the list of ignores does not have a group. + """ + import os + import ignorepo + + # Extract Ignore Collection + if ignoreGroups is None: + ignoreGroups = [] + ignores = ignorepo.extract(os.path.join(settings.DataPath, 'ignores.xml')) - # Extract Ignore Collection - if ignoreGroups is None: - ignoreGroups = [] - ignores = ignorepo.extract(os.path.join(settings.DataPath, 'ignores.xml')) + if skipCommon: + del ignores['Common'] + elif 'common' not in [ignoreGroup.lower() for ignoreGroup in ignoreGroups]: + ignoreGroups.append('Common') - if skipCommon: - del ignores['Common'] - elif 'common' not in [ignoreGroup.lower() for ignoreGroup in ignoreGroups]: - ignoreGroups.append('Common') + if '+' not in ignoreGroups: + for ignoreGroup in ignoreGroups: + if not ignoreGroup.lower() in [ignore.lower() + for ignore in ignores]: + raise RuntimeError( + "The list of ignores does not have the '%s' group." % + ignoreGroup) - if '+' not in ignoreGroups: - for ignoreGroup in ignoreGroups: - if not ignoreGroup.lower() in [ignore.lower() for ignore in ignores]: - raise RuntimeError("The list of ignores does not have the '%s' group." % ignoreGroup) - - ignoreFile = settings.RepositoryPath + os.sep + repo.StorageName + os.sep + '.hgignore' - wasCreated = not os.path.isfile(ignoreFile) - if wasCreated: - print "Creating ignore file ..." - else: - print "Rewriting ignore file ..." + ignoreFile = settings.RepositoryPath + os.sep + repo.StorageName + \ + os.sep + '.hgignore' + wasCreated = not os.path.isfile(ignoreFile) + if wasCreated: + print "Creating ignore file ..." + else: + print "Rewriting ignore file ..." - # Write Ignore File - with open(ignoreFile, 'w') as hgIgnore: - for groupName, groupPatterns in ignores.items(): - if '+' not in ignoreGroups and not groupName.lower() in [ignoreGroup.lower() for ignoreGroup in ignoreGroups]: - continue - hgIgnore.write("#\n#\tIgnore Group: %s\n#" % groupName) - # Reverse the sorting order to put the regular expressions first. - groupPatterns.sort(key=lambda p: p.Filter, reverse=True) - filteringOn = None - for pattern in groupPatterns: - if pattern.Filter == filteringOn: - hgIgnore.write("\n%s\t\t# %s" % (pattern.Value, pattern.Description)) - elif filteringOn is None: - hgIgnore.write("\nsyntax: %s\n%s\t\t# %s" % (ignorepo.ignore_syntax_name(pattern.Filter), pattern.Value, pattern.Description)) - else: - hgIgnore.write("\n\nsyntax: %s\n%s\t\t# %s" % (ignorepo.ignore_syntax_name(pattern.Filter), pattern.Value, pattern.Description)) - filteringOn = pattern.Filter - hgIgnore.write('\n\n') + # Write Ignore File + with open(ignoreFile, 'w') as hgIgnore: + for groupName, groupPatterns in ignores.items(): + if '+' not in ignoreGroups and not groupName.lower() in \ + [ignoreGroup.lower() for ignoreGroup in ignoreGroups]: + continue + hgIgnore.write("#\n#\tIgnore Group: %s\n#" % groupName) + # Reverse the sorting order to put the regular expressions first. + groupPatterns.sort(key=lambda p: p.Filter, reverse=True) + filteringOn = None + for pattern in groupPatterns: + if pattern.Filter == filteringOn: + hgIgnore.write("\n%s\t\t# %s" % (pattern.Value, + pattern.Description)) + elif filteringOn is None: + hgIgnore.write("\nsyntax: %s\n%s\t\t# %s" % ( + ignorepo.ignore_syntax_name(pattern.Filter), + pattern.Value, pattern.Description)) + else: + hgIgnore.write("\n\nsyntax: %s\n%s\t\t# %s" % + (ignorepo.ignore_syntax_name( + pattern.Filter), pattern.Value, + pattern.Description)) + filteringOn = pattern.Filter + hgIgnore.write('\n\n') - if wasCreated: - print "Adding generated ignores ..." - __addFile(repo, '.hgignore') + if wasCreated: + print "Adding generated ignores ..." + __addFile(repo, '.hgignore') - print "Committing generated ignores ..." - __commitChanges(repo, 'Created generated ignores filter.') + print "Committing generated ignores ..." + __commitChanges(repo, 'Created generated ignores filter.') def __commitChanges(repo, message): - """ Commits all changes in a managed Mercurial repository as the HgWeb - manager. + """ Commits all changes in a managed Mercurial repository as the HgWeb + manager. - @pre The requested repository must already exist. + @pre The requested repository must already exist. - @param[in] repo The targeted repository for which to commit. - @param[in] message The text to use as a commit message. + @param[in] repo The targeted repository for which to commit. + @param[in] message The text to use as a commit message. - @post Upon any error the standard error buffer contains an error message. + @post Upon any error the standard error buffer contains an error message. - @throws RuntimeError When the added files fail to commit. - """ - import subprocess - import os + @throws RuntimeError When the added files fail to commit. + """ + import subprocess + import os - statusCode = subprocess.call([settings.HgCommand, '--repository', settings.RepositoryPath + os.sep + repo.StorageName, 'commit', '--message', message, '--user', settings.HgUser + ' - HgWeb Manager']) + statusCode = subprocess.call([settings.HgCommand, '--repository', + settings.RepositoryPath + os.sep + + repo.StorageName, 'commit', '--message', + message, '--user', settings.HgUser + + ' - HgWeb Manager']) - # Zero being a successful commit and one being nothing changed. - if not ((0 == statusCode) or (1 == statusCode)): - raise RuntimeError("Failed to commit files. Status code: " + statusCode) + # Zero being a successful commit and one being nothing changed. + if not ((0 == statusCode) or (1 == statusCode)): + raise RuntimeError("Failed to commit files. Status code: " + + statusCode) def __addFile(repo, fileName): - """ Marks a file as added in a managed Mercurial repository. + """ Marks a file as added in a managed Mercurial repository. - @pre The requested repository must already exist. + @pre The requested repository must already exist. - @param[in] repo The targeted repository for which to add the file. - @param[in] fileName The directory path and the file name to add - relative to the base of the repository. + @param[in] repo The targeted repository for which to add the + file. + @param[in] fileName The directory path and the file name to add + relative to the base of the repository. - @post Upon any error the standard error buffer contains an error message. + @post Upon any error the standard error buffer contains an error message. - @throws RuntimeError When the the news files fail to be added. - """ - import subprocess - import os + @throws RuntimeError When the the news files fail to be added. + """ + import subprocess + import os - statusCode = subprocess.call([settings.HgCommand, '--repository', settings.RepositoryPath + os.sep + repo.StorageName, 'add', settings.RepositoryPath + os.sep + repo.StorageName + os.sep + fileName]) + statusCode = subprocess.call([settings.HgCommand, '--repository', + settings.RepositoryPath + os.sep + + repo.StorageName, 'add', + settings.RepositoryPath + os.sep + + repo.StorageName + os.sep + fileName]) - # Zero being a successful commit and one being nothing to add. - if not ((0 == statusCode) or (1 == statusCode)): - raise RuntimeError("Failed to commit files. Status code: " + statusCode) + # Zero being a successful commit and one being nothing to add. + if not ((0 == statusCode) or (1 == statusCode)): + raise RuntimeError("Failed to commit files. Status code: " + + statusCode) def __renameStorage(oldRepo, newName): - """ Changes the storage name of an existing repository. + """ Changes the storage name of an existing repository. - @param[in] oldRepo The existing repository to whose storage name is - expected to be changed. - @param[in] newName The new storage name for the repository. + @param[in] oldRepo The existing repository to whose storage name is + expected to be changed. + @param[in] newName The new storage name for the repository. - @throws ValueError When the supplied new storage name already exists. - """ - import os - import shutil + @throws ValueError When the supplied new storage name already exists. + """ + import os + import shutil - if not oldRepo.StorageName == newName: - print "Renaming repository %s to %s ..." % (oldRepo.StorageName, newName) - if os.path.isdir(settings.RepositoryPath + os.sep + newName): - raise ValueError("Cannot rename the existing repository '%s' because the name '%s' already exists." % (oldRepo.StorageName, newName)) - shutil.move(settings.RepositoryPath + os.sep + oldRepo.StorageName, settings.RepositoryPath + os.sep + newName) + if not oldRepo.StorageName == newName: + print "Renaming repository %s to %s ..." % (oldRepo.StorageName, + newName) + if os.path.isdir(settings.RepositoryPath + os.sep + newName): + raise ValueError( + "Cannot rename the existing repository '%s' because the" + " name '%s' already exists." % (oldRepo.StorageName, newName)) + shutil.move(settings.RepositoryPath + os.sep + oldRepo.StorageName, + settings.RepositoryPath + os.sep + newName) def __doesRepositoryStorageNameExist(repo): - """ Checks to see if a repository storage name exists. + """ Checks to see if a repository storage name exists. + + @param[in] repo The targeted repository for which to check. - @param[in] repo The targeted repository for which to check. + @return Gives true when it exists, false else-wise. + """ + import os - @return Gives true when it exists, false else-wise. - """ - import os - - if (repo is None) or (repo.StorageName is None): - return False - elif os.path.isdir(settings.RepositoryPath + os.sep + repo.StorageName + os.sep + '.hg'): - return True - else: - return False + if (repo is None) or (repo.StorageName is None): + return False + elif os.path.isdir(settings.RepositoryPath + os.sep + repo.StorageName + + os.sep + '.hg'): + return True + else: + return False def __doesRepositoryDisplayNameExist(repo): - """ Checks to see if a repository display name exists. + """ Checks to see if a repository display name exists. - @param[in] repo The targeted repository for which to check. + @param[in] repo The targeted repository for which to check. - @return Gives true when it exists, false else-wise. - """ - from manrepo import ManagedCollection + @return Gives true when it exists, false else-wise. + """ + from manrepo import ManagedCollection - if (repo is None) or (repo.StorageName is None) or (repo.DisplayName is None): - return False + if (repo is None) or (repo.StorageName is None) or\ + (repo.DisplayName is None): + return False - repoCol = ManagedCollection() - for testRepo in repoCol.Repositories: - if (testRepo.DisplayName is not None) and (not testRepo == repo) and (testRepo.DisplayName.lower() == repo.DisplayName.lower()): - return True - return False + repoCol = ManagedCollection() + for testRepo in repoCol.Repositories: + if (testRepo.DisplayName is not None) and (not testRepo == repo) and \ + (testRepo.DisplayName.lower() == repo.DisplayName.lower()): + return True + return False def __unregisterRepository(repo): - """ Removes the registration of the supplied repository. + """ Removes the registration of the supplied repository. + + @param[in] repo The targeted repository for which to unregister. - @param[in] repo The targeted repository for which to unregister. + @post The HgWeb configuration file does not contain the repository details + and is returned to a read-only state. Upon any error the standard error + buffer contains an error message. - @post The HgWeb configuration file does not contain the repository details - and is returned to a read-only state. Upon any error the standard error - buffer contains an error message. - - @throws RuntimeError When the web path is missing the configuration file. - @throws RuntimeError When the configuration file does not contain a path - section. - """ - from ConfigParser import SafeConfigParser - import os + @throws RuntimeError When the web path is missing the configuration + file. + @throws RuntimeError When the configuration file does not contain a path + section. + """ + from ConfigParser import SafeConfigParser + import os - parser = SafeConfigParser() - if not parser.read(settings.HgWebPath + os.sep + 'hgweb.config'): - raise RuntimeError("Failed to locate HgWeb configuration file.") + parser = SafeConfigParser() + if not parser.read(settings.HgWebPath + os.sep + 'hgweb.config'): + raise RuntimeError("Failed to locate HgWeb configuration file.") - if parser.has_section('paths'): - if parser.has_option('paths', repo.StorageName): - print "Unregistering repository ..." - parser.remove_option('paths', repo.StorageName) - with open(settings.HgWebPath + os.sep + 'hgweb.config', 'wb') as configfile: - parser.write(configfile) - else: - print "The repository already is unregistered." - else: - raise RuntimeError("The HgWeb configuration file does not have a paths section! Failed to unregister repository.") + if parser.has_section('paths'): + if parser.has_option('paths', repo.StorageName): + print "Unregistering repository ..." + parser.remove_option('paths', repo.StorageName) + with open(settings.HgWebPath + os.sep + 'hgweb.config', + 'wb') as configfile: + parser.write(configfile) + else: + print "The repository already is unregistered." + else: + raise RuntimeError('The HgWeb configuration file does not have a ' + 'paths section! Failed to unregister repository.') def __removeRepository(repo): - """ Removes an existing Mercurial repository. + """ Removes an existing Mercurial repository. - @pre The requested repository to delete must already exist. + @pre The requested repository to delete must already exist. - @param[in] repo The targeted repository for which to delete. + @param[in] repo The targeted repository for which to delete. - @post Upon any error the standard error buffer contains an error message. - """ - import shutil - import os - import stat + @post Upon any error the standard error buffer contains an error message. + """ + import shutil + import os + import stat - print "Removing repository directories ..." - try: - os.chmod(settings.RepositoryPath + os.sep + repo.StorageName + os.sep + '.hg' + os.sep + "hgrc", stat.S_IWRITE) - except OSError as e: - # If it's anything but the "No such file or directory", notify the user. - if not 2 == e.errno: - pass - shutil.rmtree(settings.RepositoryPath + os.sep + repo.StorageName) + print "Removing repository directories ..." + try: + os.chmod(settings.RepositoryPath + os.sep + repo.StorageName + + os.sep + '.hg' + os.sep + "hgrc", stat.S_IWRITE) + except OSError as e: + # If it's anything but the "No such file or directory", + # notify the user. + if not 2 == e.errno: + pass + shutil.rmtree(settings.RepositoryPath + os.sep + repo.StorageName) def __addRepository(repo): - """ Initialises a new Mercurial repository. + """ Initialises a new Mercurial repository. - @pre The requested repository to create cannot already exist. + @pre The requested repository to create cannot already exist. - @param[in] repo The targeted repository for which to create. + @param[in] repo The targeted repository for which to create. - @post Upon any error the standard error buffer contains an error message. + @post Upon any error the standard error buffer contains an error message. - @throws ValueError When the storage name is missing. - @throws RuntimeError When the initialisation call fails. - """ - import subprocess - import os + @throws ValueError When the storage name is missing. + @throws RuntimeError When the initialisation call fails. + """ + import subprocess + import os - print "Initialising repository directory ..." - if repo.StorageName is None: - raise ValueError('Cannot create a managed repository without a storage name.') - statusCode = subprocess.call([settings.HgCommand, 'init', settings.RepositoryPath + os.sep + repo.StorageName]) - if not (0 == statusCode): - raise RuntimeError("Failed to initialise repository. Status code: " + statusCode) + print "Initialising repository directory ..." + if repo.StorageName is None: + raise ValueError( + 'Cannot create a managed repository without a storage name.') + statusCode = subprocess.call([settings.HgCommand, 'init', + settings.RepositoryPath + os.sep + + repo.StorageName]) + if not (0 == statusCode): + raise RuntimeError('Failed to initialise repository. Status code: ' + + statusCode) def __writeRepositoryDetails(repo): - """ Writes the details of a repository to the repository's - configuration file. + """ Writes the details of a repository to the repository's + configuration file. - @param[in] repo The targeted repository for which to write the - configuration details. + @param[in] repo The targeted repository for which to write the + configuration details. - @post The HgWeb configuration file contains the new repository details and - is returned to a read-only state. - """ - import os - import stat - import sys + @post The HgWeb configuration file contains the new repository details and + is returned to a read-only state. + """ + import os + import stat + import sys - print "Saving repository configuration details ..." - config = settings.RepositoryPath + os.sep + repo.StorageName + os.sep + '.hg' + os.sep + 'hgrc' + print "Saving repository configuration details ..." + config = settings.RepositoryPath + os.sep + repo.StorageName + os.sep + \ + '.hg' + os.sep + 'hgrc' - if os.path.exists(config): - hgrcMode = os.stat(config)[stat.ST_MODE] - os.chmod(config, hgrcMode | stat.S_IWRITE) - else: - hgrcMode = stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH - repo.save() - # Ensure the repository details isn't accidentally modified. - os.chmod(config, hgrcMode & (~stat.S_IWUSR & ~stat.S_IWGRP & ~stat.S_IWOTH)) + if os.path.exists(config): + hgrcMode = os.stat(config)[stat.ST_MODE] + os.chmod(config, hgrcMode | stat.S_IWRITE) + else: + hgrcMode = stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH + repo.save() + # Ensure the repository details isn't accidentally modified. + os.chmod(config, hgrcMode & (~stat.S_IWUSR & ~stat.S_IWGRP & + ~stat.S_IWOTH)) - # Ensure the repository isn't accidentally deleted, moved, or blocked in Windows. - if "win32" == sys.platform: - __guardWindowsRepository(repo) - print 'Secured repository store in Windows.' + # Ensure the repository isn't accidentally deleted, moved, or + # blocked in Windows. + if "win32" == sys.platform: + __guardWindowsRepository(repo) + print 'Secured repository store in Windows.' def __guardWindowsRepository(repo): - """ Guards the supplied repository for a repository on a Windows system. + """ Guards the supplied repository for a repository on a Windows system. + + @param[in] repo The targeted repository for which to secure. + """ + import subprocess + import os - @param[in] repo The targeted repository for which to secure. - """ - import subprocess - import os + print 'Securing for Windows ...' + status = subprocess.call(['attrib.exe', '+H', '+I', '+S', + settings.RepositoryPath + os.sep + + repo.StorageName + os.sep + '.hg']) - print 'Securing for Windows ...' - status = subprocess.call(['attrib.exe', '+H', '+I', '+S', settings.RepositoryPath + os.sep + repo.StorageName + os.sep + '.hg']) - - if not (0 == status): - raise RuntimeError("Failed to secure repository store for windows. Status code: " + status) + if not (0 == status): + raise RuntimeError('Failed to secure repository store for ' + 'windows. Status code: ' + status) def __registerRepository(repo): - """ Adds the registration details of the repository. + """ Adds the registration details of the repository. - @param[in] repo The targeted repository for which to register in HgWeb. + @param[in] repo The targeted repository for which to register + in HgWeb. - @post The HgWeb configuration file contains the new repository details and - is returned to a read-only state. Upon any error the standard error - buffer contains an error message. + @post The HgWeb configuration file contains the new repository details and + is returned to a read-only state. Upon any error the standard error + buffer contains an error message. - @throws RuntimeError When the HgWeb configuration file cannot be found. - @throws ValueError When the supplied repository is already registered. - """ - from ConfigParser import SafeConfigParser - import os + @throws RuntimeError When the HgWeb configuration file cannot be found. + @throws ValueError When the supplied repository is already registered. + """ + from ConfigParser import SafeConfigParser + import os - parser = SafeConfigParser() - if not parser.read(settings.HgWebPath + os.sep + 'hgweb.config'): - raise RuntimeError("Failed to locate HgWeb configuration file.") + parser = SafeConfigParser() + if not parser.read(settings.HgWebPath + os.sep + 'hgweb.config'): + raise RuntimeError("Failed to locate HgWeb configuration file.") - if parser.has_section('paths'): - if parser.has_option('paths', repo.StorageName): - raise ValueError("The repository already is registered.") - else: - parser.add_section('paths') - print "Registering repository ..." - parser.set('paths', repo.StorageName, settings.RepositoryPath + os.sep + repo.StorageName) - with open(settings.HgWebPath + os.sep + 'hgweb.config', 'wb') as configfile: - parser.write(configfile) + if parser.has_section('paths'): + if parser.has_option('paths', repo.StorageName): + raise ValueError("The repository already is registered.") + else: + parser.add_section('paths') + print "Registering repository ..." + parser.set('paths', repo.StorageName, settings.RepositoryPath + + os.sep + repo.StorageName) + with open(settings.HgWebPath + os.sep + 'hgweb.config', + 'wb') as configfile: + parser.write(configfile)
--- a/src/manrepo.py Tue Apr 07 20:03:21 2015 +0200 +++ b/src/manrepo.py Fri Feb 19 18:45:37 2016 +0100 @@ -1,400 +1,420 @@ # -*- coding: utf-8 -*- -'''***************************************************************************** -*** This file is part of HgWeb Manager. *** -*** *** -*** Copyright (C) 2014 - 2015 *** -*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** -*** *** -*** This program is free software: you can redistribute it and/or modify it *** -*** under the terms of the GNU Affero General Public License as published *** -*** by the Free Software Foundation, either version 3 of the License, or *** -*** (at your option) any later version. *** -*** *** -*** This program is distributed in the hope that it will be useful, but *** -*** WITHOUT ANY WARRANTY; without even the implied warranty of *** -*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** -*** See the GNU Affero General Public License for more details. *** -*** *** -*** You should have received a copy of the GNU Affero General Public License*** -*** along with this program. If not, see <http://www.gnu.org/licenses/>. *** -*****************************************************************************''' +'''**************************************************************************** +*** This file is part of HgWeb Manager. *** +*** *** +*** Copyright (C) 2014 - 2016 *** +*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** +*** *** +*** This program is free software: you can redistribute it and/or modify *** +*** it under the terms of the GNU Affero General Public License as *** +*** published by the Free Software Foundation, either version 3 of the *** +*** License, or (at your option) any later version. *** +*** *** +*** This program is distributed in the hope that it will be useful, but *** +*** WITHOUT ANY WARRANTY; without even the implied warranty of *** +*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** +*** See the GNU Affero General Public License for more details. *** +*** *** +*** You should have received a copy of the GNU Affero General Public *** +*** License along with this program. If not, *** +*** see <http://www.gnu.org/licenses/>. *** +****************************************************************************''' from manager import settings class Repository(object): - """ Describes the properties of a repository managed by HWM and served up - by HgWeb. - """ + """ Describes the properties of a repository managed by HWM and served up + by HgWeb. + """ - # The directory name of the managed repository. - __storageName = None - # The displayed web-site name of the managed repository. - __displayName = None - # The displayed web-site description of the managed repository. - __description = None - # The displayed web-site contact information of the managed repository. - __contact = None - # The Mercurial repository interface. - __repo = None - # The collection of plug-ins enabled for a repository. - __plugIns = None + # The directory name of the managed repository. + __storageName = None + # The displayed web-site name of the managed repository. + __displayName = None + # The displayed web-site description of the managed repository. + __description = None + # The displayed web-site contact information of the managed repository. + __contact = None + # The Mercurial repository interface. + __repo = None + # The collection of plug-ins enabled for a repository. + __plugIns = None - @property - def StorageName(self): - """ Gets the name of the directory where the managed repository is located. """ - return self.__storageName + @property + def StorageName(self): + """ Gets the name of the directory where the managed repository + is located. """ + return self.__storageName - @property - def DisplayName(self): - """ Gets the name to display for the managed repository. """ - return self.__displayName + @property + def DisplayName(self): + """ Gets the name to display for the managed repository. """ + return self.__displayName - @DisplayName.setter - def DisplayName(self, value): - """ Sets the name of the managed repository to display. """ - self.__displayName = value + @DisplayName.setter + def DisplayName(self, value): + """ Sets the name of the managed repository to display. """ + self.__displayName = value + + @property + def Description(self): + """ Gets the description of the managed repository. """ + return self.__description - @property - def Description(self): - """ Gets the description of the managed repository. """ - return self.__description + @Description.setter + def Description(self, value): + """ Sets the description of the managed repository to display. """ + self.__description = value - @Description.setter - def Description(self, value): - """ Sets the description of the managed repository to display. """ - self.__description = value + @property + def Contact(self): + """ Gets the contact point for the managed repository. """ + return self.__contact - @property - def Contact(self): - """ Gets the contact point for the managed repository. """ - return self.__contact + @Contact.setter + def Contact(self, value): + """ Sets the contact point for the managed repository. """ + self.__contact = value - @Contact.setter - def Contact(self, value): - """ Sets the contact point for the managed repository. """ - self.__contact = value + @property + def PlugIns(self): + """ Gets the collection of enabled plug-ins for the managed + repository. """ + return self.__plugIns - @property - def PlugIns(self): - """ Gets the collection of enabled plug-ins for the managed repository. """ - return self.__plugIns + def __init__(self, repoName=None): + """ Initialises the object with the values from a managed repository - def __init__(self, repoName=None): - """ Initialises the object with the values from a managed repository - - @param[in] repoName The storage name of the managed repository - to load. - """ - from mercurial import ui, hg, error - import os + @param[in] repoName The storage name of the managed repository + to load. + """ + from mercurial import ui, hg, error + import os - self.__storageName = repoName - if repoName: - try: - self.__repo = hg.repository(ui.ui(), settings.RepositoryPath + os.sep + self.__storageName) - self.__displayName = self.__repo.ui.config('web', 'name', default=None) - self.__description = self.__repo.ui.config('web', 'description', default=None) - self.__contact = self.__repo.ui.config('web', 'contact', default=None) - self.__plugIns = [] - plugInList = self.__repo.ui.configitems('extensions') - for plugIn in plugInList: - self.__plugIns.append(RepositoryPlugin(plugIn[0], plugIn[1], self.__repo.ui.configitems(plugIn[0]))) - except error.RepoError: - self.__plugIns = [] - pass + self.__storageName = repoName + if repoName: + try: + self.__repo = hg.repository(ui.ui(), settings.RepositoryPath + + os.sep + self.__storageName) + self.__displayName = self.__repo.ui.config('web', 'name', + default=None) + self.__description = self.__repo.ui.config('web', + 'description', + default=None) + self.__contact = self.__repo.ui.config('web', 'contact', + default=None) + self.__plugIns = [] + plugInList = self.__repo.ui.configitems('extensions') + for plugIn in plugInList: + self.__plugIns.append(RepositoryPlugin( + plugIn[0], + plugIn[1], + self.__repo.ui.configitems(plugIn[0]))) + except error.RepoError: + self.__plugIns = [] + pass - def __eq__(self, other): - """ Determines if two repositories are the same repository. + def __eq__(self, other): + """ Determines if two repositories are the same repository. - @param[in] other The repository on the right-hand-side of the - equality operator to compare against. + @param[in] other The repository on the right-hand-side of the + equality operator to compare against. - @return Gives true when both repositories represent the same one, - else-wise gives false. - """ - return self.__storageName == other.__storageName + @return Gives true when both repositories represent the same one, + else-wise gives false. + """ + return self.__storageName == other.__storageName - def save(self): - """ Commits the repository detail properties to the repository - configuration file. + def save(self): + """ Commits the repository detail properties to the repository + configuration file. - @throws IOError When the configuration file for the repository - fails to be written. - """ - import os + @throws IOError When the configuration file for the repository + fails to be written. + """ + import os - with open(settings.RepositoryPath + os.sep + self.__storageName + os.sep + '.hg' + os.sep + 'hgrc', 'w') as hgrc: - #{ Repository Information Section + with open(settings.RepositoryPath + os.sep + self.__storageName + + os.sep + '.hg' + os.sep + 'hgrc', 'w') as hgrc: + # { Repository Information Section - hgrc.write('[web]\n') - if self.DisplayName is None: - hgrc.write('name = ' + self.StorageName + '\n') - else: - hgrc.write('name = ' + self.DisplayName + '\n') + hgrc.write('[web]\n') + if self.DisplayName is None: + hgrc.write('name = ' + self.StorageName + '\n') + else: + hgrc.write('name = ' + self.DisplayName + '\n') - if self.Description is not None: - hgrc.write('description = ' + self.Description + '\n') + if self.Description is not None: + hgrc.write('description = ' + self.Description + '\n') - if self.Contact is not None: - hgrc.write('contact = ' + self.Contact + '\n') + if self.Contact is not None: + hgrc.write('contact = ' + self.Contact + '\n') - #} Repository Information Section + # } Repository Information Section + + # { Plug-in Section - #{ Plug-in Section + if len(self.PlugIns) > 0: + hgrc.write('\n[extensions]\n') + for plugIn in self.PlugIns: + if plugIn.scriptFile is None: + hgrc.write(plugIn.name + ' =\n') + else: + hgrc.write(plugIn.name + ' = ' + plugIn.scriptFile + + '\n') - if len(self.PlugIns) > 0: - hgrc.write('\n[extensions]\n') - for plugIn in self.PlugIns: - if plugIn.scriptFile is None: - hgrc.write(plugIn.name + ' =\n') - else: - hgrc.write(plugIn.name + ' = ' + plugIn.scriptFile + '\n') - - #} Plug-in Section + # { Plug-in Settings Section - #{ Plug-in Settings Section + for plugIn in self.PlugIns: + if len(plugIn.settings) > 0: + hgrc.write("\n[%s]" % plugIn.name) + for setting in plugIn.settings: + hgrc.write("\n%s = %s" % (setting.name, + setting.value)) - for plugIn in self.PlugIns: - if len(plugIn.settings) > 0: - hgrc.write("\n[%s]" % plugIn.name) - for setting in plugIn.settings: - hgrc.write("\n%s = %s" % (setting.name, setting.value)) + # } Plug-in Settings Section - #} Plug-in Settings Section + # } Plug-in Section - self = Repository(self.StorageName) # Needed for when repositories are re-named. + # NOTE: Needed for when repositories are re-named. + self = Repository(self.StorageName) - def __str__(self): - """ Converts the object contents into a human-friendly string. """ - repo = "%s\n\tDisplay: %s\n\tDescription: %s\n\tContact: %s" % (self.StorageName, self.DisplayName, self.Description, self.Contact) - if len(self.PlugIns) > 0: - repo = repo + "\n\tPlug-ins:" - for plugIn in self.PlugIns: - repo = repo + "\n\t\t%s" % plugIn - return repo + def __str__(self): + """ Converts the object contents into a human-friendly string. """ + repo = "%s\n\tDisplay: %s\n\tDescription: %s\n\tContact: %s" % ( + self.StorageName, self.DisplayName, self.Description, self.Contact) + if len(self.PlugIns) > 0: + repo = repo + "\n\tPlug-ins:" + for plugIn in self.PlugIns: + repo = repo + "\n\t\t%s" % plugIn + return repo - def addPlugIn(self, plugIn): - """ Makes a plug-in in a repository enabled. + def addPlugIn(self, plugIn): + """ Makes a plug-in in a repository enabled. - @param[in] plugIn The plug-in that is to be enabled. + @param[in] plugIn The plug-in that is to be enabled. - @post The object now has the supplied plug-in as being enabled. + @post The object now has the supplied plug-in as being enabled. - @throws ValueError When the supplied plug-in is already enabled. - """ - if plugIn not in self.PlugIns: - self.__plugIns.append(plugIn) - else: - raise ValueError("The plug-in '%s' is already enabled." % plugIn.name) + @throws ValueError When the supplied plug-in is already enabled. + """ + if plugIn not in self.PlugIns: + self.__plugIns.append(plugIn) + else: + raise ValueError("The plug-in '%s' is already enabled." % + plugIn.name) - def removePlugIn(self, named): - """ Makes a plug-in in a repository disabled. + def removePlugIn(self, named): + """ Makes a plug-in in a repository disabled. - @param[in] named The name of the plug-in that is to be disabled. + @param[in] named The name of the plug-in that is to be disabled. - @post The object no longer has the supplied plug-in as being enabled. + @post The object no longer has the supplied plug-in as being enabled. - @throws ValueError When the supplied plug-in is already disabled. - """ - for plugIn in self.PlugIns: - if named == plugIn.name: - self.__plugIns.remove(plugIn) - return - raise ValueError("The plug-in '%s' is already disabled." % named) + @throws ValueError When the supplied plug-in is already + disabled. + """ + for plugIn in self.PlugIns: + if named == plugIn.name: + self.__plugIns.remove(plugIn) + return + raise ValueError("The plug-in '%s' is already disabled." % named) - def setSetting(self, plugInName, name, value): - """ Set's the setting of a plug-in - @details When the supplied value is None, the setting is removed. + def setSetting(self, plugInName, name, value): + """ Set's the setting of a plug-in + @details When the supplied value is None, the setting is removed. - @param[in] plugInName The name of the plug-in whose setting is - being set. - @param[in] name The name of the setting being set. - @param[in] value The value for the setting. + @param[in] plugInName The name of the plug-in whose setting is + being set. + @param[in] name The name of the setting being set. + @param[in] value The value for the setting. - @post The setting for the plug-in is modified to the supplied value. + @post The setting for the plug-in is modified to the supplied value. - @throws ValueError When the supplied plug-in name is not enabled. - """ - for plugIn in self.PlugIns: - if plugInName == plugIn.name: - plugInIndex = self.PlugIns.index(plugIn) - self.__plugIns[plugInIndex].setPlugInSetting(name, value) - return - raise ValueError("The plug-in '%s' is not enabled." % plugInName) + @throws ValueError When the supplied plug-in name is not enabled. + """ + for plugIn in self.PlugIns: + if plugInName == plugIn.name: + plugInIndex = self.PlugIns.index(plugIn) + self.__plugIns[plugInIndex].setPlugInSetting(name, value) + return + raise ValueError("The plug-in '%s' is not enabled." % plugInName) class RepositoryPlugin(object): - """ Manages a plug-in for a repository. """ - class PluginSetting(object): - """ Manages a plug-in setting found inside a repository. """ + """ Manages a plug-in for a repository. """ + class PluginSetting(object): + """ Manages a plug-in setting found inside a repository. """ - # The name of the plug-in setting. - __name = None - # The setting value for the of the plug-in option. - __value = None + # The name of the plug-in setting. + __name = None + # The setting value for the of the plug-in option. + __value = None - @property - def name(self): - """ Accessor to the option name for a plug-in. """ - return self.__name + @property + def name(self): + """ Accessor to the option name for a plug-in. """ + return self.__name - @property - def value(self): - """ Accessor to the option value for a plug-in option. """ - return self.__value + @property + def value(self): + """ Accessor to the option value for a plug-in option. """ + return self.__value - @value.setter - def value(self, value): - """ Mutator to the option value for a plug-in option. """ - self.__value = value + @value.setter + def value(self, value): + """ Mutator to the option value for a plug-in option. """ + self.__value = value - def __init__(self, name, value=None): - """ Initialises a plug-in setting. + def __init__(self, name, value=None): + """ Initialises a plug-in setting. - @param[in] name The name of the plug-in setting option. - @param[in] name The value for the plug-in setting option. + @param[in] name The name of the plug-in setting option. + @param[in] name The value for the plug-in setting option. - @post The object is ready for use. - """ - self.__name = name - self.__value = value + @post The object is ready for use. + """ + self.__name = name + self.__value = value - def __str__(self): - """ Constructs a string representation of the object and it's values. + def __str__(self): + """ Constructs a string representation of the object and it's values. - @return The representation in the form name => value - """ - return "%s => %s" % (self.name, self.value) - # The name of a repository plug-in. - __name = None - # The path and file-name of the script for the repository plug-in. - __scriptFile = None - # The supplied option settings for the repository plug-in. - __settings = None + @return The representation in the form name => value + """ + return "%s => %s" % (self.name, self.value) + # The name of a repository plug-in. + __name = None + # The path and file-name of the script for the repository plug-in. + __scriptFile = None + # The supplied option settings for the repository plug-in. + __settings = None - @property - def name(self): - """ The accessor to the name of a repository plug-in. """ - return self.__name + @property + def name(self): + """ The accessor to the name of a repository plug-in. """ + return self.__name - @property - def scriptFile(self): - """ The accessor to the path and file-name of the script for the - repository plug-in. - """ - return self.__scriptFile + @property + def scriptFile(self): + """ The accessor to the path and file-name of the script for the + repository plug-in. + """ + return self.__scriptFile - @property - def settings(self): - """ The accessor to the supplied option settings for the repository - plug-in. - """ - return self.__settings + @property + def settings(self): + """ The accessor to the supplied option settings for the repository + plug-in. + """ + return self.__settings - def __init__(self, name, scriptFile=None, plugInSettings=[]): - """ Initialises a plug-in. - @details The supplied plug-in setting must be a key-value pair - co-responding to the plug-in option name and it's value respectively. + def __init__(self, name, scriptFile=None, plugInSettings=[]): + """ Initialises a plug-in. + @details The supplied plug-in setting must be a key-value pair + co-responding to the plug-in option name and it's value respectively. - @param[in] name The name of the plug-in. - @param[in] scriptFile The path and file name of the script which - runs the plug-in. - @param[in] plugInSettings A list of settings for the plug-in. + @param[in] name The name of the plug-in. + @param[in] scriptFile The path and file name of the script which + runs the plug-in. + @param[in] plugInSettings A list of settings for the plug-in. - @post The object is ready for use. - """ - import os + @post The object is ready for use. + """ + import os - self.__name = name - if (scriptFile is not None and len(scriptFile) > 0): - if os.path.exists(scriptFile): - self.__scriptFile = scriptFile - else: - raise ValueError("The plug-in file '%s' was not found." % scriptFile) + self.__name = name + if (scriptFile is not None and len(scriptFile) > 0): + if os.path.exists(scriptFile): + self.__scriptFile = scriptFile + else: + raise ValueError("The plug-in file '%s' was not found." % + scriptFile) - self.__settings = [] - for plugInSetting in plugInSettings: - self.__settings.append(RepositoryPlugin.PluginSetting(plugInSetting[0], plugInSetting[1])) + self.__settings = [] + for plugInSetting in plugInSettings: + self.__settings.append(RepositoryPlugin.PluginSetting( + plugInSetting[0], plugInSetting[1])) - def __eq__(self, other): - """ Determines if two repository plug-ins are the same. + def __eq__(self, other): + """ Determines if two repository plug-ins are the same. - @param[in] other The plug-in on the right-hand-side of the - equality operator to compare against. + @param[in] other The plug-in on the right-hand-side of the + equality operator to compare against. - @return Gives true when both plug-ins represent the same one, - else-wise gives false. - """ - return self.name == other.name + @return Gives true when both plug-ins represent the same one, + else-wise gives false. + """ + return self.name == other.name - def __str__(self): - """ Converts the object contents into a human-friendly string. """ - plugIn = "" - if self.scriptFile is None: - plugIn = plugIn + self.name - else: - plugIn = plugIn + "%s -> %s" % (self.name, self.scriptFile) - for setting in self.settings: - plugIn = plugIn + "\n\t%s" % setting - return plugIn + def __str__(self): + """ Converts the object contents into a human-friendly string. """ + plugIn = "" + if self.scriptFile is None: + plugIn = plugIn + self.name + else: + plugIn = plugIn + "%s -> %s" % (self.name, self.scriptFile) + for setting in self.settings: + plugIn = plugIn + "\n\t%s" % setting + return plugIn - def setPlugInSetting(self, name, value): - """ Set's the plug-in setting. - @details When the plug-in setting already exists the supplied value - overwrites the existing one. When the setting does not exist, a new - entry is created. When the supplied value is None, the setting is - removed from the plug-in. + def setPlugInSetting(self, name, value): + """ Set's the plug-in setting. + @details When the plug-in setting already exists the supplied value + overwrites the existing one. When the setting does not exist, a new + entry is created. When the supplied value is None, the setting is + removed from the plug-in. - @param[in] name The name of the setting being set. - @param[in] value The value for the setting. + @param[in] name The name of the setting being set. + @param[in] value The value for the setting. - @post The setting for the plug-in is modified to the supplied value. - """ - for setting in self.settings: - if name == setting.name: - if value is None: - self.__settings.remove(setting) - else: - settingIndex = self.settings.index(setting) - self.__settings[settingIndex].value = value - return - self.__settings.append(RepositoryPlugin.PluginSetting(name, value)) + @post The setting for the plug-in is modified to the supplied value. + """ + for setting in self.settings: + if name == setting.name: + if value is None: + self.__settings.remove(setting) + else: + settingIndex = self.settings.index(setting) + self.__settings[settingIndex].value = value + return + self.__settings.append(RepositoryPlugin.PluginSetting(name, value)) class ManagedCollection(object): - """ A container of all the managed repositories. """ + """ A container of all the managed repositories. """ - # All the managed repositories - __repositories = [] + # All the managed repositories + __repositories = [] - @property - def Repositories(self): - """A collection of all managed repositories. + @property + def Repositories(self): + """A collection of all managed repositories. - @return An array of the managed repositories. - """ - return self.__repositories + @return An array of the managed repositories. + """ + return self.__repositories - def __init__(self): - """ Initialises the container with all the managed repositories. + def __init__(self): + """ Initialises the container with all the managed repositories. - @throws RuntimeError When the HgWeb configuration cannot be read. - """ - from ConfigParser import SafeConfigParser - import os + @throws RuntimeError When the HgWeb configuration cannot be read. + """ + from ConfigParser import SafeConfigParser + import os - parser = SafeConfigParser() - if not parser.read(settings.HgWebPath + os.sep + 'hgweb.config'): - raise RuntimeError("Failed to read HgWeb configuration.") + parser = SafeConfigParser() + if not parser.read(settings.HgWebPath + os.sep + 'hgweb.config'): + raise RuntimeError("Failed to read HgWeb configuration.") - for name, path in parser.items('paths'): - self.__repositories.append(Repository(name)) + for name, path in parser.items('paths'): + self.__repositories.append(Repository(name)) - def __str__(self): - """ Converts the object contents into a human-friendly string. """ - collection = "" - for repository in self.Repositories: - collection = collection + str(repository) + '\n' - collection.rstrip('\n') - return collection + def __str__(self): + """ Converts the object contents into a human-friendly string. """ + collection = "" + for repository in self.Repositories: + collection = collection + str(repository) + '\n' + collection.rstrip('\n') + return collection
--- a/src/manrepolock.py Tue Apr 07 20:03:21 2015 +0200 +++ b/src/manrepolock.py Fri Feb 19 18:45:37 2016 +0100 @@ -1,23 +1,24 @@ # -*- coding: utf-8 -*- -'''***************************************************************************** -*** This file is part of HgWeb Manager. *** -*** *** -*** Copyright (C) 2014 - 2015 *** -*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** -*** *** -*** This program is free software: you can redistribute it and/or modify it *** -*** under the terms of the GNU Affero General Public License as published *** -*** by the Free Software Foundation, either version 3 of the License, or *** -*** (at your option) any later version. *** -*** *** -*** This program is distributed in the hope that it will be useful, but *** -*** WITHOUT ANY WARRANTY; without even the implied warranty of *** -*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** -*** See the GNU Affero General Public License for more details. *** -*** *** -*** You should have received a copy of the GNU Affero General Public License*** -*** along with this program. If not, see <http://www.gnu.org/licenses/>. *** -*****************************************************************************''' +'''**************************************************************************** +*** This file is part of HgWeb Manager. *** +*** *** +*** Copyright (C) 2014 - 2016 *** +*** CodeGNU Solutions <Licensing _AT_ CodeGNU _DOT_ com> *** +*** *** +*** This program is free software: you can redistribute it and/or modify *** +*** it under the terms of the GNU Affero General Public License as *** +*** published by the Free Software Foundation, either version 3 of the *** +*** License, or (at your option) any later version. *** +*** *** +*** This program is distributed in the hope that it will be useful, but *** +*** WITHOUT ANY WARRANTY; without even the implied warranty of *** +*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *** +*** See the GNU Affero General Public License for more details. *** +*** *** +*** You should have received a copy of the GNU Affero General Public *** +*** License along with this program. If not, *** +*** see <http://www.gnu.org/licenses/>. *** +****************************************************************************''' import errno import os @@ -29,60 +30,61 @@ class RepositoryManagerLock(object): - """ Handles the locking for the repository manager. """ + """ Handles the locking for the repository manager. """ - def __init__(self): - """ Initialises the lock for use, but does not get one. """ - self.haveLock = False + def __init__(self): + """ Initialises the lock for use, but does not get one. """ + self.haveLock = False - def __isLockedProcessRunning(self): - """ Determines if a process is already running + def __isLockedProcessRunning(self): + """ Determines if a process is already running - @return When the process is running gives true, false else-wise. - """ - try: - with open(repositoryLockFile) as previousLock: - pid = int(previousLock.readline()) - os.kill(pid, 0) - return True - except OSError: - return False # Process is not running. + @return When the process is running gives true, false else-wise. + """ + try: + with open(repositoryLockFile) as previousLock: + pid = int(previousLock.readline()) + os.kill(pid, 0) + return True + except OSError: + return False # Process is not running. - def acquire(self): - """ Gets the repository lock. """ - while True: - try: - print 'Acquiring repository manager lock ...' - self.lock = os.open(repositoryLockFile, os.O_CREAT | os.O_EXCL | os.O_RDWR) - break - except OSError as e: - if e.errno != errno.EEXIST: - raise + def acquire(self): + """ Gets the repository lock. """ + while True: + try: + print 'Acquiring repository manager lock ...' + self.lock = os.open(repositoryLockFile, os.O_CREAT | + os.O_EXCL | os.O_RDWR) + break + except OSError as e: + if e.errno != errno.EEXIST: + raise - if not self.__isLockedProcessRunning(): - print 'A dead repository lock found, removing ...' - os.unlink(repositoryLockFile) - time.sleep(0.75) - self.haveLock = True - os.write(self.lock, str(os.getpid())) + if not self.__isLockedProcessRunning(): + print 'A dead repository lock found, removing ...' + os.unlink(repositoryLockFile) + time.sleep(0.75) + self.haveLock = True + os.write(self.lock, str(os.getpid())) - def release(self): - """ Frees the repository lock. """ - if self.haveLock: - print 'Releasing repository manager lock ...' - os.close(self.lock) - os.unlink(repositoryLockFile) - self.haveLock = False + def release(self): + """ Frees the repository lock. """ + if self.haveLock: + print 'Releasing repository manager lock ...' + os.close(self.lock) + os.unlink(repositoryLockFile) + self.haveLock = False - def __enter__(self): - if not self.haveLock: - self.acquire() - return self + def __enter__(self): + if not self.haveLock: + self.acquire() + return self - def __exit__(self, type, value, traceback): - if self.haveLock: - self.release() + def __exit__(self, type, value, traceback): + if self.haveLock: + self.release() - def __del__(self): - """ Ensures that when the object is gone, the lock is released. """ - self.release() + def __del__(self): + """ Ensures that when the object is gone, the lock is released. """ + self.release()