1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  | 
from docutils import nodes
from docutils.parsers.rst import Directive, directives
from sphinx import addnodes
from sphinx.domains.std import GenericObject
from sphinx.errors import SphinxError
from utils import build_table_from_list
def read_cabal_file(pkg_path):
    import re
    cabal_file = open(pkg_path, 'r').read()
    pkg_name = re.search(r'^[nN]ame\s*:\s*([-a-zA-Z0-9]+)', cabal_file, re.MULTILINE)
    if pkg_name is not None:
        pkg_name = pkg_name.group(1)
    else:
        raise RuntimeError("Failed to parse `Name:` field from %s" % pkg_path)
    pkg_version = re.search(r'^[vV]ersion\s*:\s*(\d+(\.\d+)*)', cabal_file, re.MULTILINE)
    if pkg_version is not None:
        pkg_version = pkg_version.group(1)
    else:
        raise RuntimeError("Failed to parse `Version:` field from %s" % pkg_path)
    return (pkg_name, pkg_version)
class PackageListDirective(Directive):
    has_content = True
    def run(self):
        self.assert_has_content()
        packages = []
        for line in self.content:
            (pkg_path, _, reason) = line.partition(':')
            if len(reason) == 0:
                raise RuntimeError("Missing reason for inclusion of package %s"
                                   % pkg_path)
            # Parse reason
            from docutils.statemachine import ViewList
            reason_vl = ViewList(initlist=[reason.strip()])
            reason_node = nodes.paragraph()
            self.state.nested_parse(reason_vl, 0, reason_node)
            packages.append((pkg_path, reason_node))
        # Create column headers for table
        header = [ nodes.inline(text=h)
                   for h in ["Package", "Version", "Reason for inclusion"] ]
        package_list = [header]
        for (pkg_path, reason) in sorted(packages):
            (pkg_name, pkg_version) = read_cabal_file(pkg_path)
            cells = [ nodes.paragraph(text=pkg_name),
                      nodes.inline(text=pkg_version),
                      reason ]
            package_list.append(cells)
        table = build_table_from_list(package_list, [20, 20, 40])
        table['classes'].append('longtable')
        return [table]
### Initialization
def setup(app):
    app.add_directive('ghc-package-list', PackageListDirective)
    return {'version': '1.0'}
  |