--- /dev/null
+#!/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
+