# Protobuf PHP runtime
#
# See also code generation logic under /src/google/protobuf/compiler/php.

load("@rules_pkg//pkg:mappings.bzl", "pkg_filegroup", "pkg_files")
load("@rules_pkg//pkg:tar.bzl", "pkg_tar")
load("//:protobuf_version.bzl", "PROTOBUF_PHP_VERSION", "PROTOC_VERSION")
load("//build_defs:internal_shell.bzl", "inline_sh_binary")
load("//conformance:defs.bzl", "conformance_test")
load("//php:internal_generated_files.bzl", "DESCRIPTOR_GENERATED_FILES", "WKT_GENERATED_FILES")
load("//upb/cmake:build_defs.bzl", "staleness_test")

# We must explicitly classify every checked-in php file because we can't
# distinguish gencode from hand-written code.  The former must be kept
# up-to-date though, using our staleness infrastructure.

_RUNTIME_SOURCES = [
    "src/Google/Protobuf/Descriptor.php",
    "src/Google/Protobuf/DescriptorPool.php",
    "src/Google/Protobuf/EnumDescriptor.php",
    "src/Google/Protobuf/EnumValueDescriptor.php",
    "src/Google/Protobuf/FieldDescriptor.php",
    "src/Google/Protobuf/Internal/AnyBase.php",
    "src/Google/Protobuf/Internal/CodedInputStream.php",
    "src/Google/Protobuf/Internal/CodedOutputStream.php",
    "src/Google/Protobuf/Internal/Descriptor.php",
    "src/Google/Protobuf/Internal/DescriptorPool.php",
    "src/Google/Protobuf/Internal/EnumBuilderContext.php",
    "src/Google/Protobuf/Internal/EnumDescriptor.php",
    "src/Google/Protobuf/Internal/FieldDescriptor.php",
    "src/Google/Protobuf/Internal/FileDescriptor.php",
    "src/Google/Protobuf/Internal/GetPublicDescriptorTrait.php",
    "src/Google/Protobuf/Internal/GPBDecodeException.php",
    "src/Google/Protobuf/Internal/GPBJsonWire.php",
    "src/Google/Protobuf/Internal/GPBLabel.php",
    "src/Google/Protobuf/Internal/GPBType.php",
    "src/Google/Protobuf/Internal/GPBUtil.php",
    "src/Google/Protobuf/Internal/GPBWire.php",
    "src/Google/Protobuf/Internal/GPBWireType.php",
    "src/Google/Protobuf/Internal/HasPublicDescriptorTrait.php",
    "src/Google/Protobuf/Internal/MapEntry.php",
    "src/Google/Protobuf/Internal/MapField.php",
    "src/Google/Protobuf/Internal/MapFieldIter.php",
    "src/Google/Protobuf/Internal/Message.php",
    "src/Google/Protobuf/Internal/MessageBuilderContext.php",
    "src/Google/Protobuf/Internal/OneofDescriptor.php",
    "src/Google/Protobuf/Internal/OneofField.php",
    "src/Google/Protobuf/Internal/RawInputStream.php",
    "src/Google/Protobuf/Internal/RepeatedFieldIter.php",
    "src/Google/Protobuf/Internal/TimestampBase.php",
    "src/Google/Protobuf/OneofDescriptor.php",
    "src/Google/Protobuf/PrintOptions.php",
    "src/Google/Protobuf/RepeatedField.php",
]

filegroup(
    name = "source_files",
    srcs = _RUNTIME_SOURCES +
           ["generated/" + f for f in DESCRIPTOR_GENERATED_FILES + WKT_GENERATED_FILES] + [
        "composer.json",
        ":php_ext_source_files",
    ],
    visibility = [
        "//conformance:__pkg__",
        "//php:__pkg__",
    ],
)

################################################################################
# PHP Extension
################################################################################

inline_sh_binary(
    name = "build_extension",
    cmd = """
        mkdir -p php/ext/google/protobuf/third_party/utf8_range
        cp third_party/utf8_range/* php/ext/google/protobuf/third_party/utf8_range

        pushd  php/ext/google/protobuf
        phpize
        ./configure --with-php-config=$$(which php-config)
        make
        popd
    """,
)

genrule(
    name = "extension",
    srcs = [
        ":source_files",
        "//third_party/utf8_range:utf8_range_srcs",
        "generated/ext/google/protobuf/wkt.inc",
        "generated/ext/google/protobuf/php-upb.h",
        "generated/ext/google/protobuf/php-upb.c",
    ],
    outs = ["protobuf.so"],
    cmd = """
        mkdir -p php/ext/google/protobuf
        cp -f $(location generated/ext/google/protobuf/wkt.inc) php/ext/google/protobuf
        cp -f $(location generated/ext/google/protobuf/php-upb.h) php/ext/google/protobuf
        cp -f $(location generated/ext/google/protobuf/php-upb.c) php/ext/google/protobuf
        ./$(execpath :build_extension) $@
        cp php/ext/google/protobuf/modules/protobuf.so $(OUTS)
    """,
    tools = [":build_extension"],
    visibility = ["//visibility:public"],
)

################################################################################
# Tests
################################################################################

conformance_test(
    name = "conformance_test",
    failure_list = "//conformance:failure_list_php.txt",
    maximum_edition = "2023",
    testee = "//conformance:conformance_php",
    text_format_failure_list = "//conformance:text_format_failure_list_php.txt",
)

