hook.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. """SCM hooks. Integration with git and mercurial."""
  2. from __future__ import absolute_import
  3. import sys
  4. from configparser import ConfigParser # noqa
  5. from os import chmod, getcwd
  6. from os import path as op
  7. from subprocess import PIPE, Popen
  8. from typing import List, Tuple
  9. from pylama.config import parse_options, setup_logger
  10. from pylama.main import LOGGER, check_paths, display_errors
  11. def run(command: str) -> Tuple[int, List[bytes], List[bytes]]:
  12. """Run a shell command."""
  13. with Popen(command.split(), stdout=PIPE, stderr=PIPE) as pipe:
  14. (stdout, stderr) = pipe.communicate()
  15. return (
  16. pipe.returncode,
  17. [line.strip() for line in stdout.splitlines()],
  18. [line.strip() for line in stderr.splitlines()],
  19. )
  20. def git_hook(error=True):
  21. """Run pylama after git commit."""
  22. _, files_modified, _ = run("git diff-index --cached --name-only HEAD")
  23. options = parse_options()
  24. setup_logger(options)
  25. candidates = [f.decode("utf-8") for f in files_modified]
  26. if candidates:
  27. errors = check_paths(candidates, options, rootdir=getcwd())
  28. display_errors(errors, options)
  29. sys.exit(int(error and bool(errors)))
  30. def hg_hook(_, repo, node=None, **kwargs): # noqa
  31. """Run pylama after mercurial commit."""
  32. seen = set()
  33. candidates = []
  34. if len(repo):
  35. for rev in range(repo[node], len(repo)):
  36. for file_ in repo[rev].files():
  37. file_ = op.join(repo.root, file_)
  38. if file_ in seen or not op.exists(file_):
  39. continue
  40. seen.add(file_)
  41. candidates.append(file_)
  42. options = parse_options()
  43. setup_logger(options)
  44. if candidates:
  45. errors = check_paths(candidates, options)
  46. display_errors(errors, options)
  47. sys.exit(int(bool(errors)))
  48. def install_git(path):
  49. """Install hook in Git repository."""
  50. hook = op.join(path, "pre-commit")
  51. with open(hook, "w", encoding="utf-8") as target:
  52. target.write(
  53. """#!/usr/bin/env python
  54. import sys
  55. from pylama.hook import git_hook
  56. if __name__ == '__main__':
  57. sys.exit(git_hook())
  58. """
  59. )
  60. chmod(hook, 484)
  61. def install_hg(path):
  62. """Install hook in Mercurial repository."""
  63. hook = op.join(path, "hgrc")
  64. if not op.isfile(hook):
  65. open(hook, "w+", encoding="utf-8").close()
  66. cfgp = ConfigParser()
  67. with open(hook, "r", encoding="utf-8") as source:
  68. cfgp.read_file(source)
  69. if not cfgp.has_section("hooks"):
  70. cfgp.add_section("hooks")
  71. if not cfgp.has_option("hooks", "commit"):
  72. cfgp.set("hooks", "commit", "python:pylama.hooks.hg_hook")
  73. if not cfgp.has_option("hooks", "qrefresh"):
  74. cfgp.set("hooks", "qrefresh", "python:pylama.hooks.hg_hook")
  75. with open(hook, "w+", encoding="utf-8") as target:
  76. cfgp.write(target)
  77. def install_hook(path):
  78. """Auto definition of SCM and hook installation."""
  79. is_git = op.join(path, ".git", "hooks")
  80. is_hg = op.join(path, ".hg")
  81. if op.exists(is_git):
  82. install_git(is_git)
  83. LOGGER.warning("Git hook has been installed.")
  84. elif op.exists(is_hg):
  85. install_hg(is_hg)
  86. LOGGER.warning("Mercurial hook has been installed.")
  87. else:
  88. LOGGER.error("VCS has not found. Check your path.")
  89. sys.exit(1)
  90. # pylama:ignore=F0401,E1103,D210,F0001