aboutsummaryrefslogtreecommitdiff
path: root/src/allocator.py
blob: a163b14533e6bacf8b324df981237353709ee9f4 (plain)
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import copy
import os
import shutil
import subprocess
import sys

library_path = ""
for l in subprocess.run(["ldconfig", "-v"], stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE,
                                 universal_newlines=True).stdout.splitlines():
    if not l.startswith('\t'):
        library_path += l

builddir = os.path.join(os.getcwd(), "build", "allocators")
srcdir = os.path.join(builddir, "src")

if not os.path.isdir(srcdir):
    os.makedirs(srcdir)


class Allocator_Sources (object):
    # indicate if this source was patched
    available = False
    clean = True

    def __init__(self, name, retrieve_cmds=[], prepare_cmds=[], reset_cmds=[]):
        self.name = name
        self.dir = os.path.join(srcdir, self.name)
        self.retrieve_cmds = retrieve_cmds
        self.prepare_cmds = prepare_cmds
        self.reset_cmds = reset_cmds

    def run_cmds(self, function, verbose, cwd=srcdir):
        print(function, self.name, "...")
        cmds = getattr(self, function+"_cmds")
        for cmd in cmds:
            stdout = subprocess.PIPE if not verbose else None
            stderr = subprocess.PIPE if not verbose else None
            p = subprocess.run(cmd, shell=True, cwd=cwd, stderr=stderr,
                               stdout=stdout)
            
            if p.returncode:
                print(function, self.name, "failed with", p.returncode,
                      file=sys.stderr)
                print(p.stderr, file=sys.stderr)
                return False
        return True

    def prepare(self, verbose):
        if not os.path.isdir(self.dir):
            if (not self.run_cmds("retrieve", verbose) or
                    not self.run_cmds("prepare", verbose, cwd=self.dir)):

                shutil.rmtree(self.dir, ignore_errors=True)
                exit(1)
        
        self.available = True
        return True

    def reset(self, verbose):
        if not self.run_cmds("reset", verbose, cwd=self.dir):
            exit(1)
        self.clean = True

    def patch(self, patches, verbose):
        self.prepare(verbose)
        stdout = subprocess.PIPE if not verbose else None
        stderr = subprocess.PIPE
        cwd = os.path.join(srcdir, self.name)

        print("Patching", self.name, "...")
        for patch in patches:
            with open(patch, "rb") as f:
                p = subprocess.run("patch -p1", shell=True, cwd=cwd, stderr=stderr,
                                   stdout=stdout, input=f.read())
        
                if p.returncode:
                    print("Patching of", self.name, "failed.", file=sys.stderr)
                    exit(1)
        

class Allocator (object):
    allowed_attributes = ["binary_suffix", "version", "sources", "build_cmds",
                          "LD_PRELOAD", "cmd_prefix", "color"]

    def __init__(self, name, **kwargs):
        self.name = name
        self.dir = os.path.join(builddir, self.name)
        # Update attributes
        self.__dict__.update((k, v) for k, v in kwargs.items() if k in self.allowed_attributes)

        # create all unset attributes
        for attr in self.allowed_attributes:
            if not hasattr(self, attr):
                setattr(self, attr, None)

    def build(self, verbose=False):
        if not os.path.isdir(self.dir):
            if self.sources:
                if not self.sources.available:
                    self.sources.prepare(verbose)
                if not self.sources.clean:
                    self.sources.reset(verbose)
                
            if self.build_cmds:
                print("Building", self.name, "...")
                for cmd in self.build_cmds:
                    cmd = cmd.format(**{"dir": self.dir,
                                        "srcdir": self.sources.dir})
                    stdout = subprocess.PIPE if not verbose else None
                    stderr = subprocess.PIPE
                    p = subprocess.run(cmd, cwd=builddir, shell=True,
                                       stderr=stderr, stdout=stdout)
                    if p.returncode:
                        print(cmd)
                        print(p.stderr)
                        print("Building", self.name, "failed ...")
                        shutil.rmtree(self.dir, ignore_errors=True)
                        exit(1)

        for attr in ["LD_PRELOAD", "cmd_prefix"]:
            try:
                value = getattr(self, attr)
                setattr(self, attr, value.format(**{"dir": self.dir,
                                                  "srcdir": self.sources.dir}))
            except AttributeError:
                setattr(self, attr, "")
        
        return {"cmd_prefix": self.cmd_prefix,
                "binary_suffix": self.binary_suffix or "",
                "LD_PRELOAD": self.LD_PRELOAD,
                "color": self.color}


class Allocator_Patched (object):
    def __init__(self, name, alloc, patches, **kwargs):
        self.name = name
        self.patches = patches

        self.alloc = copy.deepcopy(alloc)
        self.alloc.name = self.name
        self.alloc.dir = os.path.join(builddir, self.name)
        self.alloc.__dict__.update((k, v) for k, v in kwargs.items() if k in self.alloc.allowed_attributes)

    def build(self, verbose=False):

        if not os.path.isdir(self.alloc.dir):
            self.alloc.sources.patch(self.patches, verbose)

        return self.alloc.build(verbose=verbose)