| # Copyright 2024 The Bazel Authors. All rights reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """This is a helper script to generate the log4j2 test files. |
| |
| Run it like this from the root of the repository: |
| python3 src/tools/singlejar/data/log4j2_plugins_gen.py |
| """ |
| |
| import argparse |
| import io |
| import os |
| import struct |
| import sys |
| import zipfile |
| |
| |
| class PluginEntry: |
| |
| def __init__(self, key, class_name, name, printable, defer, category): |
| self.key = key |
| self.class_name = class_name |
| self.name = name |
| self.printable = printable |
| self.defer = defer |
| self.category = category |
| |
| def __repr__(self): |
| return ( |
| f"PluginEntry(key={self.key}, class_name={self.class_name}," |
| f" name={self.name}, printable={self.printable}, defer={self.defer}," |
| f" category={self.category})" |
| ) |
| |
| |
| def read_utf_string(buffer): |
| length = struct.unpack(">H", buffer.read(2))[0] |
| return buffer.read(length).decode("utf-8") |
| |
| |
| def write_utf_string(buffer, string): |
| encoded = string.encode("utf-8") |
| buffer.write(struct.pack(">H", len(encoded))) |
| buffer.write(encoded) |
| |
| |
| def write_cache_file(categories, output_path): |
| """Writes categories to output.""" |
| buffer = io.BytesIO() |
| buffer.write(struct.pack(">I", len(categories))) |
| |
| for category, entries in categories.items(): |
| write_utf_string(buffer, category) |
| buffer.write(struct.pack(">I", len(entries))) |
| |
| for entry in entries.values(): |
| write_utf_string(buffer, entry.key) |
| write_utf_string(buffer, entry.class_name) |
| write_utf_string(buffer, entry.name) |
| buffer.write(struct.pack(">?", entry.printable)) |
| buffer.write(struct.pack(">?", entry.defer)) |
| |
| with open(output_path, "wb") as cache_file: |
| cache_file.write(buffer.getvalue()) |
| |
| |
| def load_cache_files_from_bytes(byte_data, consolidated_plugins): |
| """Loads byte_data into consolidated_plugins.""" |
| buffer = io.BytesIO(byte_data) |
| |
| count = struct.unpack(">I", buffer.read(4))[0] |
| for _ in range(count): |
| category = read_utf_string(buffer) |
| category_map = consolidated_plugins.setdefault(category, {}) |
| |
| entries = struct.unpack(">I", buffer.read(4))[0] |
| for _ in range(entries): |
| key = read_utf_string(buffer) |
| class_name = read_utf_string(buffer) |
| name = read_utf_string(buffer) |
| printable = struct.unpack(">?", buffer.read(1))[0] |
| defer = struct.unpack(">?", buffer.read(1))[0] |
| |
| if key in category_map: |
| print( |
| f"Warning: Collision detected for key '{key}' in category" |
| f" '{category}'. Existing entry will be overwritten." |
| ) |
| |
| entry = PluginEntry(key, class_name, name, printable, defer, category) |
| category_map[key] = entry |
| |
| |
| def create_jar_with_data(dat_file_path, jar_file_path): |
| jar_internal_path = ( |
| "META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat" |
| ) |
| with zipfile.ZipFile(jar_file_path, "w", zipfile.ZIP_DEFLATED) as jar: |
| jar.write(dat_file_path, arcname=jar_internal_path) |
| |
| |
| if __name__ == "__main__": |
| parser = argparse.ArgumentParser() |
| parser.add_argument("--data_dir", default="src/tools/singlejar/data") |
| parser.add_argument("--dump") |
| args = parser.parse_args() |
| |
| if args.dump: |
| with open(args.dump, "rb") as f: |
| data_bytes = f.read() |
| |
| consolidated_plugins_dict = {} |
| load_cache_files_from_bytes(data_bytes, consolidated_plugins_dict) |
| for plugin_category, plugin_entries in consolidated_plugins_dict.items(): |
| print(f"Category: {plugin_category}") |
| for k, e in plugin_entries.items(): |
| print(f" {k}: {e}") |
| sys.exit(0) |
| |
| values = [ |
| ( |
| "log4j2_plugins_set_1.jar", |
| { |
| "cat1": { |
| "key1": PluginEntry( |
| "key1", "class1", "name1", True, False, "cat1" |
| ), |
| "key2": PluginEntry( |
| "key2", "class2", "name2", False, True, "cat1" |
| ), |
| }, |
| "cat2": { |
| "key3": PluginEntry( |
| "key3", "class3", "name3", True, True, "cat2" |
| ) |
| }, |
| }, |
| ), |
| ( |
| "log4j2_plugins_set_2.jar", |
| { |
| "cat1": { |
| "key11": PluginEntry( |
| "key11", "class1", "name1", True, False, "cat1" |
| ), |
| "key12": PluginEntry( |
| "key12", "class2", "name2", False, True, "cat1" |
| ), |
| }, |
| "cat3": { |
| "key13": PluginEntry( |
| "key13", "class3", "name3", True, True, "cat3" |
| ), |
| }, |
| }, |
| ), |
| ] |
| |
| for v in values: |
| dat = os.path.join(args.data_dir, "temp.dat") |
| write_cache_file(v[1], dat) |
| create_jar_with_data(dat, os.path.join(args.data_dir, v[0])) |
| os.remove(dat) |
| |
| write_cache_file( |
| { |
| "cat1": { |
| "key1": PluginEntry( |
| "key1", "class1", "name1", True, False, "cat1" |
| ), |
| "key11": PluginEntry( |
| "key11", "class1", "name1", True, False, "cat1" |
| ), |
| "key12": PluginEntry( |
| "key12", "class2", "name2", False, True, "cat1" |
| ), |
| "key2": PluginEntry( |
| "key2", "class2", "name2", False, True, "cat1" |
| ), |
| }, |
| "cat2": { |
| "key3": PluginEntry( |
| "key3", "class3", "name3", True, True, "cat2" |
| ), |
| }, |
| "cat3": { |
| "key13": PluginEntry( |
| "key13", "class3", "name3", True, True, "cat3" |
| ), |
| }, |
| }, |
| os.path.join(args.data_dir, "log4j2_plugins_set_result.dat"), |
| ) |