Revert "Make ReadConfigLine an iterator"
[mining-tools:gitdm.git] / ConfigFile.py
1 #
2 # Stuff for dealing with configuration files.
3 #
4 #
5 # This code is part of the LWN git data miner.
6 #
7 # Copyright 2007-11 Eklektix, Inc.
8 # Copyright 2007-11 Jonathan Corbet <corbet@lwn.net>
9 #
10 # This file may be distributed under the terms of the GNU General
11 # Public License, version 2.
12 #
13 import sys, re, datetime, os.path
14 import database
15
16 #
17 # Read a line and strip out junk.
18 #
19 def ReadConfigLine (file):
20     line = file.readline ()
21     if not line:
22         return None
23     line = line.split('#')[0] # Get rid of any comments
24     line = line.strip () # and extra white space
25     if len (line) == 0: # we got rid of everything
26         return ReadConfigLine (file)
27     return line
28
29 #
30 # Give up and die.
31 #
32 def croak (message):
33     sys.stderr.write (message + '\n')
34     sys.exit (1)
35
36 #
37 # Read a list of email aliases.
38 #
39 def ReadEmailAliases (name):
40     try:
41         file = open (name, 'r')
42     except IOError:
43         croak ('Unable to open email alias file %s' % (name))
44     line = ReadConfigLine (file)
45     while line:
46         m = re.match ('^("[^"]+"|\S+)\s+(.+)$', line)
47         if not m or len (m.groups ()) != 2:
48             croak ('Funky email alias line "%s"' % (line))
49         if m and m.group (2).find ('@') <= 0:
50             croak ('Non-addresses in email alias "%s"' % (line))
51         database.AddEmailAlias (m.group (1).replace ('"', ''), m.group (2))
52         line = ReadConfigLine (file)
53     file.close ()
54
55 #
56 # The Email/Employer map
57 #
58 EMMpat = re.compile (r'^([^\s]+)\s+([^<]+)\s*(<\s*(\d+-\d+-\d+)\s*)?$')
59
60 def ReadEmailEmployers (name):
61     try:
62         file = open (name, 'r')
63     except IOError:
64         croak ('Unable to open email/employer file %s' % (name))
65     line = ReadConfigLine (file)
66     while line:
67         m = EMMpat.match (line)
68         if not m:
69             croak ('Funky email/employer line "%s"' % (line))
70         email = m.group (1)
71         company = m.group (2).strip ()
72         enddate = ParseDate (m.group (4))
73         database.AddEmailEmployerMapping (email, company, enddate)
74         line = ReadConfigLine (file)
75     file.close ()
76
77 def ParseDate (cdate):
78     if not cdate:
79         return None
80     sdate = cdate.split ('-')
81     return datetime.date (int (sdate[0]), int (sdate[1]), int (sdate[2]))
82
83
84 def ReadGroupMap (fname, employer):
85     try:
86         file = open (fname, 'r')
87     except IOError:
88         croak ('Unable to open group map file %s' % (fname))
89     line = ReadConfigLine (file)
90     while line:
91         database.AddEmailEmployerMapping (line, employer)
92         line = ReadConfigLine (file)
93     file.close ()
94
95 #
96 # Read in a virtual employer description.
97 #
98 def ReadVirtual (file, name):
99     ve = database.VirtualEmployer (name)
100     line = ReadConfigLine (file)
101     while line:
102         sl = line.split (None, 1)
103         first = sl[0]
104         if first == 'end':
105             ve.store ()
106             return
107         #
108         # Zap the "%" syntactic sugar if it's there
109         #
110         if first[-1] == '%':
111             first = first[:-1]
112         try:
113             percent = int (first)
114         except ValueError:
115             croak ('Bad split value "%s" for virtual empl %s' % (first, name))
116         if not (0 < percent <= 100):
117             croak ('Bad split value "%s" for virtual empl %s' % (first, name))
118         ve.addsplit (' '.join (sl[1:]), percent/100.0)
119         line = ReadConfigLine (file)
120     #
121     # We should never get here
122     #
123     croak ('Missing "end" line for virtual employer %s' % (name))
124
125 #
126 # Read file type patterns for more fine graned reports
127 #
128 def ReadFileType (filename):
129     try:
130         file = open (filename, 'r')
131     except IOError:
132         croak ('Unable to open file type mapping file %s' % (filename))
133     patterns = {}
134     order = []
135     regex_order = re.compile ('^order\s+(.*)$')
136     regex_file_type = re.compile ('^filetype\s+(\S+)\s+(.+)$')
137     line = ReadConfigLine (file)
138     while line:
139         o = regex_order.match (line)
140         if o:
141             # Consider only the first definition in the config file
142             elements = o.group(1).replace (' ', '')
143             order = order or elements.split(',')
144             line = ReadConfigLine (file)
145             continue
146
147         m = regex_file_type.match (line)
148         if not m or len (m.groups ()) != 2:
149             ConfigFile.croak ('Funky file type line "%s"' % (line))
150         if not patterns.has_key (m.group (1)):
151             patterns[m.group (1)] = []
152         if m.group (1) not in order:
153             print '%s not found, appended to the last order' % m.group (1)
154             order.append (m.group (1))
155
156         patterns[m.group (1)].append (re.compile (m.group (2), re.IGNORECASE))
157
158         line = ReadConfigLine (file)
159     file.close ()
160     return patterns, order
161
162 #
163 # Read an overall config file.
164 #
165
166 def ConfigFile (name, confdir):
167     try:
168         file = open (name, 'r')
169     except IOError:
170         croak ('Unable to open config file %s' % (name))
171     line = ReadConfigLine (file)
172     while line:
173         sline = line.split (None, 2)
174         if len (sline) < 2:
175             croak ('Funky config line: "%s"' % (line))
176         if sline[0] == 'EmailAliases':
177             ReadEmailAliases (os.path.join (confdir, sline[1]))
178         elif sline[0] == 'EmailMap':
179             ReadEmailEmployers (os.path.join (confdir, sline[1]))
180         elif sline[0] == 'GroupMap':
181             if len (sline) != 3:
182                 croak ('Funky group map line "%s"' % (line))
183             ReadGroupMap (os.path.join (confdir, sline[1]), sline[2])
184         elif sline[0] == 'VirtualEmployer':
185             ReadVirtual (file, ' '.join (sline[1:]))
186         elif sline[0] == 'FileTypeMap':
187             patterns, order = ReadFileType (os.path.join (confdir, sline[1]))
188             database.FileTypes = database.FileType (patterns, order)
189         else:
190             croak ('Unrecognized config line: "%s"' % (line))
191         line = ReadConfigLine (file)
192