Start fleshing out mercurial hook

This also reports errors with hook installation using exceptions and
includes far more exceptions for mercurial since it has more failure
modes.
This commit is contained in:
Ian Cordasco 2016-06-13 20:36:44 -05:00
parent 53438fca1d
commit 6dca1d6fd7
No known key found for this signature in database
GPG key ID: 656D3395E4A9791A
4 changed files with 152 additions and 7 deletions

View file

@ -43,10 +43,52 @@ class InvalidSyntax(Flake8Exception):
super(InvalidSyntax, self).__init__(*args, **kwargs)
class GitHookAlreadyExists(Flake8Exception):
class HookInstallationError(Flake8Exception):
"""Parent exception for all hooks errors."""
pass
class GitHookAlreadyExists(HookInstallationError):
"""Exception raised when the git pre-commit hook file already exists."""
def __init__(self, *args, **kwargs):
"""Initialize the path attribute."""
self.path = kwargs.pop('path')
super(GitHookAlreadyExists, self).__init__(*args, **kwargs)
def __str__(self):
"""Provide a nice message regarding the exception."""
msg = ('The Git pre-commit hook ({0}) already exists. To convince '
'Flake8 to install the hook, please remove the existing '
'hook.')
return msg.format(self.path)
class MercurialHookAlreadyExists(HookInstallationError):
"""Exception raised when a mercurial hook is already configured."""
hook_name = None
def __init__(self, *args, **kwargs):
"""Initialize the relevant attributes."""
self.path = kwargs.pop('path')
self.value = kwargs.pop('value')
super(MercurialHookAlreadyExists, self).__init__(*args, **kwargs)
def __str__(self):
msg = ('The Mercurial {0} hook already exists with "{1}" in {2}. '
'To convince Flake8 to install the hook, please remove the '
'{0} configuration from the [hooks] section of your hgrc.')
return msg.format(self.hook_name, self.value, self.path)
class MercurialCommitHookAlreadyExists(MercurialHookAlreadyExists):
"""Exception raised when the hg commit hook is already configured."""
hook_name = 'commit'
class MercurialQRefreshHookAlreadyExists(MercurialHookAlreadyExists):
"""Exception raised when the hg commit hook is already configured."""
hook_name = 'qrefresh'

View file

@ -71,7 +71,9 @@ def install():
if not os.path.exists(hooks_directory):
os.mkdir(hooks_directory)
pre_commit_file = os.path.join(hooks_directory, 'hooks', 'pre-commit')
pre_commit_file = os.path.abspath(
os.path.join(hooks_directory, 'pre-commit')
)
if os.path.exists(pre_commit_file):
raise exceptions.GitHookAlreadyExists(
'File already exists',

View file

@ -4,13 +4,106 @@
.. autofunction:: install
"""
import configparser
import os
import subprocess
from flake8 import exceptions as exc
__all__ = ('hook', 'install')
def hook(lazy=False, strict=False):
pass
def hook(ui, repo, **kwargs):
"""Execute Flake8 on the repository provided by Mercurial.
To understand the parameters read more of the Mercurial documentation
around Hooks: https://www.mercurial-scm.org/wiki/Hook.
We avoid using the ``ui`` attribute because it can cause issues with
the GPL license tha Mercurial is under. We don't import it, but we
avoid using it all the same.
"""
from flake8.main import application
hgrc = find_hgrc(create_if_missing=False)
if hgrc is None:
print('Cannot locate your root mercurial repository.')
raise SystemExit(True)
hgconfig = configparser_for(hgrc)
strict = hgconfig.get('flake8', 'strict', fallback=True)
app = application.Application()
app.run()
if strict:
return app.result_count
return 0
def install():
pass
"""Ensure that the mercurial hooks are installed."""
hgrc = find_hgrc(create_if_missing=True)
if hgrc is None:
print('Could not locate your root mercurial repository.')
raise SystemExit(True)
hgconfig = configparser_for(hgrc)
if not hgconfig.has_section('hooks'):
hgconfig.add_section('hooks')
if hgconfig.has_option('hooks', 'commit'):
raise exc.MercurialCommitHookAlreadyExists(
path=hgrc,
value=hgconfig.get('hooks', 'commit'),
)
if hgconfig.has_option('hooks', 'qrefresh'):
raise exc.MercurialQRefreshHookAlreadyExists(
path=hgrc,
value=hgconfig.get('hooks', 'qrefresh'),
)
hgconfig.set('hooks', 'commit', 'python:flake8.main.mercurial.hook')
hgconfig.set('hooks', 'qrefresh', 'python:flake8.main.mercurial.hook')
if not hgconfig.has_section('flake8'):
hgconfig.add_section('flake8')
if not hgconfig.has_option('flake8', 'strict'):
hgconfig.set('flake8', 'strict', False)
with open(hgrc, 'w') as fd:
hgconfig.write(fd)
def find_hgrc(create_if_missing=False):
root = subprocess.Popen(
['hg', 'root'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
(hg_directory, _) = root.communicate()
if callable(getattr(hg_directory, 'decode', None)):
hg_directory = hg_directory.decode('utf-8')
if not os.path.isdir(hg_directory):
return None
hgrc = os.path.abspath(
os.path.join(hg_directory, '.hg', 'hgrc')
)
if not os.path.exists(hgrc):
if create_if_missing:
open(hgrc, 'w').close()
else:
return None
return hgrc
def configparser_for(path):
parser = configparser.ConfigParser(interpolation=None)
parser.read(path)
return parser

View file

@ -1,4 +1,5 @@
"""Module containing some of the logic for our VCS installation logic."""
from flake8 import exceptions as exc
from flake8.main import git
from flake8.main import mercurial
@ -20,8 +21,15 @@ def install(option, option_string, value, parser):
https://docs.python.org/2/library/optparse.html#optparse-option-callbacks
"""
installer = _INSTALLERS.get(value)
installer()
errored = False
try:
installer()
except exc.HookInstallationError as hook_error:
print(str(hook_error))
errored = True
raise SystemExit(errored)
def choices():
return _INSTALLERS.keys()
"""Return the list of VCS choices."""
return list(_INSTALLERS.keys())