Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / dulwich / hooks.py @ 959

History | View | Annotate | Download (5.04 KB)

1
# hooks.py -- for dealing with git hooks
2
# Copyright (C) 2012-2013 Jelmer Vernooij and others.
3
#
4
# Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
5
# General Public License as public by the Free Software Foundation; version 2.0
6
# or (at your option) any later version. You can redistribute it and/or
7
# modify it under the terms of either of these two licenses.
8
#
9
# Unless required by applicable law or agreed to in writing, software
10
# distributed under the License is distributed on an "AS IS" BASIS,
11
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
# See the License for the specific language governing permissions and
13
# limitations under the License.
14
#
15
# You should have received a copy of the licenses; if not, see
16
# <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
17
# and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
18
# License, Version 2.0.
19
#
20

    
21
"""Access to hooks."""
22

    
23
import os
24
import subprocess
25
import sys
26
import tempfile
27

    
28
from dulwich.errors import (
29
    HookError,
30
)
31

    
32

    
33
class Hook(object):
34
    """Generic hook object."""
35

    
36
    def execute(self, *args):
37
        """Execute the hook with the given args
38

39
        :param args: argument list to hook
40
        :raise HookError: hook execution failure
41
        :return: a hook may return a useful value
42
        """
43
        raise NotImplementedError(self.execute)
44

    
45

    
46
class ShellHook(Hook):
47
    """Hook by executable file
48

49
    Implements standard githooks(5) [0]:
50

51
    [0] http://www.kernel.org/pub/software/scm/git/docs/githooks.html
52
    """
53

    
54
    def __init__(self, name, path, numparam,
55
                 pre_exec_callback=None, post_exec_callback=None):
56
        """Setup shell hook definition
57

58
        :param name: name of hook for error messages
59
        :param path: absolute path to executable file
60
        :param numparam: number of requirements parameters
61
        :param pre_exec_callback: closure for setup before execution
62
            Defaults to None. Takes in the variable argument list from the
63
            execute functions and returns a modified argument list for the
64
            shell hook.
65
        :param post_exec_callback: closure for cleanup after execution
66
            Defaults to None. Takes in a boolean for hook success and the
67
            modified argument list and returns the final hook return value
68
            if applicable
69
        """
70
        self.name = name
71
        self.filepath = path
72
        self.numparam = numparam
73

    
74
        self.pre_exec_callback = pre_exec_callback
75
        self.post_exec_callback = post_exec_callback
76

    
77
        if sys.version_info[0] == 2 and sys.platform == 'win32':
78
            # Python 2 on windows does not support unicode file paths
79
            # http://bugs.python.org/issue1759845
80
            self.filepath = self.filepath.encode(sys.getfilesystemencoding())
81

    
82
    def execute(self, *args):
83
        """Execute the hook with given args"""
84

    
85
        if len(args) != self.numparam:
86
            raise HookError("Hook %s executed with wrong number of args. \
87
                            Expected %d. Saw %d. args: %s"
88
                            % (self.name, self.numparam, len(args), args))
89

    
90
        if (self.pre_exec_callback is not None):
91
            args = self.pre_exec_callback(*args)
92

    
93
        try:
94
            ret = subprocess.call([self.filepath] + list(args))
95
            if ret != 0:
96
                if (self.post_exec_callback is not None):
97
                    self.post_exec_callback(0, *args)
98
                raise HookError("Hook %s exited with non-zero status"
99
                                % (self.name))
100
            if (self.post_exec_callback is not None):
101
                return self.post_exec_callback(1, *args)
102
        except OSError:  # no file. silent failure.
103
            if (self.post_exec_callback is not None):
104
                self.post_exec_callback(0, *args)
105

    
106

    
107
class PreCommitShellHook(ShellHook):
108
    """pre-commit shell hook"""
109

    
110
    def __init__(self, controldir):
111
        filepath = os.path.join(controldir, 'hooks', 'pre-commit')
112

    
113
        ShellHook.__init__(self, 'pre-commit', filepath, 0)
114

    
115

    
116
class PostCommitShellHook(ShellHook):
117
    """post-commit shell hook"""
118

    
119
    def __init__(self, controldir):
120
        filepath = os.path.join(controldir, 'hooks', 'post-commit')
121

    
122
        ShellHook.__init__(self, 'post-commit', filepath, 0)
123

    
124

    
125
class CommitMsgShellHook(ShellHook):
126
    """commit-msg shell hook
127

128
    :param args[0]: commit message
129
    :return: new commit message or None
130
    """
131

    
132
    def __init__(self, controldir):
133
        filepath = os.path.join(controldir, 'hooks', 'commit-msg')
134

    
135
        def prepare_msg(*args):
136
            (fd, path) = tempfile.mkstemp()
137

    
138
            with os.fdopen(fd, 'wb') as f:
139
                f.write(args[0])
140

    
141
            return (path,)
142

    
143
        def clean_msg(success, *args):
144
            if success:
145
                with open(args[0], 'rb') as f:
146
                    new_msg = f.read()
147
                os.unlink(args[0])
148
                return new_msg
149
            os.unlink(args[0])
150

    
151
        ShellHook.__init__(self, 'commit-msg', filepath, 1,
152
                           prepare_msg, clean_msg)