diff --git a/.bazelignore b/.bazelignore new file mode 100644 index 00000000000..a1fd437354a --- /dev/null +++ b/.bazelignore @@ -0,0 +1,2 @@ +.bazel-user-root +.bazelisk-home diff --git a/.bazelrc b/.bazelrc index 393e2a552e3..97bc251daa1 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,5 +1,31 @@ +common --noenable_bzlmod +common --enable_platform_specific_config common --experimental_repo_remote_exec # from TensorFlow +# Bazel 7's synthesized Python package init files can shadow TensorBoard's real +# compat package init at test runtime; keep this test-only so pip packaging +# still copies the intended package tree. +test --incompatible_default_to_explicit_init_py # Use C++ backing implementations for Python proto parsing and deserialization, # which is much faster (~10x). build --define=use_fast_cpp_protos=true + +# TensorFlow 2.21 builds with C++17 across supported platforms, and protobuf +# 6.31.1 requires that language level. +common:linux --cxxopt=-std=c++17 +common:linux --host_cxxopt=-std=c++17 +common:macos --cxxopt=-std=c++17 +common:macos --host_cxxopt=-std=c++17 +common:windows --cxxopt=/std:c++17 +common:windows --host_cxxopt=/std:c++17 + +# Local shells and virtualenvs can leak Python import state into Bazel tests, +# which then import from the wrong environment instead of the test runfiles. +test --test_env=PYTHONPATH= +test --test_env=PYTHONHOME= +test --test_env=PYTHONSTARTUP= +test --test_env=PYTHONSAFEPATH= +test --test_env=PYTHONNOUSERSITE=1 +test --test_env=PYTHONUSERBASE= +test --test_env=BUILD_WORKSPACE_DIRECTORY= +test --test_env=BUILD_WORKING_DIRECTORY= diff --git a/.bazelversion b/.bazelversion index f22d756da39..1985849fb58 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -6.5.0 +7.7.0 diff --git a/.gitattributes b/.gitattributes index 752a9642c09..75e06739b02 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,10 @@ +* text=auto +*.bzl text eol=lf +*.sh text eol=lf +.bazel* text eol=lf +BUILD text eol=lf +BUILD.bazel text eol=lf +WORKSPACE text eol=lf +MODULE.bazel text eol=lf + third_party/rust/** -diff -merge linguist-generated=true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c72e042a1ce..f6fadf1d68b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,8 +25,8 @@ permissions: env: # Keep this Bazel version in sync with the `versions.check` directive # in our WORKSPACE file. - BAZEL_VERSION: '6.5.0' - BAZEL_SHA256SUM: 'a40ac69263440761199fcb8da47ad4e3f328cbe79ffbf4ecc14e5ba252857307' + BAZEL_VERSION: '7.7.0' + BAZEL_SHA256SUM: 'fe7e799cbc9140f986b063e06800a3d4c790525075c877d00a7112669824acbf' BUILDTOOLS_VERSION: '3.0.0' BUILDIFIER_SHA256SUM: 'e92a6793c7134c5431c58fbc34700664f101e5c9b1c1fcd93b97978e8b7f88db' BUILDOZER_SHA256SUM: '3d58a0b6972e4535718cdd6c12778170ea7382de7c75bc3728f5719437ffb84d' @@ -48,7 +48,7 @@ jobs: fail-fast: false matrix: tf_version_id: ['tf', 'notf'] - python_version: ['3.9'] + python_version: ['3.10'] steps: - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 - uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984 # v4.3.0 @@ -65,6 +65,11 @@ jobs: run: | python -m pip install -U pip pip install "${TENSORFLOW_VERSION}" + # tf-nightly currently pulls in tb-nightly as a dependency. Bazel's + # source-tree tests must import TensorBoard from runfiles rather than + # from site-packages, otherwise tests that rely on local-only modules + # like `tensorboard.test` resolve against the installed wheel and fail. + pip uninstall -y tensorboard tb-nightly || true if: matrix.tf_version_id != 'notf' - name: 'Install Python dependencies' run: | @@ -73,14 +78,85 @@ jobs: -r ./tensorboard/pip_package/requirements.txt \ -r ./tensorboard/pip_package/requirements_dev.txt \ ; - - name: 'Install Chrome dependencies' + - name: 'Install system dependencies' run: | + py_abi="python${{ matrix.python_version }}" sudo apt-get update - sudo apt-get install -y libgbm-dev libxss1 libasound2 + sudo apt-get install -y "${py_abi}-dev" libgbm-dev libxss1 libasound2 + # Bazel's system_python repository resolves headers relative to the + # interpreter installed by actions/setup-python. The self-hosted + # ml-build container does not provide Python.h under that prefix, so + # copy the system headers into the managed interpreter include dir. + # A real directory copy is more robust here than a symlink because + # Bazel's repository setup may materialize or traverse this path in + # ways that do not preserve symlink behavior. + sudo mkdir -p "${pythonLocation}/include" + sudo rm -rf "${pythonLocation}/include/${py_abi}" + sudo mkdir -p "${pythonLocation}/include/${py_abi}" + sudo cp -a "/usr/include/${py_abi}/." "${pythonLocation}/include/${py_abi}/" + includepy="$(python - <<'PY' + import sysconfig + print(sysconfig.get_config_var("INCLUDEPY")) + PY + )" + # upb's system_python repository rule shells out to `python3` and + # uses sysconfig.get_config_var("INCLUDEPY"), which under + # actions/setup-python inside this container points at + # /opt/hostedtoolcache/... rather than ${pythonLocation}. Materialize + # that INCLUDEPY path too so Bazel's @system_python repo can symlink + # real headers into external/system_python/python. + sudo mkdir -p "$(dirname "${includepy}")" + sudo rm -rf "${includepy}" + sudo cp -a "${pythonLocation}/include/${py_abi}" "${includepy}" + test -f "${pythonLocation}/include/${py_abi}/Python.h" + test -f "${includepy}/Python.h" + - name: 'Debug Python toolchain' + run: | + py_abi="python${{ matrix.python_version }}" + echo "pythonLocation=${pythonLocation}" + echo "PATH=${PATH}" + which python + python --version + command -v python3.10-config || true + python3.10-config --includes || true + python - <<'PY' + import os + import pathlib + import sys + import sysconfig + + print("sys.executable =", sys.executable) + for key in ("include", "platinclude", "stdlib", "platstdlib", "scripts", "data"): + print(f"{key} =", sysconfig.get_path(key)) + for key in ("INCLUDEPY", "CONFINCLUDEPY", "LIBDIR", "LDLIBRARY", "MULTIARCH"): + print(f"{key} =", sysconfig.get_config_var(key)) + include_dir = pathlib.Path(sysconfig.get_path("include")) + print("include_dir exists =", include_dir.exists(), include_dir) + print("Python.h exists =", (include_dir / "Python.h").exists()) + print("pythonLocation =", os.environ.get("pythonLocation")) + PY + ls -la "${pythonLocation}" || true + ls -la "${pythonLocation}/include" || true + ls -la "${pythonLocation}/include/${py_abi}" || true - name: 'Check Pip state' run: pip freeze --all - name: 'Bazel: fetch' run: bazel fetch //tensorboard/... + - name: 'Debug Bazel system_python repo' + run: | + output_base="$(bazel info output_base)" + echo "output_base=${output_base}" + find "${output_base}/external/system_python" -maxdepth 3 \ + \( -name 'Python.h' -o -name 'BUILD.bazel' -o -name 'WORKSPACE' \) \ + -print | sort || true + if [ -f "${output_base}/external/system_python/BUILD.bazel" ]; then + sed -n '1,200p' "${output_base}/external/system_python/BUILD.bazel" + fi + if [ -d "${output_base}/external/system_python/python" ]; then + ls -la "${output_base}/external/system_python/python" + else + echo "system_python/python directory not found" + fi - name: 'Bazel: build' # Note we suppress a flood of warnings from the proto compiler. # Googlers see b/222706811 & b/182876485 discussion and preconditions @@ -98,13 +174,21 @@ jobs: if: matrix.tf_version_id == 'notf' - name: 'Bazel: run Pip package test (with TensorFlow support)' run: | - bazel run //tensorboard/pip_package:test_pip_package -- \ + # `bazel run` has been flaky under this self-hosted container runner + # even when the smoke test itself completes successfully. Build the + # launcher target, invoke the generated binary directly, then shut + # down the Bazel server so the step exits cleanly. + bazel build //tensorboard/pip_package:test_pip_package + ./bazel-bin/tensorboard/pip_package/test_pip_package \ --tf-version "${TENSORFLOW_VERSION}" + bazel shutdown if: matrix.tf_version_id != 'notf' - name: 'Bazel: run Pip package test (non-TensorFlow only)' run: | - bazel run //tensorboard/pip_package:test_pip_package -- \ + bazel build //tensorboard/pip_package:test_pip_package + ./bazel-bin/tensorboard/pip_package/test_pip_package \ --tf-version notf + bazel shutdown if: matrix.tf_version_id == 'notf' - name: 'Bazel: run manual tests' run: | diff --git a/WORKSPACE b/WORKSPACE index 2d3bbf9fc54..3525277f2fe 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,6 +1,9 @@ workspace(name = "org_tensorflow_tensorboard") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/build_defs/repo:java.bzl", "java_import_external") +load("@bazel_tools//tools/build_defs/repo:local.bzl", "local_repository") +load("//third_party:repo.bzl", "tb_http_archive", "tb_mirror_urls") http_archive( name = "bazel_skylib", @@ -18,10 +21,10 @@ versions.check( # Preemptively assume the next Bazel major version will break us, since historically they do, # and provide a clean error message in that case. Since the maximum version is inclusive rather # than exclusive, we set it to the 999th patch release of the current major version. - maximum_bazel_version = "6.999.0", + maximum_bazel_version = "7.999.0", # Keep this version in sync with: # * The BAZEL environment variable defined in .github/workflows/ci.yml, which is used for CI and nightly builds. - minimum_bazel_version = "6.5.0", + minimum_bazel_version = "7.7.0", ) http_archive( @@ -35,6 +38,34 @@ load("@io_bazel_rules_webtesting//web:repositories.bzl", "web_test_repositories" web_test_repositories(omit_bazel_skylib = True) +http_archive( + name = "io_bazel_rules_go", + sha256 = "278b7ff5a826f3dc10f04feaf0b70d48b68748ccd512d7f98bf442077f043fe3", + urls = [ + "http://mirror.tensorflow.org/github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip", + "https://github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip", + ], +) + +load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") + +go_rules_dependencies() + +go_register_toolchains(version = "1.20.5") + +http_archive( + name = "bazel_gazelle", + sha256 = "29218f8e0cebe583643cbf93cae6f971be8a2484cdcfa1e45057658df8d54002", + urls = [ + "http://mirror.tensorflow.org/github.com/bazelbuild/bazel-gazelle/releases/download/v0.32.0/bazel-gazelle-v0.32.0.tar.gz", + "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.32.0/bazel-gazelle-v0.32.0.tar.gz", + ], +) + +load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") + +gazelle_dependencies() + # rules_python has to be placed before load("@io_bazel_rules_closure//closure:repositories.bzl") # in the dependencies list, otherwise we get "cannot load '@rules_python//python:py_xxx.bzl': no such file" http_archive( @@ -53,6 +84,8 @@ py_repositories() http_archive( name = "io_bazel_rules_closure", + patch_args = ["-p1"], + patches = ["//patches:rules_closure_soy_cli.patch"], sha256 = "ae060075a7c468eee42e6a08ddbb83f5a6663bdfdbd461261a465f4a3ae8598c", strip_prefix = "rules_closure-7f3d3351a8cc31fbaa403de7d35578683c17b447", urls = [ @@ -60,12 +93,99 @@ http_archive( ], ) +local_repository( + name = "com_google_common_html_types", + path = "third_party/safe_html_types", +) + +# rules_closure's Soy toolchain still expects safe-html-types classes that are +# compatible with protobuf-java 6.x. Vendor the adjusted library locally so the +# Bazel 7 / protobuf 6 upgrade does not depend on older transitive jars. + +java_import_external( + name = "com_google_flogger_flogger", + jar_sha256 = "b5ecd1483e041197012786f749968a62063c1964d3ecfbf96ba92a95797bb8f5", + jar_urls = [ + "http://mirror.tensorflow.org/repo1.maven.org/maven2/com/google/flogger/flogger/0.5.1/flogger-0.5.1.jar", + "https://repo1.maven.org/maven2/com/google/flogger/flogger/0.5.1/flogger-0.5.1.jar", + ], + licenses = ["notice"], +) + +java_import_external( + name = "com_google_flogger_google_extensions", + jar_sha256 = "8b0862cad85b9549f355fe383c6c63816d2f19529634e033ae06d0107ab110b9", + jar_urls = [ + "http://mirror.tensorflow.org/repo1.maven.org/maven2/com/google/flogger/google-extensions/0.5.1/google-extensions-0.5.1.jar", + "https://repo1.maven.org/maven2/com/google/flogger/google-extensions/0.5.1/google-extensions-0.5.1.jar", + ], + licenses = ["notice"], + deps = ["@com_google_flogger_flogger"], +) + +java_import_external( + name = "com_google_flogger_flogger_system_backend", + jar_sha256 = "685de33b53eb313049bbeee7f4b7a80dd09e8e754e96b048a3edab2cebb36442", + jar_urls = [ + "http://mirror.tensorflow.org/repo1.maven.org/maven2/com/google/flogger/flogger-system-backend/0.5.1/flogger-system-backend-0.5.1.jar", + "https://repo1.maven.org/maven2/com/google/flogger/flogger-system-backend/0.5.1/flogger-system-backend-0.5.1.jar", + ], + licenses = ["notice"], + deps = ["@com_google_flogger_flogger"], +) + +java_import_external( + name = "com_google_template_soy", + extra_build_file_content = "\n".join([ + ("java_binary(\n" + + " name = \"%s\",\n" + + " main_class = \"com.google.template.soy.%s\",\n" + + " output_licenses = [\"unencumbered\"],\n" + + " runtime_deps = [\":com_google_template_soy\"],\n" + + ")\n") % (name, name) + for name in ( + "SoyParseInfoGenerator", + "SoyToJbcSrcCompiler", + "SoyToJsSrcCompiler", + "SoyToPySrcCompiler", + ) + ]), + jar_sha256 = "643440022e247ef8ad25bacb83ba099ccd2ae4b1fd078d9e9e3d3dd4af00411f", + jar_urls = [ + "https://repo1.maven.org/maven2/com/google/template/soy/2022-03-07/soy-2022-03-07.jar", + ], + licenses = ["notice"], + deps = [ + "@args4j", + "@com_google_code_findbugs_jsr305", + "@com_google_code_gson", + "@com_google_common_html_types", + "@com_google_flogger_flogger", + "@com_google_flogger_flogger_system_backend", + "@com_google_flogger_google_extensions", + "@com_google_guava", + "@com_google_inject_extensions_guice_assistedinject", + "@com_google_inject_extensions_guice_multibindings", + "@com_google_inject_guice", + "@com_google_protobuf//:protobuf_java", + "@com_ibm_icu_icu4j", + "@javax_inject", + "@org_json", + "@org_ow2_asm", + "@org_ow2_asm_analysis", + "@org_ow2_asm_commons", + "@org_ow2_asm_util", + ], +) + load("@io_bazel_rules_closure//closure:repositories.bzl", "rules_closure_dependencies") rules_closure_dependencies( omit_bazel_skylib = True, + omit_com_google_common_html_types = True, omit_com_google_protobuf = True, omit_com_google_protobuf_js = True, + omit_com_google_template_soy = True, ) http_archive( @@ -98,16 +218,21 @@ node_repositories( yarn_install( name = "npm", - data = [ - "//patches:@angular+build-tooling+0.0.0-2113cd7f66a089ac0208ea84eee672b2529f4f6c.patch", - "//patches:@bazel+concatjs+5.8.1.patch", - ], # "Some rules only work by referencing labels nested inside npm packages # and therefore require turning off exports_directories_only." # This includes "ts_library". # See: https://github.com/bazelbuild/rules_nodejs/wiki/Migrating-to-5.0#exports_directories_only exports_directories_only = False, package_json = "//:package.json", + package_json_remove = ["scripts.postinstall"], + patch_args = ["-p1"], + # Under Bazel 7.7.0 on this stack, invoking patch-package from the + # repository rule is fragile. Apply the existing git-format patches + # directly in yarn_install instead. + post_install_patches = [ + "//patches:@angular+build-tooling+0.0.0-2113cd7f66a089ac0208ea84eee672b2529f4f6c.patch", + "//patches:@bazel+concatjs+5.8.1.patch", + ], yarn_lock = "//:yarn.lock", ) @@ -146,50 +271,95 @@ sass_repositories() # high as the version of protobuf we depend on below, and we cannot increase the # version below without bumping the requirements.txt version. # -# TODO(#6185): Remove the TODO below once the TF constraint no longer applies. -# -# NOTE: This dependency currently cannot be advanced past 3.19.x. This is because -# TF is currently unable to use a runtime any greater than 3.19.x, see details here: -# https://github.com/tensorflow/tensorflow/blob/9d22f4a0a9499c8e10a4312503e63e0da35ccd94/tensorflow/tools/pip_package/setup.py#L100-L107 -# -# As a result of TF's constraint and the above <= requirement, 3.19.x is the most recent -# possible protoc we can use while remaining cross-compatible with TF. At the same time, -# 3.19.x is the minimum possible protoc that will generate compiled proto code that *is* -# compatible with protobuf runtimes >= 4, as discussed here: -# https://developers.google.com/protocol-buffers/docs/news/2022-05-06 -http_archive( +# TensorFlow 2.21 uses protobuf 6.31.1 in its own build and pip package +# constraints. Keep this Bazel-side protoc version aligned with that runtime +# floor so generated Python code and the ambient `protobuf` package remain +# compatible. +tb_http_archive( + name = "tb_rules_cc", + patch_file = ["//patches:rules_cc_protobuf.patch"], + repo_mapping = { + "@rules_cc": "@tb_rules_cc", + }, + sha256 = "4b12149a041ddfb8306a8fd0e904e39d673552ce82e4296e96fac9cbf0780e59", + strip_prefix = "rules_cc-0.1.0", + urls = tb_mirror_urls("https://github.com/bazelbuild/rules_cc/archive/refs/tags/0.1.0.tar.gz"), +) + +tb_http_archive( + name = "tb_rules_java", + sha256 = "b2519fabcd360529071ade8732f208b3755489ed7668b118f8f90985c0e51324", + strip_prefix = "rules_java-8.6.1", + urls = tb_mirror_urls("https://github.com/bazelbuild/rules_java/archive/refs/tags/8.6.1.tar.gz"), +) + +local_repository( + name = "compatibility_proxy", + path = "third_party/compatibility_proxy", +) + +local_repository( + name = "protobuf_pip_deps", + path = "third_party/protobuf_pip_deps", +) + +local_repository( + name = "protobuf_pip_deps_setuptools", + path = "third_party/protobuf_pip_deps_setuptools", +) + +load("@tb_rules_java//java:rules_java_deps.bzl", "rules_java_dependencies") + +tb_http_archive( + name = "com_google_absl", + repo_mapping = { + "@rules_cc": "@tb_rules_cc", + }, + sha256 = "d8ae9aa794a571ee39c77085ee69f1d4ac276212a7d99734974d95df7baa8d13", + strip_prefix = "abseil-cpp-9ac7062b1860d895fb5a8cbf58c3e9ef8f674b5f", + urls = tb_mirror_urls("https://github.com/abseil/abseil-cpp/archive/9ac7062b1860d895fb5a8cbf58c3e9ef8f674b5f.zip"), +) + +tb_http_archive( name = "com_google_protobuf", - sha256 = "9a301cf94a8ddcb380b901e7aac852780b826595075577bb967004050c835056", - strip_prefix = "protobuf-3.19.6", - urls = [ - "http://mirror.tensorflow.org/github.com/protocolbuffers/protobuf/archive/v3.19.6.tar.gz", - "https://github.com/protocolbuffers/protobuf/archive/v3.19.6.tar.gz", # 2022-09-29 - ], + patch_file = ["//patches:protobuf_6_31_1_java_export.patch"], + repo_mapping = { + "@abseil-cpp": "@com_google_absl", + "@rules_cc": "@tb_rules_cc", + "@rules_java": "@tb_rules_java", + }, + sha256 = "6e09bbc950ba60c3a7b30280210cd285af8d7d8ed5e0a6ed101c72aff22e8d88", + strip_prefix = "protobuf-6.31.1", + urls = tb_mirror_urls("https://github.com/protocolbuffers/protobuf/archive/refs/tags/v6.31.1.zip"), ) +rules_java_dependencies() + +load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") + +protobuf_deps() + # gRPC. # -# NOTE: The version used here must be cross-compatible with our protobuf version. -# As 2023-01-13, 1.48.2 is the most recent gRPC release that was still using a 3.19.x -# version of protobuf in its own builds (more recent releases move to 3.21.x). -http_archive( +# Keep this aligned with TensorFlow 2.21's Bazel-side gRPC dependency so the +# grpc plugin and protobuf repository stay on a known-compatible combination. +tb_http_archive( name = "com_github_grpc_grpc", - sha256 = "bdb8e98145469d58c69ab9f2c9e0bd838c2836a99b5760bc0ebf658623768f52", - strip_prefix = "grpc-1.48.2", - urls = [ - "http://mirror.tensorflow.org/github.com/grpc/grpc/archive/v1.48.2.tar.gz", - "https://github.com/grpc/grpc/archive/v1.48.2.tar.gz", # 2022-09-21 - ], + sha256 = "dd6a2fa311ba8441bbefd2764c55b99136ff10f7ea42954be96006a2723d33fc", + strip_prefix = "grpc-1.74.0", + urls = tb_mirror_urls("https://github.com/grpc/grpc/archive/refs/tags/v1.74.0.tar.gz"), +) + +tb_http_archive( + name = "build_bazel_rules_swift", + sha256 = "9919ed1d8dae509645bfd380537ae6501528d8de971caebed6d5185b9970dc4d", + urls = tb_mirror_urls("https://github.com/bazelbuild/rules_swift/releases/download/2.1.1/rules_swift.2.1.1.tar.gz"), ) load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps") grpc_deps() -load("@com_github_grpc_grpc//bazel:grpc_extra_deps.bzl", "grpc_extra_deps") - -grpc_extra_deps() - http_archive( name = "rules_rust", sha256 = "08109dccfa5bbf674ff4dba82b15d40d85b07436b02e62ab27e0b894f45bb4a3", @@ -201,10 +371,11 @@ http_archive( ], ) -# WORKAROUND for rules_webtesting not declaring used com_github_gorilla_mux repo: -load("@io_bazel_rules_webtesting//web:go_repositories.bzl", "com_github_gorilla_mux") +load("@io_bazel_rules_webtesting//web:go_repositories.bzl", "go_internal_repositories", "go_repositories") + +go_repositories() -com_github_gorilla_mux() +go_internal_repositories() # Please add all new dependencies in workspace.bzl. load("//third_party:workspace.bzl", "tensorboard_workspace") diff --git a/ci/bazelrc b/ci/bazelrc index 4bda9653d6f..3cf4037d3dd 100644 --- a/ci/bazelrc +++ b/ci/bazelrc @@ -6,6 +6,12 @@ build --worker_max_instances=2 # Ensure sandboxing is on to increase hermeticity. build --spawn_strategy=sandboxed build --worker_sandboxing +# Bazel 7 may materialize frontend/npm assets with CopyFile/CopyDirectory +# actions that are not executable under processwrapper-sandbox alone. +# Keep sandboxing for normal actions, but allow these copy helpers to run +# locally so Angular/sass/esbuild repository actions remain buildable in CI. +build --strategy=CopyFile=local +build --strategy=CopyDirectory=local # Ensure the PATH env var from our virtualenv propagates into tests, which is # no longer on by default in Bazel 0.21.0 and possibly again in the future. diff --git a/patches/README.md b/patches/README.md index 5250a8cf3a1..7e271cd0368 100644 --- a/patches/README.md +++ b/patches/README.md @@ -2,6 +2,11 @@ We use [patch-package](https://www.npmjs.com/package/patch-package) to apply TensorBoard-specific patches to some of our npm/yarn dependencies. +For this Bazel 7.7.0 branch, `WORKSPACE` applies the generated patch files via +`yarn_install(post_install_patches = ...)` rather than invoking +`patch-package` during the repository rule. This keeps the patch artifacts +compatible with upstream while avoiding a brittle install-time step under our +current Bazel setup. After creating or updating a patch, ensure there is no trailing whitespace on any line (CI runs `./tensorboard/tools/whitespace_hygiene_test.py`). You can diff --git a/patches/protobuf_6_31_1_java_export.patch b/patches/protobuf_6_31_1_java_export.patch new file mode 100644 index 00000000000..b12a6e82675 --- /dev/null +++ b/patches/protobuf_6_31_1_java_export.patch @@ -0,0 +1,49 @@ +diff --git a/build_defs/java_opts.bzl b/build_defs/java_opts.bzl +--- a/build_defs/java_opts.bzl ++++ b/build_defs/java_opts.bzl +@@ -17,14 +17,5 @@ def protobuf_java_export(**kwargs): + def protobuf_java_export(**kwargs): + java_export( + javacopts = JAVA_RELEASE_OPTS, +- # https://github.com/bazelbuild/rules_jvm_external/issues/1245 +- javadocopts = [ +- "-notimestamp", +- "-use", +- "-quiet", +- "-Xdoclint:-missing", +- "-encoding", +- "UTF8", +- ], + **kwargs + ) +diff --git a/bazel/private/proto_library_rule.bzl b/bazel/private/proto_library_rule.bzl +--- a/bazel/private/proto_library_rule.bzl ++++ b/bazel/private/proto_library_rule.bzl +@@ -29,6 +29,9 @@ def _check_srcs_package(target_package, srcs): + for src in srcs: + if target_package != src.label.package: + fail("Proto source with label '%s' must be in same package as consuming rule." % src.label) ++ ++def _is_normalized(path): ++ return path == "" or paths.normalize(path) == path + + def _get_import_prefix(ctx): + """Gets and verifies import_prefix attribute if it is declared.""" +@@ -36,7 +39,7 @@ def _get_import_prefix(ctx): + + import_prefix = ctx.attr.import_prefix + +- if not paths.is_normalized(import_prefix): ++ if not _is_normalized(import_prefix): + fail("should be normalized (without uplevel references or '.' path segments)", attr = "import_prefix") + if paths.is_absolute(import_prefix): + fail("should be a relative path", attr = "import_prefix") +@@ -48,7 +51,7 @@ def _get_strip_import_prefix(ctx): + + strip_import_prefix = ctx.attr.strip_import_prefix + +- if not paths.is_normalized(strip_import_prefix): ++ if not _is_normalized(strip_import_prefix): + fail("should be normalized (without uplevel references or '.' path segments)", attr = "strip_import_prefix") + + if paths.is_absolute(strip_import_prefix): diff --git a/patches/rules_cc_protobuf.patch b/patches/rules_cc_protobuf.patch new file mode 100644 index 00000000000..e265d992eaa --- /dev/null +++ b/patches/rules_cc_protobuf.patch @@ -0,0 +1,16 @@ +diff --git a/cc/defs.bzl b/cc/defs.bzl +index 3448e77..9c298ab 100644 +--- a/cc/defs.bzl ++++ b/cc/defs.bzl +@@ -30,9 +30,11 @@ load("//cc/toolchains:cc_toolchain_suite.bzl", _cc_toolchain_suite = "cc_toolcha + load("//cc/toolchains:compiler_flag.bzl", _compiler_flag = "compiler_flag") + load("//cc/toolchains:fdo_prefetch_hints.bzl", _fdo_prefetch_hints = "fdo_prefetch_hints") + load("//cc/toolchains:fdo_profile.bzl", _fdo_profile = "fdo_profile") ++load("@com_google_protobuf//bazel:cc_proto_library.bzl", _protobuf_cc_proto_library = "cc_proto_library") + + # Rules + ++cc_proto_library = _protobuf_cc_proto_library + cc_library = _cc_library + cc_binary = _cc_binary + cc_test = _cc_test diff --git a/patches/rules_closure_soy_cli.patch b/patches/rules_closure_soy_cli.patch new file mode 100644 index 00000000000..1559d81ef68 --- /dev/null +++ b/patches/rules_closure_soy_cli.patch @@ -0,0 +1,19 @@ +diff --git a/closure/templates/closure_java_template_library.bzl b/closure/templates/closure_java_template_library.bzl +--- a/closure/templates/closure_java_template_library.bzl ++++ b/closure/templates/closure_java_template_library.bzl +@@ -133,7 +133,7 @@ def _soy_java_template_genrule_impl( + out_name = deps_flag_file_name, + targets = deps, +- flag = "--deps", ++ flag = "--depHeaders", + compatible_with = compatible_with, + ) + native.genrule( +@@ -145,7 +145,6 @@ def _soy_java_template_genrule_impl( + cmd = "$(location %s)" % soycompilerbin + + " --outputDirectory=$(@D)" + + " --javaPackage=" + java_package + + " --javaClassNameSource=filename" + +- " --allowExternalCalls=" + str(allow_external_calls) + + additional_flags + + # Include the sources and deps files as command line flags. diff --git a/tensorboard/BUILD b/tensorboard/BUILD index 181314b31a0..a61cc8ed441 100644 --- a/tensorboard/BUILD +++ b/tensorboard/BUILD @@ -45,6 +45,7 @@ py_library( srcs_version = "PY3", deps = [ "//tensorboard:expect_absl_logging_installed", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", ], ) diff --git a/tensorboard/backend/event_processing/BUILD b/tensorboard/backend/event_processing/BUILD index 5444b20c56a..9ff453ffe65 100644 --- a/tensorboard/backend/event_processing/BUILD +++ b/tensorboard/backend/event_processing/BUILD @@ -13,6 +13,7 @@ py_library( srcs_version = "PY3", visibility = ["//visibility:public"], deps = [ + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/util:io_util", "//tensorboard/util:tb_logging", @@ -38,6 +39,7 @@ py_library( ":data_provider", ":event_multiplexer", ":tag_types", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/data:ingester", "//tensorboard/plugins/audio:metadata", @@ -104,6 +106,7 @@ py_library( deps = [ ":directory_watcher", ":io_wrapper", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/util:tb_logging", ], @@ -130,6 +133,7 @@ py_library( visibility = ["//visibility:public"], deps = [ ":io_wrapper", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/util:io_util", "//tensorboard/util:tb_logging", @@ -172,6 +176,7 @@ py_library( deps = [ "//tensorboard:data_compat", "//tensorboard:dataclass_compat", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", "//tensorboard/util:platform_util", @@ -354,6 +359,7 @@ py_library( srcs_version = "PY3", visibility = ["//visibility:public"], deps = [ + "//tensorboard/compat", "//tensorboard/compat:tensorflow", ], ) @@ -366,6 +372,7 @@ py_library( deps = [ ":event_accumulator", ":io_wrapper", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", ], diff --git a/tensorboard/compat/BUILD b/tensorboard/compat/BUILD index e04bc3eb312..5c487ea37ad 100644 --- a/tensorboard/compat/BUILD +++ b/tensorboard/compat/BUILD @@ -22,8 +22,16 @@ py_library( srcs = ["__init__.py"], srcs_version = "PY3", visibility = ["//visibility:public"], + deps = ["//tensorboard:lazy"], +) + +py_test( + name = "compat_test", + srcs = ["compat_test.py"], + srcs_version = "PY3", deps = [ - "//tensorboard:lazy", + ":compat", + "//tensorboard:expect_tensorflow_installed", ], ) @@ -38,9 +46,13 @@ py_library( # as written but can be swapped out for a real dependency. py_library( name = "tensorflow", + srcs = ["__init__.py"], srcs_version = "PY3", + # Keep the package's real __init__.py on this target instead of depending + # on :compat so Bazel 7 test runfiles expose the lazy tf/tf2 exports from + # the actual package init rather than a synthesized empty package. deps = [ - ":compat", + "//tensorboard:lazy", "//tensorboard/compat/tensorflow_stub", ], ) @@ -50,10 +62,16 @@ py_library( # Depend on this rule if your code should only use the TF stub. py_library( name = "no_tensorflow", - srcs = ["notf.py"], + srcs = [ + "__init__.py", + "notf.py", + ], srcs_version = "PY3", + # Mirror :tensorflow's package layout so the no-TF variant still exposes + # the compat package exports while forcing the sentinel import. deps = [ - ":tensorflow", + "//tensorboard:lazy", + "//tensorboard/compat/tensorflow_stub", ], ) diff --git a/tensorboard/compat/__init__.py b/tensorboard/compat/__init__.py index 6786669fe2d..aedef948dd3 100644 --- a/tensorboard/compat/__init__.py +++ b/tensorboard/compat/__init__.py @@ -19,6 +19,7 @@ and defer the search and loading of the module until necessary. """ +import importlib import tensorboard.lazy as _lazy @@ -39,7 +40,7 @@ def tf(): ImportError: if a TF-like API is not available. """ try: - from tensorboard.compat import notf # noqa: F401 + importlib.import_module("tensorboard.compat.notf") except ImportError: try: import tensorflow @@ -47,9 +48,7 @@ def tf(): return tensorflow except ImportError: pass - from tensorboard.compat import tensorflow_stub - - return tensorflow_stub + return importlib.import_module("tensorboard.compat.tensorflow_stub") @_lazy.lazy_load("tensorboard.compat.tf2") diff --git a/tensorboard/compat/compat_test.py b/tensorboard/compat/compat_test.py new file mode 100644 index 00000000000..d24bf315096 --- /dev/null +++ b/tensorboard/compat/compat_test.py @@ -0,0 +1,33 @@ +# Copyright 2026 The TensorFlow 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. + +"""Tests for tensorboard.compat lazy exports.""" + +import unittest + + +class CompatTest(unittest.TestCase): + def test_tf_export(self): + from tensorboard.compat import tf + + self.assertTrue(hasattr(tf, "compat")) + + def test_tf2_export(self): + from tensorboard.compat import tf2 + + self.assertTrue(hasattr(tf2, "summary")) + + +if __name__ == "__main__": + unittest.main() diff --git a/tensorboard/data/server/descriptor.bin b/tensorboard/data/server/descriptor.bin index bd230a39479..a0475fb3e92 100644 Binary files a/tensorboard/data/server/descriptor.bin and b/tensorboard/data/server/descriptor.bin differ diff --git a/tensorboard/defs/defs.bzl b/tensorboard/defs/defs.bzl index 9589824f9d4..66c0845da94 100644 --- a/tensorboard/defs/defs.bzl +++ b/tensorboard/defs/defs.bzl @@ -236,6 +236,10 @@ def tf_ng_web_test_suite(name, deps = [], external = [], **kwargs): deps = [ "%s_bundle" % name, ], + # rules_nodejs passes this through to rules_webtesting. An empty dict + # avoids forwarding a stray None-valued attribute to web_test under + # Bazel 7.7.0 with the currently pinned rules_webtesting stack. + browser_overrides = {}, ) def tf_svg_bundle(name, srcs, out): diff --git a/tensorboard/defs/protos.bzl b/tensorboard/defs/protos.bzl index e1dbe485d32..1aac236dc8c 100644 --- a/tensorboard/defs/protos.bzl +++ b/tensorboard/defs/protos.bzl @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@com_google_protobuf//:protobuf.bzl", "proto_gen") -load("@rules_python//python:py_library.bzl", "py_library") +load("@com_google_protobuf//bazel:py_proto_library.bzl", "py_proto_library") +load("@com_github_grpc_grpc//bazel:protobuf.bzl", "well_known_proto_libs") +load("@com_github_grpc_grpc//bazel:python_rules.bzl", "py_grpc_library") # TODO(#6185): try to reduce the complexity in this rule. def tb_proto_library( @@ -25,66 +26,29 @@ def tb_proto_library( has_services = False, # The `exports` arg is unused here, but required internally for compatibility. exports = []): - outs_proto = _PyOuts(srcs, grpc = False) - outs_grpc = _PyOuts(srcs, grpc = True) if has_services else [] - outs_all = outs_proto + outs_grpc + proto_deps = [s + "_proto" for s in deps] + well_known_proto_libs() - # Dependencies we need to operate protoc (the protobuf compiler), including - # protoc itself, the intermediate generated proto output from the runtime - # bundled with protoc (to provide proto types used during the protoc code - # generation process itself), and the grpc plugin to protoc used for gRPC - # service generation. - protoc = "@com_google_protobuf//:protoc" - protoc_runtime_genproto = "@com_google_protobuf//:protobuf_python_genproto" - grpc_python_plugin = "//external:grpc_python_plugin" - - # Python generated code relies on a Python protobuf runtime to be present. - # The runtime version must be compatible (typically, >=) with the protoc - # that was used to generate the code. There is a runtime provided along - # with protoc as part of our build-time dependency on protobuf (the target - # is "@com_google_protobuf//:protobuf_python"), but we deliberately don't - # use it, because our tests may need to use a protobuf runtime that is - # higher than our protoc version in order to be compatible with generated - # protobuf code used by our dependencies (namely, TensorFlow). Instead, we - # rely on picking up protobuf ambiently from the virtual environment, the - # same way that it will behave when released in our pip package. - runtime = "//tensorboard:expect_protobuf_installed" - - proto_gen( - name = name + "_genproto", + native.proto_library( + name = name + "_proto", srcs = srcs, - deps = [s + "_genproto" for s in deps] + [protoc_runtime_genproto], - includes = [], - protoc = protoc, - gen_py = True, - outs = outs_all, + deps = proto_deps, + testonly = testonly, visibility = ["//visibility:public"], - plugin = grpc_python_plugin if has_services else None, - plugin_language = "grpc", ) - py_deps = [s + "_py_pb2" for s in deps] + [runtime] - py_library( + py_proto_library( name = name + "_py_pb2", - srcs = outs_proto, - imports = [], - srcs_version = "PY3", - deps = py_deps, + deps = [name + "_proto"], testonly = testonly, visibility = visibility, ) + if has_services: - py_library( + py_grpc_library( name = name + "_py_pb2_grpc", - srcs = outs_grpc, - imports = [], - srcs_version = "PY3", - deps = [name + "_py_pb2"] + py_deps, + srcs = [name + "_proto"], + deps = [name + "_py_pb2"], + grpc_library = "//tensorboard:expect_grpc_installed", testonly = testonly, visibility = visibility, ) - -def _PyOuts(srcs, grpc): - # Adapted from @com_google_protobuf//:protobuf.bzl. - ext = "_pb2.py" if not grpc else "_pb2_grpc.py" - return [s[:-len(".proto")] + ext for s in srcs] diff --git a/tensorboard/manager.py b/tensorboard/manager.py index 823735bd477..4d6ec770d0f 100644 --- a/tensorboard/manager.py +++ b/tensorboard/manager.py @@ -32,6 +32,29 @@ from tensorboard.util import tb_logging +_SUBPROCESS_ENV_DENYLIST = frozenset( + ( + "BUILD_WORKING_DIRECTORY", + "BUILD_WORKSPACE_DIRECTORY", + "JAVA_RUNFILES", + "PYTHONHOME", + "PYTHONPATH", + "PYTHONSAFEPATH", + "PYTHONSTARTUP", + "PYTHONUSERBASE", + "PYTHON_RUNFILES", + "RUNFILES", + "RUNFILES_DIR", + "RUNFILES_MANIFEST_FILE", + "RUNFILES_MANIFEST_ONLY", + "RUNFILES_REPO_MAPPING", + "TEST_BINARY", + "TEST_SRCDIR", + "TEST_WORKSPACE", + ) +) + + @dataclasses.dataclass(frozen=True) class TensorBoardInfo: """Holds the information about a running TensorBoard instance. @@ -385,6 +408,20 @@ class StartTimedOut: pid: int +def _subprocess_environ(): + """Create an environment for a managed TensorBoard subprocess. + + TensorBoard processes launched from Bazel tests should resolve their own + runfiles and Python import paths. Inheriting Bazel's test-only Python and + runfiles variables can make the child binary execute against the parent's + runfiles tree instead of its own. + """ + environ = os.environ.copy() + for key in _SUBPROCESS_ENV_DENYLIST: + environ.pop(key, None) + return environ + + def start(arguments, timeout=datetime.timedelta(seconds=60)): """Start a new TensorBoard instance, or reuse a compatible one. @@ -427,6 +464,7 @@ def start(arguments, timeout=datetime.timedelta(seconds=60)): try: p = subprocess.Popen( ["tensorboard" if explicit_tb is None else explicit_tb] + arguments, + env=_subprocess_environ(), stdout=stdout_fd, stderr=stderr_fd, ) diff --git a/tensorboard/manager_test.py b/tensorboard/manager_test.py index 6911398c515..e5659d1cf64 100644 --- a/tensorboard/manager_test.py +++ b/tensorboard/manager_test.py @@ -233,6 +233,30 @@ def test_arguments_list_vs_tuple_irrelevant(self): self.assertEqual(with_list, with_tuple) +class SubprocessEnvironTest(tb_test.TestCase): + def test_strips_bazel_and_python_path_state(self): + with mock.patch.dict( + os.environ, + { + "PATH": "/bin:/usr/bin", + "TMPDIR": "/tmp/tb", + "PYTHONPATH": "/tmp/runfiles", + "RUNFILES_DIR": "/tmp/runfiles", + "TEST_BINARY": "/tmp/test_binary", + "BUILD_WORKSPACE_DIRECTORY": "/tmp/workspace", + }, + clear=True, + ): + actual = manager._subprocess_environ() + + self.assertEqual(actual["PATH"], "/bin:/usr/bin") + self.assertEqual(actual["TMPDIR"], "/tmp/tb") + self.assertNotIn("PYTHONPATH", actual) + self.assertNotIn("RUNFILES_DIR", actual) + self.assertNotIn("TEST_BINARY", actual) + self.assertNotIn("BUILD_WORKSPACE_DIRECTORY", actual) + + class TensorBoardInfoIoTest(tb_test.TestCase): """Tests for `write_info_file`, `remove_info_file`, and `get_all`.""" diff --git a/tensorboard/pip_package/requirements.txt b/tensorboard/pip_package/requirements.txt index ac31021fbb8..d1f6726241e 100644 --- a/tensorboard/pip_package/requirements.txt +++ b/tensorboard/pip_package/requirements.txt @@ -17,22 +17,18 @@ absl-py >= 0.4 # NOTE: this version should be >= the grpc version in our WORKSPACE file. -grpcio >= 1.48.2 +grpcio >= 1.74.0, < 2.0 markdown >= 2.6.8 numpy >= 1.12.0 # NOTE: The packaging dependency was introduced in order to compare installed # package versions and conditionally use different supported kwargs -# (specifically the protobuf dependency). If we restrict protobuf >= 5.0.0 we -# can get rid of the packaging dependency. +# (specifically the protobuf dependency). packaging pillow # NOTE: this version must be >= the protoc version in our WORKSPACE file. -# At the same time, any constraints we specify here must allow at least some -# version to be installed that is also compatible with TensorFlow's constraints: -# https://github.com/tensorflow/tensorflow/blob/25adc4fccb4b0bb5a933eba1d246380e7b87d7f7/tensorflow/tools/pip_package/setup.py#L101 -# 4.24.0 had an issue that broke our tests, so we should avoid that release: -# https://github.com/protocolbuffers/protobuf/issues/13485 -protobuf >= 3.19.6, != 4.24.0 +# TensorFlow 2.21 requires protobuf >= 6.31.1, < 8.0.0, so keep our open-source +# runtime floor aligned with that range. +protobuf >= 6.31.1, < 8.0.0 setuptools >= 41.0.0 # Note: provides pkg_resources as well as setuptools tensorboard-data-server >= 0.7.0, < 0.8.0 werkzeug >= 1.0.1 diff --git a/tensorboard/pip_package/requirements_dev.txt b/tensorboard/pip_package/requirements_dev.txt index f9a7a3ae702..5b2ea9c4540 100644 --- a/tensorboard/pip_package/requirements_dev.txt +++ b/tensorboard/pip_package/requirements_dev.txt @@ -16,11 +16,11 @@ # Dependencies of TensorBoard used only for testing or development. # For tests -grpcio-testing==1.24.3 +grpcio-testing==1.74.0 pandas~=2.0 # For gfile S3 test -boto3==1.9.86 -moto==1.3.7 +boto3==1.34.162 +moto==4.2.14 # For gfile fsspec test fsspec>=2021.06.0 diff --git a/tensorboard/pip_package/test_pip_package.sh b/tensorboard/pip_package/test_pip_package.sh index 1595bcd8601..a4b1cb097f6 100755 --- a/tensorboard/pip_package/test_pip_package.sh +++ b/tensorboard/pip_package/test_pip_package.sh @@ -194,4 +194,6 @@ test_tf_summary() { printf '%s\n' "${import_from}" "${import_as}" "${import_attr}" | python - } +printf >&2 'All smoke tests passed.' + main "$@" diff --git a/tensorboard/plugins/audio/BUILD b/tensorboard/plugins/audio/BUILD index 8e0d8965ba1..4075740989b 100644 --- a/tensorboard/plugins/audio/BUILD +++ b/tensorboard/plugins/audio/BUILD @@ -92,6 +92,7 @@ py_library( deps = [ ":metadata", "//tensorboard/compat", + "//tensorboard/compat:tensorflow", "//tensorboard/util:lazy_tensor_creator", ], ) diff --git a/tensorboard/plugins/audio/summary.py b/tensorboard/plugins/audio/summary.py index 7f089b202e7..aa5b86d44a8 100644 --- a/tensorboard/plugins/audio/summary.py +++ b/tensorboard/plugins/audio/summary.py @@ -32,11 +32,17 @@ from tensorboard.util import encoder as encoder_util from tensorboard.plugins.audio import metadata -from tensorboard.plugins.audio import summary_v2 + + +def _summary_v2(): + from tensorboard.plugins.audio import summary_v2 + + return summary_v2 # Export V2 versions. -audio = summary_v2.audio +def audio(*args, **kwargs): + return _summary_v2().audio(*args, **kwargs) _LABELS_WARNING = ( diff --git a/tensorboard/plugins/custom_scalar/BUILD b/tensorboard/plugins/custom_scalar/BUILD index 83b59203ff7..795d5c5fc18 100644 --- a/tensorboard/plugins/custom_scalar/BUILD +++ b/tensorboard/plugins/custom_scalar/BUILD @@ -20,6 +20,7 @@ py_library( "//tensorboard:expect_protobuf_installed", "//tensorboard:plugin_util", "//tensorboard/backend:http_util", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/plugins:base_plugin", "//tensorboard/plugins/scalar:metadata", diff --git a/tensorboard/plugins/histogram/BUILD b/tensorboard/plugins/histogram/BUILD index 77fa2d1f0f8..413d3aaf939 100644 --- a/tensorboard/plugins/histogram/BUILD +++ b/tensorboard/plugins/histogram/BUILD @@ -107,6 +107,7 @@ py_library( ":metadata", "//tensorboard:expect_numpy_installed", "//tensorboard/compat", + "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", "//tensorboard/util:lazy_tensor_creator", "//tensorboard/util:tensor_util", diff --git a/tensorboard/plugins/histogram/summary.py b/tensorboard/plugins/histogram/summary.py index d804852f638..8a423961126 100644 --- a/tensorboard/plugins/histogram/summary.py +++ b/tensorboard/plugins/histogram/summary.py @@ -32,12 +32,24 @@ import numpy as np from tensorboard.plugins.histogram import metadata -from tensorboard.plugins.histogram import summary_v2 + + +def _summary_v2(): + from tensorboard.plugins.histogram import summary_v2 + + return summary_v2 + + +DEFAULT_BUCKET_COUNT = 30 # Export V3 versions. -histogram = summary_v2.histogram -histogram_pb = summary_v2.histogram_pb +def histogram(*args, **kwargs): + return _summary_v2().histogram(*args, **kwargs) + + +def histogram_pb(*args, **kwargs): + return _summary_v2().histogram_pb(*args, **kwargs) def _buckets(data, bucket_count=None): @@ -55,7 +67,7 @@ def _buckets(data, bucket_count=None): import tensorflow.compat.v1 as tf if bucket_count is None: - bucket_count = summary_v2.DEFAULT_BUCKET_COUNT + bucket_count = DEFAULT_BUCKET_COUNT with tf.name_scope( "buckets", values=[data, bucket_count] ), tf.control_dependencies( @@ -186,7 +198,7 @@ def pb(name, data, bucket_count=None, display_name=None, description=None): import tensorflow.compat.v1 as tf if bucket_count is None: - bucket_count = summary_v2.DEFAULT_BUCKET_COUNT + bucket_count = DEFAULT_BUCKET_COUNT data = np.array(data).flatten().astype(float) if data.size == 0: buckets = np.array([]).reshape((0, 3)) diff --git a/tensorboard/plugins/hparams/BUILD b/tensorboard/plugins/hparams/BUILD index 74667a28195..51d5155b500 100644 --- a/tensorboard/plugins/hparams/BUILD +++ b/tensorboard/plugins/hparams/BUILD @@ -251,6 +251,7 @@ py_library( ":protos_all_py_pb2", "//tensorboard:expect_numpy_installed", "//tensorboard/compat", + "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", ], ) diff --git a/tensorboard/plugins/image/BUILD b/tensorboard/plugins/image/BUILD index b32e02d2a3d..3ba85ff1d21 100644 --- a/tensorboard/plugins/image/BUILD +++ b/tensorboard/plugins/image/BUILD @@ -103,6 +103,7 @@ py_library( deps = [ ":metadata", "//tensorboard/compat", + "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", "//tensorboard/util:lazy_tensor_creator", ], diff --git a/tensorboard/plugins/image/summary.py b/tensorboard/plugins/image/summary.py index d6e001c6422..c2cb928fde9 100644 --- a/tensorboard/plugins/image/summary.py +++ b/tensorboard/plugins/image/summary.py @@ -25,12 +25,18 @@ import numpy as np from tensorboard.plugins.image import metadata -from tensorboard.plugins.image import summary_v2 from tensorboard.util import encoder +def _summary_v2(): + from tensorboard.plugins.image import summary_v2 + + return summary_v2 + + # Export V2 versions. -image = summary_v2.image +def image(*args, **kwargs): + return _summary_v2().image(*args, **kwargs) def op( diff --git a/tensorboard/plugins/mesh/BUILD b/tensorboard/plugins/mesh/BUILD index 14cc2d6459a..54e7796c311 100644 --- a/tensorboard/plugins/mesh/BUILD +++ b/tensorboard/plugins/mesh/BUILD @@ -108,6 +108,7 @@ py_library( srcs_version = "PY3", deps = [ ":metadata", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", "//tensorboard/util:tensor_util", @@ -151,6 +152,7 @@ py_library( srcs_version = "PY3", deps = [ "//tensorboard:expect_numpy_installed", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", ], ) diff --git a/tensorboard/plugins/projector/BUILD b/tensorboard/plugins/projector/BUILD index 628c344cfd9..5a52c36de02 100644 --- a/tensorboard/plugins/projector/BUILD +++ b/tensorboard/plugins/projector/BUILD @@ -24,6 +24,7 @@ py_library( "//tensorboard:expect_protobuf_installed", "//tensorboard/backend:http_util", "//tensorboard/backend/event_processing:plugin_asset_util", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/plugins:base_plugin", "//tensorboard/util:img_mime_type_detector", @@ -41,6 +42,7 @@ py_library( ":metadata", ":protos_all_py_pb2", "//tensorboard:expect_protobuf_installed", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", ], ) diff --git a/tensorboard/plugins/scalar/BUILD b/tensorboard/plugins/scalar/BUILD index 6a6d044f4e5..fd5c3cea12e 100644 --- a/tensorboard/plugins/scalar/BUILD +++ b/tensorboard/plugins/scalar/BUILD @@ -111,6 +111,7 @@ py_library( deps = [ ":metadata", "//tensorboard/compat", + "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", "//tensorboard/util:tensor_util", ], diff --git a/tensorboard/plugins/scalar/summary.py b/tensorboard/plugins/scalar/summary.py index fec5fdeef2d..cf3f166cd7f 100644 --- a/tensorboard/plugins/scalar/summary.py +++ b/tensorboard/plugins/scalar/summary.py @@ -22,12 +22,21 @@ import numpy as np from tensorboard.plugins.scalar import metadata -from tensorboard.plugins.scalar import summary_v2 + + +def _summary_v2(): + from tensorboard.plugins.scalar import summary_v2 + + return summary_v2 # Export V2 versions. -scalar = summary_v2.scalar -scalar_pb = summary_v2.scalar_pb +def scalar(*args, **kwargs): + return _summary_v2().scalar(*args, **kwargs) + + +def scalar_pb(*args, **kwargs): + return _summary_v2().scalar_pb(*args, **kwargs) def op(name, data, display_name=None, description=None, collections=None): diff --git a/tensorboard/plugins/text/BUILD b/tensorboard/plugins/text/BUILD index b7aa4bedc8f..15ecdeb24ee 100644 --- a/tensorboard/plugins/text/BUILD +++ b/tensorboard/plugins/text/BUILD @@ -101,6 +101,7 @@ py_library( deps = [ ":metadata", "//tensorboard/compat", + "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", "//tensorboard/util:tensor_util", ], diff --git a/tensorboard/plugins/text/summary.py b/tensorboard/plugins/text/summary.py index 915cb34e926..743df85a9df 100644 --- a/tensorboard/plugins/text/summary.py +++ b/tensorboard/plugins/text/summary.py @@ -16,12 +16,21 @@ from tensorboard.plugins.text import metadata -from tensorboard.plugins.text import summary_v2 + + +def _summary_v2(): + from tensorboard.plugins.text import summary_v2 + + return summary_v2 # Export V2 versions. -text = summary_v2.text -text_pb = summary_v2.text_pb +def text(*args, **kwargs): + return _summary_v2().text(*args, **kwargs) + + +def text_pb(*args, **kwargs): + return _summary_v2().text_pb(*args, **kwargs) def op(name, data, display_name=None, description=None, collections=None): diff --git a/tensorboard/summary/writer/BUILD b/tensorboard/summary/writer/BUILD index 4b4050c1b43..261dfdcd8c9 100644 --- a/tensorboard/summary/writer/BUILD +++ b/tensorboard/summary/writer/BUILD @@ -15,17 +15,13 @@ py_library( "record_writer.py", ], srcs_version = "PY3", - # This target depends directly on //tensorboard/compat and on the TF stub to - # ensure it doesn't pick up a TF build dependency, which may happen when using - # //tensorboard/compat:tensorflow when the code is synced internally. - # - # TODO(#4581): implement a better abstraction for filesystem layer that includes - # the option to use tf.io.gfile if available, eliminating need to rely on the - # overall switching logic from tensorboard.compat.tf (see also #3666). + # Keep both deps: the bare compat target provides the package-level tf/tf2 + # exports, while :tensorflow carries the TF-or-stub runtime wiring used by + # those exports in Bazel 7 test and binary runfiles. deps = [ "//tensorboard/compat", + "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", - "//tensorboard/compat/tensorflow_stub", ], ) diff --git a/tensorboard/util/BUILD b/tensorboard/util/BUILD index ef1b57fd27c..656c33054da 100644 --- a/tensorboard/util/BUILD +++ b/tensorboard/util/BUILD @@ -69,6 +69,7 @@ py_library( srcs_version = "PY3", deps = [ "//tensorboard/compat", + "//tensorboard/compat:tensorflow", ], ) diff --git a/third_party/compatibility_proxy/BUILD.bazel b/third_party/compatibility_proxy/BUILD.bazel new file mode 100644 index 00000000000..1f1683470ef --- /dev/null +++ b/third_party/compatibility_proxy/BUILD.bazel @@ -0,0 +1,16 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + +exports_files( + ["proxy.bzl"], + visibility = ["@tb_rules_java//test:__pkg__"], +) + +bzl_library( + name = "proxy_bzl", + srcs = ["proxy.bzl"], + deps = [ + "@bazel_tools//tools:bzl_srcs", + "@tb_rules_java//java/private:native_bzl", + ], + visibility = ["//visibility:public"], +) diff --git a/third_party/compatibility_proxy/WORKSPACE b/third_party/compatibility_proxy/WORKSPACE new file mode 100644 index 00000000000..49d774266b9 --- /dev/null +++ b/third_party/compatibility_proxy/WORKSPACE @@ -0,0 +1 @@ +workspace(name = "compatibility_proxy") diff --git a/third_party/compatibility_proxy/proxy.bzl b/third_party/compatibility_proxy/proxy.bzl new file mode 100644 index 00000000000..c4f93fa8c18 --- /dev/null +++ b/third_party/compatibility_proxy/proxy.bzl @@ -0,0 +1,22 @@ +"""Compatibility proxy for rules_java under Bazel 7.""" + +load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_jar = "http_jar") +load("@tb_rules_java//java/private:native.bzl", "NativeJavaInfo", "NativeJavaPluginInfo", "native_java_common") + +java_binary = native.java_binary +java_import = native.java_import +java_library = native.java_library +java_plugin = native.java_plugin +java_test = native.java_test + +java_package_configuration = native.java_package_configuration +java_runtime = native.java_runtime +java_toolchain = native.java_toolchain + +java_common = native_java_common +JavaInfo = NativeJavaInfo +JavaPluginInfo = NativeJavaPluginInfo +java_common_internal_compile = None +java_info_internal_merge = None + +http_jar = _http_jar diff --git a/third_party/protobuf_pip_deps/BUILD.bazel b/third_party/protobuf_pip_deps/BUILD.bazel new file mode 100644 index 00000000000..7222b7a1875 --- /dev/null +++ b/third_party/protobuf_pip_deps/BUILD.bazel @@ -0,0 +1 @@ +exports_files(["requirements.bzl"]) diff --git a/third_party/protobuf_pip_deps/WORKSPACE b/third_party/protobuf_pip_deps/WORKSPACE new file mode 100644 index 00000000000..80879e6b55c --- /dev/null +++ b/third_party/protobuf_pip_deps/WORKSPACE @@ -0,0 +1 @@ +workspace(name = "protobuf_pip_deps") diff --git a/third_party/protobuf_pip_deps/requirements.bzl b/third_party/protobuf_pip_deps/requirements.bzl new file mode 100644 index 00000000000..6928f53d186 --- /dev/null +++ b/third_party/protobuf_pip_deps/requirements.bzl @@ -0,0 +1,11 @@ +"""Minimal pip dependency shim for protobuf's Bazel build.""" + +def requirement(name): + if name == "numpy": + return "@org_tensorflow_tensorboard//tensorboard:expect_numpy_installed" + if name == "setuptools": + return "@protobuf_pip_deps_setuptools//:site_packages" + fail("Unsupported protobuf pip dependency: %s" % name) + +def install_deps(): + return None diff --git a/third_party/protobuf_pip_deps_setuptools/BUILD.bazel b/third_party/protobuf_pip_deps_setuptools/BUILD.bazel new file mode 100644 index 00000000000..d1ea5b160c6 --- /dev/null +++ b/third_party/protobuf_pip_deps_setuptools/BUILD.bazel @@ -0,0 +1,5 @@ +filegroup( + name = "site_packages", + srcs = glob(["site-packages/**"]), + visibility = ["//visibility:public"], +) diff --git a/third_party/protobuf_pip_deps_setuptools/WORKSPACE b/third_party/protobuf_pip_deps_setuptools/WORKSPACE new file mode 100644 index 00000000000..0ad533bd878 --- /dev/null +++ b/third_party/protobuf_pip_deps_setuptools/WORKSPACE @@ -0,0 +1 @@ +workspace(name = "protobuf_pip_deps_setuptools") diff --git a/third_party/protobuf_pip_deps_setuptools/site-packages/.keep b/third_party/protobuf_pip_deps_setuptools/site-packages/.keep new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/third_party/protobuf_pip_deps_setuptools/site-packages/.keep @@ -0,0 +1 @@ + diff --git a/third_party/repo.bzl b/third_party/repo.bzl new file mode 100644 index 00000000000..24ee5d2932b --- /dev/null +++ b/third_party/repo.bzl @@ -0,0 +1,91 @@ +# Copyright 2017 The TensorFlow 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. + +"""Repository helpers for TensorBoard external dependencies.""" + +def tb_mirror_urls(url): + """Returns TensorFlow mirror plus origin URLs for an HTTPS source.""" + if not url.startswith("https://"): + return [url] + return [ + "https://storage.googleapis.com/mirror.tensorflow.org/%s" % url[8:], + url, + ] + +def _get_link_dict(ctx, link_files, build_file): + link_dict = {ctx.path(v): ctx.path(Label(k)) for k, v in link_files.items()} + if build_file: + link_dict[ctx.path("BUILD.bazel")] = ctx.path(Label(build_file)) + return link_dict + +def _tb_http_archive_impl(ctx): + link_dict = _get_link_dict(ctx, ctx.attr.link_files, ctx.attr.build_file) + + patch_files = ctx.attr.patch_file + for patch_file in patch_files: + if patch_file: + ctx.path(Label(patch_file)) + + ctx.download_and_extract( + url = ctx.attr.urls, + sha256 = ctx.attr.sha256, + type = ctx.attr.type, + stripPrefix = ctx.attr.strip_prefix, + ) + + for patch_file in patch_files: + patch_file = ctx.path(Label(patch_file)) if patch_file else None + if patch_file: + ctx.patch(patch_file, strip = 1) + + for dst, src in link_dict.items(): + ctx.delete(dst) + ctx.symlink(src, dst) + +_tb_http_archive = repository_rule( + implementation = _tb_http_archive_impl, + attrs = { + "sha256": attr.string(mandatory = True), + "urls": attr.string_list(mandatory = True), + "strip_prefix": attr.string(), + "type": attr.string(), + "patch_file": attr.string_list(), + "build_file": attr.string(), + "link_files": attr.string_dict(), + }, +) + +def tb_http_archive(name, sha256, urls, **kwargs): + """Downloads and creates Bazel repos for TensorBoard dependencies.""" + if len(urls) < 2: + fail("tb_http_archive(urls) must have redundant URLs.") + + if not any([mirror in urls[0] for mirror in ( + "mirror.tensorflow.org", + "mirror.bazel.build", + "storage.googleapis.com", + )]): + fail("The first entry of tb_http_archive(urls) must be a mirror URL.") + + if native.existing_rule(name): + print("\n\033[1;33mWarning:\033[0m skipping import of repository '" + + name + "' because it already exists.\n") + return + + _tb_http_archive( + name = name, + sha256 = sha256, + urls = urls, + **kwargs + ) diff --git a/third_party/safe_html_types/BUILD.bazel b/third_party/safe_html_types/BUILD.bazel new file mode 100644 index 00000000000..8f9dfefdab8 --- /dev/null +++ b/third_party/safe_html_types/BUILD.bazel @@ -0,0 +1,16 @@ +load("@rules_java//java:defs.bzl", "java_library") + +package(default_visibility = ["//visibility:public"]) + +java_library( + name = "com_google_common_html_types", + srcs = glob(["com/google/common/html/types/*.java"]), + deps = [ + "@com_google_code_findbugs_jsr305", + "@com_google_errorprone_error_prone_annotations", + "@com_google_guava", + "@com_google_jsinterop_annotations", + "@com_google_protobuf//:protobuf_java", + "@javax_annotation_jsr250_api", + ], +) diff --git a/third_party/safe_html_types/META-INF/MANIFEST.MF b/third_party/safe_html_types/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..fdb42cceba7 --- /dev/null +++ b/third_party/safe_html_types/META-INF/MANIFEST.MF @@ -0,0 +1,6 @@ +Manifest-Version: 1.0 +Archiver-Version: Plexus Archiver +Built-By: msamuel +Created-By: Apache Maven 3.5.0 +Build-Jdk: 1.8.0_144 + diff --git a/third_party/safe_html_types/README.md b/third_party/safe_html_types/README.md new file mode 100644 index 00000000000..2574553e2fc --- /dev/null +++ b/third_party/safe_html_types/README.md @@ -0,0 +1,32 @@ +# safe_html_types vendor note + +This directory vendors the Java `com.google.common.html.types` classes needed by +TensorBoard's existing Closure / Soy toolchain during the Bazel 7.7.0 and +protobuf 6.31.1 migration. + +Why this exists: + +- TensorBoard still uses `rules_closure` / Soy tooling in Bazel. +- Upgrading protobuf to `6.31.1` exposed Java-side incompatibilities in the + older transitive safe-html-types classes used by that toolchain. +- TensorFlow 2.21 already aligns on protobuf `6.31.1`, so TensorBoard needs a + Bazel-side path that remains compatible with protobuf-java 6.x as well. + +What is special about this copy: + +- It is used as a local Bazel repository via `WORKSPACE`. +- It is intended to satisfy the Closure / Soy Java dependency graph during the + migration, not to change TensorBoard's Python/runtime behavior directly. +- Some files in this tree were adjusted so the Java code works with the newer + protobuf APIs expected by this branch's toolchain. + +Reviewer note: + +Most of the line-count increase in this PR comes from this vendored directory. +The functional Bazel/TensorBoard migration logic is concentrated in: + +- `WORKSPACE` +- `.bazelrc` +- `tensorboard/defs/protos.bzl` +- `tensorboard/compat/BUILD` +- `tensorboard/pip_package/test_pip_package.sh` diff --git a/third_party/safe_html_types/WORKSPACE b/third_party/safe_html_types/WORKSPACE new file mode 100644 index 00000000000..444edc8e1ec --- /dev/null +++ b/third_party/safe_html_types/WORKSPACE @@ -0,0 +1 @@ +workspace(name = "com_google_common_html_types") diff --git a/third_party/safe_html_types/com/google/common/html/types/BuilderUtils.java b/third_party/safe_html_types/com/google/common/html/types/BuilderUtils.java new file mode 100644 index 00000000000..f0e8d3b7ad9 --- /dev/null +++ b/third_party/safe_html_types/com/google/common/html/types/BuilderUtils.java @@ -0,0 +1,64 @@ +// **** GENERATED CODE, DO NOT MODIFY **** +// This file was generated via preprocessing from input: +// java/com/google/common/html/types/BuilderUtils.java.tpl +// *************************************** +/* + * Copyright 2016 Google Inc. 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. + */ + +package com.google.common.html.types; + +import com.google.common.annotations.GwtCompatible; +import com.google.common.escape.Escaper; +import com.google.common.escape.Escapers; +import javax.annotation.CheckReturnValue; + + +/** + * Static utility methods shared by safe-HTML types' factory and builder classes, such as + * {@link SafeHtmls}, {@link SafeHtmlBuilder}, etc. + */ +@CheckReturnValue +@GwtCompatible +final class BuilderUtils { + + private BuilderUtils() {} + + static String coerceToInterchangeValid(String text) { + // MOE elided code that uses a non-public library to make sure text only + // contains minimally-encoded Unicode scalar values that can appear in + // both HTML and XML. + return text; + + } + + static String escapeHtmlInternal(String s) { + return HTML_ESCAPER.escape(s); + + } + + // This is exactly what j.c.g.common.html.HtmlEscapers.htmlEscaper() does. However, depending on + // j.c.g.common.html is problematic because it has no android target, substantial internal only + // code, and it pulls a lot of other dependencies with it. + private static final Escaper HTML_ESCAPER = + Escapers.builder() + .addEscape('"', """) + // Note: "'" is not defined in HTML 4.01. + .addEscape('\'', "'") + .addEscape('&', "&") + .addEscape('<', "<") + .addEscape('>', ">") + .build(); +} diff --git a/third_party/safe_html_types/com/google/common/html/types/CustomSafeUrlScheme.java b/third_party/safe_html_types/com/google/common/html/types/CustomSafeUrlScheme.java new file mode 100644 index 00000000000..09010d736d6 --- /dev/null +++ b/third_party/safe_html_types/com/google/common/html/types/CustomSafeUrlScheme.java @@ -0,0 +1,227 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: webutil/html/types/html.proto + +package com.google.common.html.types; + +/** + * Protobuf enum {@code webutil.html.types.CustomSafeUrlScheme} + */ +public enum CustomSafeUrlScheme + implements com.google.protobuf.ProtocolMessageEnum { + /** + *
+ * Schemes that are safe w.r.t. XSS but that may trigger other problematic + * actions when presented in the context of a "regular" link are not + * whitelisted by default but can still be converted to SafeUrl by + * whitelisting them explicitly in the SafeUrl sanitization API. In other + * words, the caller has to indicate that they're expecting to process + * such custom schemes. + * iOS Webview does not ask for confirmation before invoking 'tel', so + * unintentional or out-of-context clicks could result in unintended calling + * charges. + *+ * + *
TEL = 0;
+ */
+ TEL(0),
+ /**
+ * SMS = 1;
+ */
+ SMS(1),
+ /**
+ * + * Similarly to 'tel' can result in unintended calling charges on iOS. + *+ * + *
CALLTO = 2;
+ */
+ CALLTO(2),
+ /**
+ * WTAI = 3;
+ */
+ WTAI(3),
+ /**
+ * + * Can start a media stream, potentially triggering an exploit for + * Stagefright. + *+ * + *
RTSP = 4;
+ */
+ RTSP(4),
+ /**
+ * + * Can open Play Store dialog with 'Install' button, though will not + * automatically install an app. + *+ * + *
MARKET = 5;
+ */
+ MARKET(5),
+ /**
+ * GEO = 6;
+ */
+ GEO(6),
+ /**
+ * SKYPE = 7;
+ */
+ SKYPE(7),
+ /**
+ * WHATSAPP = 8;
+ */
+ WHATSAPP(8),
+ /**
+ * + * Custom scheme for iBooks URIs. More background: b/32807272. + *+ * + *
ITMS_BOOKS = 9;
+ */
+ ITMS_BOOKS(9),
+ ;
+
+ /**
+ * + * Schemes that are safe w.r.t. XSS but that may trigger other problematic + * actions when presented in the context of a "regular" link are not + * whitelisted by default but can still be converted to SafeUrl by + * whitelisting them explicitly in the SafeUrl sanitization API. In other + * words, the caller has to indicate that they're expecting to process + * such custom schemes. + * iOS Webview does not ask for confirmation before invoking 'tel', so + * unintentional or out-of-context clicks could result in unintended calling + * charges. + *+ * + *
TEL = 0;
+ */
+ public static final int TEL_VALUE = 0;
+ /**
+ * SMS = 1;
+ */
+ public static final int SMS_VALUE = 1;
+ /**
+ * + * Similarly to 'tel' can result in unintended calling charges on iOS. + *+ * + *
CALLTO = 2;
+ */
+ public static final int CALLTO_VALUE = 2;
+ /**
+ * WTAI = 3;
+ */
+ public static final int WTAI_VALUE = 3;
+ /**
+ * + * Can start a media stream, potentially triggering an exploit for + * Stagefright. + *+ * + *
RTSP = 4;
+ */
+ public static final int RTSP_VALUE = 4;
+ /**
+ * + * Can open Play Store dialog with 'Install' button, though will not + * automatically install an app. + *+ * + *
MARKET = 5;
+ */
+ public static final int MARKET_VALUE = 5;
+ /**
+ * GEO = 6;
+ */
+ public static final int GEO_VALUE = 6;
+ /**
+ * SKYPE = 7;
+ */
+ public static final int SKYPE_VALUE = 7;
+ /**
+ * WHATSAPP = 8;
+ */
+ public static final int WHATSAPP_VALUE = 8;
+ /**
+ * + * Custom scheme for iBooks URIs. More background: b/32807272. + *+ * + *
ITMS_BOOKS = 9;
+ */
+ public static final int ITMS_BOOKS_VALUE = 9;
+
+
+ public final int getNumber() {
+ return value;
+ }
+
+ /**
+ * @deprecated Use {@link #forNumber(int)} instead.
+ */
+ @java.lang.Deprecated
+ public static CustomSafeUrlScheme valueOf(int value) {
+ return forNumber(value);
+ }
+
+ public static CustomSafeUrlScheme forNumber(int value) {
+ switch (value) {
+ case 0: return TEL;
+ case 1: return SMS;
+ case 2: return CALLTO;
+ case 3: return WTAI;
+ case 4: return RTSP;
+ case 5: return MARKET;
+ case 6: return GEO;
+ case 7: return SKYPE;
+ case 8: return WHATSAPP;
+ case 9: return ITMS_BOOKS;
+ default: return null;
+ }
+ }
+
+ public static com.google.protobuf.Internal.EnumLiteMapValues of this type are guaranteed to be safe to use in HTML contexts, such as, assignment to + * the innerHTML DOM property, or interpolation into a HTML template in HTML PC_DATA context, in + * the sense that the use will not result in a Cross-Site-Scripting vulnerability. + */ +@CheckReturnValue +@Immutable +@JsType +public final class SafeHtml { + + /** The SafeHtml wrapping an empty string. */ + public static final SafeHtml EMPTY = new SafeHtml(""); + + private final String privateDoNotAccessOrElseSafeHtmlWrappedValue; + + SafeHtml(String html) { + if (html == null) { + throw new NullPointerException(); + } + this.privateDoNotAccessOrElseSafeHtmlWrappedValue = html; + } + + @Override + public int hashCode() { + return privateDoNotAccessOrElseSafeHtmlWrappedValue.hashCode() ^ 0x33b02fa9; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof SafeHtml)) { + return false; + } + SafeHtml that = (SafeHtml) other; + return this.privateDoNotAccessOrElseSafeHtmlWrappedValue.equals( + that.privateDoNotAccessOrElseSafeHtmlWrappedValue); + } + + /** + * Returns a debug representation of this value's underlying string, NOT the string representation + * of the SafeHtml. + * + *
Having {@code toString()} return a debug representation is intentional. This type has + * a GWT-compiled JavaScript version; JavaScript has no static typing and a distinct method + * method name provides a modicum of type-safety. + * + * @see #getSafeHtmlString + */ + @Override + public String toString() { + return "SafeHtml{" + privateDoNotAccessOrElseSafeHtmlWrappedValue + "}"; + } + + /** + * Returns this value's underlying string. See class documentation for what guarantees exist on + * the returned string. + */ + // NOTE(mlourenco): jslayout depends on this exact method name when generating code, be careful if + // changing it. + public String getSafeHtmlString() { + return privateDoNotAccessOrElseSafeHtmlWrappedValue; + } +} diff --git a/third_party/safe_html_types/com/google/common/html/types/SafeHtmlBuilder.java b/third_party/safe_html_types/com/google/common/html/types/SafeHtmlBuilder.java new file mode 100644 index 00000000000..ea70d08ee90 --- /dev/null +++ b/third_party/safe_html_types/com/google/common/html/types/SafeHtmlBuilder.java @@ -0,0 +1,1079 @@ +// **** GENERATED CODE, DO NOT MODIFY **** +// This file was generated via preprocessing from input: +// java/com/google/common/html/types/SafeHtmlBuilder.java.tpl +// Please make changes to that file and run +// java/com/google/common/html/types/gen_srcs.sh +// to regenerate the .java files. +// *************************************** +/* + * Copyright 2016 Google Inc. 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. + */ + +package com.google.common.html.types; + +import static com.google.common.html.types.BuilderUtils.coerceToInterchangeValid; +import static com.google.common.html.types.BuilderUtils.escapeHtmlInternal; + +import com.google.common.annotations.GwtCompatible; +import com.google.errorprone.annotations.CompileTimeConstant; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import javax.annotation.CheckReturnValue; +import javax.annotation.Generated; +import javax.annotation.Nullable; +import javax.annotation.concurrent.NotThreadSafe; + +/** + * Builder for HTML elements which conform to the {@link SafeHtml} contract. Supports setting + * element name, individual attributes and content. + * + *
While this builder disallows some invalid HTML constructs (for example, void elements with
+ * content) it does not guarantee well-formed HTML (for example, attribute values are not strictly
+ * enforced if they pose no security risk). A large number of runtime failures are possible and it
+ * is therefore recommended to thoroughly unit test code using this builder.
+ */
+@Generated(value = "//java/com/google/common/html/types:gen_srcs.sh")
+@GwtCompatible
+@NotThreadSafe
+public final class SafeHtmlBuilder {
+ // Keep these regular expressions compatible across Java and JavaScript native implementations.
+ // They are uncompiled because we couldn't depend on java.util.regex.Pattern or
+ // com.google.gwt.regexp.shared.RegExp
+ private static final String VALID_ELEMENT_NAMES_REGEXP = "[a-z0-9-]+";
+ private static final String VALID_DATA_ATTRIBUTES_REGEXP = "data-[a-zA-Z-]+";
+
+ private static final Set If {@code elementName} is not a void element then the string representation of the builder
+ * is {@code {@code embed}, {@code object}, {@code script}, {@code style}, {@code template} are not
+ * supported because their content has special semantics, and they can result the execution of
+ * code not under application control. Some of these have dedicated creation methods.
+ *
+ * @throws IllegalArgumentException if {@code elementName} contains invalid characters or is not
+ * supported
+ * @see http://whatwg.org/html/syntax.html#void-elements
+ */
+ public SafeHtmlBuilder(@CompileTimeConstant final String elementName) {
+ if (elementName == null) {
+ throw new NullPointerException();
+ }
+ if (!elementName.matches(VALID_ELEMENT_NAMES_REGEXP)) {
+ throw new IllegalArgumentException(
+ "Invalid element name \""
+ + elementName
+ + "\". "
+ + "Only lowercase letters, numbers and '-' allowed.");
+ }
+ if (UNSUPPORTED_ELEMENTS.contains(elementName)) {
+ throw new IllegalArgumentException("Element \"" + elementName + "\" is not supported.");
+ }
+ this.elementName = elementName;
+ }
+
+ /**
+ * Causes the builder to use a slash on the tag of a void element, emitting e.g. {@code This setting has no effect for non-void elements.
+ *
+ * @see http://www.w3.org/TR/html5/syntax.html#start-tags
+ */
+ public SafeHtmlBuilder useSlashOnVoid() {
+ useSlashOnVoid = true;
+ return this;
+ }
+ /** These elements are whitelisted to use action with a SafeUrl value. */
+ private static final Set The attribute {@code action} with a {@code SafeUrl} value is allowed on these elements:
+ *
+ * The attribute {@code cite} with a {@code SafeUrl} value is allowed on these elements:
+ *
+ * The attribute {@code formaction} with a {@code SafeUrl} value is allowed on these elements:
+ *
+ * The attribute {@code formmethod} with a {@code String} value is allowed on these elements:
+ *
+ * The attribute {@code href} with a {@code SafeUrl} value is allowed on these elements:
+ *
+ * On {@code link} elements, {@code href} may only be set to a SafeUrl value if {@code rel} is
+ * one of the following values:
+ *
+ * The attribute {@code icon} with a {@code SafeUrl} value is allowed on these elements:
+ *
+ * The attribute {@code media} with a {@code String} value is allowed on these elements:
+ *
+ * The attribute {@code method} with a {@code String} value is allowed on these elements:
+ *
+ * The attribute {@code pattern} with a {@code String} value is allowed on these elements:
+ *
+ * The attribute {@code poster} with a {@code SafeUrl} value is allowed on these elements:
+ *
+ * If this is a {@code link}} element, and {@code href} has been set from a {@link SafeUrl},
+ * then {@code value} has to be an allowed value. See {@link #setHref(SafeHtml)}.
+ *
+ * @throws IllegalArgumentException if this is a {@code link} element and this value of {@code
+ * rel} is not allowed
+ */
+ public SafeHtmlBuilder setRel(String value) {
+ checkLinkDependentAttributes(value, hrefValueContract);
+ return setAttribute("rel", value);
+ }
+
+ /** Sets the {@code required} attribute for this element. */
+ public SafeHtmlBuilder setRequired(String value) {
+ return setAttribute("required", value);
+ }
+
+ /** Sets the {@code reversed} attribute for this element. */
+ public SafeHtmlBuilder setReversed(String value) {
+ return setAttribute("reversed", value);
+ }
+
+ /** Sets the {@code role} attribute for this element. */
+ public SafeHtmlBuilder setRole(String value) {
+ return setAttribute("role", value);
+ }
+
+ /** Sets the {@code rows} attribute for this element. */
+ public SafeHtmlBuilder setRows(String value) {
+ return setAttribute("rows", value);
+ }
+
+ /** Sets the {@code rowspan} attribute for this element. */
+ public SafeHtmlBuilder setRowspan(String value) {
+ return setAttribute("rowspan", value);
+ }
+
+ /** Sets the {@code selected} attribute for this element. */
+ public SafeHtmlBuilder setSelected(String value) {
+ return setAttribute("selected", value);
+ }
+
+ /** Sets the {@code shape} attribute for this element. */
+ public SafeHtmlBuilder setShape(String value) {
+ return setAttribute("shape", value);
+ }
+
+ /** Sets the {@code size} attribute for this element. */
+ public SafeHtmlBuilder setSize(String value) {
+ return setAttribute("size", value);
+ }
+
+ /** Sets the {@code sizes} attribute for this element. */
+ public SafeHtmlBuilder setSizes(String value) {
+ return setAttribute("sizes", value);
+ }
+
+ /** Sets the {@code span} attribute for this element. */
+ public SafeHtmlBuilder setSpan(String value) {
+ return setAttribute("span", value);
+ }
+
+ /** Sets the {@code spellcheck} attribute for this element. */
+ public SafeHtmlBuilder setSpellcheck(String value) {
+ return setAttribute("spellcheck", value);
+ }
+
+ /** These elements are whitelisted to use src with a SafeUrl value. */
+ private static final Set The attribute {@code src} with a {@code SafeUrl} value is allowed on these elements:
+ *
+ * The attribute {@code srcdoc} with a {@code SafeHtml} value is allowed on these elements:
+ *
+ * The attribute {@code type} with a {@code String} value is allowed on these elements:
+ *
+ * Protocol-message forms are intended to be opaque. The fields of the protocol message should
+ * be considered encapsulated and are not intended for direct inspection or manipulation. Protocol
+ * message forms of this type should be produced by {@link #toProto(SafeHtml)} or its
+ * equivalent in other implementation languages.
+ *
+ * Important: It is unsafe to invoke this method on a protocol message that has been
+ * received from an entity outside the application's trust domain. Data coming from the browser
+ * is outside the application's trust domain.
+ */
+ public static SafeHtml fromProto(SafeHtmlProto proto) {
+ return create(proto.getPrivateDoNotAccessOrElseSafeHtmlWrappedValue());
+ }
+
+ /**
+ * Wraps a SafeScript inside a <script type="text/javascript"> tag.
+ */
+ public static SafeHtml fromScript(SafeScript script) {
+ return create("");
+ }
+
+ /**
+ * Wraps a SafeScript inside a <script type="text/javascript"> tag.
+ * The tag has a nonce attribute populated from the provided CSP nonce value.
+ */
+ public static SafeHtml fromScriptWithCspNonce(SafeScript script, String cspNonce) {
+ return create("");
+ }
+
+ /**
+ * Creates a <script type="text/javascript" src="url"><script> where the
+ * {@code src} attribute points to the given {@code trustedResourceUrl}.
+ */
+ public static SafeHtml fromScriptUrl(TrustedResourceUrl trustedResourceUrl) {
+ String escapedUrl = htmlEscapeInternal(trustedResourceUrl.getTrustedResourceUrlString());
+ return create("");
+ }
+
+ /**
+ * Creates a <script defer type="text/javascript" src="url"><script> where the
+ * {@code src} attribute points to the given {@code trustedResourceUrl}.
+ */
+ public static SafeHtml fromScriptUrlDeferred(TrustedResourceUrl trustedResourceUrl) {
+ String escapedUrl = htmlEscapeInternal(trustedResourceUrl.getTrustedResourceUrlString());
+ return create("");
+ }
+
+ /**
+ * Creates a <script type="text/javascript" src="url"><script> where the
+ * {@code src} attribute points to the given {@code trustedResourceUrl}.
+ * The tag has a nonce attribute populated from the provided CSP nonce value.
+ */
+ public static SafeHtml fromScriptUrlWithCspNonce(TrustedResourceUrl trustedResourceUrl,
+ String cspNonce) {
+ String escapedUrl = htmlEscapeInternal(trustedResourceUrl.getTrustedResourceUrlString());
+ return create("");
+ }
+
+ /**
+ * Creates a <script defer type="text/javascript" src="url"><script> where the
+ * {@code src} attribute points to the given {@code trustedResourceUrl}.
+ * The tag has a nonce attribute populated from the provided CSP nonce value.
+ */
+ public static SafeHtml fromScriptUrlWithCspNonceDeferred(TrustedResourceUrl trustedResourceUrl,
+ String cspNonce) {
+ String escapedUrl = htmlEscapeInternal(trustedResourceUrl.getTrustedResourceUrlString());
+ return create("");
+ }
+
+ /**
+ * Wraps a SafeStyleSheet inside a <style type="text/css"> tag.
+ */
+ public static SafeHtml fromStyleSheet(SafeStyleSheet safeStyleSheet) {
+ Preconditions.checkArgument(!safeStyleSheet.getSafeStyleSheetString().contains("<"));
+ return create("");
+ }
+
+ /**
+ * Creates a <style type="text/css" src="url"><style> where the
+ * {@code src} attribute points to the given {@code trustedResourceUrl}.
+ */
+ public static SafeHtml fromStyleUrl(TrustedResourceUrl trustedResourceUrl) {
+ String escapedUrl = htmlEscapeInternal(trustedResourceUrl.getTrustedResourceUrlString());
+ return create("");
+ }
+
+ /**
+ * Serializes a SafeHtml into its opaque protocol message representation.
+ *
+ * Protocol message forms of this type are intended to be opaque. The fields of the returned
+ * protocol message should be considered encapsulated and are not intended for direct inspection
+ * or manipulation. Protocol messages can be converted back into a SafeHtml using
+ * {@link #fromProto(SafeHtmlProto)}.
+ */
+ public static SafeHtmlProto toProto(SafeHtml safeHtml) {
+ return SafeHtmlProto.newBuilder().setPrivateDoNotAccessOrElseSafeHtmlWrappedValue(
+ safeHtml.getSafeHtmlString()).build();
+ }
+
+ /**
+ * Converts, by HTML-escaping, an arbitrary string into a contract-compliant {@link SafeHtml}.
+ */
+ public static SafeHtml htmlEscape(String text) {
+ return create(htmlEscapeInternal(text));
+ }
+
+ /**
+ * Converts an arbitrary string into an HTML comment by HTML-escaping the contents and embedding
+ * the result between HTML comment markers.
+ *
+ * Escaping is needed because Internet Explorer supports conditional comments and so may render
+ * HTML markup within comments.
+ */
+ public static SafeHtml comment(String text) {
+ return create("");
+ }
+
+
+ /**
+ * Creates a new SafeHtml which contains, in order, the string representations of the given
+ * {@code htmls}.
+ */
+ public static SafeHtml concat(SafeHtml... htmls) {
+ return concat(Arrays.asList(htmls));
+ }
+
+ /**
+ * Creates a new SafeHtml which contains, in order, the string representations of the given
+ * {@code htmls}.
+ */
+ public static SafeHtml concat(Iterable Having {@code toString()} return a debug representation is intentional. This type has
+ * a GWT-compiled JavaScript version; JavaScript has no static typing and a distinct method
+ * method name provides a modicum of type-safety.
+ *
+ * @see #getSafeScriptString
+ */
+ @Override
+ public String toString() {
+ return "SafeScript{" + privateDoNotAccessOrElseSafeScriptWrappedValue + "}";
+ }
+
+ /**
+ * Returns this value's underlying string. See class documentation for what guarantees exist on
+ * the returned string.
+ */
+ public String getSafeScriptString() {
+ return privateDoNotAccessOrElseSafeScriptWrappedValue;
+ }
+}
diff --git a/third_party/safe_html_types/com/google/common/html/types/SafeScriptProto.java b/third_party/safe_html_types/com/google/common/html/types/SafeScriptProto.java
new file mode 100644
index 00000000000..b51c657fc52
--- /dev/null
+++ b/third_party/safe_html_types/com/google/common/html/types/SafeScriptProto.java
@@ -0,0 +1,604 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: webutil/html/types/html.proto
+
+package com.google.common.html.types;
+
+/**
+ * This performs ZERO VALIDATION of the data. We assume that resources should be safe because
+ * they are part of the binary, and therefore not attacker controlled.
+ *
+ * @param contextClass Class relative to which to load the resource.
+ */
+ @GwtIncompatible("Resources")
+ public static SafeScript fromResource(
+ Class> contextClass, @CompileTimeConstant final String resourceName, Charset charset)
+ throws IOException {
+ return create(Resources.toString(Resources.getResource(contextClass, resourceName), charset));
+ }
+
+ /**
+ * Deserializes a SafeScriptProto into a SafeScript instance.
+ *
+ * Protocol-message forms are intended to be opaque. The fields of the protocol message should
+ * be considered encapsulated and are not intended for direct inspection or manipulation. Protocol
+ * message forms of this type should be produced by {@link #toProto(SafeScript)} or its equivalent
+ * in other implementation languages.
+ *
+ * Important: It is unsafe to invoke this method on a protocol message that has been
+ * received from an entity outside the application's trust domain. Data coming from the browser
+ * is outside the application's trust domain.
+ */
+ public static SafeScript fromProto(SafeScriptProto proto) {
+ return create(proto.getPrivateDoNotAccessOrElseSafeScriptWrappedValue());
+ }
+
+ /**
+ * Serializes a SafeScript into its opaque protocol message representation.
+ *
+ * Protocol message forms of this type are intended to be opaque. The fields of the returned
+ * protocol message should be considered encapsulated and are not intended for direct inspection
+ * or manipulation. Protocol messages can be converted back into a SafeScript using
+ * {@link #fromProto(SafeScriptProto)}.
+ */
+ public static SafeScriptProto toProto(SafeScript script) {
+ return SafeScriptProto.newBuilder()
+ .setPrivateDoNotAccessOrElseSafeScriptWrappedValue(script.getSafeScriptString()).build();
+ }
+
+ static SafeScript create(String script) {
+ return new SafeScript(script);
+ }
+}
diff --git a/third_party/safe_html_types/com/google/common/html/types/SafeStyle.java b/third_party/safe_html_types/com/google/common/html/types/SafeStyle.java
new file mode 100644
index 00000000000..3a3571677e2
--- /dev/null
+++ b/third_party/safe_html_types/com/google/common/html/types/SafeStyle.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2016 Google Inc. 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.
+ */
+
+package com.google.common.html.types;
+
+import javax.annotation.CheckReturnValue;
+import javax.annotation.concurrent.Immutable;
+import jsinterop.annotations.JsType;
+
+/**
+ * A string-like object which represents a sequence of CSS declarations
+ * ({@code propertyName1: propertyvalue1; propertyName2: propertyValue2; ...}) and that carries the
+ * security type contract that its value, as a string, will not cause untrusted script execution
+ * (XSS) when evaluated as CSS in a browser.
+ *
+ * A SafeStyle's string representation ({@link #getSafeStyleString()}) can safely be:
+ *
}
+ * instead of the default {@code
}. Slashes are required if rendering XHTML and optional in
+ * HTML 5.
+ *
+ *
+ *
+ *
+ * @throws IllegalArgumentException if the {@code action} attribute with a {@code SafeUrl} value
+ * is not allowed on this element
+ */
+ public SafeHtmlBuilder setAction(SafeUrl value) {
+ if (!ACTION_SAFE_URL_ELEMENT_WHITELIST.contains(elementName)) {
+ throw new IllegalArgumentException(
+ "Attribute \"action\" with a SafeUrl value can only be used "
+ + "by one of the following elements: "
+ + ACTION_SAFE_URL_ELEMENT_WHITELIST);
+ }
+ return setAttribute("action", value.getSafeUrlString());
+ }
+
+ /** Sets the {@code align} attribute for this element. */
+ public SafeHtmlBuilder setAlign(String value) {
+ return setAttribute("align", value);
+ }
+
+ /** Sets the {@code alt} attribute for this element. */
+ public SafeHtmlBuilder setAlt(String value) {
+ return setAttribute("alt", value);
+ }
+
+ /** Sets the {@code autocapitalize} attribute for this element. */
+ public SafeHtmlBuilder setAutocapitalize(String value) {
+ return setAttribute("autocapitalize", value);
+ }
+
+ /** Sets the {@code autocomplete} attribute for this element. */
+ public SafeHtmlBuilder setAutocomplete(String value) {
+ return setAttribute("autocomplete", value);
+ }
+
+ /** Sets the {@code autofocus} attribute for this element. */
+ public SafeHtmlBuilder setAutofocus(String value) {
+ return setAttribute("autofocus", value);
+ }
+
+ /** Sets the {@code bgcolor} attribute for this element. */
+ public SafeHtmlBuilder setBgcolor(String value) {
+ return setAttribute("bgcolor", value);
+ }
+
+ /** Sets the {@code border} attribute for this element. */
+ public SafeHtmlBuilder setBorder(String value) {
+ return setAttribute("border", value);
+ }
+
+ /** Sets the {@code checked} attribute for this element. */
+ public SafeHtmlBuilder setChecked(String value) {
+ return setAttribute("checked", value);
+ }
+
+ /** These elements are whitelisted to use cite with a SafeUrl value. */
+ private static final Set
+ *
+ *
+ * @throws IllegalArgumentException if the {@code cite} attribute with a {@code SafeUrl} value is
+ * not allowed on this element
+ */
+ public SafeHtmlBuilder setCite(SafeUrl value) {
+ if (!CITE_SAFE_URL_ELEMENT_WHITELIST.contains(elementName)) {
+ throw new IllegalArgumentException(
+ "Attribute \"cite\" with a SafeUrl value can only be used "
+ + "by one of the following elements: "
+ + CITE_SAFE_URL_ELEMENT_WHITELIST);
+ }
+ return setAttribute("cite", value.getSafeUrlString());
+ }
+
+ /** Sets the {@code class} attribute for this element. */
+ public SafeHtmlBuilder setClass(String value) {
+ return setAttribute("class", value);
+ }
+
+ /** Sets the {@code color} attribute for this element. */
+ public SafeHtmlBuilder setColor(String value) {
+ return setAttribute("color", value);
+ }
+
+ /** Sets the {@code cols} attribute for this element. */
+ public SafeHtmlBuilder setCols(String value) {
+ return setAttribute("cols", value);
+ }
+
+ /** Sets the {@code colspan} attribute for this element. */
+ public SafeHtmlBuilder setColspan(String value) {
+ return setAttribute("colspan", value);
+ }
+
+ /** Values that can be passed to {@link #setDir(DirValue)}. */
+ public enum DirValue {
+
+ /** Value of {@code auto}. */
+ AUTO("auto"),
+ /** Value of {@code ltr}. */
+ LTR("ltr"),
+ /** Value of {@code rtl}. */
+ RTL("rtl");
+
+ private final String value;
+
+ private DirValue(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+ }
+
+ /** Sets the {@code dir} attribute for this element. */
+ public SafeHtmlBuilder setDir(DirValue value) {
+ return setAttribute("dir", value.toString());
+ }
+
+ /** Sets the {@code disabled} attribute for this element. */
+ public SafeHtmlBuilder setDisabled(String value) {
+ return setAttribute("disabled", value);
+ }
+
+ /** Sets the {@code draggable} attribute for this element. */
+ public SafeHtmlBuilder setDraggable(String value) {
+ return setAttribute("draggable", value);
+ }
+
+ /** Sets the {@code face} attribute for this element. */
+ public SafeHtmlBuilder setFace(String value) {
+ return setAttribute("face", value);
+ }
+
+ /** Sets the {@code for} attribute for this element. */
+ public SafeHtmlBuilder setFor(@CompileTimeConstant final String value) {
+ return setAttribute("for", value);
+ }
+
+ /**
+ * Sets the {@code for} attribute for this element to a {@link CompileTimeConstant} {@code prefix}
+ * and a {@code value} joined by a hyphen.
+ *
+ * @throws IllegalArgumentException if {@code prefix} is an empty string
+ */
+ public SafeHtmlBuilder setForWithPrefix(@CompileTimeConstant final String prefix, String value) {
+ if (prefix.trim().length() == 0) {
+ throw new IllegalArgumentException("Prefix cannot be empty string");
+ }
+ return setAttribute("for", prefix + "-" + value);
+ }
+
+ /** These elements are whitelisted to use formaction with a SafeUrl value. */
+ private static final Set
+ *
+ *
+ * @throws IllegalArgumentException if the {@code formaction} attribute with a {@code SafeUrl}
+ * value is not allowed on this element
+ */
+ public SafeHtmlBuilder setFormaction(SafeUrl value) {
+ if (!FORMACTION_SAFE_URL_ELEMENT_WHITELIST.contains(elementName)) {
+ throw new IllegalArgumentException(
+ "Attribute \"formaction\" with a SafeUrl value can only be used "
+ + "by one of the following elements: "
+ + FORMACTION_SAFE_URL_ELEMENT_WHITELIST);
+ }
+ return setAttribute("formaction", value.getSafeUrlString());
+ }
+
+ /** These elements are whitelisted to use formmethod with a String value. */
+ private static final Set
+ *
+ *
+ * @throws IllegalArgumentException if the {@code formmethod} attribute with a {@code String}
+ * value is not allowed on this element
+ */
+ public SafeHtmlBuilder setFormmethod(String value) {
+ if (!FORMMETHOD_STRING_ELEMENT_WHITELIST.contains(elementName)) {
+ throw new IllegalArgumentException(
+ "Attribute \"formmethod\" with a String value can only be used "
+ + "by one of the following elements: "
+ + FORMMETHOD_STRING_ELEMENT_WHITELIST);
+ }
+ return setAttribute("formmethod", value);
+ }
+
+ /** Sets the {@code frameborder} attribute for this element. */
+ public SafeHtmlBuilder setFrameborder(String value) {
+ return setAttribute("frameborder", value);
+ }
+
+ /** Sets the {@code height} attribute for this element. */
+ public SafeHtmlBuilder setHeight(String value) {
+ return setAttribute("height", value);
+ }
+
+ /** Sets the {@code hidden} attribute for this element. */
+ public SafeHtmlBuilder setHidden(String value) {
+ return setAttribute("hidden", value);
+ }
+
+ /** These elements are whitelisted to use href with a SafeUrl value. */
+ private static final Set
+ *
+ *
+ *
+ *
+ *
+ * @throws IllegalArgumentException if the {@code href} attribute with a {@code SafeUrl} value is
+ * not allowed on this element
+ * @throws IllegalArgumentException if this a {@code link} element and the value of {@code rel}
+ * does not allow the SafeUrl contract on {@code href}
+ */
+ public SafeHtmlBuilder setHref(SafeUrl value) {
+ if (!HREF_SAFE_URL_ELEMENT_WHITELIST.contains(elementName) && !elementName.equals("link")) {
+ throw new IllegalArgumentException(
+ "Attribute \"href\" with a SafeUrl value can only be used "
+ + "by one of the following elements: "
+ + HREF_SAFE_URL_ELEMENT_WHITELIST);
+ }
+ if (elementName.equals("link")) {
+ checkLinkDependentAttributes(attributes.get("rel"), AttributeContract.SAFE_URL);
+ }
+ hrefValueContract = AttributeContract.SAFE_URL;
+ return setAttribute("href", value.getSafeUrlString());
+ }
+
+ /** Sets the {@code href} attribute for this element. */
+ public SafeHtmlBuilder setHref(TrustedResourceUrl value) {
+ hrefValueContract = AttributeContract.TRUSTED_RESOURCE_URL;
+ return setAttribute("href", value.getTrustedResourceUrlString());
+ }
+
+ /** These elements are whitelisted to use icon with a SafeUrl value. */
+ private static final Set
+ *
+ *
+ * @throws IllegalArgumentException if the {@code icon} attribute with a {@code SafeUrl} value is
+ * not allowed on this element
+ */
+ public SafeHtmlBuilder setIcon(SafeUrl value) {
+ if (!ICON_SAFE_URL_ELEMENT_WHITELIST.contains(elementName)) {
+ throw new IllegalArgumentException(
+ "Attribute \"icon\" with a SafeUrl value can only be used "
+ + "by one of the following elements: "
+ + ICON_SAFE_URL_ELEMENT_WHITELIST);
+ }
+ return setAttribute("icon", value.getSafeUrlString());
+ }
+
+ /** Sets the {@code id} attribute for this element. */
+ public SafeHtmlBuilder setId(@CompileTimeConstant final String value) {
+ return setAttribute("id", value);
+ }
+
+ /**
+ * Sets the {@code id} attribute for this element to a {@link CompileTimeConstant} {@code prefix}
+ * and a {@code value} joined by a hyphen.
+ *
+ * @throws IllegalArgumentException if {@code prefix} is an empty string
+ */
+ public SafeHtmlBuilder setIdWithPrefix(@CompileTimeConstant final String prefix, String value) {
+ if (prefix.trim().length() == 0) {
+ throw new IllegalArgumentException("Prefix cannot be empty string");
+ }
+ return setAttribute("id", prefix + "-" + value);
+ }
+
+ /** Sets the {@code ismap} attribute for this element. */
+ public SafeHtmlBuilder setIsmap(String value) {
+ return setAttribute("ismap", value);
+ }
+
+ /** Sets the {@code label} attribute for this element. */
+ public SafeHtmlBuilder setLabel(String value) {
+ return setAttribute("label", value);
+ }
+
+ /** Sets the {@code lang} attribute for this element. */
+ public SafeHtmlBuilder setLang(String value) {
+ return setAttribute("lang", value);
+ }
+
+ /** Sets the {@code list} attribute for this element. */
+ public SafeHtmlBuilder setList(@CompileTimeConstant final String value) {
+ return setAttribute("list", value);
+ }
+
+ /**
+ * Sets the {@code list} attribute for this element to a {@link CompileTimeConstant} {@code
+ * prefix} and a {@code value} joined by a hyphen.
+ *
+ * @throws IllegalArgumentException if {@code prefix} is an empty string
+ */
+ public SafeHtmlBuilder setListWithPrefix(@CompileTimeConstant final String prefix, String value) {
+ if (prefix.trim().length() == 0) {
+ throw new IllegalArgumentException("Prefix cannot be empty string");
+ }
+ return setAttribute("list", prefix + "-" + value);
+ }
+
+ /** Sets the {@code loop} attribute for this element. */
+ public SafeHtmlBuilder setLoop(String value) {
+ return setAttribute("loop", value);
+ }
+
+ /** Sets the {@code max} attribute for this element. */
+ public SafeHtmlBuilder setMax(String value) {
+ return setAttribute("max", value);
+ }
+
+ /** Sets the {@code maxlength} attribute for this element. */
+ public SafeHtmlBuilder setMaxlength(String value) {
+ return setAttribute("maxlength", value);
+ }
+
+ /** These elements are whitelisted to use media with a String value. */
+ private static final Set
+ *
+ *
+ * @throws IllegalArgumentException if the {@code media} attribute with a {@code String} value is
+ * not allowed on this element
+ */
+ public SafeHtmlBuilder setMedia(String value) {
+ if (!MEDIA_STRING_ELEMENT_WHITELIST.contains(elementName)) {
+ throw new IllegalArgumentException(
+ "Attribute \"media\" with a String value can only be used "
+ + "by one of the following elements: "
+ + MEDIA_STRING_ELEMENT_WHITELIST);
+ }
+ return setAttribute("media", value);
+ }
+
+ /** These elements are whitelisted to use method with a String value. */
+ private static final Set
+ *
+ *
+ * @throws IllegalArgumentException if the {@code method} attribute with a {@code String} value is
+ * not allowed on this element
+ */
+ public SafeHtmlBuilder setMethod(String value) {
+ if (!METHOD_STRING_ELEMENT_WHITELIST.contains(elementName)) {
+ throw new IllegalArgumentException(
+ "Attribute \"method\" with a String value can only be used "
+ + "by one of the following elements: "
+ + METHOD_STRING_ELEMENT_WHITELIST);
+ }
+ return setAttribute("method", value);
+ }
+
+ /** Sets the {@code min} attribute for this element. */
+ public SafeHtmlBuilder setMin(String value) {
+ return setAttribute("min", value);
+ }
+
+ /** Sets the {@code multiple} attribute for this element. */
+ public SafeHtmlBuilder setMultiple(String value) {
+ return setAttribute("multiple", value);
+ }
+
+ /** Sets the {@code muted} attribute for this element. */
+ public SafeHtmlBuilder setMuted(String value) {
+ return setAttribute("muted", value);
+ }
+
+ /** Sets the {@code name} attribute for this element. */
+ public SafeHtmlBuilder setName(@CompileTimeConstant final String value) {
+ return setAttribute("name", value);
+ }
+
+ /**
+ * Sets the {@code name} attribute for this element to a {@link CompileTimeConstant} {@code
+ * prefix} and a {@code value} joined by a hyphen.
+ *
+ * @throws IllegalArgumentException if {@code prefix} is an empty string
+ */
+ public SafeHtmlBuilder setNameWithPrefix(@CompileTimeConstant final String prefix, String value) {
+ if (prefix.trim().length() == 0) {
+ throw new IllegalArgumentException("Prefix cannot be empty string");
+ }
+ return setAttribute("name", prefix + "-" + value);
+ }
+
+ /** These elements are whitelisted to use pattern with a String value. */
+ private static final Set
+ *
+ *
+ * @throws IllegalArgumentException if the {@code pattern} attribute with a {@code String} value
+ * is not allowed on this element
+ */
+ public SafeHtmlBuilder setPattern(String value) {
+ if (!PATTERN_STRING_ELEMENT_WHITELIST.contains(elementName)) {
+ throw new IllegalArgumentException(
+ "Attribute \"pattern\" with a String value can only be used "
+ + "by one of the following elements: "
+ + PATTERN_STRING_ELEMENT_WHITELIST);
+ }
+ return setAttribute("pattern", value);
+ }
+
+ /** Sets the {@code placeholder} attribute for this element. */
+ public SafeHtmlBuilder setPlaceholder(String value) {
+ return setAttribute("placeholder", value);
+ }
+
+ /** These elements are whitelisted to use poster with a SafeUrl value. */
+ private static final Set
+ *
+ *
+ * @throws IllegalArgumentException if the {@code poster} attribute with a {@code SafeUrl} value
+ * is not allowed on this element
+ */
+ public SafeHtmlBuilder setPoster(SafeUrl value) {
+ if (!POSTER_SAFE_URL_ELEMENT_WHITELIST.contains(elementName)) {
+ throw new IllegalArgumentException(
+ "Attribute \"poster\" with a SafeUrl value can only be used "
+ + "by one of the following elements: "
+ + POSTER_SAFE_URL_ELEMENT_WHITELIST);
+ }
+ return setAttribute("poster", value.getSafeUrlString());
+ }
+
+ /** Sets the {@code preload} attribute for this element. */
+ public SafeHtmlBuilder setPreload(String value) {
+ return setAttribute("preload", value);
+ }
+
+ /**
+ * Sets the {@code rel} attribute for this element.
+ *
+ *
+ *
+ *
+ * @throws IllegalArgumentException if the {@code src} attribute with a {@code SafeUrl} value is
+ * not allowed on this element
+ */
+ public SafeHtmlBuilder setSrc(SafeUrl value) {
+ if (!SRC_SAFE_URL_ELEMENT_WHITELIST.contains(elementName)) {
+ throw new IllegalArgumentException(
+ "Attribute \"src\" with a SafeUrl value can only be used "
+ + "by one of the following elements: "
+ + SRC_SAFE_URL_ELEMENT_WHITELIST);
+ }
+ return setAttribute("src", value.getSafeUrlString());
+ }
+
+ /** Sets the {@code src} attribute for this element. */
+ public SafeHtmlBuilder setSrc(TrustedResourceUrl value) {
+ return setAttribute("src", value.getTrustedResourceUrlString());
+ }
+
+ /** These elements are whitelisted to use srcdoc with a SafeHtml value. */
+ private static final Set
+ *
+ *
+ * @throws IllegalArgumentException if the {@code srcdoc} attribute with a {@code SafeHtml} value
+ * is not allowed on this element
+ */
+ public SafeHtmlBuilder setSrcdoc(SafeHtml value) {
+ if (!SRCDOC_SAFE_HTML_ELEMENT_WHITELIST.contains(elementName)) {
+ throw new IllegalArgumentException(
+ "Attribute \"srcdoc\" with a SafeHtml value can only be used "
+ + "by one of the following elements: "
+ + SRCDOC_SAFE_HTML_ELEMENT_WHITELIST);
+ }
+ return setAttribute("srcdoc", value.getSafeHtmlString());
+ }
+
+ /** Sets the {@code start} attribute for this element. */
+ public SafeHtmlBuilder setStart(String value) {
+ return setAttribute("start", value);
+ }
+
+ /** Sets the {@code step} attribute for this element. */
+ public SafeHtmlBuilder setStep(String value) {
+ return setAttribute("step", value);
+ }
+
+ /** Sets the {@code style} attribute for this element. */
+ public SafeHtmlBuilder setStyle(SafeStyle value) {
+ return setAttribute("style", value.getSafeStyleString());
+ }
+
+ /** Sets the {@code summary} attribute for this element. */
+ public SafeHtmlBuilder setSummary(String value) {
+ return setAttribute("summary", value);
+ }
+
+ /** Sets the {@code tabindex} attribute for this element. */
+ public SafeHtmlBuilder setTabindex(String value) {
+ return setAttribute("tabindex", value);
+ }
+
+ /** Values that can be passed to {@link #setTarget(TargetValue)}. */
+ public enum TargetValue {
+
+ /** Value of {@code _blank}. */
+ BLANK("_blank"),
+ /** Value of {@code _self}. */
+ SELF("_self");
+
+ private final String value;
+
+ private TargetValue(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+ }
+
+ /** Sets the {@code target} attribute for this element. */
+ public SafeHtmlBuilder setTarget(TargetValue value) {
+ return setAttribute("target", value.toString());
+ }
+
+ /** Sets the {@code title} attribute for this element. */
+ public SafeHtmlBuilder setTitle(String value) {
+ return setAttribute("title", value);
+ }
+
+ /** Sets the {@code translate} attribute for this element. */
+ public SafeHtmlBuilder setTranslate(String value) {
+ return setAttribute("translate", value);
+ }
+
+ /** These elements are whitelisted to use type with a String value. */
+ private static final Set
+ *
+ *
+ * @throws IllegalArgumentException if the {@code type} attribute with a {@code String} value is
+ * not allowed on this element
+ */
+ public SafeHtmlBuilder setType(String value) {
+ if (!TYPE_STRING_ELEMENT_WHITELIST.contains(elementName)) {
+ throw new IllegalArgumentException(
+ "Attribute \"type\" with a String value can only be used "
+ + "by one of the following elements: "
+ + TYPE_STRING_ELEMENT_WHITELIST);
+ }
+ return setAttribute("type", value);
+ }
+
+ /** Sets the {@code valign} attribute for this element. */
+ public SafeHtmlBuilder setValign(String value) {
+ return setAttribute("valign", value);
+ }
+
+ /** Sets the {@code value} attribute for this element. */
+ public SafeHtmlBuilder setValue(String value) {
+ return setAttribute("value", value);
+ }
+
+ /** Sets the {@code width} attribute for this element. */
+ public SafeHtmlBuilder setWidth(String value) {
+ return setAttribute("width", value);
+ }
+
+ /** Sets the {@code wrap} attribute for this element. */
+ public SafeHtmlBuilder setWrap(String value) {
+ return setAttribute("wrap", value);
+ }
+
+ /**
+ * Sets a custom data attribute, {@code name}, to {@code value} for this element. {@code value}
+ * must consist only of letters and {@code -}.
+ *
+ * @param name including the "data-" prefix, e.g. "data-tooltip"
+ * @throws IllegalArgumentException if the attribute name isn't valid
+ * @see
+ * http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes
+ */
+ public SafeHtmlBuilder setDataAttribute(@CompileTimeConstant final String name, String value) {
+ if (!name.matches(VALID_DATA_ATTRIBUTES_REGEXP)) {
+ throw new IllegalArgumentException(
+ "Invalid data attribute name \""
+ + name
+ + "\"."
+ + "Name must start with \"data-\" and be followed by letters and '-'.");
+ }
+ return setAttribute(name, value);
+ }
+
+ /**
+ * Appends the given {@code htmls} as this element's content, in sequence.
+ *
+ * @throws IllegalStateException if this builder represents a void element
+ */
+ public SafeHtmlBuilder appendContent(SafeHtml... htmls) {
+ checkNotVoidElement();
+ Collections.addAll(contents, htmls);
+ return this;
+ }
+
+ /**
+ * Appends the given {@code htmls} as this element's content, in the sequence the Iterable returns
+ * them.
+ *
+ * @throws IllegalStateException if this builder represents a void element
+ */
+ public SafeHtmlBuilder appendContent(Iterable
+ * IMPORTANT: It is unsafe to accept this message from an untrusted source,
+ * since it's trivial for an attacker to forge serialized messages that
+ * don't fulfill the type's safety contract -- for example, it could contain
+ * attacker controlled script. A system which receives a SafeHtmlProto
+ * implicitly trusts the producer of the SafeHtmlProto. So, it's generally safe
+ * to return this message in RPC responses, but generally unsafe to accept it
+ * in RPC requests.
+ *
+ *
+ * Protobuf type {@code webutil.html.types.SafeHtmlProto}
+ */
+public final class SafeHtmlProto extends
+ com.google.protobuf.GeneratedMessageV3 implements
+ // @@protoc_insertion_point(message_implements:webutil.html.types.SafeHtmlProto)
+ SafeHtmlProtoOrBuilder {
+ // Use SafeHtmlProto.newBuilder() to construct.
+ private SafeHtmlProto(com.google.protobuf.GeneratedMessageV3.Builder> builder) {
+ super(builder);
+ }
+ private SafeHtmlProto() {
+ privateDoNotAccessOrElseSafeHtmlWrappedValue_ = "";
+ }
+
+ @java.lang.Override
+ public final com.google.protobuf.UnknownFieldSet
+ getUnknownFields() {
+ return this.unknownFields;
+ }
+ private SafeHtmlProto(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ this();
+ int mutable_bitField0_ = 0;
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder();
+ try {
+ boolean done = false;
+ while (!done) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ done = true;
+ break;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ done = true;
+ }
+ break;
+ }
+ case 18: {
+ com.google.protobuf.ByteString bs = input.readBytes();
+ bitField0_ |= 0x00000001;
+ privateDoNotAccessOrElseSafeHtmlWrappedValue_ = bs;
+ break;
+ }
+ }
+ }
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(this);
+ } catch (java.io.IOException e) {
+ throw new com.google.protobuf.InvalidProtocolBufferException(
+ e).setUnfinishedMessage(this);
+ } finally {
+ this.unknownFields = unknownFields.build();
+ }
+ }
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return com.google.common.html.types.Html.internal_static_webutil_html_types_SafeHtmlProto_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return com.google.common.html.types.Html.internal_static_webutil_html_types_SafeHtmlProto_fieldAccessorTable
+ .ensureFieldAccessorsInitialized(
+ com.google.common.html.types.SafeHtmlProto.class, com.google.common.html.types.SafeHtmlProto.Builder.class);
+ }
+
+ private int bitField0_;
+ public static final int PRIVATE_DO_NOT_ACCESS_OR_ELSE_SAFE_HTML_WRAPPED_VALUE_FIELD_NUMBER = 2;
+ private volatile java.lang.Object privateDoNotAccessOrElseSafeHtmlWrappedValue_;
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD];
+ */
+ public boolean hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD];
+ */
+ public java.lang.String getPrivateDoNotAccessOrElseSafeHtmlWrappedValue() {
+ java.lang.Object ref = privateDoNotAccessOrElseSafeHtmlWrappedValue_;
+ if (ref instanceof java.lang.String) {
+ return (java.lang.String) ref;
+ } else {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ if (bs.isValidUtf8()) {
+ privateDoNotAccessOrElseSafeHtmlWrappedValue_ = s;
+ }
+ return s;
+ }
+ }
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD];
+ */
+ public com.google.protobuf.ByteString
+ getPrivateDoNotAccessOrElseSafeHtmlWrappedValueBytes() {
+ java.lang.Object ref = privateDoNotAccessOrElseSafeHtmlWrappedValue_;
+ if (ref instanceof java.lang.String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ privateDoNotAccessOrElseSafeHtmlWrappedValue_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized == 1) return true;
+ if (isInitialized == 0) return false;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ com.google.protobuf.GeneratedMessageV3.writeString(output, 2, privateDoNotAccessOrElseSafeHtmlWrappedValue_);
+ }
+ unknownFields.writeTo(output);
+ }
+
+ public int getSerializedSize() {
+ int size = memoizedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, privateDoNotAccessOrElseSafeHtmlWrappedValue_);
+ }
+ size += unknownFields.getSerializedSize();
+ memoizedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ public boolean equals(final java.lang.Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof com.google.common.html.types.SafeHtmlProto)) {
+ return super.equals(obj);
+ }
+ com.google.common.html.types.SafeHtmlProto other = (com.google.common.html.types.SafeHtmlProto) obj;
+
+ boolean result = true;
+ result = result && (hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue() == other.hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue());
+ if (hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue()) {
+ result = result && getPrivateDoNotAccessOrElseSafeHtmlWrappedValue()
+ .equals(other.getPrivateDoNotAccessOrElseSafeHtmlWrappedValue());
+ }
+ result = result && unknownFields.equals(other.unknownFields);
+ return result;
+ }
+
+ @java.lang.Override
+ public int hashCode() {
+ if (memoizedHashCode != 0) {
+ return memoizedHashCode;
+ }
+ int hash = 41;
+ hash = (19 * hash) + getDescriptor().hashCode();
+ if (hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue()) {
+ hash = (37 * hash) + PRIVATE_DO_NOT_ACCESS_OR_ELSE_SAFE_HTML_WRAPPED_VALUE_FIELD_NUMBER;
+ hash = (53 * hash) + getPrivateDoNotAccessOrElseSafeHtmlWrappedValue().hashCode();
+ }
+ hash = (29 * hash) + unknownFields.hashCode();
+ memoizedHashCode = hash;
+ return hash;
+ }
+
+ public static com.google.common.html.types.SafeHtmlProto parseFrom(
+ java.nio.ByteBuffer data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static com.google.common.html.types.SafeHtmlProto parseFrom(
+ java.nio.ByteBuffer data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static com.google.common.html.types.SafeHtmlProto parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static com.google.common.html.types.SafeHtmlProto parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static com.google.common.html.types.SafeHtmlProto parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static com.google.common.html.types.SafeHtmlProto parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static com.google.common.html.types.SafeHtmlProto parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessageV3
+ .parseWithIOException(PARSER, input);
+ }
+ public static com.google.common.html.types.SafeHtmlProto parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessageV3
+ .parseWithIOException(PARSER, input, extensionRegistry);
+ }
+ public static com.google.common.html.types.SafeHtmlProto parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessageV3
+ .parseDelimitedWithIOException(PARSER, input);
+ }
+ public static com.google.common.html.types.SafeHtmlProto parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessageV3
+ .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+ }
+ public static com.google.common.html.types.SafeHtmlProto parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessageV3
+ .parseWithIOException(PARSER, input);
+ }
+ public static com.google.common.html.types.SafeHtmlProto parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessageV3
+ .parseWithIOException(PARSER, input, extensionRegistry);
+ }
+
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder() {
+ return DEFAULT_INSTANCE.toBuilder();
+ }
+ public static Builder newBuilder(com.google.common.html.types.SafeHtmlProto prototype) {
+ return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() {
+ return this == DEFAULT_INSTANCE
+ ? new Builder() : new Builder().mergeFrom(this);
+ }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ /**
+ *
+ * IMPORTANT: It is unsafe to accept this message from an untrusted source,
+ * since it's trivial for an attacker to forge serialized messages that
+ * don't fulfill the type's safety contract -- for example, it could contain
+ * attacker controlled script. A system which receives a SafeHtmlProto
+ * implicitly trusts the producer of the SafeHtmlProto. So, it's generally safe
+ * to return this message in RPC responses, but generally unsafe to accept it
+ * in RPC requests.
+ *
+ *
+ * Protobuf type {@code webutil.html.types.SafeHtmlProto}
+ */
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessageV3.Builder
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD];
+ */
+ public boolean hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD];
+ */
+ public java.lang.String getPrivateDoNotAccessOrElseSafeHtmlWrappedValue() {
+ java.lang.Object ref = privateDoNotAccessOrElseSafeHtmlWrappedValue_;
+ if (!(ref instanceof java.lang.String)) {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ if (bs.isValidUtf8()) {
+ privateDoNotAccessOrElseSafeHtmlWrappedValue_ = s;
+ }
+ return s;
+ } else {
+ return (java.lang.String) ref;
+ }
+ }
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD];
+ */
+ public com.google.protobuf.ByteString
+ getPrivateDoNotAccessOrElseSafeHtmlWrappedValueBytes() {
+ java.lang.Object ref = privateDoNotAccessOrElseSafeHtmlWrappedValue_;
+ if (ref instanceof String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ privateDoNotAccessOrElseSafeHtmlWrappedValue_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD];
+ */
+ public Builder setPrivateDoNotAccessOrElseSafeHtmlWrappedValue(
+ java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000001;
+ privateDoNotAccessOrElseSafeHtmlWrappedValue_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD];
+ */
+ public Builder clearPrivateDoNotAccessOrElseSafeHtmlWrappedValue() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ privateDoNotAccessOrElseSafeHtmlWrappedValue_ = getDefaultInstance().getPrivateDoNotAccessOrElseSafeHtmlWrappedValue();
+ onChanged();
+ return this;
+ }
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD];
+ */
+ public Builder setPrivateDoNotAccessOrElseSafeHtmlWrappedValueBytes(
+ com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000001;
+ privateDoNotAccessOrElseSafeHtmlWrappedValue_ = value;
+ onChanged();
+ return this;
+ }
+ public final Builder setUnknownFields(
+ final com.google.protobuf.UnknownFieldSet unknownFields) {
+ return super.setUnknownFields(unknownFields);
+ }
+
+ public final Builder mergeUnknownFields(
+ final com.google.protobuf.UnknownFieldSet unknownFields) {
+ return super.mergeUnknownFields(unknownFields);
+ }
+
+
+ // @@protoc_insertion_point(builder_scope:webutil.html.types.SafeHtmlProto)
+ }
+
+ // @@protoc_insertion_point(class_scope:webutil.html.types.SafeHtmlProto)
+ private static final com.google.common.html.types.SafeHtmlProto DEFAULT_INSTANCE;
+ static {
+ DEFAULT_INSTANCE = new com.google.common.html.types.SafeHtmlProto();
+ }
+
+ public static com.google.common.html.types.SafeHtmlProto getDefaultInstance() {
+ return DEFAULT_INSTANCE;
+ }
+
+ @java.lang.Deprecated public static final com.google.protobuf.Parser
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD];
+ */
+ boolean hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue();
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD];
+ */
+ java.lang.String getPrivateDoNotAccessOrElseSafeHtmlWrappedValue();
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD];
+ */
+ com.google.protobuf.ByteString
+ getPrivateDoNotAccessOrElseSafeHtmlWrappedValueBytes();
+}
diff --git a/third_party/safe_html_types/com/google/common/html/types/SafeHtmls.java b/third_party/safe_html_types/com/google/common/html/types/SafeHtmls.java
new file mode 100644
index 00000000000..a746a4e72f4
--- /dev/null
+++ b/third_party/safe_html_types/com/google/common/html/types/SafeHtmls.java
@@ -0,0 +1,198 @@
+// **** GENERATED CODE, DO NOT MODIFY ****
+// This file was generated via preprocessing from input:
+// java/com/google/common/html/types/SafeHtmls.java.tpl
+// ***************************************
+/*
+ * Copyright 2016 Google Inc. 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.
+ */
+
+package com.google.common.html.types;
+
+import static com.google.common.html.types.BuilderUtils.coerceToInterchangeValid;
+import static com.google.common.html.types.BuilderUtils.escapeHtmlInternal;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Preconditions;
+import java.util.Arrays;
+import javax.annotation.CheckReturnValue;
+
+/**
+ * Protocol conversions, builders and factory methods for {@link SafeHtml}.
+ */
+@CheckReturnValue
+@GwtCompatible
+public final class SafeHtmls {
+
+ /**
+ * Deserializes a SafeHtmlProto into a SafeHtml instance.
+ *
+ *
+ * Message containing JavaScript code that is safe to use as the content of an
+ * HTML script element.
+ *
+ *
+ * Protobuf type {@code webutil.html.types.SafeScriptProto}
+ */
+public final class SafeScriptProto extends
+ com.google.protobuf.GeneratedMessageV3 implements
+ // @@protoc_insertion_point(message_implements:webutil.html.types.SafeScriptProto)
+ SafeScriptProtoOrBuilder {
+ // Use SafeScriptProto.newBuilder() to construct.
+ private SafeScriptProto(com.google.protobuf.GeneratedMessageV3.Builder> builder) {
+ super(builder);
+ }
+ private SafeScriptProto() {
+ privateDoNotAccessOrElseSafeScriptWrappedValue_ = "";
+ }
+
+ @java.lang.Override
+ public final com.google.protobuf.UnknownFieldSet
+ getUnknownFields() {
+ return this.unknownFields;
+ }
+ private SafeScriptProto(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ this();
+ int mutable_bitField0_ = 0;
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder();
+ try {
+ boolean done = false;
+ while (!done) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ done = true;
+ break;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ done = true;
+ }
+ break;
+ }
+ case 50: {
+ com.google.protobuf.ByteString bs = input.readBytes();
+ bitField0_ |= 0x00000001;
+ privateDoNotAccessOrElseSafeScriptWrappedValue_ = bs;
+ break;
+ }
+ }
+ }
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(this);
+ } catch (java.io.IOException e) {
+ throw new com.google.protobuf.InvalidProtocolBufferException(
+ e).setUnfinishedMessage(this);
+ } finally {
+ this.unknownFields = unknownFields.build();
+ }
+ }
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return com.google.common.html.types.Html.internal_static_webutil_html_types_SafeScriptProto_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return com.google.common.html.types.Html.internal_static_webutil_html_types_SafeScriptProto_fieldAccessorTable
+ .ensureFieldAccessorsInitialized(
+ com.google.common.html.types.SafeScriptProto.class, com.google.common.html.types.SafeScriptProto.Builder.class);
+ }
+
+ private int bitField0_;
+ public static final int PRIVATE_DO_NOT_ACCESS_OR_ELSE_SAFE_SCRIPT_WRAPPED_VALUE_FIELD_NUMBER = 6;
+ private volatile java.lang.Object privateDoNotAccessOrElseSafeScriptWrappedValue_;
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD];
+ */
+ public boolean hasPrivateDoNotAccessOrElseSafeScriptWrappedValue() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD];
+ */
+ public java.lang.String getPrivateDoNotAccessOrElseSafeScriptWrappedValue() {
+ java.lang.Object ref = privateDoNotAccessOrElseSafeScriptWrappedValue_;
+ if (ref instanceof java.lang.String) {
+ return (java.lang.String) ref;
+ } else {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ if (bs.isValidUtf8()) {
+ privateDoNotAccessOrElseSafeScriptWrappedValue_ = s;
+ }
+ return s;
+ }
+ }
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD];
+ */
+ public com.google.protobuf.ByteString
+ getPrivateDoNotAccessOrElseSafeScriptWrappedValueBytes() {
+ java.lang.Object ref = privateDoNotAccessOrElseSafeScriptWrappedValue_;
+ if (ref instanceof java.lang.String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ privateDoNotAccessOrElseSafeScriptWrappedValue_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized == 1) return true;
+ if (isInitialized == 0) return false;
+
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ com.google.protobuf.GeneratedMessageV3.writeString(output, 6, privateDoNotAccessOrElseSafeScriptWrappedValue_);
+ }
+ unknownFields.writeTo(output);
+ }
+
+ public int getSerializedSize() {
+ int size = memoizedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.GeneratedMessageV3.computeStringSize(6, privateDoNotAccessOrElseSafeScriptWrappedValue_);
+ }
+ size += unknownFields.getSerializedSize();
+ memoizedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ public boolean equals(final java.lang.Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof com.google.common.html.types.SafeScriptProto)) {
+ return super.equals(obj);
+ }
+ com.google.common.html.types.SafeScriptProto other = (com.google.common.html.types.SafeScriptProto) obj;
+
+ boolean result = true;
+ result = result && (hasPrivateDoNotAccessOrElseSafeScriptWrappedValue() == other.hasPrivateDoNotAccessOrElseSafeScriptWrappedValue());
+ if (hasPrivateDoNotAccessOrElseSafeScriptWrappedValue()) {
+ result = result && getPrivateDoNotAccessOrElseSafeScriptWrappedValue()
+ .equals(other.getPrivateDoNotAccessOrElseSafeScriptWrappedValue());
+ }
+ result = result && unknownFields.equals(other.unknownFields);
+ return result;
+ }
+
+ @java.lang.Override
+ public int hashCode() {
+ if (memoizedHashCode != 0) {
+ return memoizedHashCode;
+ }
+ int hash = 41;
+ hash = (19 * hash) + getDescriptor().hashCode();
+ if (hasPrivateDoNotAccessOrElseSafeScriptWrappedValue()) {
+ hash = (37 * hash) + PRIVATE_DO_NOT_ACCESS_OR_ELSE_SAFE_SCRIPT_WRAPPED_VALUE_FIELD_NUMBER;
+ hash = (53 * hash) + getPrivateDoNotAccessOrElseSafeScriptWrappedValue().hashCode();
+ }
+ hash = (29 * hash) + unknownFields.hashCode();
+ memoizedHashCode = hash;
+ return hash;
+ }
+
+ public static com.google.common.html.types.SafeScriptProto parseFrom(
+ java.nio.ByteBuffer data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static com.google.common.html.types.SafeScriptProto parseFrom(
+ java.nio.ByteBuffer data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static com.google.common.html.types.SafeScriptProto parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static com.google.common.html.types.SafeScriptProto parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static com.google.common.html.types.SafeScriptProto parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static com.google.common.html.types.SafeScriptProto parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static com.google.common.html.types.SafeScriptProto parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessageV3
+ .parseWithIOException(PARSER, input);
+ }
+ public static com.google.common.html.types.SafeScriptProto parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessageV3
+ .parseWithIOException(PARSER, input, extensionRegistry);
+ }
+ public static com.google.common.html.types.SafeScriptProto parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessageV3
+ .parseDelimitedWithIOException(PARSER, input);
+ }
+ public static com.google.common.html.types.SafeScriptProto parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessageV3
+ .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+ }
+ public static com.google.common.html.types.SafeScriptProto parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessageV3
+ .parseWithIOException(PARSER, input);
+ }
+ public static com.google.common.html.types.SafeScriptProto parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessageV3
+ .parseWithIOException(PARSER, input, extensionRegistry);
+ }
+
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder() {
+ return DEFAULT_INSTANCE.toBuilder();
+ }
+ public static Builder newBuilder(com.google.common.html.types.SafeScriptProto prototype) {
+ return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() {
+ return this == DEFAULT_INSTANCE
+ ? new Builder() : new Builder().mergeFrom(this);
+ }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ /**
+ *
+ * Message containing JavaScript code that is safe to use as the content of an
+ * HTML script element.
+ *
+ *
+ * Protobuf type {@code webutil.html.types.SafeScriptProto}
+ */
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessageV3.Builder
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD];
+ */
+ public boolean hasPrivateDoNotAccessOrElseSafeScriptWrappedValue() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD];
+ */
+ public java.lang.String getPrivateDoNotAccessOrElseSafeScriptWrappedValue() {
+ java.lang.Object ref = privateDoNotAccessOrElseSafeScriptWrappedValue_;
+ if (!(ref instanceof java.lang.String)) {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ if (bs.isValidUtf8()) {
+ privateDoNotAccessOrElseSafeScriptWrappedValue_ = s;
+ }
+ return s;
+ } else {
+ return (java.lang.String) ref;
+ }
+ }
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD];
+ */
+ public com.google.protobuf.ByteString
+ getPrivateDoNotAccessOrElseSafeScriptWrappedValueBytes() {
+ java.lang.Object ref = privateDoNotAccessOrElseSafeScriptWrappedValue_;
+ if (ref instanceof String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ privateDoNotAccessOrElseSafeScriptWrappedValue_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD];
+ */
+ public Builder setPrivateDoNotAccessOrElseSafeScriptWrappedValue(
+ java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000001;
+ privateDoNotAccessOrElseSafeScriptWrappedValue_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD];
+ */
+ public Builder clearPrivateDoNotAccessOrElseSafeScriptWrappedValue() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ privateDoNotAccessOrElseSafeScriptWrappedValue_ = getDefaultInstance().getPrivateDoNotAccessOrElseSafeScriptWrappedValue();
+ onChanged();
+ return this;
+ }
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD];
+ */
+ public Builder setPrivateDoNotAccessOrElseSafeScriptWrappedValueBytes(
+ com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000001;
+ privateDoNotAccessOrElseSafeScriptWrappedValue_ = value;
+ onChanged();
+ return this;
+ }
+ public final Builder setUnknownFields(
+ final com.google.protobuf.UnknownFieldSet unknownFields) {
+ return super.setUnknownFields(unknownFields);
+ }
+
+ public final Builder mergeUnknownFields(
+ final com.google.protobuf.UnknownFieldSet unknownFields) {
+ return super.mergeUnknownFields(unknownFields);
+ }
+
+
+ // @@protoc_insertion_point(builder_scope:webutil.html.types.SafeScriptProto)
+ }
+
+ // @@protoc_insertion_point(class_scope:webutil.html.types.SafeScriptProto)
+ private static final com.google.common.html.types.SafeScriptProto DEFAULT_INSTANCE;
+ static {
+ DEFAULT_INSTANCE = new com.google.common.html.types.SafeScriptProto();
+ }
+
+ public static com.google.common.html.types.SafeScriptProto getDefaultInstance() {
+ return DEFAULT_INSTANCE;
+ }
+
+ @java.lang.Deprecated public static final com.google.protobuf.Parser
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD];
+ */
+ boolean hasPrivateDoNotAccessOrElseSafeScriptWrappedValue();
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD];
+ */
+ java.lang.String getPrivateDoNotAccessOrElseSafeScriptWrappedValue();
+ /**
+ *
+ * IMPORTANT: Never set or read this field, even from tests, it is private.
+ * See documentation at the top of .proto file for programming language
+ * packages with which to create or read this message.
+ *
+ *
+ * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD];
+ */
+ com.google.protobuf.ByteString
+ getPrivateDoNotAccessOrElseSafeScriptWrappedValueBytes();
+}
diff --git a/third_party/safe_html_types/com/google/common/html/types/SafeScripts.java b/third_party/safe_html_types/com/google/common/html/types/SafeScripts.java
new file mode 100644
index 00000000000..a1a22d6dac2
--- /dev/null
+++ b/third_party/safe_html_types/com/google/common/html/types/SafeScripts.java
@@ -0,0 +1,99 @@
+// **** GENERATED CODE, DO NOT MODIFY ****
+// This file was generated via preprocessing from input:
+// java/com/google/common/html/types/SafeScripts.java.tpl
+// ***************************************
+/*
+ * Copyright 2016 Google Inc. 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.
+ */
+
+package com.google.common.html.types;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.io.Resources;
+import com.google.errorprone.annotations.CompileTimeConstant;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import javax.annotation.CheckReturnValue;
+
+
+/**
+ * Protocol conversions and factory methods for {@link SafeScript}.
+ */
+@CheckReturnValue
+@GwtCompatible(emulated = true)
+public final class SafeScripts {
+
+ private SafeScripts() {}
+
+ /**
+ * Creates a SafeScript from the given compile-time constant string {@code script}.
+ */
+ public static SafeScript fromConstant(@CompileTimeConstant final String script) {
+ if (script.length() == 0) {
+ return SafeScript.EMPTY;
+ }
+ return create(script);
+ }
+
+ /**
+ * Creates a SafeScript from the given compile-time constant {@code resourceName} using the given
+ * {@code charset}.
+ *
+ *
+ *