# Copyright 2011-2014 Splunk, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"): you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os
import re
import sys
class Validator(object):
""" Base class for validators that check and format search command options.
You must inherit from this class and override :code:`Validator.__call__` and
:code:`Validator.format`. :code:`Validator.__call__` should convert the
value it receives as argument and then return it or raise a
:code:`ValueError`, if the value will not convert.
:code:`Validator.format` should return a human readable version of the value
it receives as argument the same way :code:`str` does.
"""
def __call__(self, value):
raise NotImplementedError()
def format(self, value):
raise NotImplementedError()
class Boolean(Validator):
""" Validates Boolean option values.
"""
truth_values = {
'1': True, '0': False,
't': True, 'f': False,
'true': True, 'false': False,
'y': True, 'n': False,
'yes': True, 'no': False
}
def __call__(self, value):
if not (value is None or isinstance(value, bool)):
value = str(value).lower()
if value not in Boolean.truth_values:
raise ValueError('Unrecognized truth value: %s' % value)
value = Boolean.truth_values[value]
return value
class Fieldname(Validator):
""" Validates field name option values.
"""
pattern = re.compile(r'''[_.a-zA-Z-][_.a-zA-Z0-9-]*$''')
def __call__(self, value):
value = str(value)
if Fieldname.pattern.match(value) is None:
raise ValueError('Illegal characters in fieldname: %s' % value)
return value
class File(Validator):
""" Validates file option values.
"""
def __init__(self, mode='r', buffering=-1):
self.mode = mode
self.buffering = buffering
def __call__(self, value):
if value is not None:
try:
path = str(value)
if not os.path.isabs(path):
path = os.path.join(File._var_run_splunk, path)
value = open(path, self.mode, self.buffering)
except IOError as e:
raise ValueError(
'Cannot open %s with mode=%s and buffering=%s: %s'
% (value, self.mode, self.buffering, e))
return value
def format(self, value):
return value.name
_var_run_splunk = os.path.join(
os.environ['SPLUNK_HOME'], "var", "run", "splunk")
class Integer(Validator):
""" Validates integer option values.
"""
def __init__(self, minimum=-sys.maxint-1, maximum=sys.maxint):
self.minimum = minimum
self.maximum = maximum
def __call__(self, value):
if value is not None:
value = int(value)
if not (self.minimum <= value <= self.maximum):
raise ValueError(
'Expected integer in the range [%d,%d]: %d'
% (self.minimum, self.maximum, value))
return value
class Duration(Validator):
""" Validates duration option values.
"""
def __call__(self, value):
if value is None:
return None
try:
p = value.split(':', 2)
_60 = Duration._60
_unsigned = Duration._unsigned
if len(p) == 1:
result = _unsigned(p[0])
if len(p) == 2:
result = 60 * _unsigned(p[0]) + _60(p[1])
if len(p) == 3:
result = 3600 * _unsigned(p[0]) + 60 * _60(p[1]) + _60(p[2])
except ValueError:
raise ValueError("Invalid duration value: %s", value)
return result
def format(self, value):
value = int(value)
s = value % 60
m = value / 60 % 60
h = value / (60 * 60)
return '%02d:%02d:%02d' % (h, m, s)
_60 = Integer(0, 59)
_unsigned = Integer(0)
class OptionName(Validator):
""" Validates option names.
"""
pattern = re.compile(r'''[a-zA-Z][_a-zA-Z0-9]*$''')
def __call__(self, value):
value = str(value)
if OptionName.pattern.match(value) is None:
raise ValueError('Illegal characters in option name: %s' % value)
return value
class RegularExpression(Validator):
""" Validates regular expression option values.
"""
def __call__(self, value):
value = str(value)
try:
value = re.compile(value)
except re.error as e:
raise ValueError('%s: %s' % (str(e).capitalize(), value))
return value
def format(self, value):
return value.pattern
class Set(Validator):
""" Validates set option values.
"""
def __init__(self, *args):
self.membership = args
def __call__(self, value):
if value is not None:
value = str(value)
if value not in self.membership:
raise ValueError('Unrecognized value: %s' % value)
return value