collection of useful functions
authorAlexander Kanevskiy <alexander.kanevskiy@intel.com>
Mon, 12 Aug 2013 21:45:32 +0000 (00:45 +0300)
committerAlexander Kanevskiy <alexander.kanevskiy@intel.com>
Mon, 12 Aug 2013 21:45:32 +0000 (00:45 +0300)
gerrithooks/misc.py [new file with mode: 0644]

diff --git a/gerrithooks/misc.py b/gerrithooks/misc.py
new file mode 100644 (file)
index 0000000..967cf86
--- /dev/null
@@ -0,0 +1,163 @@
+#!/usr/bin/env
+# -*- coding: UTF-8 -*-
+# vim: sw=4 ts=4 expandtab ai
+#
+# Copyright (c) 2013 Intel, Inc.
+# License: GPLv2
+# Author: Alexander Kanevskiy <alexander.kanevskiy@intel.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License, version 2,
+# as published by the Free Software Foundation.
+#
+# 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
+# General Public License for more details.
+
+""" Misc functions to use in rest of gerrit hooks modules (e.g. logging) """
+
+import os
+import sys
+import signal
+import subprocess
+import pwd
+
+import logging
+import logging.config
+
+
+def daemonize(stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
+    """Daemonize process"""
+    try:
+        pid = os.fork()
+        if pid > 0:
+            sys.exit(0) # Exit first parent.
+    except OSError, err:
+        sys.stderr.write("First fork failed: (%d) %sn" % \
+            (err.errno, err.strerror))
+        sys.exit(1)
+    os.setsid()
+    signal.signal(signal.SIGHUP, signal.SIG_IGN)
+    os.chdir("/")
+    os.umask(0)
+    try:
+        pid = os.fork()
+        if pid > 0:
+            sys.exit(0)
+    except OSError, err:
+        sys.stderr.write("Second fork failed: (%d) %sn" % \
+            (err.errno, err.strerror))
+        sys.exit(1)
+
+    for filed in sys.stdout, sys.stderr:
+        filed.flush()
+
+    new_stdin = open(stdin, 'r')
+    new_stdout = open(stdout, 'a+', 0)
+    new_stderr = open(stderr, 'a+', 0)
+    os.dup2(new_stdin.fileno(), sys.stdin.fileno())
+    os.dup2(new_stdout.fileno(), sys.stdout.fileno())
+    os.dup2(new_stderr.fileno(), sys.stderr.fileno())
+    sys.stdin, sys.stdout, sys.stderr = new_stdin, new_stdout, new_stderr
+
+
+def cmd_inout(command, args, cmd_input=None, extra_env=None, cwd=None,
+        capture_stderr=False, output_f=None, filter_fn=None, 
+        filter_kwargs={}, logger=None):
+    """
+    Run command in subprocess
+    """
+    env = os.environ.copy()
+    if extra_env is not None:
+        env.update(extra_env)
+    if not command:
+        return (None, None, -255)
+    cmd = [command] + args
+    debug_msg = " ".join(cmd)
+    if output_f:
+        debug_msg += " > %s" % output_f.name
+    if filter_fn:
+        debug_msg += ", filtering through %s()" % filter_fn.__name__
+    if logger:
+        logger.debug(debug_msg)
+
+    if not output_f:
+        output_f = subprocess.PIPE
+    stdout_arg = subprocess.PIPE if filter_fn else output_f
+    stderr_arg = subprocess.PIPE if capture_stderr else None
+    popen = subprocess.Popen(cmd,
+                             stdin=subprocess.PIPE,
+                             stdout=stdout_arg,
+                             stderr=stderr_arg,
+                             env=env,
+                             cwd=cwd)
+    if filter_fn:
+        if filter_fn(popen.stdout, output_f, **filter_kwargs):
+            raise Exception("Filtering command output in failed!")
+    (stdout, stderr) = popen.communicate(cmd_input)
+
+    return stdout, stderr, popen.returncode
+
+def parse_gitconfig(input_cfg=None):
+    """
+    Read configuration data from git.
+
+    This internal method populates the GitConfig cache.
+
+    """
+    cfg = {}
+    if input_cfg is None or not input_cfg:
+        return cfg
+    for line in input_cfg.rstrip('\0').split('\0'):  # pylint: disable=W1401
+                                             # Backslash is not anomalous
+        if '\n' in line:
+            key, val = line.split('\n', 1)
+        else:
+            key = line
+            val = None
+        if key in cfg:
+            cfg[key].append(val)
+        else:
+            cfg[key] = [val]
+    return cfg
+
+def find_config(name, dirs=None, subdir=None):
+    """Find readable configuration file in the list of dirs."""
+
+    if not dirs:
+        homedir = pwd.getpwuid(os.getuid()).pw_dir
+        dirs = []
+        if subdir:
+            dirs.append(os.path.join(homedir,"."+subdir))
+            dirs.append(os.path.join("/etc", subdir))
+        else:
+            dirs.append(homedir)
+            dirs.append("/etc")
+    for dirname in dirs:
+        confpath = os.path.join(dirname, name)
+        if os.access(confpath, os.R_OK):
+            return confpath
+    return None
+
+def configure_logging(appname):
+    """Setup logging"""
+    homedir = pwd.getpwuid(os.getuid()).pw_dir
+
+    log_confname = "gerrit-hooks-log.conf"
+    log_config = find_config(log_confname, subdir="gerrit-hooks")
+    if not log_config:
+        raise SystemExit("Log configuration file %s not found or not readable" \
+                % log_confname)
+
+    if sys.platform == 'darwin':
+        syslog_socket = "/var/run/syslog"
+    else:
+        syslog_socket = "/dev/log"
+
+    # Configure logging
+    logging.config.fileConfig(log_config, {'syslog_socket': syslog_socket})
+    logger = logging.getLogger(appname)
+    logger.debug("configure_logging: using logging config %s", log_config)
+    return logger
+