Skip to content

Commit

Permalink
docs/howto: place data using the Go API
Browse files Browse the repository at this point in the history
This adds a guide demonstrating how to replicate the effect of the cue
command's --path flag using the Go API.

Preview-Path: /docs/howto/place-data-go-api/
Signed-off-by: Paul Jolly <[email protected]>
Change-Id: I0e5618207da2bc78cff9df715b1a4827503142dd
Dispatch-Trailer: {"type":"trybot","CL":1199814,"patchset":3,"ref":"refs/changes/14/1199814/3","targetBranch":"master"}
  • Loading branch information
myitcv authored and cueckoo committed Aug 28, 2024
1 parent 6acf2a6 commit 6a274ce
Show file tree
Hide file tree
Showing 4 changed files with 365 additions and 0 deletions.
142 changes: 142 additions & 0 deletions content/docs/howto/place-data-go-api/en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
---
title: Placing data using the Go API
tags: [go api]
authors: [myitcv,jpluscplusm]
toc_hide: true
---

{{{with _script_ "en" "set caches to speed up re-running"}}}
export GOMODCACHE=/caches/gomodcache
export GOCACHE=/caches/gobuild
{{{end}}}

The `cue` command allows non-CUE data to be "placed" at a specific location in
its evaluation with the `--path`/`-l` flag.
This guide demonstrates how to achieve the same result using the Go API.

## Set up the environment

{{{with step}}}
If you don't already have CUE or Go modules, initialize them:

{{{with script "en" "start modules"}}}
cue mod init cue.example
#ellipsis 0
go mod init go.example
{{{end}}}
{{{end}}}

## Create some data files

