Created
October 25, 2012 20:34
-
-
Save jaredwy/3955225 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights | |
# reserved. Use of this source code is governed by a BSD-style license that | |
# can be found in the LICENSE file. | |
from optparse import OptionParser | |
from subprocess import Popen, PIPE, STDOUT | |
from tempfile import mktemp | |
import os | |
import shlex | |
import shutil | |
import sys | |
import urllib | |
# default URL values | |
chromium_url = 'http://git.chromium.org/chromium/src.git' | |
depot_tools_url = 'http://src.chromium.org/svn/trunk/tools/depot_tools' | |
def check_url(url): | |
""" Check the URL and raise an exception if invalid. """ | |
if ':' in url[:7]: | |
parts = url.split(':', 1) | |
if (parts[0] in ["http", "https", "git"] and \ | |
parts[1] == urllib.quote(parts[1])): | |
return url | |
sys.stderr.write('Invalid URL: '+url+"\n") | |
raise Exception('Invalid URL: '+url) | |
def get_exec_environ(): | |
env = os.environ | |
env['PATH'] = depot_tools_dir + os.pathsep + env['PATH'] | |
return env | |
def run(args, **kwargs): | |
'''Run a command and capture the output iteratively''' | |
if isinstance(args, str): | |
args = shlex.split(args.replace('\\', '\\\\')) | |
cwd = kwargs.get("cwd", os.getcwd()) | |
quiet = kwargs.get("quiet", False) | |
print "-> Running '%s' in %s" % (" ".join(args), os.path.relpath(cwd)) | |
cmd = Popen(args, cwd=cwd, stdout=PIPE, stderr=STDOUT, | |
env=kwargs.get("env", get_exec_environ()), | |
shell=(sys.platform == 'win32')) | |
output = '' | |
while True: | |
out = cmd.stdout.read(1) | |
if out == '' and cmd.poll() != None: | |
break | |
output += out | |
if not quiet: | |
sys.stdout.write(out) | |
if cmd.wait() != 0: | |
raise Exception("Command failed: \"%s\"" % " ".join(args), output) | |
return output | |
def get_current_branch(path): | |
return run("git rev-parse --abbrev-ref HEAD", cwd=path, quiet=True) | |
def get_chromium_compat_rev(cef_url, path, cef_rev): | |
if not os.path.isdir(path): | |
path = mktemp() | |
run("git clone --depth 1 %s %s" % (cef_url, path), quiet = True) | |
if cef_rev == "None": | |
cef_rev = get_git_rev(path, get_current_branch(path)) | |
compat_cmd = "git cat-file -p %s:cef3/CHROMIUM_BUILD_COMPATIBILITY.txt" % cef_rev | |
compat_value = run(compat_cmd, cwd = path, quiet = True) | |
config = eval(compat_value, {'__builtins__': None}, None) | |
if not 'chromium_revision' in config: | |
raise Exception("Missing chromium_revision value") | |
return str(int(config['chromium_revision'])) | |
def get_svn_rev(path, branch): | |
svn_rev = "None" | |
cmd = ("git log --grep=^git-svn-id: -n 1 %s" % branch).split() | |
try: | |
process = Popen(cmd, cwd=path, stdout = PIPE, stderr = PIPE) | |
for line in process.stdout: | |
if line.find("git-svn-id") > 0: | |
svn_rev = line.split("@")[1].split()[0] | |
break | |
except IOError, (errno, strerror): | |
sys.stderr.write('Failed to read git log: ' + strerror + "\n") | |
raise | |
return svn_rev | |
def get_git_rev_for_svn_rvn(path, svn_rev): | |
git_rev = "None" | |
cmd = ("git log --grep=^git-svn-id:.*@%s --oneline" % svn_rev).split() | |
try: | |
process = Popen(cmd, cwd=path, stdout = PIPE, stderr = PIPE) | |
git_rev = process.communicate()[0].split()[0] | |
except IOError, (errno, strerror): | |
sys.stderr.write('Failed to read git log: ' + strerror + "\n") | |
raise | |
return git_rev | |
def get_git_rev(path, branch): | |
git_rev = "None" | |
cmd = ("git describe --always %s" % branch).split() | |
try: | |
process = Popen(cmd, cwd=path, stdout = PIPE, stderr = PIPE) | |
git_rev = process.communicate()[0].strip() | |
except IOError, (errno, strerror): | |
sys.stderr.write('Failed to read git log: ' + strerror + "\n") | |
raise | |
return git_rev | |
def get_git_origin(path): | |
git_origin = "None" | |
get_origin_cmd = "git remote show origin -n".split() | |
try: | |
process = Popen(get_origin_cmd, cwd=path, stdout = PIPE, stderr = PIPE) | |
for line in process.stdout: | |
if line.startswith(" Fetch URL: "): | |
git_origin = line.replace(" Fetch URL: ", "").strip() | |
break | |
except IOError, (errno, strerror): | |
sys.stderr.write('Failed to read git log: ' + strerror + "\n") | |
raise | |
return git_origin | |
def get_checkout_info(path, fetch_latest = True): | |
""" Retrieves the origin URL, git HEAD revision and last SVN revision """ | |
url = 'None' | |
origin_svn_rev = 'None' | |
origin_git_rev = 'None' | |
local_svn_rev = 'None' | |
local_git_rev = 'None' | |
if os.path.isdir(path): | |
if fetch_latest: | |
run("git fetch", cwd = path, quiet = True) | |
url = get_git_origin(path) | |
branch = get_current_branch(path) | |
origin_svn_rev = get_svn_rev(path, "origin/%s" % branch) | |
origin_git_rev = get_git_rev(path, "origin/%s" % branch) | |
local_svn_rev = get_svn_rev(path, branch) | |
local_git_rev = get_git_rev(path, branch) | |
return { | |
'url' : url, | |
'local' : { | |
'svn-revision' : local_svn_rev, | |
'git-revision' : local_git_rev | |
}, | |
'origin' : { | |
'svn-revision' : origin_svn_rev, | |
'git-revision' : origin_git_rev | |
} | |
} | |
# cannot be loaded as a module | |
if __name__ != "__main__": | |
sys.stderr.write('This file cannot be loaded as a module!') | |
sys.exit() | |
# parse command-line options | |
desc = """ | |
This utility implements automation for the download, update, build and | |
distribution of CEF. | |
""" | |
parser = OptionParser(description=desc) | |
parser.add_option('--url', dest='url', | |
help='CEF source URL') | |
parser.add_option('--download-dir', dest='downloaddir', metavar='DIR', | |
help='download directory with no spaces [required]') | |
parser.add_option('--revision', dest='revision', | |
help='CEF source revision') | |
parser.add_option('--force-config', | |
action='store_true', dest='forceconfig', default=False, | |
help='force Chromium configuration') | |
parser.add_option('--force-clean', | |
action='store_true', dest='forceclean', default=False, | |
help='force revert of all Chromium changes, deletion of '+\ | |
'all unversioned files including the CEF folder and '+\ | |
'trigger the force-update, force-build and '+\ | |
'force-distrib options') | |
parser.add_option('--force-update', | |
action='store_true', dest='forceupdate', default=False, | |
help='force Chromium and CEF update') | |
parser.add_option('--force-build', | |
action='store_true', dest='forcebuild', default=False, | |
help='force CEF debug and release builds') | |
parser.add_option('--force-distrib', | |
action='store_true', dest='forcedistrib', default=False, | |
help='force creation of CEF binary distribution') | |
parser.add_option('--no-debug-build', | |
action='store_true', dest='nodebugbuild', default=False, | |
help="don't perform the CEF debug build") | |
parser.add_option('--no-release-build', | |
action='store_true', dest='noreleasebuild', default=False, | |
help="don't perform the CEF release build") | |
parser.add_option('--no-distrib', | |
action='store_true', dest='nodistrib', default=False, | |
help="don't create the CEF binary distribution") | |
(options, args) = parser.parse_args() | |
# the downloaddir and url options are required | |
if options.downloaddir is None: | |
print "ERROR: Download directory is required" | |
parser.print_help(sys.stderr) | |
sys.exit() | |
if options.url is None: | |
print "ERROR: CEF URL is required" | |
parser.print_help(sys.stderr) | |
sys.exit() | |
cef_url = check_url(options.url) | |
download_dir = os.path.abspath(options.downloaddir) | |
if not os.path.exists(download_dir): | |
# create the download directory | |
os.makedirs(download_dir) | |
# set the expected script extension | |
if sys.platform == 'win32': | |
script_ext = '.bat' | |
else: | |
script_ext = '.sh' | |
# check if the "depot_tools" directory exists | |
depot_tools_dir = os.path.join(download_dir, 'depot_tools') | |
if not os.path.exists(depot_tools_dir): | |
# checkout depot_tools | |
run('svn checkout %s %s' % (depot_tools_url, depot_tools_dir), | |
cwd = download_dir, quiet = True) | |
chromium_dir = os.path.join(download_dir, 'chromium') | |
if not os.path.exists(chromium_dir): | |
# create the "chromium" directory | |
os.makedirs(chromium_dir) | |
chromium_src_dir = os.path.join(chromium_dir, 'src') | |
cef_src_dir = os.path.join(chromium_src_dir, 'cef') | |
cef_tools_dir = os.path.join(cef_src_dir, 'tools') | |
# retrieve the current CEF URL and revision | |
info = get_checkout_info(cef_src_dir) | |
cef_rev = info['origin']['git-revision'] | |
if not options.revision is None: | |
cef_rev = str(options.revision) | |
current_cef_url = info['url'] | |
current_cef_rev = info['local']['git-revision'] | |
# retrieve the compatible Chromium revision | |
chromium_rev = get_chromium_compat_rev(cef_url, cef_src_dir, cef_rev) | |
# retrieve the current Chromium URL and revision | |
info = get_checkout_info(chromium_src_dir, False) | |
current_chromium_url = info['url'] | |
current_chromium_rev = info['local']['svn-revision'] | |
# test if the CEF URL changed | |
cef_url_changed = current_cef_url != cef_url | |
print "-- CEF URL: %s" % current_cef_url | |
if cef_url_changed: | |
print "\t-> CHANGED TO: %s" % cef_url | |
# test if the CEF revision changed | |
cef_rev_changed = current_cef_rev != cef_rev | |
print "-- CEF Revision: %s" % current_cef_rev | |
if cef_url_changed: | |
print "\t-> CHANGED TO: %s" % cef_rev | |
# test if the Chromium URL changed | |
chromium_url_changed = current_chromium_url != chromium_url | |
print "-- Chromium URL: %s" % current_chromium_url | |
if cef_url_changed: | |
print "\t-> CHANGED TO: %s" % chromium_url | |
# test if the Chromium revision changed | |
chromium_rev_changed = current_chromium_rev != chromium_rev | |
print "-- Chromium Revision: %s" % current_chromium_rev | |
if cef_url_changed: | |
print "\t-> CHANGED TO: %s" % chromium_rev | |
# true if anything changed | |
any_changed = chromium_url_changed or chromium_rev_changed or \ | |
cef_url_changed or cef_rev_changed | |
if not any_changed: | |
print "*** NO CHANGE ***" | |
if chromium_url_changed or options.forceconfig: | |
# run gclient config to create the .gclient file | |
run('gclient config %s --git-deps' % chromium_url, cwd = chromium_dir) | |
path = os.path.join(chromium_dir, '.gclient') | |
if not os.path.exists(path): | |
raise Exception('.gclient file was not created') | |
# read the resulting .gclient file | |
fp = open(path, 'r') | |
data = fp.read() | |
fp.close() | |
# populate "custom_deps" section | |
data = data.replace('"custom_deps" : {', '"custom_deps" : {'+\ | |
"\n "+'"src/third_party/WebKit/LayoutTests": None,'+\ | |
"\n "+'"src/chrome_frame/tools/test/reference_build/chrome": None,'+\ | |
"\n "+'"src/chrome/tools/test/reference_build/chrome_mac": None,'+\ | |
"\n "+'"src/chrome/tools/test/reference_build/chrome_win": None,'+\ | |
"\n "+'"src/chrome/tools/test/reference_build/chrome_linux": None,') | |
# write the new .gclient file | |
fp = open(path, 'w') | |
fp.write(data) | |
fp.close() | |
if options.forceclean: | |
if os.path.exists(chromium_src_dir): | |
# revert all Chromium changes and delete all unversioned files | |
run('gclient revert -n', cwd = chromium_dir) | |
# force update, build and distrib steps | |
options.forceupdate = True | |
options.forcebuild = True | |
options.forcedistrib = True | |
if chromium_url_changed or chromium_rev_changed or options.forceupdate: | |
# download/update the Chromium source cod | |
fetch_rev = "HEAD" | |
if os.path.isdir(chromium_src_dir): | |
fetch_rev = get_git_rev_for_svn_rvn( | |
chromium_src_dir, current_chromium_rev) | |
run('gclient sync --jobs 8 -n --force --revision=src@%s' % fetch_rev, | |
cwd = chromium_dir) | |
checkout_rev = get_git_rev_for_svn_rvn(chromium_src_dir, chromium_rev) | |
run('gclient sync --jobs 8 --revision=src@%s' % checkout_rev, | |
cwd = chromium_dir) | |
if not os.path.exists(cef_src_dir) or cef_url_changed: | |
if cef_url_changed and os.path.exists(cef_src_dir): | |
# delete the cef directory (it will be re-downloaded) | |
shutil.rmtree(cef_src_dir) | |
# download the CEF source code | |
run("git clone %s %s" % (cef_url, cef_src_dir)) | |
elif cef_rev_changed or options.forceupdate: | |
# update the CEF source code | |
stashed = run("git stash", cwd = cef_src_dir).find( | |
"No local changes to save") < 0 | |
ref = cef_rev | |
if ref == "None": | |
ref = "origin/%s" % get_current_branch(cef_src_dir) | |
run("git fetch origin", cwd = cef_src_dir) | |
run("git reset --hard %s" % ref, cwd = cef_src_dir) | |
if stashed: | |
run("git stash pop", cwd = cef_src_dir) | |
if any_changed or options.forceupdate: | |
# create CEF projects | |
path = os.path.join(cef_src_dir, 'cef_create_projects' + script_ext) | |
run(path, cwd = cef_src_dir, quiet = True) | |
if any_changed or options.forcebuild: | |
path = os.path.join(cef_tools_dir, 'build_projects' + script_ext) | |
if not options.nodebugbuild: | |
run(path +' Debug', cwd = cef_tools_dir) | |
if not options.noreleasebuild: | |
run(path +' Release', cwd = cef_tools_dir) | |
if any_changed or options.forcedistrib: | |
if not options.nodistrib: | |
# make CEF binary distribution | |
path = os.path.join(cef_tools_dir, 'make_distrib' + script_ext) | |
run(path, cwd = cef_tools_dir) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment