summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <daniel.silverstone@codethink.co.uk>2012-10-01 16:06:27 +0100
committerDaniel Silverstone <daniel.silverstone@codethink.co.uk>2012-10-01 16:06:27 +0100
commitc1b4d19515b86d3216a6db3cebaf24ff16b2a0bb (patch)
treef1054bca5961243efecd4871d6101a5d0edc6c2e
parent6cf00a01a1bc271e281d7999f76ff8e3ab067509 (diff)
downloadlorry-controller-c1b4d19515b86d3216a6db3cebaf24ff16b2a0bb.tar.gz
Add initial configuration parser and ignores
-rw-r--r--.gitignore1
-rwxr-xr-xlorry-controller8
-rw-r--r--lorrycontroller/__init__.py4
-rw-r--r--lorrycontroller/confparser.py111
4 files changed, 124 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/lorry-controller b/lorry-controller
index 1ead6c7..1b2fb74 100755
--- a/lorry-controller
+++ b/lorry-controller
@@ -11,6 +11,7 @@ defaults = {
'work-area': '/home/lorry/controller-area'
}
+from lorrycontroller.confparser import LorryControllerConfig
class LorryController(cliapp.Application):
@@ -39,6 +40,13 @@ class LorryController(cliapp.Application):
self.rungit(['reset', '--hard', 'origin/master'])
self.rungit(['clean', '-fdx'])
+ if not os.path.exists('git/lorry-controller.conf'):
+ logging.error("Unable to find lorry-controller.conf in git")
+ raise SystemExit(4)
+
+ conf = LorryControllerConfig(self.settings,
+ 'git/lorry-controller.conf')
+
def rungit(self, args):
self.runcmd(['git']+args, cwd=os.path.join(self.settings['work-area'],
diff --git a/lorrycontroller/__init__.py b/lorrycontroller/__init__.py
new file mode 100644
index 0000000..3c29d56
--- /dev/null
+++ b/lorrycontroller/__init__.py
@@ -0,0 +1,4 @@
+# Copyright (C) 2012 Codethink Limited
+#
+
+import confparser
diff --git a/lorrycontroller/confparser.py b/lorrycontroller/confparser.py
new file mode 100644
index 0000000..ebe1316
--- /dev/null
+++ b/lorrycontroller/confparser.py
@@ -0,0 +1,111 @@
+# Copyright (C) 2012 Codethink Limited
+#
+
+import json
+import logging
+import re
+import glob
+import os
+
+default_values = [
+ ( u'serial', 0 ),
+ ( u'create', u'never' ),
+ ( u'destroy', u'never' ),
+ ( u'interval', u'1m' ),
+ ( u'stagger', False ),
+ ( u'type', u'invalid_type' ),
+]
+
+valid_whens = set(["always", "never", "unchanged"])
+valid_interval = re.compile(r"^([1-9][0-9]*)([mhd])?$")
+interval_mults = {
+ None: 1,
+ 'm': 60,
+ 'h': 60 * 60,
+ 'd': 60 * 60 * 24,
+}
+class LorryControllerConfig(object):
+ '''This encapsulates the configuration for lorry-controller.'''
+
+ def __init__(self, settings, confpath):
+ self.settings = settings
+ confpath = os.path.join(settings['work-area'], confpath)
+ logging.debug("Parsing configuration: %s" % confpath)
+ with open(confpath, "r") as fh:
+ self._raw_conf = json.load(fh)
+ logging.debug("Validating configuration semantics")
+ self._validate__raw_conf()
+ logging.debug("Configuration loaded")
+
+ def _validate__raw_conf(self):
+ '''Validate the entire raw config.'''
+ if type(self._raw_conf) != list:
+ self._give_up("Configuration was not a list.")
+ for entry in self._raw_conf:
+ if type(entry) != dict:
+ self._give_up("Configuration entry was not a dict.")
+ if type(entry.get('type', None)) != unicode:
+ self._give_up("Configuration entry lacked a suitable 'type' "
+ "field.")
+ # Set the defaults
+ for key, defval in default_values:
+ entry[key] = entry.get(key, defval)
+ # And validate the generic values such as serial
+ self._validate__generics(entry)
+ # Now validate the rest
+ validator = getattr(self, '_validate_' + entry['type'], None)
+ if validator is None:
+ self._give_up("Configuration entry had unknown type: %s" %
+ entry['type'])
+ validator(entry)
+
+ def _validate__generics(self, entry):
+ '''Validate the generic entries such as 'serial'.'''
+ for key, defval in default_values:
+ if type(defval) != type(entry[key]):
+ self._give_up("Invalid type for '%s': %r" % (key, entry[key]))
+ self._validate__when(entry, 'create')
+ if entry['create'] == "unchanged":
+ self._give_up("Invalid value for create: unchanged")
+ self._validate__when(entry, 'destroy')
+ entry['interval-parsed'] = self._parse_interval(entry['interval'])
+
+ def _validate__when(self, entry, key):
+ if entry[key] not in valid_whens:
+ self._give_up("Invalid value for %s: %s" % (key, entry[key]))
+
+ def _parse_interval(self, interval):
+ m = valid_interval.match(interval.lower())
+ if m is None:
+ self._give_up("Unable to parse '%s' as an interval" % interval)
+ num, mult = m.groups()
+ num = int(num)
+ mult = interval_mults.get(mult, None)
+ if mult is None:
+ self._give_up("Somehow, '%s' managed to appear as a multiplier!" %
+ m.group(2))
+ logging.debug("Converted interval %r to %r", interval, (num * mult))
+ return num * mult
+
+ def _validate_lorries(self, entry):
+ '''Validate a 'lorries' stanza.'''
+ if type(entry.get('globs', None)) != list:
+ self._give_up("Lorries stanzas need lists for their 'globs'")
+ all_lorries = set()
+ git_base = os.path.join(self.settings['work-area'], 'git')
+ for glob_entry in entry['globs']:
+ if type(glob_entry) != unicode:
+ self._give_up("Lorries globs should be strings")
+ fullglob = os.path.join(git_base, glob_entry)
+ all_lorries = all_lorries.union(set(glob.iglob(fullglob)))
+ for lorry in all_lorries:
+ if not lorry.startswith(git_base):
+ self._give_up("Glob found %s which is outside the git base")
+
+ logging.debug("Expanded globs in entry to %d lorries" %
+ len(all_lorries))
+ entry['lorries'] = all_lorries
+
+ def _give_up(self, *args, **kwargs):
+ logging.error(*args, **kwargs)
+ raise SystemExit(5)