{{{with step}}}
Write some CUE code and JSON data
(if you don't already have some code that you want to update and use):

{{{with upload "en" "initial cue code"}}}
#location left right
-- some.cue --
package example

// The data will be placed at this location.
input: {
name!: string
location: *"your part of the world" | string
}

output: """
Hello, \(input.name)!
How's the weather in \(input.location)?
"""
-- input.json --
{
"name": "Charlie"
}
{{{end}}}
{{{end}}}

{{{with step}}}
Check that the data file can be combined successfully with the CUE:

{{{with script "en" "test cue"}}}
cue export . input.json --path input: -e output --out text
{{{end}}}
{{{end}}}

## Write some Go

{{{with step}}}
Write a Go program that places the data in the `input.json` file at a specific
location within its CUE evaluation
(or adapt your existing code to do the same):

{{{with upload "en" "go program"}}}
#location top-left
-- main.go --
package main

import (
"fmt"
"log"
"os"

"cuelang.org/go/cue"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/load"
"cuelang.org/go/encoding/json"
)

func main() {
ctx := cuecontext.New()
// Load the package in the current directory.
bis := load.Instances([]string{"."}, nil)
v := ctx.BuildInstance(bis[0])

// Load the input data.
jsonBytes, err := os.ReadFile("input.json")
if err != nil {
log.Fatal(err)
}

// Parse the input data to a CUE expression.
jsonData, err := json.Extract("input.json", jsonBytes)
if err != nil {
log.Fatal(err)
}

// Place the parsed data as the value of the "input" field.
complete := v.FillPath(cue.ParsePath("input"), jsonData)

// Extract the string value of the "output" field and print it.
output := complete.LookupPath(cue.ParsePath("output"))
msg, _ := output.String() // We know that "output" is a string type.
fmt.Printf("%v\n", msg)
}
{{{end}}}
{{{end}}}

## Run the program

{{{with step}}}
Add a dependency on `cuelang.org/go` and ensure the Go module is tidy:

{{{with script "en" "go test"}}}
#ellipsis 0
go get cuelang.org/go@$CUELANG_CUE_LATEST
#ellipsis 0
go mod tidy
{{{end}}}
{{{end}}}

{{{with step}}}
Run the program,
printing the same multi-line string value that `cue` produced earlier:

{{{with script "en" "go run"}}}
go run .
{{{end}}}
{{{end}}}

## Related content

- {{< linkto/related/concept "how-cue-works-with-go" >}}
- All pages tagged with {{< tag "go api" >}}
81 changes: 81 additions & 0 deletions content/docs/howto/place-data-go-api/gen_cache.cue
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package site
{
content: {
docs: {
howto: {
"place-data-go-api": {
page: {
cache: {
upload: {
"initial cue code": "cCDR5sNYSrEu2VXlWD62h3u6GdC/q2rCqvM8RQbYLl8="
"go program": "Gzyh+JVAzI2GEWyf7DIg6z9AwsBNbpQwZIkHwJ3lyMM="
}
multi_step: {
hash: "EU18HI7QMRIP19IS6GQ5IVJ8OIHKKKHASQ9BAP8DIUJCAE6864L0===="
scriptHash: "B2ACPKB2I7S9HP09ENHJFI1UHG1SO348DOOJ6DIDMB2U9GAQLNBG===="
steps: [{
doc: ""
cmd: "export GOMODCACHE=/caches/gomodcache"
exitCode: 0
output: ""
}, {
doc: ""
cmd: "export GOCACHE=/caches/gobuild"
exitCode: 0
output: ""
}, {
doc: ""
cmd: "cue mod init cue.example"
exitCode: 0
output: ""
}, {
doc: "#ellipsis 0"
cmd: "go mod init go.example"
exitCode: 0
output: """
...
"""
}, {
doc: ""
cmd: "cue export . input.json --path input: -e output --out text"
exitCode: 0
output: """
Hello, Charlie!
How's the weather in your part of the world?
"""
}, {
doc: "#ellipsis 0"
cmd: "go get cuelang.org/[email protected]"
exitCode: 0
output: """
...
"""
}, {
doc: "#ellipsis 0"
cmd: "go mod tidy"
exitCode: 0
output: """
...
"""
}, {
doc: ""
cmd: "go run ."
exitCode: 0
output: """
Hello, Charlie!
How's the weather in your part of the world?
"""
}]
}
}
}
}
}
}
}
}
3 changes: 3 additions & 0 deletions content/docs/howto/place-data-go-api/page.cue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package site

content: docs: howto: "place-data-go-api": page: _
139 changes: 139 additions & 0 deletions hugo/content/en/docs/howto/place-data-go-api/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
title: Placing data using the Go API
tags: [go api]
authors: [myitcv,jpluscplusm]
toc_hide: true
---

The `cue` command allows non-CUE data to be "placed" at a specific location in
its evaluation with the `--path`/`-l` flag.
This guide demonstrates how to achieve the same result using the Go API.

## Set up the environment

{{< step stepNumber="1" >}}
If you don't already have CUE or Go modules, initialize them:

```text { title="TERMINAL" type="terminal" codeToCopy="Y3VlIG1vZCBpbml0IGN1ZS5leGFtcGxlCmdvIG1vZCBpbml0IGdvLmV4YW1wbGU=" }
$ cue mod init cue.example
$ go mod init go.example
...
```
{{< /step >}}

## Create some data files

{{< step stepNumber="2" >}}
Write some CUE code and JSON data
(if you don't already have some code that you want to update and use):

{{< code-tabs >}}
{{< code-tab name="some.cue" language="cue" area="left" >}}
package example

// The data will be placed at this location.
input: {
name!: string
location: *"your part of the world" | string
}

output: """
Hello, \(input.name)!
How's the weather in \(input.location)?
"""
{{< /code-tab >}}{{< code-tab name="input.json" language="json" area="right" >}}
{
"name": "Charlie"
}
{{< /code-tab >}}{{< /code-tabs >}}
{{< /step >}}

{{< step stepNumber="3" >}}
Check that the data file can be combined successfully with the CUE:

```text { title="TERMINAL" type="terminal" codeToCopy="Y3VlIGV4cG9ydCAuIGlucHV0Lmpzb24gLS1wYXRoIGlucHV0OiAtZSBvdXRwdXQgLS1vdXQgdGV4dA==" }
$ cue export . input.json --path input: -e output --out text
Hello, Charlie!
How's the weather in your part of the world?
```
{{< /step >}}

## Write some Go

{{< step stepNumber="4" >}}
Write a Go program that places the data in the `input.json` file at a specific
location within its CUE evaluation
(or adapt your existing code to do the same):

{{< code-tabs >}}
{{< code-tab name="main.go" language="go" area="top-left" >}}
package main

import (
"fmt"
"log"
"os"

"cuelang.org/go/cue"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/load"
"cuelang.org/go/encoding/json"
)

func main() {
ctx := cuecontext.New()
// Load the package in the current directory.
bis := load.Instances([]string{"."}, nil)
v := ctx.BuildInstance(bis[0])

// Load the input data.
jsonBytes, err := os.ReadFile("input.json")
if err != nil {
log.Fatal(err)
}

// Parse the input data to a CUE expression.
jsonData, err := json.Extract("input.json", jsonBytes)
if err != nil {
log.Fatal(err)
}

// Place the parsed data as the value of the "input" field.
complete := v.FillPath(cue.ParsePath("input"), jsonData)

// Extract the string value of the "output" field and print it.
output := complete.LookupPath(cue.ParsePath("output"))
msg, _ := output.String() // We know that "output" is a string type.
fmt.Printf("%v\n", msg)
}
{{< /code-tab >}}{{< /code-tabs >}}
{{< /step >}}

## Run the program

{{< step stepNumber="5" >}}
Add a dependency on `cuelang.org/go` and ensure the Go module is tidy:

```text { title="TERMINAL" type="terminal" codeToCopy="Z28gZ2V0IGN1ZWxhbmcub3JnL2dvQHYwLjEwLjAKZ28gbW9kIHRpZHk=" }
$ go get cuelang.org/[email protected]
...
$ go mod tidy
...
```
{{< /step >}}

{{< step stepNumber="6" >}}
Run the program,
printing the same multi-line string value that `cue` produced earlier:

```text { title="TERMINAL" type="terminal" codeToCopy="Z28gcnVuIC4=" }
$ go run .
Hello, Charlie!
How's the weather in your part of the world?
```
{{< /step >}}

## Related content

- {{< linkto/related/concept "how-cue-works-with-go" >}}
- All pages tagged with {{< tag "go api" >}}

0 comments on commit 6a274ce

Please sign in to comment.