Project

General

Profile

1
#!/usr/bin/env python
2
# Translates a data dictionary spreadsheet to Redmine formatting
3

    
4
import csv
5
import re
6
import sys
7

    
8
# Spreadsheet format
9
source_sep = ', '
10

    
11
##### URLs
12

    
13
url_comment_re = r'(?:\([^)]*\))'
14

    
15
def simplify_url(url): return re.sub(r'\(.*?\)', r'', url)
16

    
17
def url_comment_text(comment):
18
    if not comment: return comment
19
    
20
    match = re.match(r'^\(\d*:?(.*?)\)$', comment)
21
    assert match
22
    text, = match.groups()
23
    return text
24

    
25
def url_term(url):
26
    '''Prefixes any provider in the URL to the term name, to create a namespace.
27
    Each hierarchical component of the provider is stored in a URL comment.
28
    '''
29
    match = re.match(r'^('+url_comment_re+r'*).*?([\w:-]+)$', url)
30
    assert match
31
    provider_str, term = match.groups()
32
    provider = filter(bool, map(url_comment_text,
33
        re.findall(url_comment_re, provider_str)))
34
    
35
    return ':'.join(provider+[term])
36

    
37
##### Redmine
38

    
39
sp = ' ' # Unicode thin space
40

    
41
def redmine_bold(text): return '*'+text+'*'
42

    
43
def redmine_url(text, url):
44
    if url: return '"'+text+'":'+url
45
    else: return text
46

    
47
def source2redmine_url(url):
48
    if url: return redmine_url(url_term(url), simplify_url(url))
49
    else: return ''
50

    
51
def redmine_add_links(page_name, text):
52
    # Link citations to entry in sources list
53
    text = re.sub(r'(?<=\[)(.*?)(?=\])', sp+'[['+page_name+r'#\g<0>]]'+sp, text)
54
        # sp prevents [[[, which Redmine would parse incorrectly
55
    return text
56

    
57
class RedmineTableWriter:
58
    '''Formats rows as a Redmine table'''
59
    
60
    def __init__(self, stream):
61
        self.stream = stream
62
    
63
    def writerow(self, row):
64
        self.stream.write(('|'.join(['']+row+['']))+'\n')
65

    
66
class RedmineDictWriter:
67
    '''Formats rows as Redmine sections containing a table'''
68
    
69
    def __init__(self, term_col, def_col, header, stream):
70
        self.term_col = term_col
71
        self.def_col = def_col
72
        self.header = header
73
        self.page_name = header[term_col]
74
        self.stream = stream
75
    
76
    def writerow(self, row):
77
        row = map(lambda f: redmine_add_links(self.page_name, f), row)
78
        
79
        term = row[self.term_col]
80
        def_ = row[self.def_col]
81
        self.stream.write('h3. '+term+'\n\n')
82
        if def_: self.stream.write(def_+'\n\n')
83
        
84
        table = RedmineTableWriter(self.stream)
85
        for i, col_name in enumerate(self.header):
86
            if not i in set([self.term_col, self.def_col]):
87
                value = row[i]
88
                if value: table.writerow([redmine_bold(col_name), value])
89
        self.stream.write('\n')
90

    
91

    
92
def main():
93
    try: _prog_name, term_col, def_col, sources_col = sys.argv
94
    except ValueError: raise SystemExit('Usage: '+sys.argv[0]
95
        +' <spreadsheet term_col# definition_col# sources_col# >redmine')
96
    term_col, def_col, sources_col = map(int, [term_col, def_col, sources_col])
97
    
98
    # Translate input
99
    reader = csv.reader(sys.stdin)
100
    header = reader.next()
101
    writer = RedmineDictWriter(term_col, def_col, header, sys.stdout)
102
    for row in reader:
103
        term = row[term_col]
104
        sources = row[sources_col].split(source_sep)
105
        
106
        row[term_col] = redmine_url(term, simplify_url(sources[0]))
107
        row[sources_col] = source_sep.join(map(source2redmine_url, sources))
108
        
109
        writer.writerow(row)
110

    
111
main()
(13-13/69)