File: raps_deps.py

package info (click to toggle)
loki-ecmwf 0.3.4-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 6,200 kB
  • sloc: python: 72,475; f90: 2,105; sh: 271; makefile: 49; ansic: 47
file content (133 lines) | stat: -rw-r--r-- 4,171 bytes parent folder | download | duplicates (2)
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# (C) Copyright 2018- ECMWF.
# This software is licensed under the terms of the Apache Licence Version 2.0
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
# In applying this licence, ECMWF does not waive the privileges and immunities
# granted to it by virtue of its status as an intergovernmental organisation
# nor does it submit to any jurisdiction.

from pathlib import Path
import re


class RapsDependencyFile:
    """
    Wrapper class for GNUmake-style dependency files generated by RAPS.
    """

    def __init__(self, content=None, path=None):
        self.path = path
        self.content = content or []

    @classmethod
    def from_file(cls, path):
        re_deps = re.compile(r'(?P<target>.*):\s(?P<deps>[\s\S]*)', re.MULTILINE)
        re_assign = re.compile(r'(?P<target>.*)\s=\s(?P<objs>[\s\S]*)', re.MULTILINE)

        path = Path(path)
        with path.open('r') as f:
            source = f.read()

        content = []
        for block in source.split('\n\n'):
            deps = re_deps.search(block)
            if deps is not None:
                groups = deps.groupdict()
                deps = groups['deps'].split(' \\\n\t')
                deps = [d.strip() for d in deps]
                content.append(Dependency(target=groups['target'], deps=deps))

            assign = re_assign.search(block)
            if assign is not None:
                groups = assign.groupdict()
                objects = groups['objs']
                objects = objects.split('#')[0] if '#' in objects else objects
                objects = [o.strip() for o in objects.split(' \\\n\t')]
                content.append(Assignment(target=groups['target'], objects=objects))

        return cls(content=content, path=path)

    @property
    def content_map(self):
        return {d.target: d for d in self.content}

    def write(self, path=None):
        path = path or self.path

        content = """#
#--- Automatically generated -- please do not edit this file
#

"""
        content += '\n\n'.join(str(c) for c in self.content)
        with Path(path).open('w') as f:
            f.write(content)

    def replace(self, key, replacement):
        """
        Replace specific rule/assignment with another based on the
        targets name as a key.
        """
        for i, o in enumerate(self.content):
            if o.target == key:
                self.content[i] = replacement


class Dependency:

    def __init__(self, target, deps):
        self.target = target
        self.deps = deps

    def __repr__(self):
        deps = ' \\\n\t'.join(self.deps)
        return f'{self.target}: {deps}'

    def find(self, name):
        hits = [d for d in self.deps if name == Path(d).name]
        if len(hits) == 0:
            return None
        return hits if len(hits) > 1 else hits[0]

    def replace(self, target, replacement):
        if target in self.target:
            self.target = self.target.replace(target, replacement)
        for i, dep in enumerate(self.deps):
            if target in dep:
                self.deps[i] = dep.replace(target, replacement)


class Assignment:

    def __init__(self, target, objects):
        self.target = target
        self.objects = objects

    def __repr__(self):
        objects = ' \\\n\t'.join(self.objects)
        return f'{self.target} = {objects}'

    def replace(self, target, replacement):
        if target in self.target:
            self.target = self.target.replace(target, replacement)
        for i, obj in enumerate(self.objects):
            if target in obj:
                self.objects[i] = obj.replace(target, replacement)

    def append_inplace(self, target, replacement):
        for i, obj in enumerate(self.objects):
            if target in obj:
                new = obj.replace(target, replacement)
                self.objects[i:i+1] = [obj, new]


class Rule:

    def __init__(self, target, deps, cmds):
        self.target = target
        self.deps = deps
        self.cmds = cmds

    def __repr__(self):
        deps = ' '.join(self.deps)
        cmds = ' \n\t'.join(self.cmds)
        return f'{self.target}: {deps} \n\t{cmds}'