10bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Copyright (C) 2009 Kevin Ollivier  All rights reserved.
20bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#
30bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Redistribution and use in source and binary forms, with or without
40bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# modification, are permitted provided that the following conditions
50bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# are met:
60bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# 1. Redistributions of source code must retain the above copyright
70bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#    notice, this list of conditions and the following disclaimer.
80bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# 2. Redistributions in binary form must reproduce the above copyright
90bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#    notice, this list of conditions and the following disclaimer in the
100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#    documentation and/or other materials provided with the distribution.
110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#
120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#
240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch# Helper functions for the WebKit build.
250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
26231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockimport commands
270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochimport glob
280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochimport os
29231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockimport platform
30cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Blockimport re
31231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockimport shutil
320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochimport sys
330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochimport urllib
340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochimport urlparse
350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef get_output(command):
370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Windows-compatible function for getting output from a command.
390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
40231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if sys.platform.startswith('win'):
41231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        f = os.popen(command)
42231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return f.read().strip()
43231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    else:
44231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return commands.getoutput(command)
450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef get_excludes(root, patterns):
470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Get a list of exclude patterns going down several dirs.
490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    TODO: Make this fully recursive.
500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    excludes = []
520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for pattern in patterns:
540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        subdir_pattern = os.sep + '*'
550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for subdir in [subdir_pattern, subdir_pattern*2, subdir_pattern*3]:
560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            adir = root + subdir + os.sep + pattern
570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            files = glob.glob(adir)
580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            for afile in files:
590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                excludes.append(os.path.basename(afile))
600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return excludes
620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef get_dirs_for_features(root, features, dirs):
640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Find which directories to include in the list of build dirs based upon the
660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    enabled port(s) and features.
670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    outdirs = dirs
690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for adir in dirs:
700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for feature in features:
710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            relpath = os.path.join(adir, feature)
720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            featuredir = os.path.join(root, relpath)
730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if os.path.exists(featuredir) and not relpath in outdirs:
740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                outdirs.append(relpath)
750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return outdirs
770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef download_if_newer(url, destdir):
790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Checks if the file on the server is newer than the one in the user's tree,
810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    and if so, downloads it.
820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Returns the filename of the downloaded file if downloaded, or None if
840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    the existing file matches the one on the server.
850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    obj = urlparse.urlparse(url)
870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    filename = os.path.basename(obj.path)
880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    destfile = os.path.join(destdir, filename)
890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    urlobj = urllib.urlopen(url)
910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    size = long(urlobj.info().getheader('Content-Length'))
920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    def download_callback(downloaded, block_size, total_size):
940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        downloaded = block_size * downloaded
950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if downloaded > total_size:
960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            downloaded = total_size
970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        sys.stdout.write('%s %d of %d bytes downloaded\r' % (filename, downloaded, total_size))
980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # NB: We don't check modified time as Python doesn't yet handle timezone conversion
1000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # properly when converting strings to time objects.
1010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if not os.path.exists(destfile) or os.path.getsize(destfile) != size:
1020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        urllib.urlretrieve(url, destfile, download_callback)
1030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        print ''
1040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return destfile
1050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return None
1070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
108231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockdef update_wx_deps(conf, wk_root, msvc_version='msvc2008'):
1090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
1100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Download and update tools needed to build the wx port.
1110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    """
112cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    import Logs
1130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Logs.info('Ensuring wxWebKit dependencies are up-to-date.')
1140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    wklibs_dir = os.path.join(wk_root, 'WebKitLibraries')
116f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    waf = download_if_newer('http://wxwebkit.wxcommunity.com/downloads/deps/waf', os.path.join(wk_root, 'Tools', 'wx'))
1170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if waf:
1180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        # TODO: Make the build restart itself after an update.
1190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Logs.warn('Build system updated, please restart build.')
1200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        sys.exit(1)
1210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    # since this module is still experimental
1232fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    wxpy_dir = os.path.join(wk_root, 'Source', 'WebKit', 'wx', 'bindings', 'python')
124231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    swig_module = download_if_newer('http://wxwebkit.wxcommunity.com/downloads/deps/swig.py.txt', wxpy_dir)
125231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if swig_module:
126231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        shutil.copy(os.path.join(wxpy_dir, 'swig.py.txt'), os.path.join(wxpy_dir, 'swig.py'))
1270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if sys.platform.startswith('win'):
1290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        Logs.info('downloading deps package')
1300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        archive = download_if_newer('http://wxwebkit.wxcommunity.com/downloads/deps/wxWebKitDeps-%s.zip' % msvc_version, wklibs_dir)
1310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if archive and os.path.exists(archive):
1320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            os.system('unzip -o %s -d %s' % (archive, os.path.join(wklibs_dir, msvc_version)))
1330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    elif sys.platform.startswith('darwin'):
135231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        # export the right compiler for building the dependencies
136231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if platform.release().startswith('10'): # Snow Leopard
137231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            os.environ['CC'] = conf.env['CC'][0]
138231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            os.environ['CXX'] = conf.env['CXX'][0]
139f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        os.system('%s/Tools/wx/install-unix-extras' % wk_root)
1400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef includeDirsForSources(sources):
1420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    include_dirs = []
1430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for group in sources:
1440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for source in group:
1450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            dirname = os.path.dirname(source)
1460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if not dirname in include_dirs:
1470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                include_dirs.append(dirname)
1480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return include_dirs
1500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochdef flattenSources(sources):
1520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    flat_sources = []
1530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    for group in sources:
1540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        flat_sources.extend(group)
1550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return flat_sources
157cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block
158cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Blockdef git_branch_name():
159cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    try:
160cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        branches = commands.getoutput("git branch --no-color")
161cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        match = re.search('^\* (.*)', branches, re.MULTILINE)
162cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        if match:
163cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block            return ".%s" % match.group(1)
164cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    except:
165cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        pass
166cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block
167cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    return ""
168cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block
169cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Blockdef get_config(wk_root):
170cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    config_file = os.path.join(wk_root, 'WebKitBuild', 'Configuration')
171cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    config = 'Debug'
172cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block
173cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    if os.path.exists(config_file):
174cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        config = open(config_file).read()
175cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block
176cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    return config
177cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block
178cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Blockdef svn_revision():
179643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if os.system("git-svn info") == 0:
180cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        info = commands.getoutput("git-svn info ../..")
181cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    else:
182cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        info = commands.getoutput("svn info")
183cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block
184cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    for line in info.split("\n"):
185cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block        if line.startswith("Revision: "):
186cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block            return line.replace("Revision: ", "").strip()
187cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block
188cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    return ""
189