[wx] Unreviewed build fix. Don't error out or hang if we have
[WebKit-https.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 urllib2
34 import urllib
35 import urlparse
36
37
38 def get_output(command):
39     """
40     Windows-compatible function for getting output from a command.
41     """
42     if sys.platform.startswith('win'):
43         f = os.popen(command)
44         return f.read().strip()
45     else:
46         return commands.getoutput(command)
47
48
49 def get_excludes(root, patterns):
50     """
51     Get a list of exclude patterns going down several dirs.
52     TODO: Make this fully recursive.
53     """
54     excludes = []
55
56     for pattern in patterns:
57         subdir_pattern = os.sep + '*'
58         for subdir in [subdir_pattern, subdir_pattern * 2, subdir_pattern * 3]:
59             adir = root + subdir + os.sep + pattern
60             files = glob.glob(adir)
61             for afile in files:
62                 excludes.append(os.path.basename(afile))
63
64     return excludes
65
66
67 def get_dirs_for_features(root, features, dirs):
68     """
69     Find which directories to include in the list of build dirs based upon the
70     enabled port(s) and features.
71     """
72     outdirs = dirs
73     for adir in dirs:
74         for feature in features:
75             relpath = os.path.join(adir, feature)
76             featuredir = os.path.join(root, relpath)
77             if os.path.exists(featuredir) and not relpath in outdirs:
78                 outdirs.append(relpath)
79
80     return outdirs
81
82
83 def download_if_newer(url, destdir):
84     """
85     Checks if the file on the server is newer than the one in the user's tree,
86     and if so, downloads it.
87
88     Returns the filename of the downloaded file if downloaded, or None if
89     the existing file matches the one on the server.
90     """
91     obj = urlparse.urlparse(url)
92     filename = os.path.basename(obj.path)
93     destfile = os.path.join(destdir, filename)
94
95     try:
96         urlobj = urllib2.urlopen(url, timeout=20)
97     except:
98         if os.path.exists(destfile):
99             return None # 
100         else:
101             raise
102     size = long(urlobj.info().getheader('Content-Length'))
103
104     def download_callback(downloaded, block_size, total_size):
105         downloaded = block_size * downloaded
106         if downloaded > total_size:
107             downloaded = total_size
108         sys.stdout.write('%s %d of %d bytes downloaded\r' % (filename, downloaded, total_size))
109
110     # NB: We don't check modified time as Python doesn't yet handle timezone conversion
111     # properly when converting strings to time objects.
112     if not os.path.exists(destfile) or os.path.getsize(destfile) != size:
113         urllib.urlretrieve(url, destfile, download_callback)
114         print ''
115         return destfile
116
117     return None
118
119
120 def update_wx_deps(conf, wk_root, msvc_version='msvc2008'):
121     """
122     Download and update tools needed to build the wx port.
123     """
124     import Logs
125     Logs.info('Ensuring wxWebKit dependencies are up-to-date.')
126
127     wklibs_dir = os.path.join(wk_root, 'WebKitLibraries')
128     waf = download_if_newer('http://wxwebkit.kosoftworks.com/downloads/deps/waf', os.path.join(wk_root, 'Tools', 'wx'))
129     if waf:
130         # TODO: Make the build restart itself after an update.
131         Logs.warn('Build system updated, please restart build.')
132         sys.exit(1)
133
134     # since this module is still experimental
135     wxpy_dir = os.path.join(wk_root, 'Source', 'WebKit', 'wx', 'bindings', 'python')
136     swig_module = download_if_newer('http://wxwebkit.kosoftworks.com/downloads/deps/swig.py.txt', wxpy_dir)
137     if swig_module:
138         shutil.copy(os.path.join(wxpy_dir, 'swig.py.txt'), os.path.join(wxpy_dir, 'swig.py'))
139
140     if sys.platform.startswith('win'):
141         Logs.info('downloading deps package')
142         archive = download_if_newer('http://wxwebkit.kosoftworks.com/downloads/deps/wxWebKitDeps-%s.zip' % msvc_version, wklibs_dir)
143         if archive and os.path.exists(archive):
144             os.system('unzip -o %s -d %s' % (archive, os.path.join(wklibs_dir, msvc_version)))
145
146     elif sys.platform.startswith('darwin'):
147         # export the right compiler for building the dependencies
148         if platform.release().startswith('10'):  # Snow Leopard
149             os.environ['CC'] = conf.env['CC'][0]
150             os.environ['CXX'] = conf.env['CXX'][0]
151         os.system('%s/Tools/wx/install-unix-extras' % wk_root)
152
153
154 def includeDirsForSources(sources):
155     include_dirs = []
156     for group in sources:
157         for source in group:
158             dirname = os.path.dirname(source)
159             if not dirname in include_dirs:
160                 include_dirs.append(dirname)
161
162     return include_dirs
163
164
165 def flattenSources(sources):
166     flat_sources = []
167     for group in sources:
168         flat_sources.extend(group)
169
170     return flat_sources
171
172 def git_branch_name():
173     try:
174         branches = commands.getoutput("git branch --no-color")
175         match = re.search('^\* (.*)', branches, re.MULTILINE)
176         if match:
177             return "%s" % match.group(1)
178     except:
179         pass
180
181     return ""
182
183 def is_git_branch_build():
184     branch = git_branch_name()
185     is_branch_build = commands.getoutput("git config --bool branch.%s.webKitBranchBuild" % branch)
186     if is_branch_build == "true":
187         return True
188     elif is_branch_build == "false":
189         return False
190         
191     # not defined for this branch, use the default
192     is_branch_build = commands.getoutput("git config --bool core.webKitBranchBuild")
193     return is_branch_build == "true"
194
195 def get_base_product_dir(wk_root):
196     build_dir = os.path.join(wk_root, 'WebKitBuild')
197     git_branch = git_branch_name()
198     if git_branch != "" and is_git_branch_build():
199         build_dir = os.path.join(build_dir, git_branch)
200         
201     return build_dir
202
203 def get_config(wk_root):
204     config_file = os.path.join(get_base_product_dir(wk_root), 'Configuration')
205     config = 'Debug'
206
207     if os.path.exists(config_file):
208         config = open(config_file).read()
209
210     return config
211
212
213 def get_arch(wk_root):
214     arch_file = os.path.join(get_base_product_dir(wk_root), 'Architecture')
215     arch = 'x86_64'
216
217     if os.path.exists(arch_file):
218         arch = open(arch_file).read()
219
220     return arch
221
222
223 def svn_revision():
224     if os.system("git-svn info") == 0:
225         info = commands.getoutput("git-svn info ../..")
226     else:
227         info = commands.getoutput("svn info")
228
229     for line in info.split("\n"):
230         if line.startswith("Revision: "):
231             return line.replace("Revision: ", "").strip()
232
233     return ""