build.py (3947B)
1 # This Source Code Form is subject to the terms of the Mozilla Public 2 # License, v. 2.0. If a copy of the MPL was not distributed with this 3 # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 5 import json 6 import os.path 7 import re 8 import sys 9 10 BASE = os.path.dirname(__file__.replace("\\", "/")) 11 sys.path.insert(0, BASE) # For importing `data.py` 12 13 from mako import exceptions 14 from mako.lookup import TemplateLookup 15 from mako.template import Template 16 17 import data 18 19 RE_PYTHON_ADDR = re.compile(r"<.+? object at 0x[0-9a-fA-F]+>") 20 21 OUT_DIR = os.environ.get("OUT_DIR", "") 22 23 24 def main(): 25 usage = ( 26 "Usage: %s [ servo | gecko ] [ style-crate | geckolib <template> ]" 27 % sys.argv[0] 28 ) 29 if len(sys.argv) < 3: 30 abort(usage) 31 engine = sys.argv[1] 32 output = sys.argv[2] 33 34 if engine not in ["servo", "gecko"] or output not in [ 35 "style-crate", 36 "geckolib", 37 ]: 38 abort(usage) 39 40 properties = data.PropertiesData(engine=engine) 41 properties_template = os.path.join(BASE, "properties.mako.rs") 42 properties_file = render( 43 properties_template, 44 engine=engine, 45 data=properties, 46 __file__=properties_template, 47 OUT_DIR=OUT_DIR, 48 ) 49 if output == "style-crate": 50 write(OUT_DIR, "properties.rs", properties_file) 51 52 if engine == "servo": 53 properties_dict = { 54 kind: { 55 p.name: {"pref": getattr(p, "servo_pref")} 56 for prop in properties_list 57 if prop.enabled_in_content() 58 for p in [prop] + prop.aliases 59 } 60 for kind, properties_list in [ 61 ("longhands", properties.longhands), 62 ("shorthands", properties.shorthands), 63 ] 64 } 65 as_html = render( 66 os.path.join(BASE, "properties.html.mako"), properties=properties_dict 67 ) 68 as_json = json.dumps(properties_dict, indent=4, sort_keys=True) 69 70 # Four dotdots: /path/to/target(4)/debug(3)/build(2)/style-*(1)/out 71 # Do not ascend above the target dir, because it may not be called target 72 # or even have a parent (see CARGO_TARGET_DIR). 73 doc_servo = os.path.join(OUT_DIR, "..", "..", "..", "..", "doc", "stylo") 74 75 write(doc_servo, "css-properties.html", as_html) 76 write(doc_servo, "css-properties.json", as_json) 77 write(OUT_DIR, "css-properties.json", as_json) 78 elif output == "geckolib": 79 if len(sys.argv) < 4: 80 abort(usage) 81 template = sys.argv[3] 82 header = render(template, data=properties) 83 sys.stdout.write(header) 84 85 86 def abort(message): 87 print(message, file=sys.stderr) 88 sys.exit(1) 89 90 91 def render(filename, **context): 92 try: 93 lookup = TemplateLookup( 94 directories=[BASE], input_encoding="utf8", strict_undefined=True 95 ) 96 template = Template( 97 open(filename, "rb").read(), 98 filename=filename, 99 input_encoding="utf8", 100 lookup=lookup, 101 strict_undefined=True, 102 ) 103 # Uncomment to debug generated Python code: 104 # write("/tmp", "mako_%s.py" % os.path.basename(filename), template.code) 105 return template.render(**context) 106 except Exception: 107 # Uncomment to see a traceback in generated Python code: 108 # raise 109 abort(exceptions.text_error_template().render()) 110 111 112 def write(directory, filename, content): 113 if not os.path.exists(directory): 114 os.makedirs(directory) 115 full_path = os.path.join(directory, filename) 116 open(full_path, "w", encoding="utf-8", newline="").write(content) 117 118 python_addr = RE_PYTHON_ADDR.search(content) 119 if python_addr: 120 abort('Found "{}" in {} ({})'.format(python_addr.group(0), filename, full_path)) 121 122 123 if __name__ == "__main__": 124 main()