-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcheck_config.py
More file actions
340 lines (297 loc) · 11.4 KB
/
Copy pathcheck_config.py
File metadata and controls
340 lines (297 loc) · 11.4 KB
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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# Perforce Defect Tracking Integration Project
# <http://www.ravenbrook.com/project/p4dti/>
#
# CHECK_CONFIG.PY -- VALIDATE CONFIGURATION PARAMETERS
#
# Nick Barnes, Ravenbrook Limited, 2001-01-18
#
#
# 1. INTRODUCTION
#
# This module defines a set of functions that check that a parameter is
# suitable for a particular purpose (e.g., using as an e-mail address).
# They return if the parameter is suitable and raise a clear error
# message if it is not.
#
# Checking the configuration is intended to:
#
# 1. Keep the support cost low by allowing administrators to identify
# and fix incorrect configurations by themselves [Requirements, 35];
#
# 2. Keep installation time low by finding problems with the
# configuration early [Requirements, 63].
#
# See job000048, job000075, job000165, job000168 and job000170 for
# problems we've had with inadequate configuration checking.
#
# The intended readership of this document is project developers.
#
# This document is not confidential.
import catalog
import re
import types
error = "P4DTI configuration error"
# 2. CHECKING FUNCTIONS
# 2.1. Check that parameter is a boolean (0 or 1)
def check_bool(config, name):
param = getattr(config, name)
if param not in [0,1]:
# "Configuration parameter '%s' must be 0 or 1."
raise error, catalog.msg(200, name)
# 2.2. Check that parameter is a date
#
# We require dates to be strings of the form "2001-03-14 12:34:56" [ISO
# 8601].
def check_date(config, name):
param = getattr(config, name)
check_string(config, name)
date_re = "^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)$"
match = re.match(date_re, param)
if match:
year,month,date,hour,minute,second = map(int, match.groups())
if (1 <= month and month <= 12 and 1 <= date and date <= 31
and hour <= 23 and minute <= 59 and second <= 59):
return
# "Configuration parameter '%s' (value '%s') is not a valid date.
# The right format is 'YYYY-MM-DD HH:MM:SS'."
raise error, catalog.msg(201, (name, param))
# 2.3. Check that parameter looks like an e-mail address
#
# [RFC 822] defines an 'addr-spec' as follows.
#
# addr-spec = local-part "@" domain
# local-part = word *("." word)
# word = atom
# domain = sub-domain *("." sub-domain)
# sub-domain = domain-ref
# domain-ref = atom
# atom = 1*<any CHAR except specials, SPACE and CTLs>
# specials = "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "\"
# / <"> / "." / "[" / "]"
#
# (A CHAR is an ASCII character.)
#
# This isn't the full story. "Structured field bodies" in RFC822 also
# permit quoting, domain literals and comments. This code doesn't
# recognise these features. So users of the P4DTI will have to get by
# without.
def check_email(config, name):
param = getattr(config, name)
check_string(config, name)
atom_re = "[!#$%&'*+\\-/0-9=?A-Z^_`a-z{|}~]+"
email_re = "^%s(\\.%s)*@%s(\\.%s)*$" % (atom_re, atom_re,
atom_re, atom_re)
if not re.match(email_re, param):
# "Configuration parameter '%s' (value '%s') is not a valid
# e-mail address."
raise error, catalog.msg(202, (name, param))
# 2.4. Check that parameter is a Python function
def check_function(config, name):
param = getattr(config, name)
if (type(param) not in [types.FunctionType,
types.MethodType,
types.BuiltinFunctionType,
types.BuiltinMethodType]
and not hasattr(param, '__call__')):
# "Configuration parameter '%s' must be a function."
raise error, catalog.msg(203, name)
# 2.5. Check that parameter looks like a network host
#
# We don't do more than check that the parameter is a string. We could
# check that it matches a regexp or we could look it up in DNS. But in
# fact it's not a severe problem not fail to try to check that the host
# exists at this point, because the P4DTI tries to connect to all hosts
# (defect tracker, Perforce, SMTP) when it starts up so any problems
# will be found quickly.
def check_host(config, name):
check_string(config, name)
# 2.6. Check that parameter is an integer
def check_int(config, name):
param = getattr(config, name)
if not isinstance(param, types.IntType):
# "Configuration parameter '%s' must be an integer."
raise error, catalog.msg(204, name)
# 2.7. Check that parameter is a list
def check_list_of(config, name, type, typename):
check_list(config, name)
param = getattr(config, name)
for item in param:
if not isinstance(item, type):
# "Configuration parameter '%s' must be a list of %s."
raise error, catalog.msg(206, (name, typename))
def check_list_of_string_pairs(config, name):
check_list(config, name)
param = getattr(config, name)
for item in param:
if not (isinstance(item, types.TupleType) and
len(item) == 2 and
isinstance(item[0], types.StringType) and
isinstance(item[1], types.StringType)):
# "Configuration parameter '%s' must be a list of pairs of strings."
raise error, catalog.msg(212, name)
def check_list(config, name):
param = getattr(config, name)
if not isinstance(param, types.ListType):
# "Configuration parameter '%s' must be a list."
raise error, catalog.msg(205, name)
# 2.8. Check that parameter is a string
def check_string(config, name):
param = getattr(config, name)
if not isinstance(param, types.StringType):
# "Configuration parameter '%s' must be a string."
raise error, catalog.msg(207, name)
# 2.9. Check that parameter is a string or None
#
# This is used for optional configuration parameters.
def check_string_or_none(config, name):
param = getattr(config, name)
if not (param == None or
isinstance(param, types.StringType)):
# "Configuration parameter '%s' must be None or a string."
raise error, catalog.msg(208, name)
# 2.10. Check that parameter is an identifier
#
# Replicator and Perforce server identifiers must be from 1 to 32
# characters long, start with a letter or underscore, and consist only
# of letters, numbers and underscores.
def check_identifier(config, name):
param = getattr(config, name)
check_string(config, name)
if (len(param) < 1 or len(param) > 32
or not re.match('^[A-Za-z_][A-Za-z_0-9]*$', param)):
# "Configuration parameter '%s' (value '%s') must be from 1 to
# 32 characters long, start with a letter or number, and consist
# of letters, numbers and underscores only."
raise error, catalog.msg(209, (name, param))
# 2.11. Check that parameters is suitable for use as a changelist URL
#
# A changelist URL must contain exactly one instance of the %d format
# specifier. Any other percentage signs must be doubled.
def check_changelist_url(config, name):
param = getattr(config, name)
if param == None:
return
check_string(config, name)
i = 0
found = 0
while i < len(param):
if param[i] == '%':
i = i + 1
if i >= len(param) or param[i] not in "%d":
found = 0
break
if param[i] == 'd':
found = found + 1
i = i + 1
if found != 1:
# "Configuration parameter '%s' (value '%s') must contain
# exactly one %%d format specifier, any number of doubled
# percents, but no other format specifiers."
raise error, catalog.msg(210, (name, param))
# 2.12. Check that parameter is suitable for use as a job URL
#
# A job URL must contain exactly one instance of the %s format
# specifier. Any other percentage signs must be doubled.
def check_job_url(config, name):
param = getattr(config, name)
if param == None:
return
check_string(config, name)
i = 0
found = 0
while i < len(param):
if param[i] == '%':
i = i + 1
if i >= len(param) or param[i] not in "%s":
found = 0
break
if param[i] == 's':
found = found + 1
i = i + 1
if found != 1:
# "Configuration parameter '%s' (value '%s') must contain
# exactly one %%s format specifier, any number of doubled
# percents, but no other format specifiers."
raise error, catalog.msg(211, (name, param))
# A. REFERENCES
#
# [ISO 8601] "Representation of dates and times"; ISO; 1988-06-15.
#
# [Requirements] "Perforce Defect Tracking Integration Project
# Requirements"; Gareth Rees; Ravenbrook Limited; 2000-05-24;
# <http://www.ravenbrook.com/project/p4dti/req/>.
#
# [RFC 822] "Standard for the format of ARPA Internet text messages";
# David H Crocker; 1982-08-13; <ftp://src.doc.ic.ac.uk/rfc/rfc822.txt>.
#
#
# B. DOCUMENT HISTORY
#
# 2001-01-18 NB Moved from configure_bugzilla.py so we can share with
# other DTs.
#
# 2001-01-23 GDR Extended check_email so that it checks RFC822 address
# syntax.
#
# 2001-02-04 GDR Alphabetized. Added check_date.
#
# 2001-02-16 NB Added check_function (for checking replicate_p
# parameter).
#
# 2001-03-02 RB Transferred copyright to Perforce under their license.
#
# 2001-03-12 GDR Use messages when raising errors.
#
# 2001-03-14 GDR Formatted as a document; added references to
# requirements. The check_date function checks the range of the date
# components.
#
# 2001-03-15 GDR Added check_identifier.
#
# 2001-03-24 GDR Added check_changelist_url.
#
# 2001-07-09 NB Add check_job_url.
#
# 2001-11-21 GDR check_function() allows methods as well as ordinary
# functions. Check functions now take the module as the first argument
# instead of the parameter (this avoids duplicate of code and so reduces
# incorrect error messages).
#
# 2002-02-15 GDR Determine a function by the existence of a __call__
# method.
#
# 2003-11-25 NB Added check_list_of_string_pairs
#
#
# C. COPYRIGHT AND LICENSE
#
# This file is copyright (c) 2001 Perforce Software, Inc. All rights
# reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.
#
#
# $Id: //info.ravenbrook.com/project/p4dti/version/2.4/code/replicator/check_config.py#1 $