Skip to content

Commit

Permalink
docs/tutorial: using modules with the Go API
Browse files Browse the repository at this point in the history
This adds a tutorial on using the Go API in modules-aware mode.

Closes cue-lang/docs-and-content#94

Preview-Path: /docs/tutorial/using-modules-with-go-api/
Signed-off-by: Paul Jolly <paul@myitcv.io>
Change-Id: I17a67855b3c7487f2f67943aae2b6d4c497f6eed
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cuelang.org/+/1189727
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
  • Loading branch information
myitcv authored and jpluscplusm committed May 1, 2024
1 parent bcf703c commit 1067927
Show file tree
Hide file tree
Showing 4 changed files with 606 additions and 0 deletions.
241 changes: 241 additions & 0 deletions content/docs/tutorial/using-modules-with-go-api/en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
---
title: Using modules with the Go API
authors:
- myitcv
- jpluscplusm
tags:
- go api
- modules
- tooling
toc_hide: true
---

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

{{{with _script_ "en" "HIDDEN use non-prerelease cue command to mirror API use"}}}
export PATH=/cues/$CUELANG_CUE_LATEST:$PATH
{{{end}}}

{{{with _script_ "en" "HIDDEN setup auth"}}}
mkdir -p $HOME/.config/cue
cat <<EOD > $HOME/.config/cue/logins.json
{"registries":{"registry.cue.works":{"access_token":"${TEST_USER_AUTHN_CUE_USER_NEW}","token_type":"Bearer"}}}
EOD
{{{end}}}

## Introduction

In this tutorial you will
use CUE's Go API to work with a CUE module dependency fetched from the Central Registry.

Along the way you will:

- Login to the Central Registry, and authenticate the `cue` command
- Create a CUE module that depends on an existing, well-known module
- Use `cue mod tidy` to fetch and organise your module's dependencies
- Load your CUE using the Go API working in a modules-aware mode

{{< info >}}
This tutorial describes an experimental feature whose details are subject to change.
{{< /info >}}

## Prerequisites

