summaryrefslogtreecommitdiff
blob: 7e3ebf755698a89920c9735cb2c1549e06853755 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#!/usr/bin/python -O
#
# /usr/sbin/webapp-config
#       Python script for managing the deployment of web-based
#       applications
#
#       Originally written for the Gentoo Linux distribution
#
# Copyright (c) 1999-2007 Authors
#       Released under v2 of the GNU GPL
#
# Author(s)     Stuart Herbert
#               Renat Lumpau   <rl03@gentoo.org>
#               Gunnar Wrobel  <wrobel@gentoo.org>
#
# ========================================================================
''' Helper functions for config protected files.'''

__version__ = "$Id: protect.py 133 2005-11-06 14:34:04Z wrobel $"

# ========================================================================
# Dependencies
# ------------------------------------------------------------------------

import re, os, os.path

import WebappConfig.wrapper

from WebappConfig.debug     import OUT

# ========================================================================
# Config protection helper class
# ------------------------------------------------------------------------

class Protection:
    '''
    A small helper class to handle config protection.
    '''

    def __init__(self, cat, pn, pvr, pm):
        '''
        This is distribution specific so the information is provided by
        wrapper.py
        '''
        self.config_protect = WebappConfig.wrapper.config_protect(cat, pn, pvr, pm)
        self.protect_prefix = WebappConfig.wrapper.protect_prefix
        self.update_command = WebappConfig.wrapper.update_command

    # ------------------------------------------------------------------------
    # Outputs:
    #   $my_return = the new mangled name (that you can use instead of
    #       $2)

    def get_protectedname(self,
                          destination,
                          filename):
        '''
        Woh.  Somewhere, we've decided that we're trying to overwrite a file
        that we really want to save.  So, we need a new name for the file that
        we want to install - which is where we come in.

        NOTE:
          The filename that we produce is compatible with Gentoo's
          etc-update tool.  This is deliberate.

        Inputs:
          destination -  the directory that the file is being installed into
          filename    - the original name of the file

        Let's test the code on some examples:

        >>> import os.path
        >>> here = os.path.dirname(os.path.realpath(__file__))

        >>> a = Protection('','horde','3.0.5','portage')
        >>> a.get_protectedname(here + '/tests/testfiles/protect/empty',
        ...                     'test')#doctest: +ELLIPSIS
        '.../tests/testfiles/protect/empty//._cfg0000_test'

        >>> a.get_protectedname(here + '/tests/testfiles/protect/simple',
        ...                     'test')#doctest: +ELLIPSIS
        '.../tests/testfiles/protect/simple//._cfg0001_test'

        >>> a.get_protectedname(here + '/tests/testfiles/protect/complex',
        ...                     'test')#doctest: +ELLIPSIS
        '.../tests/testfiles/protect/complex//._cfg0801_test'

        '''

        my_file    = os.path.basename(filename)
        my_filedir = destination + '/' + os.path.dirname(filename)

        # find the highest numbered protected file that already
        # exists, and increment it by one

        entries = os.listdir(my_filedir)

        OUT.debug('Identifying possible file number', 7)

        numbers = []
        prefix  = self.protect_prefix
        rep = re.compile(prefix.replace('.','\.') + '(\d{4})_')

        for i in entries:
            rem = rep.match(i)
            if rem:
                numbers.append(int(rem.group(1)))

        if numbers:
            max_n = max(numbers) + 1
        else:
            max_n = 0

        return  my_filedir + '/%s%.4d_%s' % (prefix, max_n, my_file)


    def dirisconfigprotected(self, installdir):
        '''
        Traverses the path of parent directories for the
        given install dir and checks if any matches the list
        of config protected files.

        >>> a = Protection('','horde','3.0.5','portage')

        Add a virtual config protected directory:

        >>> a.config_protect += ' /my/strange/htdocs/'
        >>> a.dirisconfigprotected('/my/strange/htdocs/where/i/installed/x')
        True
        >>> a.dirisconfigprotected('/my/strange/htdocs/where/i/installed/x/')
        True
        >>> a.config_protect += ' /my/strange/htdocs'
        >>> a.dirisconfigprotected('/my/strange/htdocs/where/i/installed/x')
        True
        >>> a.dirisconfigprotected('/my/strange/htdocs/where/i/installed/x/')
        True

        >>> a.config_protect += ' bad_user /my/strange/htdocs'
        >>> a.dirisconfigprotected('/my/bad_user/htdocs/where/i/installed/x')
        False
        >>> a.dirisconfigprotected('/my/strange/htdocs/where/i/installed/x/')
        True

        >>> a.dirisconfigprotected('/')
        False
        '''

        my_master = []
        for i in self.config_protect.split(' '):
            if i[0] == '/':
                if i[-1] == '/':
                    my_master.append(i[:-1])
                else:
                    my_master.append(i)

        if installdir[0] != '/':
            OUT.die('BUG! Don\'t call this with a relative path.')

        if installdir[-1] == '/':
            my_dir = installdir[:-1]
        else:
            my_dir = installdir

        while my_dir:

            if my_dir == '.' or my_dir == '/':
                return False

            for x in my_master:
                if my_dir == x:
                    return True

            my_dir = os.path.dirname(my_dir)

        # nope, the directory isn't config-protected at this time
        return False

    def how_to_update(self, dirs):
        '''
        Instruct the user how to update the application.

        >>> OUT.color_off()
        >>> a = Protection('','horde','3.0.5','portage')

        >>> a.how_to_update(['/my/strange/htdocs/where/i/installed/x'])
        * One or more files have been config protected
        * To complete your install, you need to run the following command(s):
        * 
        * CONFIG_PROTECT="/my/strange/htdocs/where/i/installed/x" etc-update
        * 
        >>> a.how_to_update(['/a/','/c/'])
        * One or more files have been config protected
        * To complete your install, you need to run the following command(s):
        * 
        * CONFIG_PROTECT="/a/" etc-update
        * CONFIG_PROTECT="/c/" etc-update
        * 
        >>> a.how_to_update(['/a//test3','/a//test3/abc', '/c/'])
        * One or more files have been config protected
        * To complete your install, you need to run the following command(s):
        * 
        * CONFIG_PROTECT="/a//test3" etc-update
        * CONFIG_PROTECT="/c/" etc-update
        * 

        Add a virtual config protected directory:

        >>> a.config_protect += ' /my/strange/htdocs/'
        >>> a.how_to_update(['/my/strange/htdocs/where/i/installed/x'])
        * One or more files have been config protected
        * To complete your install, you need to run the following command(s):
        * 
        * etc-update
        '''
        my_command = self.update_command

        directories = []

        for i in dirs:
            present = False
            if directories:
                for j in directories:
                    if (i == j[:len(i)] or 
                        j == i[:len(j)]):
                        present = True
                        break
            if not present:
                directories.append(i)

        my_command_list = ''

        for i in directories:
            if not self.dirisconfigprotected(i):
                my_command_list += 'CONFIG_PROTECT="' + i + '" ' + my_command + '\n'

        if not my_command_list:
            my_command_list = my_command

        OUT.warn('One or more files have been config protected\nTo comple'
                 'te your install, you need to run the following command(s):\n\n'
                 + my_command_list)

if __name__ == '__main__':
    import doctest, sys
    doctest.testmod(sys.modules[__name__])