Skip to content

Commit

Permalink
Merge pull request #432 from authzed/add-zed-schema-compile-command
Browse files Browse the repository at this point in the history
Add zed schema compile command
  • Loading branch information
tstirrat15 authored Feb 5, 2025
2 parents 507e8ca + 49a926e commit b49f8bb
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
dist/
temp/

# Local-only files
go.work
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@ The `--explain` flag can be used on `permission check` to see a trace:
zed permission check document:firstdoc writer user:emilia --explain
```

## FAQ

### `commands` vs `cmd`

`zed` is used both via WASM in the playground and as a CLI. The commands in `commands` are
the commands that zed uses in the playground to talk to the WASM instance of SpiceDB.
The commands in `cmd` are those which are CLI-only.

## Acknowledgements

zed is a community project fueled by contributions from both organizations and individuals.
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2
github.com/authzed/authzed-go v1.3.0
github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b
github.com/authzed/spicedb v1.40.0
github.com/authzed/spicedb v1.40.1-0.20250203174657-98e88a128ae5
github.com/brianvoe/gofakeit/v6 v6.28.0
github.com/ccoveille/go-safecast v1.5.0
github.com/cenkalti/backoff/v4 v4.3.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -678,8 +678,8 @@ github.com/authzed/consistent v0.1.0 h1:tlh1wvKoRbjRhMm2P+X5WQQyR54SRoS4MyjLOg17
github.com/authzed/consistent v0.1.0/go.mod h1:plwHlrN/EJUCwQ+Bca0MhM1KnisPs7HEkZI5giCXrcc=
github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b h1:wbh8IK+aMLTCey9sZasO7b6BWLAJnHHvb79fvWCXwxw=
github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b/go.mod h1:s3qC7V7XIbiNWERv7Lfljy/Lx25/V1Qlexb0WJuA8uQ=
github.com/authzed/spicedb v1.40.0 h1:VcYmSZEHNjZXmEI+VIn1qDP8SgeFTFbZuW7UilYj3ns=
github.com/authzed/spicedb v1.40.0/go.mod h1:/UVC4ZJkMUZFN4MVjjOLAU7m/fqitkBP57ZPffyicOs=
github.com/authzed/spicedb v1.40.1-0.20250203174657-98e88a128ae5 h1:3BcKukzgDYDwyUKiYn8b6nxgSZBrDfd4eHvfz15+Sos=
github.com/authzed/spicedb v1.40.1-0.20250203174657-98e88a128ae5/go.mod h1:/UVC4ZJkMUZFN4MVjjOLAU7m/fqitkBP57ZPffyicOs=
github.com/aws/aws-sdk-go-v2 v1.32.7 h1:ky5o35oENWi0JYWUZkB7WYvVPP+bcRF5/Iq7JWSb5Rw=
github.com/aws/aws-sdk-go-v2 v1.32.7/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U=
github.com/aws/aws-sdk-go-v2/config v1.28.7 h1:GduUnoTXlhkgnxTD93g1nv4tVPILbdNQOzav+Wpg7AE=
Expand Down
1 change: 1 addition & 0 deletions internal/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func Run() {
registerImportCmd(rootCmd)
registerValidateCmd(rootCmd)
registerBackupCmd(rootCmd)
registerPreviewCmd(rootCmd)

// Register shared commands.
commands.RegisterPermissionCmd(rootCmd)
Expand Down
119 changes: 119 additions & 0 deletions internal/cmd/preview.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package cmd

import (
"errors"
"fmt"
"os"
"path/filepath"

newcompiler "github.com/authzed/spicedb/pkg/composableschemadsl/compiler"
newinput "github.com/authzed/spicedb/pkg/composableschemadsl/input"
"github.com/authzed/spicedb/pkg/schemadsl/compiler"
"github.com/authzed/spicedb/pkg/schemadsl/generator"
"github.com/ccoveille/go-safecast"
"github.com/jzelinskie/cobrautil/v2"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"golang.org/x/term"

"github.com/authzed/zed/internal/commands"
)

func registerPreviewCmd(rootCmd *cobra.Command) {
rootCmd.AddCommand(previewCmd)

previewCmd.AddCommand(schemaCmd)

schemaCmd.AddCommand(schemaCompileCmd)
schemaCompileCmd.Flags().String("out", "", "output filepath; omitting writes to stdout")
}

var previewCmd = &cobra.Command{
Use: "preview <subcommand>",
Short: "Experimental commands that have been made available for preview",
}

var schemaCmd = &cobra.Command{
Use: "schema <subcommand>",
Short: "Manage schema for a permissions system",
}

var schemaCompileCmd = &cobra.Command{
Use: "compile <file>",
Args: cobra.ExactArgs(1),
Short: "Compile a schema that uses extended syntax into one that can be written to SpiceDB",
Example: `
Write to stdout:
zed preview schema compile root.zed
Write to an output file:
zed preview schema compile --out compiled.zed
`,
ValidArgsFunction: commands.FileExtensionCompletions("zed"),
RunE: schemaCompileCmdFunc,
}

// Compiles an input schema written in the new composable schema syntax
// and produces it as a fully-realized schema
func schemaCompileCmdFunc(cmd *cobra.Command, args []string) error {
stdOutFd, err := safecast.ToInt(uint(os.Stdout.Fd()))
if err != nil {
return err
}
outputFilepath := cobrautil.MustGetString(cmd, "out")
if outputFilepath == "" && !term.IsTerminal(stdOutFd) {
return fmt.Errorf("must provide stdout or output file path")
}

inputFilepath := args[0]
inputSourceFolder := filepath.Dir(inputFilepath)
var schemaBytes []byte
schemaBytes, err = os.ReadFile(inputFilepath)
if err != nil {
return fmt.Errorf("failed to read schema file: %w", err)
}
log.Trace().Str("schema", string(schemaBytes)).Str("file", args[0]).Msg("read schema from file")

if len(schemaBytes) == 0 {
return errors.New("attempted to compile empty schema")
}

compiled, err := newcompiler.Compile(newcompiler.InputSchema{
Source: newinput.Source(inputFilepath),
SchemaString: string(schemaBytes),
}, newcompiler.AllowUnprefixedObjectType(),
newcompiler.SourceFolder(inputSourceFolder))
if err != nil {
return err
}

// Attempt to cast one kind of OrderedDefinition to another
oldDefinitions := make([]compiler.SchemaDefinition, 0, len(compiled.OrderedDefinitions))
for _, definition := range compiled.OrderedDefinitions {
oldDefinition, ok := definition.(compiler.SchemaDefinition)
if !ok {
return fmt.Errorf("could not convert definition to old schemadefinition: %v", oldDefinition)
}
oldDefinitions = append(oldDefinitions, oldDefinition)
}

// This is where we functionally assert that the two systems are compatible
generated, _, err := generator.GenerateSchema(oldDefinitions)
if err != nil {
return fmt.Errorf("could not generate resulting schema: %w", err)
}

// Add a newline at the end for hygiene's sake
terminated := generated + "\n"

if outputFilepath == "" {
// Print to stdout
fmt.Print(terminated)
} else {
err = os.WriteFile(outputFilepath, []byte(terminated), 0o_600)
if err != nil {
return err
}
}

return nil
}

0 comments on commit b49f8bb

Please sign in to comment.