Rubberstamped by Eric Seidel.
[WebKit.git] / Tools / waf / build / build_utils.py
1 # Copyright (C) 2009 Kevin Ollivier  All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
5 # are met:
6 # 1. Redistributions of source code must retain the above copyright
7 #    notice, this list of conditions and the following disclaimer.
8 # 2. Redistributions in binary form must reproduce the above copyright
9 #    notice, this list of conditions and the following disclaimer in the
10 #    documentation and/or other materials provided with the distribution.
11 #
12 # THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
13 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
15 # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
16 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
17 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
18 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
19 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
20 # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 #
24 # Helper functions for the WebKit build.
25
26 import commands
27 import glob
28 import os
29 import platform
30 import re
31 import shutil
32 import sys
33 import urllib
34 import urlparse
35
36
37 def get_output(command):
38     """
39     Windows-compatible function for getting output from a command.
40     """
41     if sys.platform.startswith('win'):
42         f = os.popen(command)
43         return f.read().strip()
44     else:
45         return commands.getoutput(command)
46
47
48 def get_excludes(root, patterns):
49     """
50     Get a list of exclude patterns going down several dirs.
51     TODO: Make this fully recursive.
52     """
53     excludes = []
54
55     for pattern in patterns:
56         subdir_pattern = os.sep + '*'
57         for subdir in [subdir_pattern, subdir_pattern * 2, subdir_pattern * 3]:
58             adir = root + subdir + os.sep + pattern
59             files = glob.glob(adir)
60             for afile in files:
61                 excludes.append(os.path.basename(afile))
62
63     return excludes
64
65
66 def get_dirs_for_features(root, features, dirs):
67     """
68     Find which directories to include in the list of build dirs based upon the
69     enabled port(s) and features.
70     """
71     outdirs = dirs
72     for adir in dirs:
73         for feature in features:
74             relpath = os.path.join(adir, feature)
75             featuredir = os.path.join(root, relpath)
76             if os.path.exists(featuredir) and not relpath in outdirs:
77                 outdirs.append(relpath)
78
79     return outdirs
80
81
82 def download_if_newer(url, destdir):
83     """
84     Checks if the file on the server is newer than the one in the user's tree,
85     and if so, downloads it.
86
87     Returns the filename of the downloaded file if downloaded, or None if
88     the existing file matches the one on the server.
89     """
90     obj = urlparse.urlparse(url)
91     filename = os.path.basename(obj.path)
92     destfile = os.path.join(destdir, filename)
93
94     urlobj = urllib.urlopen(url)
95     size = long(urlobj.info().getheader('Content-Length'))
96
97     def download_callback(downloaded, block_size, total_size):
98         downloaded = block_size * downloaded
99         if downloaded > total_size:
100             downloaded = total_size
101         sys.stdout.write('%s %d of %d bytes downloaded\r' % (filename, downloaded, total_size))
102
103     # NB: We don't check modified time as Python doesn't yet handle timezone conversion
104     # properly when converting strings to time objects.
105     if not os.path.exists(destfile) or os.path.getsize(destfile) != size:
106         urllib.urlretrieve(url, destfile, download_callback)
107         print ''
108         return destfile
109
110     return None
111
112
113 def update_wx_deps(conf, wk_root, msvc_version='msvc2008'):
114     """
115     Download and update tools needed to build the wx port.
116     """
117     import Logs
118     Logs.info('Ensuring wxWebKit dependencies are up-to-date.')
119
120     wklibs_dir = os.path.join(wk_root, 'WebKitLibraries')
121     waf = download_if_newer('http://wxwebkit.wxcommunity.com/downloads/deps/waf', os.path.join(wk_root, 'Tools', 'wx'))
122     if waf:
123         # TODO: Make the build restart itself after an update.
124         Logs.warn('Build system updated, please restart build.')
125         sys.exit(1)
126
127     # since this module is still experimental
128     wxpy_dir = os.path.join(wk_root, 'Source', 'WebKit', 'wx', 'bindings', 'python')
129     swig_module = download_if_newer('http://wxwebkit.wxcommunity.com/downloads/deps/swig.py.txt', wxpy_dir)
130     if swig_module:
131         shutil.copy(os.path.join(wxpy_dir, 'swig.py.txt'), os.path.join(wxpy_dir, 'swig.py'))
132
133     if sys.platform.startswith('win'):
134         Logs.info('downloading deps package')
135         archive = download_if_newer('http://wxwebkit.wxcommunity.com/downloads/deps/wxWebKitDeps-%s.zip' % msvc_version, wklibs_dir)
136         if archive and os.path.exists(archive):
137             os.system('unzip -o %s -d %s' % (archive, os.path.join(wklibs_dir, msvc_version)))
138
139     elif sys.platform.startswith('darwin'):
140         # export the right compiler for building the dependencies
141         if platform.release().startswith('10'):  # Snow Leopard
142             os.environ['CC'] = conf.env['CC'][0]
143             os.environ['CXX'] = conf.env['CXX'][0]
144         os.system('%s/Tools/wx/install-unix-extras' % wk_root)
145
146
147 def includeDirsForSources(sources):
148     include_dirs = []
149     for group in sources:
150         for source in group:
151             dirname = os.path.dirname(source)
152             if not dirname in include_dirs:
153                 include_dirs.append(dirname)
154
155     return include_dirs
156
157
158 def flattenSources(sources):
159     flat_sources = []
160     for group in sources:
161         flat_sources.extend(group)
162
163     return flat_sources
164
165
166 def git_branch_name():
167     try:
168         branches = commands.getoutput("git branch --no-color")
169         match = re.search('^\* (.*)', branches, re.MULTILINE)
170         if match:
171             return ".%s" % match.group(1)
172     except:
173         pass
174
175     return ""
176
177
178 def get_config(wk_root):
179     config_file = os.path.join(wk_root, 'WebKitBuild', 'Configuration')
180     config = 'Debug'
181
182     if os.path.exists(config_file):
183         config = open(config_file).read()
184
185     return config
186
187
188 def get_arch(wk_root):
189     arch_file = os.path.join(wk_root, 'WebKitBuild', 'Architecture')
190     arch = 'x86_64'
191
192     if os.path.exists(arch_file):
193         arch = open(arch_file).read()
194
195     return arch
196
197
198 def svn_revision():
199     if os.system("git-svn info") == 0:
200         info = commands.getoutput("git-svn info ../..")
201     else:
202         info = commands.getoutput("svn info")
203
204     for line in info.split("\n"):
205         if line.startswith("Revision: "):
206             return line.replace("Revision: ", "").strip()
207
208     return ""