Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow targets to specify output of the rule #1

Merged
merged 8 commits into from
Dec 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion COPYING
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Copyright 2018 Prodrive Technologies B.V.
Copyright 2018 Google LLC
Copyright 2018-2019 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,18 @@ You can then add directives along these lines to your `BUILD.bazel` files:
load("@bazel_pandoc//:pandoc.bzl", "pandoc")

pandoc(
name = "foo",
src = "foo.md",
from_format = "markdown",
to_format = "latex",
name = "foo", # required
src = "foo.md", # required
from_format = "markdown", # optional, inferred from src extension by default
to_format = "latex", # optional, inferred from output extension by default
output = "awesome_doc.tex", # optional, derived from name and to_format by default
)
```

In the example above, an output file called `foo.tex` will be created in
the `bazel-bin` directory. The `to_format` field is used to
automatically derive a file extension of the output file.
In the example above, an output file called `awesome_doc.tex` will be created
in the `bazel-bin` directory.

At least one of the `to_format` or `output` attributes must be provided.

# Platform support

Expand Down
54 changes: 33 additions & 21 deletions pandoc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -51,44 +51,56 @@ PANDOC_EXTENSIONS = {

def _pandoc_impl(ctx):
toolchain = ctx.toolchains["@bazel_pandoc//:pandoc_toolchain_type"]
cli_args = []
cli_args.extend(ctx.attr.options)
if ctx.attr.from_format:
cli_args.extend(["--from", ctx.attr.from_format])
if ctx.attr.to_format:
cli_args.extend(["--to", ctx.attr.to_format])
cli_args.extend(["-o", ctx.outputs.output.path])
cli_args.extend([ctx.file.src.path])
ctx.actions.run(
mnemonic = "Pandoc",
executable = toolchain.pandoc.files.to_list()[0].path,
arguments = ctx.attr.options + [
"--from",
ctx.attr.from_format,
"--to",
ctx.attr.to_format,
"-o",
ctx.outputs.out.path,
ctx.files.src[0].path,
],
arguments = cli_args,
inputs = depset(
direct = ctx.files.src,
transitive = [toolchain.pandoc.files],
),
outputs = [ctx.outputs.out],
outputs = [ctx.outputs.output],
)

_pandoc = rule(
attrs = {
"extension": attr.string(),
"from_format": attr.string(),
"options": attr.string_list(),
"src": attr.label(allow_files = True),
"src": attr.label(allow_single_file = True, mandatory = True),
"to_format": attr.string(),
"output": attr.output(mandatory = True),
},
outputs = {"out": "%{name}.%{extension}"},
toolchains = ["@bazel_pandoc//:pandoc_toolchain_type"],
implementation = _pandoc_impl,
)

def pandoc(**kwargs):
# Derive extension of the output file based on the desired format.
# Use the generic .xml syntax for XML-based formats and .txt for
# ones with no commonly used extension.
to_format = kwargs["to_format"]
if to_format not in PANDOC_EXTENSIONS:
fail("Unknown output format: " + to_format)
def _check_format(format, attr_name):
if format not in PANDOC_EXTENSIONS:
fail("Unknown `%{attr}` format: %{format}".fmt(attr = attr_name, format = format))
return format

def _infer_output(name, to_format):
"""Derives output file based on the desired format.

_pandoc(extension = PANDOC_EXTENSIONS[to_format], **kwargs)
Use the generic .xml syntax for XML-based formats and .txt for
ones with no commonly used extension.
"""
to_format = _check_format(to_format, "to_format")
ext = PANDOC_EXTENSIONS[to_format]
return name + "." + ext

def pandoc(**kwargs):
if "output" not in kwargs:
if "to_format" not in kwargs:
fail("One of `output` or `to_format` attributes must be provided")
to_format = _check_format(kwargs["to_format"], "to_format")
kwargs["output"] = _infer_output(kwargs["name"], to_format)
_pandoc(**kwargs)
9 changes: 8 additions & 1 deletion sample/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
load("//:pandoc.bzl", "PANDOC_EXTENSIONS", "pandoc")

# Conversion of README to various formats for testing.

[pandoc(
name = "readme_" + fmt,
src = "//:README.md",
from_format = "markdown",
to_format = fmt,
) for fmt in PANDOC_EXTENSIONS.keys()]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please run buildifier on these files?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Out of curiosiity, do you have a git presubmit hook for that? It seems buildifier alreadys returns 0.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have that set up right now. I usually just do a %!buildifier in Vim after making some edits. For a presubmit, we could always invoke buildifier and use cmp to compare changes against the input if we wanted one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's also one way to do it. Whatever works best for you :)

# You can also specify the output, the format is then inferred from the extension,
# and the rule name is not used.
pandoc(
name = "gen_html_page",
src = "//:README.md",
output = "index.html",
)
55 changes: 54 additions & 1 deletion sample/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
Once you have set up your workspace,
you can generate the [README](../README.md) in a multitude of formats.


## Target defined with `to_format`

For instance:

```sh
Expand All @@ -11,7 +14,57 @@ bazel build @bazel_pandoc//sample:readme_html
bazel build @bazel_pandoc//sample:readme_epub
```

You can also produce the README in all formats know to the rule:
These targets are defined (actually with a _for loop_) with

```python
pandoc(
name = "readme_plain",
src = "//:README.md",
from_format = "markdown",
to_format = "plain",
)
pandoc(
name = "readme_html",
src = "//:README.md",
from_format = "markdown",
to_format = "html",
)
pandoc(
name = "readme_epub",
src = "//:README.md",
from_format = "markdown",
to_format = "epub",
)
```

You notice that the output file is derived from the rule name:
- bazel-bin/sample/readme_plain.txt
- bazel-bin/sample/readme_html.html
- bazel-bin/sample/readme_epub.epub

NB: `from_format` is optional and inferred from the file extension by default.


## Target defined with `output`

It's also possible to specify the output

```python
pandoc(
name = "gen_html_page",
src = "//:README.md",
output = "index.html",
)

```
As a result,
```sh
bazel build //sample:gen_html_page
```
produces an HTML document in:
- bazel-bin/sample/index.html

Finally can also produce the README in all formats know to the rule:

```sh
bazel build @bazel_pandoc//sample/...
Expand Down