Respect --stamp and --nostamp flags for stamping (#234)

Instead of a boolean stamp attribute, introduce a tristate which uses the value of the --[no]stamp flag by default.

Suggested by @alexeagle at https://github.com/bazelbuild/stardoc/commit/eea50daed4f8fed806f3f7596265884dc634f824#r141241326
diff --git a/docs/stardoc_rule.md b/docs/stardoc_rule.md
index 83569e4..8360501 100644
--- a/docs/stardoc_rule.md
+++ b/docs/stardoc_rule.md
@@ -39,7 +39,7 @@
 | <a id="stardoc-module_extension_template"></a>module_extension_template |  The input file template for generating documentation of module extensions.   |  `Label("@stardoc//stardoc:templates/markdown_tables/module_extension.vm")` |
 | <a id="stardoc-footer_template"></a>footer_template |  The input file template for generating the footer of the output documentation. Optional.   |  `None` |
 | <a id="stardoc-render_main_repo_name"></a>render_main_repo_name |  Render labels in the main repository with a repo component (either the module name or workspace name).   |  `True` |
-| <a id="stardoc-stamp"></a>stamp |  Whether to provide stamping information to templates.   |  `False` |
+| <a id="stardoc-stamp"></a>stamp |  Whether to provide stamping information to templates, where it can be accessed via `$util.formatBuildTimestamp()` and`$stamping`. Example: <pre><code class="language-vm">Built on `$util.formatBuildTimestamp($stamping.volatile.BUILD_TIMESTAMP, "UTC", "yyyy-MM-dd HH:mm")`</code></pre> Possible values: <ul> <li>`stamp = 1`: Always provide stamping information, even in     [--nostamp](https://bazel.build/docs/user-manual#flag--stamp) builds.     This setting should be avoided, since it potentially kills remote caching for the target     and any downstream actions that depend on it.</li> <li>`stamp = 0`: Do not provide stamping information.</li> <li>`stamp = -1`: Provide stamping information only if the      [--stamp](https://bazel.build/docs/user-manual#flag--stamp) flag is set.</li> </ul> Stamped targets are not rebuilt unless their dependencies change.   |  `-1` |
 | <a id="stardoc-kwargs"></a>kwargs |  Further arguments to pass to stardoc.   |  none |
 
 
diff --git a/stardoc/private/BUILD b/stardoc/private/BUILD
index e3561b1..5d08906 100644
--- a/stardoc/private/BUILD
+++ b/stardoc/private/BUILD
@@ -1,11 +1,30 @@
 load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+load("//stardoc/private:stamp_detector.bzl", "stamp_detector")
 
 bzl_library(
     name = "stardoc_lib",
-    srcs = ["stardoc.bzl"],
+    srcs = [
+        "stamp_detector.bzl",
+        "stardoc.bzl",
+    ],
     visibility = ["//stardoc:__pkg__"],
 )
 
+config_setting(
+    name = "stamp_enabled",
+    values = {"stamp": "1"},
+    visibility = ["//visibility:private"],
+)
+
+stamp_detector(
+    name = "stamp_detector",
+    enabled = select({
+        "stamp_enabled": True,
+        "//conditions:default": False,
+    }),
+    visibility = ["//visibility:private"],
+)
+
 # Sources needed for release tarball.
 filegroup(
     name = "distro_srcs",
diff --git a/stardoc/private/stamp_detector.bzl b/stardoc/private/stamp_detector.bzl
new file mode 100644
index 0000000..c016dce
--- /dev/null
+++ b/stardoc/private/stamp_detector.bzl
@@ -0,0 +1,33 @@
+# Copyright 2024 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Detector for the --stamp flag"""
+
+StampDetectorInfo = provider(
+    doc = "Result of detecting the --stamp flag",
+    fields = {
+        "enabled": "True if --stamp is enabled",
+    },
+)
+
+def _stamp_detector_impl(ctx):
+    return [StampDetectorInfo(enabled = ctx.attr.enabled)]
+
+stamp_detector = rule(
+    _stamp_detector_impl,
+    doc = """Detects if the --stamp flag is enabled""",
+    attrs = {
+        "enabled": attr.bool(mandatory = True, doc = "True if --stamp flag is enabled"),
+    },
+)
diff --git a/stardoc/private/stardoc.bzl b/stardoc/private/stardoc.bzl
index 0f614dd..dc227a2 100644
--- a/stardoc/private/stardoc.bzl
+++ b/stardoc/private/stardoc.bzl
@@ -14,8 +14,21 @@
 
 """Starlark rule for stardoc: a documentation generator tool written in Java."""
 
+load("//stardoc/private:stamp_detector.bzl", "StampDetectorInfo")
+
+def _is_stamp_enabled(ctx):
+    if ctx.attr.stamp == 1:
+        return True
+    elif ctx.attr.stamp == 0:
+        return False
+    elif ctx.attr.stamp == -1:
+        return ctx.attr._stamp_detector[StampDetectorInfo].enabled
+    else:
+        fail("`stamp` is expected to be one of [-1, 0, 1]")
+
 def _renderer_action_run(ctx, out_file, proto_file):
     """Helper for declaring the markdown renderer action"""
+    stamp_enabled = _is_stamp_enabled(ctx)
     renderer_args = ctx.actions.args()
     renderer_args.add("--input=" + str(proto_file.path))
     renderer_args.add("--output=" + str(ctx.outputs.out.path))
@@ -30,7 +43,7 @@
     renderer_args.add("--module_extension_template=" + str(ctx.file.module_extension_template.path))
     if ctx.file.footer_template:
         renderer_args.add("--footer_template=" + str(ctx.file.footer_template.path))
-    if ctx.attr.stamp:
+    if stamp_enabled:
         renderer_args.add("--stamping_stable_status_file=" + str(ctx.info_file.path))
         renderer_args.add("--stamping_volatile_status_file=" + str(ctx.version_file.path))
 
@@ -48,7 +61,7 @@
         inputs.append(ctx.file.table_of_contents_template)
     if ctx.file.footer_template:
         inputs.append(ctx.file.footer_template)
-    if ctx.attr.stamp:
+    if stamp_enabled:
         inputs.append(ctx.info_file)
         inputs.append(ctx.version_file)
 
@@ -122,9 +135,30 @@
         doc = "The input file template for generating the footer of the output documentation. Optional.",
         allow_single_file = [".vm"],
     ),
-    "stamp": attr.bool(
-        doc = "Whether to provide stamping information to templates",
-        default = False,
+    "stamp": attr.int(
+        doc = """
+        Whether to provide stamping information to templates, where it can be accessed via
+        `$util.formatBuildTimestamp()` and`$stamping`. Example:
+        ```vm
+        Built on `$util.formatBuildTimestamp($stamping.volatile.BUILD_TIMESTAMP, "UTC", "yyyy-MM-dd HH:mm")`
+        ```
+
+        Possible values:
+        * `stamp = 1`: Always provide stamping information, even in
+          [--nostamp](https://bazel.build/docs/user-manual#flag--stamp) builds.
+          This setting should be avoided, since it potentially kills remote caching for the target
+          and any downstream actions that depend on it.
+        * `stamp = 0`: Do not provide stamping information.
+        * `stamp = -1`: Provide stamping information only if the
+           [--stamp](https://bazel.build/docs/user-manual#flag--stamp) flag is set.
+
+        Stamped targets are not rebuilt unless their dependencies change.
+        """,
+        default = -1,
+    ),
+    "_stamp_detector": attr.label(
+        default = "//stardoc/private:stamp_detector",
+        providers = [StampDetectorInfo],
     ),
 }
 
@@ -138,16 +172,13 @@
     outputs = [out_file]
     return [DefaultInfo(files = depset(outputs), runfiles = ctx.runfiles(files = outputs))]
 
-# TODO(arostovtsev): replace with ... attrs = { ... } | _common_renderer_attrs
-# in rule definition below after we drop support for Bazel 5.
 _stardoc_markdown_renderer_attrs = {
     "src": attr.label(
         doc = "The .binaryproto file from which to generate documentation.",
         allow_single_file = [".binaryproto"],
         mandatory = True,
     ),
-}
-_stardoc_markdown_renderer_attrs.update(_common_renderer_attrs.items())
+} | _common_renderer_attrs
 
 stardoc_markdown_renderer = rule(
     _stardoc_markdown_renderer_impl,
diff --git a/stardoc/stardoc.bzl b/stardoc/stardoc.bzl
index d42a7a6..fc8825c 100644
--- a/stardoc/stardoc.bzl
+++ b/stardoc/stardoc.bzl
@@ -36,7 +36,7 @@
         module_extension_template = Label("//stardoc:templates/markdown_tables/module_extension.vm"),
         footer_template = None,
         render_main_repo_name = True,
-        stamp = False,
+        stamp = -1,
         **kwargs):
     """Generates documentation for exported starlark rule definitions in a target starlark file.
 
@@ -63,7 +63,22 @@
       footer_template: The input file template for generating the footer of the output documentation. Optional.
       render_main_repo_name: Render labels in the main repository with a repo component (either
         the module name or workspace name).
-      stamp: Whether to provide stamping information to templates.
+      stamp: Whether to provide stamping information to templates, where it can be accessed via
+        `$util.formatBuildTimestamp()` and`$stamping`. Example:
+        ```vm
+        Built on `$util.formatBuildTimestamp($stamping.volatile.BUILD_TIMESTAMP, "UTC", "yyyy-MM-dd HH:mm")`
+        ```
+        Possible values:
+        <ul>
+        <li>`stamp = 1`: Always provide stamping information, even in
+            [--nostamp](https://bazel.build/docs/user-manual#flag--stamp) builds.
+            This setting should be avoided, since it potentially kills remote caching for the target
+            and any downstream actions that depend on it.</li>
+        <li>`stamp = 0`: Do not provide stamping information.</li>
+        <li>`stamp = -1`: Provide stamping information only if the
+             [--stamp](https://bazel.build/docs/user-manual#flag--stamp) flag is set.</li>
+        </ul>
+        Stamped targets are not rebuilt unless their dependencies change.
       **kwargs: Further arguments to pass to stardoc.
     """
 
diff --git a/test/BUILD b/test/BUILD
index 89f8265..9f42d94 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -351,7 +351,7 @@
     golden_file = "testdata/stamping_test/golden.md",
     header_template = "testdata/stamping_test/stamping_header.vm",
     input_file = "testdata/stamping_test/input.bzl",
-    stamp = True,
+    stamp = 1,
 )
 
 stardoc_test(
@@ -359,7 +359,7 @@
     golden_file = "testdata/stamping_test/golden_stamping_off.md",
     header_template = "testdata/stamping_test/stamping_header_stamping_off.vm",
     input_file = "testdata/stamping_test/input.bzl",
-    stamp = False,
+    stamp = 0,
 )
 
 sh_test(
diff --git a/test/testdata/stamping_test/golden.md b/test/testdata/stamping_test/golden.md
index 681f575..6fdacc1 100644
--- a/test/testdata/stamping_test/golden.md
+++ b/test/testdata/stamping_test/golden.md
@@ -1,6 +1,6 @@
 This Stardoc was built in the `AD` era.
 
-Host empty: `false`.
+Host is a non-empty string.
 
 This key does not exist: ``.
 
diff --git a/test/testdata/stamping_test/stamping_header.vm b/test/testdata/stamping_test/stamping_header.vm
index e1d84b9..8eab852 100644
--- a/test/testdata/stamping_test/stamping_header.vm
+++ b/test/testdata/stamping_test/stamping_header.vm
@@ -3,7 +3,11 @@
 This Stardoc was built in the `$util.formatBuildTimestamp($stamping.volatile.BUILD_TIMESTAMP, "UTC", "G")` era.
 
 ## Should test a stable value, but stable contains quasi sensitive info, so don't print that in the test output
-Host empty: `$stamping.stable.BUILD_HOST.isEmpty()`.
+#if ($stamping.stable.BUILD_HOST)
+Host is a non-empty string.
+#else
+Host is empty or null.
+#end
 
 ## Sometimes Stardoc is built without --workspace_status_command (e.g. in build tests), luckily "$!foo" will tell
 ## Velocity to ignore null values: