# Copyright (C) 2018 and later: Unicode, Inc. and others. # License & terms of use: http://www.unicode.org/copyright.html # Python 2/3 Compatibility (ICU-20299) # TODO(ICU-20301): Remove this. from __future__ import print_function from icutools.databuilder import * from icutools.databuilder import utils from icutools.databuilder.request_types import * import os import sys def generate(config, io, common_vars): requests = [] if len(io.glob("misc/*")) == 0: print("Error: Cannot find data directory; please specify --src_dir", file=sys.stderr) exit(1) requests += generate_cnvalias(config, io, common_vars) requests += generate_ulayout(config, io, common_vars) requests += generate_confusables(config, io, common_vars) requests += generate_conversion_mappings(config, io, common_vars) requests += generate_brkitr_brk(config, io, common_vars) requests += generate_stringprep(config, io, common_vars) requests += generate_brkitr_dictionaries(config, io, common_vars) requests += generate_normalization(config, io, common_vars) requests += generate_coll_ucadata(config, io, common_vars) requests += generate_full_unicore_data(config, io, common_vars) requests += generate_unames(config, io, common_vars) requests += generate_misc(config, io, common_vars) requests += generate_curr_supplemental(config, io, common_vars) requests += generate_translit(config, io, common_vars) # Res Tree Files # (input dirname, output dirname, resfiles.mk path, mk version var, mk source var, use pool file, dep files) requests += generate_tree(config, io, common_vars, "locales", None, config.use_pool_bundle, []) requests += generate_tree(config, io, common_vars, "curr", "curr", config.use_pool_bundle, []) requests += generate_tree(config, io, common_vars, "lang", "lang", config.use_pool_bundle, []) requests += generate_tree(config, io, common_vars, "region", "region", config.use_pool_bundle, []) requests += generate_tree(config, io, common_vars, "zone", "zone", config.use_pool_bundle, []) requests += generate_tree(config, io, common_vars, "unit", "unit", config.use_pool_bundle, []) requests += generate_tree(config, io, common_vars, "coll", "coll", # Never use pool bundle for coll, brkitr, or rbnf False, # Depends on timezoneTypes.res and keyTypeData.res. # TODO: We should not need this dependency to build collation. # TODO: Bake keyTypeData.res into the common library? [DepTarget("coll_ucadata"), DepTarget("misc_res"), InFile("unidata/UCARules.txt")]) requests += generate_tree(config, io, common_vars, "brkitr", "brkitr", # Never use pool bundle for coll, brkitr, or rbnf False, [DepTarget("brkitr_brk"), DepTarget("dictionaries")]) requests += generate_tree(config, io, common_vars, "rbnf", "rbnf", # Never use pool bundle for coll, brkitr, or rbnf False, []) requests += [ ListRequest( name = "icudata_list", variable_name = "icudata_all_output_files", output_file = TmpFile("icudata.lst"), include_tmp = False ) ] return requests def generate_cnvalias(config, io, common_vars): # UConv Name Aliases input_file = InFile("mappings/convrtrs.txt") output_file = OutFile("cnvalias.icu") return [ SingleExecutionRequest( name = "cnvalias", category = "cnvalias", dep_targets = [], input_files = [input_file], output_files = [output_file], tool = IcuTool("gencnval"), args = "-s {IN_DIR} -d {OUT_DIR} " "{INPUT_FILES[0]}", format_with = {} ) ] def generate_confusables(config, io, common_vars): # CONFUSABLES txt1 = InFile("unidata/confusables.txt") txt2 = InFile("unidata/confusablesWholeScript.txt") cfu = OutFile("confusables.cfu") return [ SingleExecutionRequest( name = "confusables", category = "confusables", dep_targets = [DepTarget("cnvalias")], input_files = [txt1, txt2], output_files = [cfu], tool = IcuTool("gencfu"), args = "-d {OUT_DIR} -i {OUT_DIR} " "-c -r {IN_DIR}/{INPUT_FILES[0]} -w {IN_DIR}/{INPUT_FILES[1]} " "-o {OUTPUT_FILES[0]}", format_with = {} ) ] def generate_conversion_mappings(config, io, common_vars): # UConv Conversion Table Files input_files = [InFile(filename) for filename in io.glob("mappings/*.ucm")] output_files = [OutFile("%s.cnv" % v.filename[9:-4]) for v in input_files] # TODO: handle BUILD_SPECIAL_CNV_FILES? Means to add --ignore-siso-check flag to makeconv return [ RepeatedOrSingleExecutionRequest( name = "conversion_mappings", category = "conversion_mappings", dep_targets = [], input_files = input_files, output_files = output_files, tool = IcuTool("makeconv"), # BEGIN android-changed # args = "-s {IN_DIR} -d {OUT_DIR} -c {INPUT_FILE_PLACEHOLDER}", args = "-s {IN_DIR} -d {OUT_DIR} -c --small {INPUT_FILE_PLACEHOLDER}", # END android-changed format_with = {}, repeat_with = { "INPUT_FILE_PLACEHOLDER": utils.SpaceSeparatedList(file.filename for file in input_files) } ) ] def generate_brkitr_brk(config, io, common_vars): # BRK Files input_files = [InFile(filename) for filename in io.glob("brkitr/rules/*.txt")] output_files = [OutFile("brkitr/%s.brk" % v.filename[13:-4]) for v in input_files] return [ RepeatedExecutionRequest( name = "brkitr_brk", category = "brkitr_rules", dep_targets = [DepTarget("cnvalias"), DepTarget("ulayout")], input_files = input_files, output_files = output_files, tool = IcuTool("genbrk"), args = "-d {OUT_DIR} -i {OUT_DIR} " "-c -r {IN_DIR}/{INPUT_FILE} " "-o {OUTPUT_FILE}", format_with = {}, repeat_with = {} ) ] def generate_stringprep(config, io, common_vars): # SPP FILES input_files = [InFile(filename) for filename in io.glob("sprep/*.txt")] output_files = [OutFile("%s.spp" % v.filename[6:-4]) for v in input_files] bundle_names = [v.filename[6:-4] for v in input_files] return [ RepeatedExecutionRequest( name = "stringprep", category = "stringprep", dep_targets = [InFile("unidata/NormalizationCorrections.txt")], input_files = input_files, output_files = output_files, tool = IcuTool("gensprep"), args = "-s {IN_DIR}/sprep -d {OUT_DIR} -i {OUT_DIR} " "-b {BUNDLE_NAME} -m {IN_DIR}/unidata -u 3.2.0 {BUNDLE_NAME}.txt", format_with = {}, repeat_with = { "BUNDLE_NAME": bundle_names } ) ] def generate_brkitr_dictionaries(config, io, common_vars): # Dict Files input_files = [InFile(filename) for filename in io.glob("brkitr/dictionaries/*.txt")] output_files = [OutFile("brkitr/%s.dict" % v.filename[20:-4]) for v in input_files] extra_options_map = { "brkitr/dictionaries/burmesedict.txt": "--bytes --transform offset-0x1000", "brkitr/dictionaries/cjdict.txt": "--uchars", "brkitr/dictionaries/khmerdict.txt": "--bytes --transform offset-0x1780", "brkitr/dictionaries/laodict.txt": "--bytes --transform offset-0x0e80", "brkitr/dictionaries/thaidict.txt": "--bytes --transform offset-0x0e00" } extra_optionses = [extra_options_map[v.filename] for v in input_files] return [ RepeatedExecutionRequest( name = "dictionaries", category = "brkitr_dictionaries", dep_targets = [], input_files = input_files, output_files = output_files, tool = IcuTool("gendict"), args = "-i {OUT_DIR} " "-c {EXTRA_OPTIONS} " "{IN_DIR}/{INPUT_FILE} {OUT_DIR}/{OUTPUT_FILE}", format_with = {}, repeat_with = { "EXTRA_OPTIONS": extra_optionses } ) ] def generate_normalization(config, io, common_vars): # NRM Files input_files = [InFile(filename) for filename in io.glob("in/*.nrm")] # nfc.nrm is pre-compiled into C++; see generate_full_unicore_data input_files.remove(InFile("in/nfc.nrm")) output_files = [OutFile(v.filename[3:]) for v in input_files] return [ RepeatedExecutionRequest( name = "normalization", category = "normalization", dep_targets = [], input_files = input_files, output_files = output_files, tool = IcuTool("icupkg"), args = "-t{ICUDATA_CHAR} {IN_DIR}/{INPUT_FILE} {OUT_DIR}/{OUTPUT_FILE}", format_with = {}, repeat_with = {} ) ] def generate_coll_ucadata(config, io, common_vars): # Collation Dependency File (ucadata.icu) input_file = InFile("in/coll/ucadata-%s.icu" % config.coll_han_type) output_file = OutFile("coll/ucadata.icu") return [ SingleExecutionRequest( name = "coll_ucadata", category = "coll_ucadata", dep_targets = [], input_files = [input_file], output_files = [output_file], tool = IcuTool("icupkg"), args = "-t{ICUDATA_CHAR} {IN_DIR}/{INPUT_FILES[0]} {OUT_DIR}/{OUTPUT_FILES[0]}", format_with = {} ) ] def generate_full_unicore_data(config, io, common_vars): # The core Unicode properties files (pnames.icu, uprops.icu, ucase.icu, ubidi.icu) # are hardcoded in the common DLL and therefore not included in the data package any more. # They are not built by default but need to be built for ICU4J data, # both in the .jar and in the .dat file (if ICU4J uses the .dat file). # See ICU-4497. if not config.include_uni_core_data: return [] basenames = [ "pnames.icu", "uprops.icu", "ucase.icu", "ubidi.icu", "nfc.nrm" ] input_files = [InFile("in/%s" % bn) for bn in basenames] output_files = [OutFile(bn) for bn in basenames] return [ RepeatedExecutionRequest( name = "unicore", category = "unicore", input_files = input_files, output_files = output_files, tool = IcuTool("icupkg"), args = "-t{ICUDATA_CHAR} {IN_DIR}/{INPUT_FILE} {OUT_DIR}/{OUTPUT_FILE}" ) ] def generate_unames(config, io, common_vars): # Unicode Character Names input_file = InFile("in/unames.icu") output_file = OutFile("unames.icu") return [ SingleExecutionRequest( name = "unames", category = "unames", dep_targets = [], input_files = [input_file], output_files = [output_file], tool = IcuTool("icupkg"), args = "-t{ICUDATA_CHAR} {IN_DIR}/{INPUT_FILES[0]} {OUT_DIR}/{OUTPUT_FILES[0]}", format_with = {} ) ] def generate_ulayout(config, io, common_vars): # Unicode text layout properties basename = "ulayout" input_file = InFile("in/%s.icu" % basename) output_file = OutFile("%s.icu" % basename) return [ SingleExecutionRequest( name = basename, category = basename, dep_targets = [], input_files = [input_file], output_files = [output_file], tool = IcuTool("icupkg"), args = "-t{ICUDATA_CHAR} {IN_DIR}/{INPUT_FILES[0]} {OUT_DIR}/{OUTPUT_FILES[0]}", format_with = {} ) ] def generate_misc(config, io, common_vars): # Misc Data Res Files input_files = [InFile(filename) for filename in io.glob("misc/*.txt")] input_basenames = [v.filename[5:] for v in input_files] output_files = [OutFile("%s.res" % v[:-4]) for v in input_basenames] return [ RepeatedExecutionRequest( name = "misc_res", category = "misc", dep_targets = [], input_files = input_files, output_files = output_files, tool = IcuTool("genrb"), args = "-s {IN_DIR}/misc -d {OUT_DIR} -i {OUT_DIR} " "-k -q " "{INPUT_BASENAME}", format_with = {}, repeat_with = { "INPUT_BASENAME": input_basenames } ) ] def generate_curr_supplemental(config, io, common_vars): # Currency Supplemental Res File input_file = InFile("curr/supplementalData.txt") input_basename = "supplementalData.txt" output_file = OutFile("curr/supplementalData.res") return [ SingleExecutionRequest( name = "curr_supplemental_res", category = "curr_supplemental", dep_targets = [], input_files = [input_file], output_files = [output_file], tool = IcuTool("genrb"), args = "-s {IN_DIR}/curr -d {OUT_DIR}/curr -i {OUT_DIR} " "-k " "{INPUT_BASENAME}", format_with = { "INPUT_BASENAME": input_basename } ) ] def generate_translit(config, io, common_vars): input_files = [ InFile("translit/root.txt"), InFile("translit/en.txt"), InFile("translit/el.txt") ] dep_files = set(InFile(filename) for filename in io.glob("translit/*.txt")) dep_files -= set(input_files) dep_files = list(sorted(dep_files)) input_basenames = [v.filename[9:] for v in input_files] output_files = [ OutFile("translit/%s.res" % v[:-4]) for v in input_basenames ] return [ RepeatedOrSingleExecutionRequest( name = "translit_res", category = "translit", dep_targets = dep_files, input_files = input_files, output_files = output_files, tool = IcuTool("genrb"), args = "-s {IN_DIR}/translit -d {OUT_DIR}/translit -i {OUT_DIR} " "-k " "{INPUT_BASENAME}", format_with = { }, repeat_with = { "INPUT_BASENAME": utils.SpaceSeparatedList(input_basenames) } ) ] def generate_tree( config, io, common_vars, sub_dir, out_sub_dir, use_pool_bundle, dep_targets): requests = [] category = "%s_tree" % sub_dir out_prefix = "%s/" % out_sub_dir if out_sub_dir else "" # TODO: Clean this up for curr input_files = [InFile(filename) for filename in io.glob("%s/*.txt" % sub_dir)] if sub_dir == "curr": input_files.remove(InFile("curr/supplementalData.txt")) input_basenames = [v.filename[len(sub_dir)+1:] for v in input_files] output_files = [ OutFile("%s%s.res" % (out_prefix, v[:-4])) for v in input_basenames ] # Generate Pool Bundle if use_pool_bundle: input_pool_files = [OutFile("%spool.res" % out_prefix)] pool_target_name = "%s_pool_write" % sub_dir use_pool_bundle_option = "--usePoolBundle {OUT_DIR}/{OUT_PREFIX}".format( OUT_PREFIX = out_prefix, **common_vars ) requests += [ SingleExecutionRequest( name = pool_target_name, category = category, dep_targets = dep_targets, input_files = input_files, output_files = input_pool_files, tool = IcuTool("genrb"), args = "-s {IN_DIR}/{IN_SUB_DIR} -d {OUT_DIR}/{OUT_PREFIX} -i {OUT_DIR} " "--writePoolBundle -k " "{INPUT_BASENAMES_SPACED}", format_with = { "IN_SUB_DIR": sub_dir, "OUT_PREFIX": out_prefix, "INPUT_BASENAMES_SPACED": utils.SpaceSeparatedList(input_basenames) } ), ] dep_targets = dep_targets + [DepTarget(pool_target_name)] else: use_pool_bundle_option = "" # Generate Res File Tree requests += [ RepeatedOrSingleExecutionRequest( name = "%s_res" % sub_dir, category = category, dep_targets = dep_targets, input_files = input_files, output_files = output_files, tool = IcuTool("genrb"), # BEGIN android-changed args = "-s {IN_DIR}/{IN_SUB_DIR} -d {OUT_DIR}/{OUT_PREFIX} -i {OUT_DIR} " + ("--omitCollationRules " if sub_dir == "coll" else "") + "{EXTRA_OPTION} -k " "{INPUT_BASENAME}", # END android-changed format_with = { "IN_SUB_DIR": sub_dir, "OUT_PREFIX": out_prefix, "EXTRA_OPTION": use_pool_bundle_option }, repeat_with = { "INPUT_BASENAME": utils.SpaceSeparatedList(input_basenames) } ) ] # Generate res_index file # Exclude the deprecated locale variants and root; see ICU-20628. This # could be data-driven, but we do not want to perform I/O in this script # (for example, we do not want to read from an XML file). excluded_locales = set([ "ja_JP_TRADITIONAL", "th_TH_TRADITIONAL", "de_", "de__PHONEBOOK", "es_", "es__TRADITIONAL", "root", ]) # Put alias locales in a separate structure; see ICU-20627 dependency_data = io.read_locale_deps(sub_dir) if "aliases" in dependency_data: alias_locales = set(dependency_data["aliases"].keys()) else: alias_locales = set() alias_files = [] installed_files = [] for f in input_files: file_stem = IndexRequest.locale_file_stem(f) if file_stem in excluded_locales: continue destination = alias_files if file_stem in alias_locales else installed_files destination.append(f) cldr_version = dependency_data["cldrVersion"] if sub_dir == "locales" else None index_file_txt = TmpFile("{IN_SUB_DIR}/{INDEX_NAME}.txt".format( IN_SUB_DIR = sub_dir, **common_vars )) index_res_file = OutFile("{OUT_PREFIX}{INDEX_NAME}.res".format( OUT_PREFIX = out_prefix, **common_vars )) index_file_target_name = "%s_index_txt" % sub_dir requests += [ IndexRequest( name = index_file_target_name, category = category, installed_files = installed_files, alias_files = alias_files, txt_file = index_file_txt, output_file = index_res_file, cldr_version = cldr_version, args = "-s {TMP_DIR}/{IN_SUB_DIR} -d {OUT_DIR}/{OUT_PREFIX} -i {OUT_DIR} " "-k " "{INDEX_NAME}.txt", format_with = { "IN_SUB_DIR": sub_dir, "OUT_PREFIX": out_prefix } ) ] return requests