- **Access to the [Central Registry](https://registry.cue.works)** -- if you
need to practise using the Central Registry, then first follow the
tutorial: [Working with the Central Registry]({{< relref "docs/tutorial/working-with-the-central-registry" >}})
- **A tool to edit text files** -- any text editor you have will be fine;
for example: [VSCode](https://code.visualstudio.com/) or [Vim](https://neovim.io/)
- **A command terminal** -- the `cue` command works on all platforms;
use any terminal on Linux or macOS, or PowerShell, `cmd.exe` or
[WSL](https://learn.microsoft.com/en-us/windows/wsl/install) on Windows.
- **An installed `go` binary** -- [installation details](https://go.dev/doc/install)
- **An installed `cue` binary** -- [installation details]({{< relref "/docs/introduction/installation" >}})

## Set up the `cue` command

{{{with step}}}
Enable the modules experiment:

{{{with script "en" "enable modules"}}}
export CUE_EXPERIMENT=modules
{{{end}}}
{{{end}}}

{{{with step}}}
Authenticate the `cue` command with the Central Registry:

{{{with script "en" "#norun cue login"}}}
#norun
cue login
{{{end}}}

Later in this tutorial the `cue` command will fetch a well-known module from
the Central Registry, which requires authentication.
{{{end}}}

## Create a CUE module

{{{with step}}}
Initialize a new main CUE module in an empty directory:

{{{with script "en" "cue mod init"}}}
cue mod init an.example/config@v0
{{{end}}}

You won't publish this module, so the name you give it is unimportant.
{{{end}}}

{{{with step}}}
Create the file `main.cue`, holding the code for the main module:

{{{with upload "en" "initial main.cue"}}}
-- main.cue --
package config

import "github.com/cue-labs/examples/frostyconfig@v0"

config: frostyconfig.#Config & {
appName: "alpha"
port: 80
features: logging: true
}
{{{end}}}

Your main module defines some concrete values for a configuration,
constrained by the `frostyconfig.#Config` schema.
{{{end}}}

{{< info >}}
Your module imports and uses the `frostyconfig` package first introduced in the tutorial:
[Working with a custom registry]({{< relref "docs/tutorial/working-with-a-custom-module-registry" >}}).
You don't need to follow that tutorial right now - it's only mentioned for context.
{{< /info >}}

{{{with step}}}
Ensure the CUE module is tidy:

{{{with script "en" "initial cue mod tidy"}}}
cue mod tidy
{{{end}}}

This fetches the `frostyconfig` module (and any dependencies it might have)
from the Central Registry.
{{{end}}}

{{{with step}}}
Export the configuration from your CUE module:

{{{with script "en" "first export"}}}
cue export
{{{end}}}

This export shows that your CUE is valid and you can successfully use a
dependency from the Central Registry.
{{{end}}}

## Create a Go module and program

{{{with _script_ "en" "HIDDEN unset CUE_EXPERIMENT so Go code's behaviour can't rely on it"}}}
unset CUE_EXPERIMENT
{{{end}}}

{{{with step}}}
Initialize a Go module for your program:

{{{with script "en" "go mod init"}}}
#ellipsis 0
go mod init an.example/config
{{{end}}}

You won't publish this module, so the name you give it is unimportant.
{{{end}}}

{{{with step}}}
Create the file `main.go` containing this Go program:

{{{with upload "en" "initial go code"}}}
-- main.go --
package main

import (
"fmt"
"log"

"cuelang.org/go/cue"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/load"
"cuelang.org/go/mod/modconfig"
)

func main() {
ctx := cuecontext.New()

// Create a registry client. Passing a nil config
// will give us client that behaves like the cue command.
reg, err := modconfig.NewRegistry(nil)
if err != nil {
log.Fatal(err)
}

// Load the package from the current directory.
// We don't need to specify a Config in this example.
insts := load.Instances([]string{"."}, &load.Config{
Registry: reg,
})

// The current directory just has one file without any build tags,
// and that file belongs to the example package, so we get a single
// instance as a result.
v := ctx.BuildInstance(insts[0])
if err := v.Err(); err != nil {
log.Fatal(err)
}

// Lookup the 'config' field and print it out
config := v.LookupPath(cue.ParsePath("config"))
fmt.Println(config)
}
{{{end}}}

This program loads the CUE package in the current directory,
and then prints a message based on the `config` field.
{{{end}}}

{{{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}}}

You can use `@latest` in place of the specific version mentioned here.
{{{end}}}

## Run the Go program

{{{with step}}}
Run the Go program:

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

## Summary

Well done - you've finished this tutorial! In completing it, you:

- **created a main module** that depends on a well-known module from the Central Registry, and
- **used the Go API to load the main module**, transparently using the module's dependencies.

## Related content

- {{< linkto/related/reference "modules" >}}
- {{< linkto/related/tutorial "working-with-a-custom-module-registry" >}}
127 changes: 127 additions & 0 deletions content/docs/tutorial/using-modules-with-go-api/gen_cache.cue
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package site
{
content: {
docs: {
tutorial: {
"using-modules-with-go-api": {
page: {
cache: {
upload: {
"initial main.cue": "LqMDMqBvt0Ctp5zTY2qrIb7JMj7m+v2m4Mt9Oq+4ZPw="
"initial go code": "nzL9ZkY5KwTMIqy4Iuwpt37CQL7aKRI+huoSixMTqEk="
}
multi_step: {
hash: "EC6V042M6UT9TPSI408P8HKJELI13N2KUU56B67IKTUVSUFRJKB0===="
scriptHash: "RFAN5OA0N7FHCG58RI26POLSG0QQMN9PS72O0V65QH0EA4FU1G00===="
steps: [{
doc: ""
cmd: "export GOMODCACHE=/caches/gomodcache"
exitCode: 0
output: ""
}, {
doc: ""
cmd: "export GOCACHE=/caches/gobuild"
exitCode: 0
output: ""
}, {
doc: ""
cmd: "export PATH=/cues/v0.8.2:$PATH"
exitCode: 0
output: ""
}, {
doc: ""
cmd: "mkdir -p $HOME/.config/cue"
exitCode: 0
output: ""
}, {
doc: ""
cmd: """
cat <<EOD >$HOME/.config/cue/logins.json
{"registries":{"registry.cue.works":{"access_token":"${TEST_USER_AUTHN_CUE_USER_NEW}","token_type":"Bearer"}}}
EOD
"""
exitCode: 0
output: ""
}, {
doc: ""
cmd: "export CUE_EXPERIMENT=modules"
exitCode: 0
output: ""
}, {
doc: ""
cmd: "cue mod init an.example/config@v0"
exitCode: 0
output: ""
}, {
doc: ""
cmd: "cue mod tidy"
exitCode: 0
output: ""
}, {
doc: ""
cmd: "cue export"
exitCode: 0
output: """
{
"config": {
"appName": "alpha",
"port": 80,
"features": {
"logging": true
}
}
}
"""
}, {
doc: ""
cmd: "unset CUE_EXPERIMENT"
exitCode: 0
output: ""
}, {
doc: "#ellipsis 0"
cmd: "go mod init an.example/config"
exitCode: 0
output: """
...
"""
}, {
doc: "#ellipsis 0"
cmd: "go get cuelang.org/go@v0.8.2"
exitCode: 0
output: """
...
"""
}, {
doc: "#ellipsis 0"
cmd: "go mod tidy"
exitCode: 0
output: """
...
"""
}, {
doc: ""
cmd: "go run ."
exitCode: 0
output: """
{
\tappName: "alpha"
\tport: 80
\tfeatures: {
\t\tlogging: true
\t}
}
"""
}]
}
}
}
}
}
}
}
}
5 changes: 5 additions & 0 deletions content/docs/tutorial/using-modules-with-go-api/page.cue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package site

content: docs: tutorial: "using-modules-with-go-api": page: {
testUserAuthn: ["cue-user-new"]
}

0 comments on commit 1067927

Please sign in to comment.