| #!/usr/bin/env python3 |
| # Copyright 2026 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| import subprocess |
| import shlex |
| import os |
| import fnmatch |
| |
| # Set PRINT_GIT_LS_FILES=1 in your environment to print |
| # the `git ls-files` commands used during generation. |
| print_git_ls_files = bool(os.environ.get("PRINT_GIT_LS_FILES")) |
| |
| gn_in = open("BUILD.input.gn", "rb") |
| gn_file = gn_in.read() |
| gn_in.close() |
| |
| fuchsia_dir = os.environ["FUCHSIA_DIR"] |
| assert fuchsia_dir, "FUCHSIA_DIR environment variable should be set before calling this script!" |
| |
| # We are transitioning from v29 to v35rc1. This generator script outputs a BUILD.gn that |
| # works for both commits, depending on a use_new_protobuf gni argument. This is a soft |
| # transition artifact that should be cleaned up before closing b/468025056. |
| protobuf_v29 = "2d4414f384dc499af113b5991ce3eaa9df6dd931" |
| protobuf_v35rc1 = "8a74921d1cadfb987d7816d1cae9d2dbe89348a5" |
| |
| def get_files(paths, commit, exclude=[], append=[]): |
| # Read files from the specific git commit using git ls-tree |
| cmd = ["git", "ls-tree", "-r", "--name-only", commit] |
| if print_git_ls_files: |
| print(' '.join(shlex.quote(c) for c in cmd)) |
| git_ls = subprocess.Popen( |
| cmd, |
| stdout=subprocess.PIPE, |
| cwd=os.path.join(fuchsia_dir, "third_party", "protobuf", "src")) |
| stdout, _ = git_ls.communicate() |
| files = stdout.decode().splitlines() |
| |
| # Match globs |
| filtered_files = [] |
| for path_glob in paths: |
| for f in files: |
| if fnmatch.fnmatch(f, path_glob): |
| excluded = False |
| for ex in exclude: |
| if fnmatch.fnmatch(f, ex): |
| excluded = True |
| break |
| if not excluded: |
| filtered_files.append(f) |
| |
| # Format strings |
| result = b"" |
| for f in sorted(list(set(filtered_files))): |
| result += f' "src/{f}",\n'.encode() |
| |
| if append: |
| for item in append: |
| result += b' "' + item.encode() + b'",\n' |
| return result |
| |
| # Replace public header place holders: |
| gn_file = gn_file.replace( |
| b"PROTOBUF_LITE_PUBLIC_V29", |
| get_files( |
| ["src/google/protobuf/*.h", "src/google/protobuf/*.inc"], |
| exclude=["*/compiler/*", "*/testing/*", "*/util/*"], |
| commit=protobuf_v29 |
| ) |
| ) |
| gn_file = gn_file.replace( |
| b"PROTOBUF_LITE_PUBLIC_V35", |
| get_files( |
| ["src/google/protobuf/*.h", "src/google/protobuf/*.inc"], |
| exclude=["*/compiler/*", "*/testing/*", "*/util/*"], |
| commit=protobuf_v35rc1 |
| ) |
| ) |
| gn_file = gn_file.replace( |
| b"PROTOBUF_FULL_PUBLIC_V29", |
| get_files( |
| ["src/google/protobuf/*.h", "src/google/protobuf/*.inc"], |
| exclude=["*/compiler/*", "*/testing/*"], |
| commit=protobuf_v29 |
| ) |
| ) |
| gn_file = gn_file.replace( |
| b"PROTOBUF_FULL_PUBLIC_V35", |
| get_files( |
| ["src/google/protobuf/*.h", "src/google/protobuf/*.inc"], |
| exclude=["*/compiler/*", "*/testing/*"], |
| commit=protobuf_v35rc1 |
| ) |
| ) |
| |
| # Replace UPB_LIB_SOURCES: |
| gn_file = gn_file.replace( |
| b"UPB_LIB_SOURCES_V29", |
| get_files( |
| [ |
| "upb/port/*.h", |
| "upb/port/*.inc", |
| "upb/port/*.cc", |
| "upb/base/*.h", |
| "upb/base/*.cc", |
| "upb/mem/*.h", |
| "upb/mem/*.cc", |
| ], |
| exclude=["*_test.cc"], |
| append=[ |
| "//build/secondary/third_party/protobuf/upb_generator/common.cc", |
| ], |
| commit=protobuf_v29 |
| ) |
| ) |
| gn_file = gn_file.replace( |
| b"UPB_LIB_SOURCES_V35", |
| get_files( |
| [ |
| "upb/**/*.h", |
| "upb/**/*.inc", |
| "upb/**/*.c", |
| ], |
| exclude=[ |
| "*_test.cc", |
| "*test*", |
| "*benchmark*", |
| "upb/conformance/*", |
| "upb/cmake/*", |
| "upb/reflection/stage0/*", |
| "upb/reflection/stage1/*", |
| "upb/reflection/cmake/*", |
| "upb/json/*", |
| "upb/util/*", |
| "upb/text/*", |
| "upb/io/*", |
| ], |
| append=[ |
| "//build/secondary/third_party/protobuf/upb_generator/common.cc", |
| "src/upb/reflection/stage0/google/protobuf/descriptor.upb.c", |
| "src/upb/reflection/stage0/google/protobuf/descriptor.upb.h", |
| ], |
| commit=protobuf_v35rc1 |
| ) |
| ) |
| |
| # Replace PROTOC_LIB_SOURCES: |
| gn_file = gn_file.replace( |
| b"PROTOC_LIB_SOURCES_V29", |
| get_files( |
| ["src/google/protobuf/compiler/*.cc"], |
| exclude=["*/main.cc", "*test*", "*mock*", "src/google/protobuf/compiler/cpp/tools/*"], |
| append=["src/src/google/protobuf/testing/file.cc"], |
| commit=protobuf_v29 |
| ) |
| ) |
| gn_file = gn_file.replace( |
| b"PROTOC_LIB_SOURCES_V35", |
| get_files( |
| ["src/google/protobuf/compiler/*.cc"], |
| exclude=["*/main.cc", "*test*", "*mock*", "src/google/protobuf/compiler/cpp/tools/*"], |
| append=["src/src/google/protobuf/testing/file.cc"], |
| commit=protobuf_v35rc1 |
| ) |
| ) |
| |
| gn_out = open("BUILD.gn", "wb") |
| gn_out.write( |
| b"# THIS FILE IS GENERATED FROM BUILD.input.gn BY gen.py\n# EDIT BUILD.input.gn FIRST AND THEN RUN gen.py\n#\n#\n" |
| ) |
| gn_out.write(gn_file) |
| gn_out.close() |
| |
| try: |
| cmd = [os.path.join(fuchsia_dir, "scripts", "fx"), "gn", "format", "BUILD.gn"] |
| subprocess.check_output(cmd, text=True) |
| except subprocess.CalledProcessError as e: |
| print(f"Error formatting BUILD.gn: {e}") |