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

Please add a Skylark builtin for parsing JSON to a dict (useful for repo rules) #3732

Closed
jmillikin opened this issue Sep 14, 2017 · 13 comments
Closed
Assignees
Labels
P2 We'll consider working on this in future. (Assignee optional) team-ExternalDeps External dependency handling, remote repositiories, WORKSPACE file. type: feature request

Comments

@jmillikin
Copy link
Contributor

When writing repository rules that inspect the state of the local system, I commonly want to run some local command and inspect its machine-readable output. The rule would then make configuration decisions based on available features, versions, installed plugins, and so on.

Nearly all tools that offer machine-readable version data use JSON, or at least offer it as an option. Rather than try to hack my way through with .split and .index, it would be much nicer if I could take a JSON string and have Bazel parse it directly into a dict within Skylark. A builtin json_to_dict(str) -> dict function would do nicely.

Using cmake as an example, I want to get its version using repository_ctx.execute():

$ cmake -E capabilities
{"version":{"isDirty":false,"major":3,"minor":9,"patch":1,"string":"3.9.1","suffix":""}}

... and then use that (3,9,1) tuple to decide whether it's recent enough, or should be ignored in favor of an external repository.

There was a previous issue open about this (#1813), but it had unclear motivations and was closed without action taken.

@laszlocsomor
Copy link
Contributor

@laurentlb , @vladmos : WDYT?

@erickj
Copy link

erickj commented Mar 18, 2018

FTR - simply for kicks and because I was curious about using JSON content as filters in an aspect rule... I've written this toy program to parse JSON using a push down automaton:

https://github.com/erickj/bazel_json/blob/master/lib/json_parser.bzl

some examples of how to use it here:
https://github.com/erickj/bazel_json/blob/master/test/json_parse_tests.bzl

It needs quite a bit more work, but it should be a good start for anyone looking for basic JSON parsing

@laurentlb
Copy link
Contributor

Where does the input come from? Are you inserting the string inside a .bzl file and you want to parse it? In that case, why do you use json?

In general, parsing/transforming json should be done during execution (outside Skylark).

@jmillikin
Copy link
Contributor Author

Where does the input come from? Are you inserting the string inside a .bzl file and you want to parse it? In that case, why do you use json?

See the original post -- the JSON is coming from an external binary, which uses it as a machine-readable output format. Even if cmake wrote out Skylark-compatible Python expressions, it'd be hard to parse them from Skylark.

In general, parsing/transforming json should be done during execution (outside Skylark).

That's fine for normal builds, but for repository_rule implementations it would be nice if we could do at least basic parsing without having to shell out to some very large dependency like Python.

@erickj
Copy link

erickj commented Mar 23, 2018

+1 for use during repository rule execution. Using the parser I linked above above I've found it useful to read and write intermediate build info in JSON, then just execute cat -> json_parse to get a structured object.

Also I've recently found a convenient pattern in using JSON to serialiaze highly structured data to enable using providers as a pseudo interface between macros and repository rule impls. e.g. I recently wrote a macro that creates a list of structs, in which each struct (defined as a provider) is composed of several mixed scalar types, a list of strings, and a dict. This list of structs acts as a declarative dsl for downloading, "installing", and aliasing some bootstrap dependencies into a repostiroy rule.

AFAIU, using attrs to pass this structure into a repository rule would need to deconstruct and then reconstruct the data into flattened string lists, string dicts, etc... OR construct some weird intermediate rule based representation so that I could use labels to point to my structures. (Please let me know if I'm wrong here, you'd literally make my week)

In any case, JSON makes it super easy. struct.toJson -> attr.string_list -> MyProvider(**parse_json) and viola I have my data on both sides of the repo rule.

@ttsugriy
Copy link
Contributor

ttsugriy commented Dec 14, 2018

Even if cmake wrote out Skylark-compatible Python expressions, it'd be hard to parse them from Skylark.

But it's possible to generate an object like

config = {
  "foo": {
    ...
  },
  ...
}

and just load this instance. An even cleaner version would be to generate and use struct.

@jin
Copy link
Member

jin commented Dec 28, 2018

Running into this: coursier spits out a JSON map of Maven artifact dependencies. Having a built-in Starlark construct (even if only in repository rules) can reduce a lot of the work to write special tools, or use jq, to parse such data.

cc @andyscott

@laurentlb
Copy link
Contributor

Moving to the ExternalDeps team, because this feature would be useful in the context of workspaces (e.g. with repository_ctx.execute()).

@dslomov dslomov added P2 We'll consider working on this in future. (Assignee optional) and removed untriaged labels Apr 9, 2019
@dslomov
Copy link
Contributor

dslomov commented Apr 9, 2019

@dkelmer wdyt?

@jin
Copy link
Member

jin commented Jun 17, 2019

FWIW, rules_jvm_external has been using @erickj's bazel-json parser in Starlark and we haven't ran into any issues with it since the beginning of the project.

@cgruber
Copy link
Contributor

cgruber commented Jun 18, 2019

That's good to hear, @jin - I was looking at it as well. Glad to hear you're having good success with it.

@jmillikin-stripe
Copy link
Contributor

There's now a couple implementations of a JSON API in non-Bazel tools built on Starlark. To see if we can settle on a reasonable shared JSON API, I sent bazelbuild/starlark#83 as a proposed standard JSON module in the Starlark spec.

@irengrig irengrig assigned laurentlb and unassigned dkelmer Nov 28, 2019
alandonovan pushed a commit to google/starlark-go that referenced this issue Jun 11, 2020
This change defines a standard Starlark module for JSON encoding and decoding.
See json.go for documentation.

It is intended to subsume, generalize, and eventually
replace Bazel's ill-conceived struct.to_json method.

The json module is predeclared in the Starlark REPL environment.

See related issues:
bazelbuild/bazel#7896
https://buganizer.corp.google.com/issues/23962735
https://buganizer.corp.google.com/issues/70210417
bazelbuild/bazel#7879 (comment)
bazelbuild/bazel#5542
bazelbuild/bazel#10176
bazelbuild/starlark#83
bazelbuild/bazel#3732

Change-Id: I297ffaee9349eedeeb52f5a88f40636a4095f997
alandonovan pushed a commit to google/starlark-go that referenced this issue Jun 11, 2020
This change defines a standard Starlark module for JSON encoding and decoding.
See json.go for documentation.

It is intended to subsume, generalize, and eventually
replace Bazel's ill-conceived struct.to_json method.

The json module is predeclared in the Starlark REPL environment.

See related issues:
bazelbuild/bazel#7896
https://buganizer.corp.google.com/issues/23962735
https://buganizer.corp.google.com/issues/70210417
bazelbuild/bazel#7879 (comment)
bazelbuild/bazel#5542
bazelbuild/bazel#10176
bazelbuild/starlark#83
bazelbuild/bazel#3732
@philwo philwo added the team-OSS Issues for the Bazel OSS team: installation, release processBazel packaging, website label Jun 15, 2020
bazel-io pushed a commit that referenced this issue Oct 21, 2020
This change predeclares 'json', the new Starlark module
for JSON encoding/decoding/indenting, in all Bazel Starlark
environments (alongside depset, select, etc).

The new function works for any legal value, not just struct,
and avoids polluting the struct field namespace.

struct.to_json is deprecated, along with struct.to_proto,
and will be disabled by the new flag --incompatible_struct_has_no_methods.
(The replacement for to_proto will be added shortly.)

Updates bazelbuild/starlark#83
Updates #3732
Updates #1813

RELNOTES: The Starlark json module is now available.
Use json.encode(x) to encode a Starlark value as JSON.
struct.to_json(x) is deprecated and will be disabled by
the --incompatible_struct_has_no_methods flag.
PiperOrigin-RevId: 338259618
@refi64
Copy link

refi64 commented Jul 11, 2021

This has been implemented for a while now, can this be closed?

@philwo philwo removed the team-OSS Issues for the Bazel OSS team: installation, release processBazel packaging, website label Nov 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P2 We'll consider working on this in future. (Assignee optional) team-ExternalDeps External dependency handling, remote repositiories, WORKSPACE file. type: feature request
Projects
None yet
Development

No branches or pull requests