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

cmd/go: get go list context function formatted as json #27915

Open
jimmyfrasche opened this issue Sep 28, 2018 · 10 comments
Open

cmd/go: get go list context function formatted as json #27915

jimmyfrasche opened this issue Sep 28, 2018 · 10 comments
Labels
FeatureRequest GoCommand cmd/go NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@jimmyfrasche
Copy link
Member

The context template function available to go list has some useful data, even after ignoring the overlap with go env -json. There's no way to output the context as json, making it hard to use the results programatically.

cc: @bcmills @rsc @ianlancetaylor @alandonovan

@jimmyfrasche jimmyfrasche added NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. FeatureRequest labels Sep 28, 2018
@xuruiray
Copy link

go list should output a json array, but it output each element of array , i need to add , before every element

@jimmyfrasche
Copy link
Member Author

@xuruiray that's unrelated to this issue. When go list -json returns a sequence of json documents. It's not returning an array in a single json document. This is extremely unlikely to change as much code relies on the current format.

@bcmills bcmills added the GoCommand cmd/go label Sep 28, 2018
@bcmills
Copy link
Contributor

bcmills commented Sep 28, 2018

@xuruiray See #27655 (comment).

@alandonovan
Copy link
Contributor

alandonovan commented Oct 1, 2018

We can't change the declaration of go/build.Context to have json: tags on its fields, as that is a backward incompatible change. I suppose it could have a MarshalJSON method.

As a workaround, can you extract the fields you need in a convenient format based on a command such as this one?

$ go list -f '{{printf "{GOROOT=%q, GOOS=%q, GOPATH=%q, CgoEnabled=%t, UseAllFiles=%t, Compiler=%q, BuildTags=%q, InstallSuffix=%q}" context.GOROOT context.GOOS context.GOPATH context.CgoEnabled context.UseAllFiles context.Compiler context.BuildTags context.InstallSuffix}}' errors

{GOROOT="/usr/local/google/home/adonovan/goroot", GOOS="linux", GOPATH="/usr/local/google/home/adonovan/go", CgoEnabled=true, UseAllFiles=false, Compiler="gc", BuildTags=[], InstallSuffix=""}

@bcmills
Copy link
Contributor

bcmills commented Oct 1, 2018

We can't change the declaration of go/build.Context to have json: tags on its fields, as that is a backward incompatible change.

Could you give some more detail on that? We're allowed to add fields, so nobody should be reyling on convertibility anyway (especially given #16085), and we're allowed to add methods, so nobody should be relying on the fact that go/build.Context currently cannot be marshalled.

@alandonovan
Copy link
Contributor

Oh, I forgot that we'd relax the convertibility rules. So then yes, we could add field tags to Context.

@jimmyfrasche
Copy link
Member Author

The go list command actually copies the build.Context's contents into a locally defined struct for printing. It's the same as build.Context but without all the function pointers. It already has json tags, even.

@alandonovan
Copy link
Contributor

So it does. One possible solution would be to add a "json" function to the set of functions available to the template, that would call json.Marshal on its operand. For example:

$ git diff
diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go
index f3cb4e47ec..31512763df 100644
--- a/src/cmd/go/internal/list/list.go
+++ b/src/cmd/go/internal/list/list.go
@@ -344,7 +344,14 @@ func runList(cmd *base.Command, args []string) {
                fm := template.FuncMap{
                        "join":    strings.Join,
                        "context": context,
-                       "module":  modload.ModuleInfo,
+                       "json": func(x interface{}) (string, error) {
+                               y, err := json.MarshalIndent(x, "\t", "")
+                               if err != nil {
+                                       return "", err
+                               }
+                               return string(y), nil
+                       },
+                       "module": modload.ModuleInfo,
                }
                tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
                if err != nil {
$ go list -f '{{context | json}}' errors
{
        "GOARCH": "amd64",
        "GOOS": "linux",
        "GOROOT": "/usr/local/google/home/adonovan/goroot",
        "GOPATH": "/usr/local/google/home/adonovan/go",
        "CgoEnabled": true,
        "Compiler": "gc",
        "ReleaseTags": [
        "go1.1",
        "go1.2",
        "go1.3",
        "go1.4",
        "go1.5",
        "go1.6",
        "go1.7",
        "go1.8",
        "go1.9",
        "go1.10",
        "go1.11"
        ]
        }

@jimmyfrasche
Copy link
Member Author

Since this is the only thing you can't already get as json, maybe it should be a method on that local context type? Like `go list -f '{{context.Json}}'

@jimmyfrasche
Copy link
Member Author

In the meantime, here's a workaround that formats BuildTags/ReleaseTags as json as well:

{{define "List"}}
	[
		{{range $i, $_ := .}}
			{{if $i}},{{end}}
			{{.|printf "%q"}}
		{{end}}
	]
{{end}}
{{with context}}
	{
		"GOARCH":        {{.GOARCH|printf "%q"}},
		"GOOS":          {{.GOOS|printf "%q"}},
		"GOROOT":        {{.GOROOT|printf "%q"}},
		"GOPATH":        {{.GOPATH|printf "%q"}},
		"CgoEnabled":    {{.CgoEnabled}},
		"UseAllFiles":   {{.UseAllFiles}},
		"Compiler":      {{.Compiler|printf "%q"}},
		"BuildTags":     {{template "List" .BuildTags}},
		"ReleaseTags":   {{template "List" .ReleaseTags}},
		"InstallSuffix": {{.InstallSuffix|printf "%q"}}
	}
{{end}}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
FeatureRequest GoCommand cmd/go NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

5 participants