diff options
Diffstat (limited to 'gitlint/options.py')
-rw-r--r-- | gitlint/options.py | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/gitlint/options.py b/gitlint/options.py new file mode 100644 index 0000000..a1ae59c --- /dev/null +++ b/gitlint/options.py @@ -0,0 +1,122 @@ +from abc import abstractmethod +import os + +from gitlint.utils import ustr, sstr + + +class RuleOptionError(Exception): + pass + + +class RuleOption(object): + """ Base class representing a configurable part (i.e. option) of a rule (e.g. the max-length of the title-max-line + rule). + This class should not be used directly. Instead, use on the derived classes like StrOption, IntOption to set + options of a particular type like int, str, etc. + """ + + def __init__(self, name, value, description): + self.name = ustr(name) + self.description = ustr(description) + self.value = None + self.set(value) + + @abstractmethod + def set(self, value): + """ Validates and sets the option's value """ + pass # pragma: no cover + + def __str__(self): + return sstr(self) # pragma: no cover + + def __unicode__(self): + return u"({0}: {1} ({2}))".format(self.name, self.value, self.description) # pragma: no cover + + def __repr__(self): + return self.__str__() # pragma: no cover + + def __eq__(self, other): + return self.name == other.name and self.description == other.description and self.value == other.value + + def __ne__(self, other): + return not self.__eq__(other) # required for py2 + + +class StrOption(RuleOption): + def set(self, value): + self.value = ustr(value) + + +class IntOption(RuleOption): + def __init__(self, name, value, description, allow_negative=False): + self.allow_negative = allow_negative + super(IntOption, self).__init__(name, value, description) + + def _raise_exception(self, value): + if self.allow_negative: + error_msg = u"Option '{0}' must be an integer (current value: '{1}')".format(self.name, value) + else: + error_msg = u"Option '{0}' must be a positive integer (current value: '{1}')".format(self.name, value) + raise RuleOptionError(error_msg) + + def set(self, value): + try: + self.value = int(value) + except ValueError: + self._raise_exception(value) + + if not self.allow_negative and self.value < 0: + self._raise_exception(value) + + +class BoolOption(RuleOption): + def set(self, value): + value = ustr(value).strip().lower() + if value not in ['true', 'false']: + raise RuleOptionError(u"Option '{0}' must be either 'true' or 'false'".format(self.name)) + self.value = value == 'true' + + +class ListOption(RuleOption): + """ Option that is either a given list or a comma-separated string that can be splitted into a list when being set. + """ + + def set(self, value): + if isinstance(value, list): + the_list = value + else: + the_list = ustr(value).split(",") + + self.value = [ustr(item.strip()) for item in the_list if item.strip() != ""] + + +class PathOption(RuleOption): + """ Option that accepts either a directory or both a directory and a file. """ + + def __init__(self, name, value, description, type=u"dir"): + self.type = type + super(PathOption, self).__init__(name, value, description) + + def set(self, value): + value = ustr(value) + + error_msg = u"" + + if self.type == 'dir': + if not os.path.isdir(value): + error_msg = u"Option {0} must be an existing directory (current value: '{1}')".format(self.name, value) + elif self.type == 'file': + if not os.path.isfile(value): + error_msg = u"Option {0} must be an existing file (current value: '{1}')".format(self.name, value) + elif self.type == 'both': + if not os.path.isdir(value) and not os.path.isfile(value): + error_msg = (u"Option {0} must be either an existing directory or file " + u"(current value: '{1}')").format(self.name, value) + else: + error_msg = u"Option {0} type must be one of: 'file', 'dir', 'both' (current: '{1}')".format(self.name, + self.type) + + if error_msg: + raise RuleOptionError(error_msg) + + self.value = os.path.realpath(value) |