Skip to content

Instantly share code, notes, and snippets.

@chrmoritz
Last active August 11, 2018 11:45
Show Gist options
  • Select an option

  • Save chrmoritz/ba453f27676da13928e237010491b0af to your computer and use it in GitHub Desktop.

Select an option

Save chrmoritz/ba453f27676da13928e237010491b0af to your computer and use it in GitHub Desktop.
import sys
import re
import base64
import hashlib
from jinja2 import Environment
from urllib2 import urlopen
from threading import Thread
def getV8TarballSha256(v8_tag, v8_sha256):
sha256 = hashlib.sha256()
sha256.update(urlopen("https://github.com/v8/v8/archive/{}.tar.gz".format(v8_tag)).read())
v8_sha256[0] = sha256.hexdigest()
def main():
# get latest stable v8_tag from omahaproxy
omahaproxy = urlopen("https://omahaproxy.appspot.com/all?os=mac&channel=stable").read()
v8_tag = re.search("mac,stable,.*,(.*)", omahaproxy).group(1)
# calculate tarball sha256 in another thread, becausing doenloading it takes the longest time
v8_sha256 = ['']
sha_thread = Thread(target=getV8TarballSha256, args=(v8_tag, v8_sha256))
sha_thread.start()
# read main DEPS file from v8 github repo via raw.githubusercontent.com
V8_DEPS = urlopen("https://raw.githubusercontent.com/v8/v8/{}/DEPS".format(v8_tag)).read()
dep_locals = {'Var': lambda x: dep_locals['vars'][x], 'False': False, 'True': True}
exec(V8_DEPS, {"__builtins__": None}, dep_locals)
# throw if recursedeps array in main DEPS file changed
# TODO: handle recursedeps properly
if dep_locals['recursedeps'] != ['v8/buildtools', 'v8/third_party/android_tools']:
raise Exception("incompatible recuredeps array found")
# parse deps from main DEPS file
deps = {}
for d, r in dep_locals['deps'].items():
# blacklisting target os here instead of whitelisting checkout_mac, TODO: handle target cpu conditions?
if isinstance(r, dict):
if r['condition'] in ['checkout_android', 'checkout_chromeos',
'checkout_fuchsia', 'checkout_ios', 'checkout_linux', 'checkout_win']:
continue
r = r['url']
repo = re.search("(.*)@(.*)", r)
deps[d] = {'path': d, 'url': repo.group(1), 'rev': repo.group(2)}
# parse hooks from main DEPS file
hooks = []
for h in dep_locals['hooks']:
if 'condition' in h:
c_locals = {
'host_os': 'mac',
'build_for_node': False,
'checkout_android': False,
'checkout_fuchsia': False,
'checkout_win': False,
'checkout_linux': False,
'False': False,
'True': True}
c_locals.update(dep_locals['vars'])
exec('condition_result = ' + h['condition'], {"__builtins__": None}, c_locals)
if not c_locals['condition_result']:
continue
hooks.append('system "' + '", "'.join(h['action']) + '"')
# read recursive DEPS file for buildtools from chromium.googlesource.com (base64 encoded)
BT_DEPS = base64.standard_b64decode(urlopen(
"https://chromium.googlesource.com/chromium/buildtools.git/+/{}/DEPS?format=TEXT".format(deps['v8/buildtools']['rev'])).read())
bt_dep_locals = {'Var': lambda x: bt_dep_locals['vars'][x], 'False': False, 'True': True}
exec(BT_DEPS, {"__builtins__": None}, bt_dep_locals)
# parse deps from buildtools recursice DEPS file
for d, r in bt_dep_locals['deps'].items():
if isinstance(r, dict): # shouldn't be needed here, just in case they use it in the future
if r['condition'] in ['checkout_android', 'checkout_chromeos',
'checkout_fuchsia', 'checkout_ios', 'checkout_linux', 'checkout_win']:
continue
r = r['url']
repo = re.search("(.*)@(.*)", r)
deps[d] = {'path': d, 'url': repo.group(1), 'rev': repo.group(2)}
env = Environment(trim_blocks=True)
FORMULA_TEMPLATE = env.from_string("""\
class V8 < Formula
desc "Google's JavaScript engine"
homepage "https://github.com/v8/v8/wiki"
url "https://github.com/v8/v8/archive/{{ v8_tag }}.tar.gz"
sha256 "{{ v8_sha256 }}"
bottle do
cellar :any
sha256 "179a8442510eb0a022ea6823cd6a76044c14c4fe18415710cac3d746d432020e" => :high_sierra
sha256 "8106efc14371982af11a66d8db533dc0589bc240950e0e445467cf6ce8871393" => :sierra
sha256 "487f2ca72096ee27d13533a6dad2d472a92ba40ef518a45226f19e94d4a79242" => :el_capitan
sha256 "dc9af3e08eda8a4acd1ff3c6b47a4c5170a92dbab7d2d79958a14d8aa42eefac" => :yosemite
sha256 "7bcd1bbd66c11305eeea0c36ca472de8a639f511abe0909c8815b1208dbce7b6" => :mavericks
end
# https://bugs.chromium.org/p/chromium/issues/detail?id=620127
depends_on :macos => :el_capitan
# depot_tools/GN require Python 2.7+
depends_on "python@2" => :build
needs :cxx11
{% for d in deps.values() %}
{% include ResourceTemplate %}
{% endfor %}
def install
(buildpath/"v8").install Dir.glob("*", File::FNM_DOTMATCH) - %w[. .. .brew_home]
# autogenerated installing resources to paths according to DEPS file
{% for d in deps.values() %}
(buildpath/"{{ d.path }}").install resource("{{ d.path }}")
{% endfor %}
# add depot_tools to PATH (for download_from_google_storage tool)
ENV.prepend_path "PATH", buildpath/"v8/third_party/depot_tools"
# autogenerated system calls for hooks in DEPS file
{% for h in hooks %}
{{ h }}
{% endfor %}
cd "v8" do
output_path = "out.gn/x64.release"
gn_args = {
:is_debug => false,
:is_component_build => true,
:v8_use_external_startup_data => false,
:v8_enable_i18n_support => true,
}
# Transform to args string
gn_args_string = gn_args.map { |k, v| "#{k}=#{v}" }.join(" ")
# Build with gn + ninja
system "gn",
"gen",
"--args=#{gn_args_string}",
output_path
system "ninja",
"-j", ENV.make_jobs,
"-C", output_path,
"-v",
"d8"
# Install all the things
include.install Dir["include/*"]
cd output_path do
lib.install Dir["lib*.dylib"]
# Install d8 and icudtl.dat in libexec and symlink
# because they need to be in the same directory.
libexec.install Dir["d8", "icudt*.dat"]
(bin/"d8").write <<~EOS
#!/bin/bash
exec "#{libexec}/d8" --icu-data-file="#{libexec}/icudtl.dat" "$@"
EOS
end
end
end
test do
assert_equal "Hello World!", shell_output("#{bin}/d8 -e 'print(\\"Hello World!\\");'").chomp
assert_match %r{12/\\d{2}/2012}, shell_output("#{bin}/d8 -e 'print(new Intl.DateTimeFormat(\\"en-US\\").format(new Date(Date.UTC(2012, 11, 20, 3, 0, 0))));'").chomp
end
end
""")
RESOURCE_TEMPLATE = env.from_string("""\
resource "{{ d.path }}" do
url "{{ d.url }}",
:revision => "{{ d.rev }}"
end
""")
sha_thread.join() # waiting for v8 tarball hasher thread
formula = FORMULA_TEMPLATE.render(
v8_tag=v8_tag,
v8_sha256=v8_sha256[0],
deps=deps,
hooks=hooks,
ResourceTemplate=RESOURCE_TEMPLATE)
print(formula)
return 0
if __name__ == '__main__':
sys.exit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment