summaryrefslogtreecommitdiff
path: root/bench/Project.py
blob: 1c6178fb67bc275510587f94dd5bd8b319487736 (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
# benchmark -- automated system for testing distcc correctness
# and performance on various source trees.

# Copyright (C) 2002, 2003 by Martin Pool
# Copyright 2008 Google Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
# USA.

import re, os, sys, time
from buildutil import make_dir, run_cmd


# Trees of software to be built.
trees = { }


class Project:
    """Defines a project to be built and tested.

    The Python process remains in the top-level directory for the
    whole process.  Commands are kicked off in subdirectories if
    necessary.

    'subdir' variables give just a single component of a name; 'dir' variables
    give a full path."""
    
    def __init__(self, url,
                 package_file=None,
                 name=None,
                 md5=None,
                 unpacked_subdir=None,
                 build_subdir=None,
                 configure_cmd=None,
                 pre_build_cmd = None,
                 build_cmd=None,
                 include_server_args=""):
        """Specification of a project to build.

        url: the url to download the file.
        package_file: the filename of the downloaded url.  If not
           specified, taken to be basename(url).  This should rarely
           need to be specified.
           specified on the commandline to just benchmark a single project.
        name: the name used to identify the project when listing projects
           on the benchmark commandline.  If not specified, taken to be
           package_file, but with the .tar.* extension removed.
        md5: the output of 'md5sum package_file'; used to verify a download.
        unpacked_subdir: The top-level directory created when we untar the
           package_file.  If not specified, taken to be self.name, which is
           typically right (at least for projects make using autotools).
        build_subdir: the subdirectory of unpacked_subdir where building
           should be done; we create it if needed.  Defaults to '.'.
           You should only need to change this if your project does not
           have its configure script in the top-level directory.
        configure_cmd: the command to generate the project's Makefile.
           It is run in build_subdir.  Defaults to './configure'.
        pre_build_cmd: a command to run before running the build command.
           It is run in build_subdir.  Defaults to running nothing.
        build_cmd: The command to build the project from the Makefile.
           We add VAR=val arguments, so build_cmd must be a single command
           that is either a form of 'make', or takes the same style
           arguments.  Defaults to 'make'.
        include_server_args: include server tweaks such as stat reset triggers
           for builds that modify source files.
        """

        self.url = url
        if not package_file:
            package_file = url.split('/')[-1]
        self.package_file = package_file

        if not name:
            name = re.match(r"(.*)\.tar(\.gz|\.bz2|)$", package_file).group(1)
        self.name = name

        self.md5 = md5
        
        self.configure_cmd = configure_cmd or "./configure"
        self.build_cmd = build_cmd or "make"
        self.pre_build_cmd = pre_build_cmd

        self.package_dir = "packages"
        self.download_dir = "download"

        # By default, we assume the package creates an unpacked
        # directory whose name is the same as the tarball.  For
        # example, Wine's tarball is "Wine-xxxxxxx", but it unpacks to
        # "wine-xxxxxxxx".
        # TODO(csilvers): figure out automatically if only one TLD.
        self.unpacked_subdir = unpacked_subdir or self.name
        self.build_subdir = build_subdir
        self.include_server_args = include_server_args

    def register(self):
        trees[self.name] = self


    def __repr__(self):
        return "Project(name=%s)" % `self.name`


    def download(self, force=0):
        """Download package from vendor site.

        If force is 1, download even if the file already exists.
        """

        make_dir(self.package_dir)
        make_dir(self.download_dir)
            
        if not os.path.isfile(os.path.join(self.package_dir, self.package_file)):
            # XXX: snarf gets upset if the HTTP server returns "416
            # Requested Range Not Satisfiable" because the file is already
            # totally downloaded.  This is kind of a snarf bug.
            print "** Downloading"
            run_cmd("cd %s && wget --continue %s" %
                    (self.download_dir, self.url))
            run_cmd("mv %s %s" %
                    (os.path.join(self.download_dir, self.package_file),
                     self.package_dir))

    def md5check(self):
        if self.md5:
            print "** Checking source package integrity"
            run_cmd("cd %s && echo '%s' | md5sum -c /dev/stdin" %
                    (self.package_dir, self.md5))


    def pre_actions(self, actions):
        """Perform actions preparatory to building according to selection."""
        
        if 'download' in actions:
            self.download()
        if 'md5check' in actions:
            self.md5check()