source: repositoryhooksystemplugin/0.11/repository_hook_system/filesystemhooks.py

Last change on this file was 6999, checked in by Jeff Hammel, 14 years ago

wrap file mode operations in try except, fixes #6135

File size: 5.3 KB
Line 
1import os
2import repository_hook_system.listener as listener
3
4from repository_hook_system.interface import IRepositoryHookSetup
5from repository_hook_system.listener import command_line
6from repository_hook_system.listener import option_parser
7from trac.core import *
8from utils import command_line_args
9from utils import iswritable
10
11class FileSystemHooks(Component):
12    """
13    Implementation of IRepositoryHookSetup for hooks that live on the
14    filesystem.  Currently, the filenames associated with the hooks must
15    be the same as the hook names
16    """
17   
18    implements(IRepositoryHookSetup)
19    abstract = True
20    mode = 0750 # mode to write hook files
21
22    ### these methods must be implemented by the provider class
23
24    def filename(self, hookname):
25        raise NotImplementedError
26
27    def args(self):
28        raise NotImplementedError
29
30    ### methods for manipulating the files
31
32    def file_contents(self, hookname):
33        """
34        return the lines of the file for a given hook,
35        or None if the file does not yet exist
36        """ 
37        filename = self.filename(hookname)
38        if not os.path.exists(filename):
39            return None
40
41        f = file(filename)
42        retval =  [ i.rstrip() for i in f.readlines() ]
43        f.close()
44        return retval
45
46    def marker(self):
47        """marker to place in the file to identify the hook"""
48        return "# trac repository hook system"
49
50    def projects_enabled(self, hookname):
51        """
52        returns enabled projects, or None if the stub is not found
53        returns a tuple of (lines, index, list_of_projects) when found
54        this won't work properly if the command line is used more than once
55        in the file
56        """
57        lines = self.file_contents(hookname)
58        if lines is None:
59            return None
60
61        retval = None
62        invoker = listener.filename()
63        for index, line in enumerate(lines):
64            if ' %s ' % invoker in line and not line.strip().startswith('#'):
65                if retval is not None:
66                    # TODO: raise an error indicate that multiple invocations
67                    # detected in the hook file
68                    pass 
69                args = command_line_args(line)
70                parser = option_parser()
71                options, args = parser.parse_args(args)
72                retval = index, lines, options.projects
73
74        return retval
75
76    def create(self, hookname):
77        """create the stub for given hook and return the file object"""
78       
79        filename = self.filename(hookname)
80        try:
81            os.mknod(filename, self.mode)
82        except: # won't work on windows
83            pass
84        f = file(filename, 'w')
85        print >> f, "#!/bin/bash"
86        return f
87
88    ### methods for IRepositoryHookSetup
89
90    def enable(self, hookname):
91        # TODO:  remove multiple blank lines when writing
92
93        if self.is_enabled(hookname):
94            return # nothing to do
95
96        if not self.can_enable(hookname):
97            return # XXX err more gracefully
98
99        def print_hook(f):
100            print >> f, '%s%s' % (os.linesep, self.marker())
101            print >> f, command_line(self.env.path, hookname, *self.args())
102
103        filename = self.filename(hookname)
104        if os.path.exists(filename):
105            projects = self.projects_enabled(hookname)
106            if projects is None:           
107                f = file(filename, 'a')
108                print_hook(f)               
109            else:
110                project = os.path.realpath(self.env.path)
111                index, lines, projects = projects
112                projects.append(project)
113                lines[index] = command_line(projects, hookname, *self.args())
114                f = file(filename, 'w')
115                for line in lines:
116                    print >> f, line                   
117        else:
118            f = self.create(hookname)
119            print_hook(f)
120           
121        f.close()
122
123    def disable(self, hookname):
124        if not self.is_enabled(hookname):
125            return 
126        index, lines, projects = self.projects_enabled(hookname)
127        projects = [ os.path.realpath(project) 
128                     for project in projects ]
129        project = os.path.realpath(self.env.path)
130       
131        projects.remove(project)
132        if projects:
133            lines[index] = command_line(projects, hookname, *self.args())
134        else:
135            lines.pop(index)
136            # TODO: list bounds checking
137            if lines[index-1] == self.marker():
138                index = index-1
139                lines.pop(index)
140            if not lines[index-1].strip():
141                lines.pop(index-1)
142           
143        f = file(self.filename(hookname), 'w')
144        for line in lines:
145            print >> f, line
146        f.close()
147
148    def is_enabled(self, hookname):
149        if os.path.exists(self.filename(hookname)):
150            projects = self.projects_enabled(hookname)
151            if projects is not None:
152                index, lines, projects = projects
153                projects = [ os.path.realpath(project) for project in projects ]
154                project = os.path.realpath(self.env.path)
155                if project in projects: 
156                    return True
157        return False
158
159    def can_enable(self, hookname):
160        return iswritable(self.filename(hookname))
Note: See TracBrowser for help on using the repository browser.