conformance_test(
    name = "conformance_test_c",
    failure_list = "//conformance:failure_list_php_c.txt",
    maximum_edition = "2023",
    testee = "//conformance:conformance_php_c",
    text_format_failure_list = "//conformance:text_format_failure_list_php.txt",
)

genrule(
    name = "copy_php_amalgamation_h",
    srcs = ["//upb:php-upb.h"],
    outs = ["generated/ext/google/protobuf/php-upb.h"],
    cmd = "cp $< $@",
)

genrule(
    name = "copy_php_amalgamation_c",
    srcs = ["//upb:php-upb.c"],
    outs = ["generated/ext/google/protobuf/php-upb.c"],
    cmd = "cp $< $@",
)

staleness_test(
    name = "test_amalgamation_staleness",
    outs = [
        "ext/google/protobuf/php-upb.c",
        "ext/google/protobuf/php-upb.h",
        "ext/google/protobuf/wkt.inc",
    ],
    generated_pattern = "generated/%s",
    tags = ["manual"],
)

# The WKTs have to be checked in to support the Composer builds. This
# generule and test ensure the source are current.

# Make sure we error if new files start showing up, since that may go unnoticed.
_CHECK_GENCODE = """
for f in $$(find $(@D) -name "*.php"); do
    local=$$(echo $$f | sed "s:bazel-out.*.bin.php.::g");
    if [[ "$(OUTS)" != *$$local* ]]; then
        echo "Extra generated file $$local!  Please update the lists in php/internal_generated_files.bzl" && exit 1;
    fi
done
"""

# These must be combined due to windows sandbox isolation issues.
genrule(
    name = "gen_wkt_sources",
    srcs = [
        "//src/google/protobuf:well_known_type_protos",
        "//src/google/protobuf:descriptor_proto_srcs",
    ],
    outs = ["generated/" + wkt for wkt in WKT_GENERATED_FILES + DESCRIPTOR_GENERATED_FILES] + [
        "generated/ext/google/protobuf/wkt.inc",
    ],
    cmd = """
        $(execpath //:protoc) --php_out=internal_generate_c_wkt:$(RULEDIR)/generated/src --unsafe_allow_out_dir_escape --proto_path=src $(locations //src/google/protobuf:well_known_type_protos);
        $(execpath //:protoc) --php_out=internal:$(RULEDIR)/generated/src --proto_path=src $(location //src/google/protobuf:descriptor_proto_srcs);
    """ + _CHECK_GENCODE,
    tags = ["manual"],
    tools = ["//:protoc"],
)

staleness_test(
    name = "proto_staleness_test",
    outs = glob(
        ["src/**/*.php"],
        allow_empty = True,
        exclude = _RUNTIME_SOURCES + WKT_GENERATED_FILES + DESCRIPTOR_GENERATED_FILES,
    ) + WKT_GENERATED_FILES + DESCRIPTOR_GENERATED_FILES,
    generated_pattern = "generated/%s",
    tags = ["manual"],
)

################################################################################
# PECL .tgz Release
################################################################################

pkg_files(
    name = "php_ext_source_files",
    srcs = glob(
        [
            "ext/google/protobuf/*.h",
            "ext/google/protobuf/*.c",
        ],
        exclude = [
            "*/php-upb.*",
            "*/wkt.inc",
        ],
    ) + [
        "ext/google/protobuf/config.m4",
        "ext/google/protobuf/config.w32",
        "//:LICENSE",
    ],
)

pkg_files(
    name = "utf8_range_files",
    srcs = [
        "//third_party/utf8_range:LICENSE",
        "//third_party/utf8_range:utf8_range_srcs",
    ],
    prefix = "third_party/utf8_range",
)

pkg_files(
    name = "generated_files",
    srcs = [
        "ext/google/protobuf/php-upb.c",
        "ext/google/protobuf/php-upb.h",
        "ext/google/protobuf/wkt.inc",
    ],
    prefix = "third_party/utf8_range",
)

pkg_filegroup(
    name = "pecl_release_files",
    srcs = [
        ":generated_files",
        ":php_ext_source_files",
        ":utf8_range_files",
    ],
    prefix = "protobuf-%s" % PROTOBUF_PHP_VERSION,
)

# PECL .tgz without package.xml
pkg_tar(
    name = "release_without_package",
    srcs = [
        ":pecl_release_files",
    ],
    out = "release_without_package.tgz",
    extension = "tgz",
)

# Generate PECL package.xml
genrule(
    name = "generate_package_xml",
    srcs = [
        ":release_without_package",
        "ext/google/protobuf/template_package.xml",
    ],
    outs = ["package.xml"],
    cmd = " ".join([
        "$(location ext/google/protobuf/generate_package_xml.sh)",
        "$(location ext/google/protobuf/template_package.xml)",
        PROTOBUF_PHP_VERSION,
        PROTOC_VERSION,
        "$$(tar -tf $(location :release_without_package) | sed -z -e 's;\\n;,;g')",
        "$(location package.xml)",
    ]),
    tools = ["ext/google/protobuf/generate_package_xml.sh"],
)

pkg_tar(
    name = "release",
    srcs = [
        ":generate_package_xml",
        ":pecl_release_files",
    ],
    out = "protobuf-%s.tgz" % PROTOBUF_PHP_VERSION,
    extension = "tgz",
)
