blob: 869fd6227abee45edf5e015ad3d91e5b99a48797 [file] [log] [blame]
# 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"),
)