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}'
|