# SPLAT! config variables and default settings. # # Do not edit this file to change your configuration. Instead, # copy and edit ../splat.conf. See the comments in that file # for installation details. # # Read the rest of this file for information on what variables # you can set and what to set them to. # # $Id: config.py 20220 2003-01-16 21:19:50Z akuchlin $ # Since SPLAT! is a Quixote application, all Quixote config variables # apply to SPLAT!. In addition to the variables listed here, you can # set any of Quixote's config variables in splat.conf. # # In particular, Quixote defines a number of variables that affect # SPLAT!'s performance and security: # DISPLAY_EXCEPTIONS (security) # SECURE_ERRORS (security) # RUN_ONCE (performance) # (The default settings prefer performance and security over # convenience, so you might want to change them for testing/ # debugging.) # # See Quixote's config.py for details on its config variables. # ---------------------------------------------------------------------- # Essential variables # (must be set in splat.conf) # BASE_URL is the absolute URL used to access your SPLAT! bug database # via the web. It's needed so the splat_mail script can put the URL of # your bug database in e-mail it generates. BASE_URL should *not* end # with a slash. Example: # BASE_URL = "http://www.example.com/bugs" BASE_URL = None # Note that all email addresses are represented as tuples # (email_address, real_name) # so that automated messages sent out by the system have nice, friendly # "From" and "To" headers. For example: # ADMIN_ADDR = ("bugs-admin@example.com", "SPLAT! Administrator") # ADMIN_ADDR is the email address that will be used as the SMTP sender # address of all automated messages sent by SPLAT!. It will also be # used as the "From" address for all email that recipients aren't # supposed to reply to. Make this an alias to a human (probably # yourself) so you can receive bounce messages, find out who is being # confused by SPLAT! messages (and when), etc. ADMIN_ADDR = None # BUG_ADDR is the email address that people use to correspond directly # with SPLAT!: bug submissions and updates are sent here. Make sure # your email system is configured to pipe messages received by this # address to the "splat_mail" script. BUG_ADDR = None # These three control the session cookie that SPLAT! user to attach # users to their sessions. You must set SESSION_COOKIE_DOMAIN to the # name of your server (or domain), and SESSION_COOKIE_PATH should be set # to the URL path where your SPLAT! database is accessed, relative to # SESSION_COOKIE_DOMAIN. For example: # SESSION_COOKIE_DOMAIN = "www.example.com" # SESSION_COOKIE_PATH = "/bugs/" SESSION_COOKIE_NAME = "splat_session" SESSION_COOKIE_DOMAIN = None SESSION_COOKIE_PATH = None # ---------------------------------------------------------------------- # Very important filename variables # (almost certainly need to be set in splat.conf) # DB_FILENAME is the name of the file containing the SPLAT! bug # database. If it doesn't exist, it will be created for you. If you # want to support multiple bug databases, you'll have to have different # instances of the splat.fcgi script, different config files, different # URL prefixes to browse them, and different BUG_ADDR email addresses # for submitting to them. DB_FILENAME = None # DEBUG_LOG and ERROR_LOG are actually Quixote configuration # variables; see quixote's config.py for details. # ---------------------------------------------------------------------- # Non-essential email addresses # (might be useful to set in splat.conf) # The next three variables are lists of addresses, used as follows: # - NEWBUG_ADDRS - notified for every new bug submission # - CHANGE_ADDRS - notified for every change to any bug (except # for creation and resolution) # - RESOLVE_ADDRS - notified for every bug resolution # Normally, the latter two are empty, since the per-bug nosy lists are # supposed to take care of notifying everyone interested in a bug. If # you have (or are!) a control-freak micro-manager who likes to know # every little thing going on with bugs in your system, you could add # their address to CHANGE_ADDRS and RESOLVE_ADDRS. NEWBUG_ADDRS = [] CHANGE_ADDRS = [] RESOLVE_ADDRS = [] # If MAIL_DEBUG_ADDR is provided, all e-mail generated by SPLAT! is # instead sent only to this address. If you're testing, hacking on, or # debugging SPLAT!, you should probably set this to your own email # address. MAIL_DEBUG_ADDR = None # ---------------------------------------------------------------------- # Bug classification scheme # (don't mess with these until you get SPLAT! working) # Config variables to customize SPLAT!'s model of a bug. You can't # change the fact that SPLAT! classifies bugs along three axes: # * bug type (a somewhat vague value-judgment about the character # of the bug; NOT to be confused with priority) # * bug component (the component of your software responsible for # the bug) # * bug priority (an integer, by default 1 .. 5) # But you can change the possible values for those three axes, as # well as the possible bug resolutions, using the following variables. # BUG_TYPES allows you to distinguish different types of bugs without # making a value judgment about the priority of fixing the bug, or a # technical judgment about which component of the software is # responsible. # # Separating bug type from bug priority is useful because, for # example, a usability problem that affects every user every time # they use the software might be higher priority than a crash # that happens only on alternate Tuesdays in months ending in "y" # for users with red hair. ;-) BUG_TYPES = ["security", "crash", "data mangled", "data checking", "usability", "appearance", "feature request", "design flaw", "missing info", ] BUG_TYPE_EXPLANATION = { "security": "endangers the integrity of your server, " "the privacy of a user, or any other " "sensitive information", "crash": "causes an immediate fatal error in your " "software, rendering it temporarily unusable", "data mangled": "lose/garble user input, or store it incorrectly " "in database", "data checking": "incorrect/inadequate checking of user input " "leading to bad data in the database", "usability": "unnecessarily confusing or awkward user interface", "appearance": "aesthetic unpleasantness, spelling/grammatical error", "feature request": "new functionality that needs to be added", "design flaw": "fundamental flaw in design that needs to be " "addressed by re-thinking part of the system from " "the ground up", "missing info": "fundamental domain information missing, not " "available, or not known to software group", } # BUG_PRIORITIES allows you to change the number of priority levels for # your software and the descriptions attached to them. Priority level 1 # is highest priority, and N (where N is the length of the # BUG_PRIORITIES list) is the lowest (this generally only matters when # sorting bugs by priority level). BUG_PRIORITIES = ["critical", "serious", "moderate", "low", "unimportant", ] BUG_PRIORITY_EXPLANATION = { "critical": "must be fixed immediately -- nothing else matters", "serious": "must be fixed before the next release", "moderate": "should be fixed in the next few releases", "low": "would be nice to fix eventually", "unimportant": "don't really have to fix this", } # BUG_COMPONENTS lets you categorize bugs according to components of # your software. Obviously, this depends on the nature of your # software, so there is no default value; if you leave it as None, users # will be allowed to supply anything for the bug component (probably not # a good idea). It should be a list of strings. BUG_COMPONENTS = [] BUG_COMPONENT_EXPLANATION = {} # BUG_RESOLUTIONS lists the possible ways you can resolve a bug. Only # resolved bugs have a resolution, obviously; and every resolved bug # also has a textual explanation of how it was resolved. BUG_RESOLUTIONS = ["not a bug", "fixed", "already fixed", "out-of-date", "refused", "deferred", "irreproducible", "duplicate", "external", ] BUG_RESOLUTION_EXPLANATION = { "not a bug": "the behaviour described is the intended behaviour " "according to the software's specification, design, " "and implementation", "fixed": "bug has been fixed as a result of this bug report", "already fixed": "bug was already fixed as a result of another report, " "although the fix may not have been released yet", "out-of-date": "the information in this bug report is no longer " "relevant to the current code", "refused": "this is a bug, but it will not be fixed", "deferred": "bug will be fixed in a future release", "irreproducible": "all attempts to reproduce the bug failed, and reading " "the code showed no clue as to why the observed " "behaviour might be happening", "duplicate": "this bug report is essentially identical to a " "previous bug report (not necessarily fixed yet)", "external": "this is a bug in external software", } # ---------------------------------------------------------------------- # No user-serviceable parts after this point. from types import StringType, ListType, TupleType from urlparse import urlparse from quixote.config import Config as BaseConfig, ConfigError from optik import OptionParser as BaseOptionParser, Option class Config (BaseConfig): config_vars = BaseConfig.config_vars + [ 'base_url', 'db_filename', 'admin_addr', 'bug_addr', 'newbug_addrs', 'change_addrs', 'resolve_addrs', 'bug_types', 'bug_type_explanation', 'bug_priorities', 'bug_priority_explanation', 'bug_components', 'bug_component_explanation', 'bug_resolutions', 'bug_resolution_explanation', ] def _is_mailbox (self, val): return (type(val) is TupleType and map(type, val) == [StringType, StringType]) def _check_mailbox (self, source, var): val = getattr(self, var) if not (val is None or self._is_mailbox(val)): raise ConfigError("must be a pair of strings, not %r" % (val,), source, var) def _check_mailbox_list (self, source, var): val = getattr(self, var) if val is None: return if type(val) is not ListType: raise ConfigError( "must be a list of email addresses, not %r" % (val,), source, var) for v in val: if not self._is_mailbox(v): raise ConfigError( "each element of the list must be a " "pair of strings, not %r" % (v,), source, var) def check_values (self, source): self._check_mailbox(source, 'mail_from') self._check_mailbox(source, 'admin_addr') self._check_mailbox(source, 'bug_addr') self._check_mailbox_list(source, 'newbug_addrs') self._check_mailbox_list(source, 'change_addrs') self._check_mailbox_list(source, 'resolve_addrs') def read_defaults (self): self.read_from_module("quixote.config") self.read_from_module("splat.config") def get_base_url (self, absolute=1): """ Return the base URL for this SPLAT! installation, ie. the URL of the bug index web page. """ if absolute: return self.base_url else: # Return just the path component of base_url. return urlparse(self.base_url)[2] def get_bug_url (self, bug, absolute=1): return "%s/%s/" % (self.get_base_url(absolute), bug) def is_valid_bug_type (self, bug_type): return bug_type in self.bug_types def get_bug_type_explanation (self, bug_type): return self.bug_type_explanation[bug_type] def is_valid_priority (self, priority): return 1 <= priority <= len(self.bug_priorities) def get_max_priority (self): return len(self.bug_priorities) def get_priority_description (self, priority): if not self.is_valid_priority(priority): raise ValueError, "invalid bug priority: %s" % priority return self.bug_priorities[priority-1] def get_priority_explanation (self, priority): return self.bug_priority_explanation[self.bug_priorities[priority-1]] def is_valid_component (self, component): return self.bug_components is None or component in self.bug_components def get_component_explanation (self, component): if self.bug_component_explanation is None: return None else: return self.bug_component_explanation.get(component) def is_valid_resolution (self, resolution): return resolution in self.bug_resolutions def get_resolution_explanation (self, resolution): return self.bug_resolution_explanation[resolution] class OptionParser (BaseOptionParser): standard_option_list = BaseOptionParser.standard_option_list + [ Option("-f", "--db-file", type="string", dest="db_filename", help="open bug database in FILE", metavar="FILE"), Option("-c", "--config-file", type="string", dest="config_file", help="read configuration data from FILE", metavar="FILE"), ] _config = None def get_config (options=None): """get_config(options : optik.Values) -> splat.config.Config Given the following inputs: * the standard SPLAT! configuration options * a collection of command-line option values in 'options' * a user-specified config file (the "-c" option) assembles a single Config object that encompasses all those preferences. You only need to pass 'options' the first time you call get_config() in a given process. After that first call, a pre-initialized config object is returned. """ import sys global _config if _config is None: if options is None: raise RuntimeError( "config object not initialized yet -- " "pass 'options' object to get_config() the first time") _config = Config() try: if options.config_file: _config.read_file(options.config_file) if options.db_filename: _config.db_filename = options.db_filename except ConfigError, err: sys.exit("error: " + str(err)) if _config.db_filename is None: sys.exit( "error: no database filename given; either use -f to set it directly,\n" " or -c to point to a config file that sets DB_FILENAME.") return _config