Skip to content

Commit 2b9412f

Browse files
Introduce extra_opts to handle additional input
E.g. to specify location of breathe projects
1 parent 49e35a1 commit 2b9412f

3 files changed

Lines changed: 39 additions & 24 deletions

File tree

bazel/rules/rules_score/private/sphinx_module.bzl

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,18 @@ def _score_html_impl(ctx):
113113
Phase 2: Generate HTML with external needs and merge all dependency HTML
114114
"""
115115

116+
run_args = [] # Copy of the args to forward along to debug runner
117+
args = ctx.actions.args() # Args passed to the action
118+
119+
# Expand location references in extra_opts and collect as sphinx arguments.
120+
# targets must include all labels referenced via $(location ...) / $(execpaths ...).
121+
extra_opts_targets = ctx.attr.srcs + ctx.attr.docs_library_deps
122+
for opt in ctx.attr.extra_opts:
123+
expanded = ctx.expand_location(opt, targets = extra_opts_targets)
124+
print("???????? expanded opts location: ", expanded)
125+
args.add(expanded)
126+
run_args.append(expanded)
127+
116128
# Collect all transitive dependencies with deduplication
117129
modules = []
118130
sphinx_toolchain = ctx.toolchains["//bazel/rules/rules_score:toolchain_type"].sphinxinfo
@@ -138,18 +150,6 @@ def _score_html_impl(ctx):
138150
content = json.encode_indent(needs_external_needs, indent = " "),
139151
)
140152

141-
# Read template and substitute PROJECT_NAME
142-
config_file = ctx.actions.declare_file(ctx.label.name + "/conf.py")
143-
template = sphinx_toolchain.conf_template.files.to_list()[0]
144-
145-
ctx.actions.expand_template(
146-
template = template,
147-
output = config_file,
148-
substitutions = {
149-
"{PROJECT_NAME}": ctx.label.name.replace("_", " ").title(),
150-
},
151-
)
152-
153153
source_prefix = ctx.label.name
154154
sphinx_source_files = []
155155

@@ -182,13 +182,6 @@ def _score_html_impl(ctx):
182182
new_path = entry.prefix + original.short_path.removeprefix(entry.strip_prefix)
183183
_relocate(original, new_path)
184184

185-
needs_external_needs_json = ctx.actions.declare_file(ctx.label.name + "/needs_external_needs.json")
186-
187-
ctx.actions.write(
188-
output = needs_external_needs_json,
189-
content = json.encode_indent(needs_external_needs, indent = " "),
190-
)
191-
192185
config_file = _create_config_py(ctx)
193186

194187
# Sphinx only accepts a single directory to read its doc sources from.
@@ -219,7 +212,7 @@ def _score_html_impl(ctx):
219212
ctx.actions.run(
220213
inputs = html_inputs,
221214
outputs = [sphinx_html_output],
222-
arguments = html_args,
215+
arguments = html_args + [args],
223216
progress_message = "Building HTML: %s" % ctx.label.name,
224217
executable = sphinx_toolchain.sphinx.files_to_run.executable,
225218
tools = [
@@ -287,6 +280,10 @@ _score_html = rule(
287280
allow_files = True,
288281
doc = "Submodule symbols.needs targets for this module.",
289282
),
283+
extra_opts = attr.string_list(
284+
doc = "Additional options to pass onto Sphinx. These are added after " +
285+
"other options, but before the source/output args.",
286+
),
290287
),
291288
toolchains = ["//bazel/rules/rules_score:toolchain_type"],
292289
)
@@ -303,6 +300,7 @@ def sphinx_module(
303300
docs_library_deps = [],
304301
sphinx = Label("//bazel/rules/rules_score:score_build"),
305302
strip_prefix = "",
303+
extra_opts = [],
306304
testonly = False,
307305
visibility = ["//visibility:public"]):
308306
"""Build a Sphinx module with transitive HTML dependencies.
@@ -323,6 +321,9 @@ def sphinx_module(
323321
source files. e.g., given `//sphinxdocs/docs:foo.md`, stripping `docs/` makes
324322
Sphinx see `foo.md` in its generated source directory. If not
325323
specified, then {any}`native.package_name` is used.
324+
extra_opts: {type}`list[str]` Additional options to pass onto Sphinx building.
325+
On each provided option, a location expansion is performed.
326+
See {any}`ctx.expand_location`.
326327
visibility: Bazel visibility
327328
"""
328329
_score_needs(
@@ -341,6 +342,7 @@ def sphinx_module(
341342
deps = deps,
342343
docs_library_deps = docs_library_deps,
343344
needs = [d + "_needs" for d in deps],
345+
extra_opts = extra_opts,
344346
testonly = testonly,
345347
visibility = visibility,
346348
)

bazel/rules/rules_score/src/sphinx_html_merge.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,11 @@ def main():
178178
help="Dependency HTML directory in format NAME:PATH",
179179
)
180180

181+
parser.add_argument(
182+
"-Dbreathe_projects",
183+
help="Override Breathe projects mapping (e.g., -Dbreathe_projects='{\"com\": \"path/to/xml\"}')",
184+
)
185+
181186
args = parser.parse_args()
182187

183188
# Parse dependencies

bazel/rules/rules_score/src/sphinx_wrapper.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,13 @@ def validate_arguments(args: argparse.Namespace) -> None:
110110
raise ValueError(f"Index file does not exist: {args.index_file}")
111111

112112

113-
def build_sphinx_arguments(args: argparse.Namespace) -> List[str]:
113+
def build_sphinx_arguments(args: argparse.Namespace, extra_args: List[str] = None) -> List[str]:
114114
"""
115115
Build the argument list for Sphinx.
116116
117117
Args:
118118
args: Parsed command-line arguments
119+
extra_args: Additional arguments to forward to Sphinx (e.g., -D options from extra_opts)
119120
120121
Returns:
121122
List of arguments to pass to Sphinx
@@ -154,6 +155,10 @@ def build_sphinx_arguments(args: argparse.Namespace) -> List[str]:
154155

155156
base_arguments.extend(["-b", args.builder])
156157

158+
# Forward extra options (e.g., -D flags) to Sphinx
159+
if extra_args:
160+
base_arguments.extend(extra_args)
161+
157162
return base_arguments
158163

159164

@@ -240,7 +245,7 @@ def parse_arguments() -> argparse.Namespace:
240245
help=f"Port to use for live preview (default: {DEFAULT_PORT}). Use 0 for auto-detection.",
241246
)
242247

243-
return parser.parse_args()
248+
return parser.parse_known_args()
244249

245250

246251
def main() -> int:
@@ -251,14 +256,17 @@ def main() -> int:
251256
Exit code (0 for success, non-zero for failure)
252257
"""
253258
try:
254-
args = parse_arguments()
259+
args, extra_args = parse_arguments()
255260
validate_arguments(args)
261+
logger.info(f"[DEBUG] extra_args from parse_known_args: {extra_args}")
262+
logger.info(f"[DEBUG] sys.argv was: {sys.argv}")
256263
# Create processor instance
257264
stdout_processor = StdoutProcessor()
258265
stderr_processor = StderrProcessor()
259266
# Redirect stdout and stderr
260267
with redirect_stderr(stderr_processor), redirect_stdout(stdout_processor):
261-
sphinx_args = build_sphinx_arguments(args)
268+
sphinx_args = build_sphinx_arguments(args, extra_args)
269+
logger.info(f"[DEBUG] Final sphinx_args: {sphinx_args}")
262270
exit_code = run_sphinx_build(sphinx_args, args.builder)
263271
return exit_code
264272
except ValueError as e:

0 commit comments

Comments
 (0)