gonix

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 15, 2023 License: Apache-2.0 Imports: 6 Imported by: 0

README

Go bindings to nix API

Go Report Card GoDoc

Building

These bindings depend on the unstable nix C API, that's not currently merged upstream. You must pull nix from github:tweag/nix/nix-c-bindings, and make both nix.dev and pkg-config available in your buildInputs for the cgo buindings to work. Consult the flake.nix for an expample.

Documentation

Overview

Package gonix provides bindings to the nix APIs. It can work with any store supported by nix, including working with `/nix/store` directly or over the nix-daemon.

Example
package main

import (
	"fmt"

	"github.com/farcaller/gonix"
)

func main() {
	ctx := gonix.NewContext()
	store, err := gonix.NewStore(ctx, "dummy", nil)
	if err != nil {
		panic(fmt.Errorf("failed to create a store: %v", err))
	}
	state := store.NewState(nil)

	val, err := state.EvalExpr("builtins.toJSON { answer = 42; }", ".")
	if err != nil {
		panic(fmt.Errorf("failed to eval: %v", err))
	}

	strVal, err := val.GetString()
	if err != nil {
		panic(fmt.Errorf("failed to convert the value to string: %v", err))
	}

	fmt.Println(strVal)
}
Output:

{"answer":42}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func GcNow added in v0.2.0

func GcNow()

GcNow triggers the nix garbage collector manually.

func GetSetting added in v0.2.0

func GetSetting(ctx *Context, name string) (string, error)

GetSetting returns the value of a setting.

Example
package main

import (
	"fmt"

	"github.com/farcaller/gonix"
)

func main() {
	ctx := gonix.NewContext()
	val, err := gonix.GetSetting(ctx, "trace-verbose")
	if err != nil {
		panic(fmt.Errorf("failed to read the setting: %v", err))
	}

	fmt.Println(val)
}
Output:

false

func InitPlugins added in v0.2.0

func InitPlugins(ctx *Context) error

InitPlugins loads the plugins specified in Nix's plugin-files setting.

This function should be called once (if needed), after all the required settings were set.

func RegisterGlobalPrimOp added in v0.2.0

func RegisterGlobalPrimOp(ctx *Context, name string, args []string, doc string, fun PrimOpFunc) error

RegisterGlobalPrimOp registers the primop in the `builtins` attrset. Only applies to the [State]s created after the call.

Example
package main

import (
	"fmt"

	"github.com/farcaller/gonix"
)

func main() {
	ctx := gonix.NewContext()
	store, _ := gonix.NewStore(ctx, "dummy", nil)

	gonix.RegisterGlobalPrimOp(
		ctx,
		"summer",
		[]string{"arg0", "arg1", "arg2"},
		"docs",
		func(ctx *gonix.Context, state *gonix.State, args ...*gonix.Value) *gonix.Value {
			var sum int64 = 0
			for _, val := range args {
				i, _ := val.GetInt()
				sum += i
			}
			r, _ := state.NewInt(sum)
			return r
		})

	state := store.NewState(nil)

	res, _ := state.EvalExpr(`builtins.summer 1 2 3`, ".")

	fmt.Println(res)
}
Output:

6

func SetSetting added in v0.2.0

func SetSetting(ctx *Context, name, value string) error

SetSetting sets the setting to the passed value. This value affects all the calls done to nix API within the lifetime of the executable (irregardless of the context passed).

func Version added in v0.2.0

func Version() string

Version returns the API version.

Example:

v := Version()

Output:

2.18.0pre20230828_af7d89a

Types

type BuildOutputs

type BuildOutputs map[string]string

BuildOutputs is a map for the derivation outputs to output paths.

type Context

type Context struct {
	// contains filtered or unexported fields
}

Context contains the current execution context and the last raised error.

func NewContext

func NewContext() *Context

NewContext creates a new context.

type ExternalValue added in v0.2.0

type ExternalValue struct {
	// contains filtered or unexported fields
}

ExternalValue is a wrapper around a go value passed into nix.

func (*ExternalValue) Content added in v0.2.0

func (ev *ExternalValue) Content() ExternalValueProvider

Content returns the ExternalValueProvider of this value.

func (ExternalValue) String added in v0.2.0

func (ev ExternalValue) String() string

type ExternalValueProvider added in v0.2.0

type ExternalValueProvider interface {
	// Print is called when printing the external value.
	Print() string

	// ShowType is called when `:t` is invoked on the value.
	ShowType() string

	// TypeOf is called when `builtins.typeOf` is invoked on the value.
	TypeOf() string

	// CoerceToString is called when "${str}" or `builtins.toString` is invoked on the value.
	//
	// if coerceMore is true, CoerceToString was invoked trough a `builtins.toString` call
	// (which also converts nulls, integers, booleans and lists to a string).
	//
	// if copyToStore is true, referenced paths are copied to the Nix store as a side effect.
	CoerceToString(addContext func(string) error, copyMore, copyToStore bool) (string, error)

	// Equal is called for a comparison of two external values. If `other` is not an external
	// value, Equal isn't called and instead `false` is always returned.
	Equal(other ExternalValueProvider) bool

	// PrintValueAsJSON is called when the value is converted to JSON. The result must
	// be valid JSON.
	PrintValueAsJSON(strict, copyToStore bool) string
}

ExternalValueProvider is the interface that external values must implement to be passed into the nix Value.

type PrimOp added in v0.2.0

type PrimOp struct {
	// contains filtered or unexported fields
}

PrimOp is a wrapper around a nix primop.

func NewPrimOp added in v0.2.0

func NewPrimOp(ctx *Context, name string, args []string, doc string, fun PrimOpFunc) (*PrimOp, error)

type PrimOpFunc added in v0.2.0

type PrimOpFunc func(ctx *Context, state *State, args ...*Value) *Value

type State

type State struct {
	// contains filtered or unexported fields
}

State is the execution state in a given Store.

func (*State) Call added in v0.2.0

func (s *State) Call(fun, argument *Value) (*Value, error)

Call calls a given function with a given argument and returns tne result.

Example
package main

import (
	"fmt"

	"github.com/farcaller/gonix"
)

func main() {
	ctx := gonix.NewContext()
	store, err := gonix.NewStore(ctx, "dummy", nil)
	if err != nil {
		panic(fmt.Errorf("failed to create a store: %v", err))
	}
	state := store.NewState(nil)

	f, err := state.EvalExpr("value: value * 2", ".")
	if err != nil {
		panic(fmt.Errorf("failed to eval a function: %v", err))
	}
	v, err := state.NewInt(21)
	if err != nil {
		panic(fmt.Errorf("failed to create an int: %v", err))
	}
	res, err := state.Call(f, v)
	if err != nil {
		panic(fmt.Errorf("failed to call a function: %v", err))
	}

	fmt.Println(res)
}
Output:

42

func (*State) EvalExpr

func (s *State) EvalExpr(expr, path string) (*Value, error)

EvalExpr evaluates the expression and returns the result.

Example
package main

import (
	"fmt"

	"github.com/farcaller/gonix"
)

func main() {
	ctx := gonix.NewContext()
	store, err := gonix.NewStore(ctx, "dummy", nil)
	if err != nil {
		panic(fmt.Errorf("failed to create a store: %v", err))
	}
	state := store.NewState(nil)

	val, err := state.EvalExpr("101 - 59", ".")
	if err != nil {
		panic(fmt.Errorf("failed to eval: %v", err))
	}

	fmt.Println(val)
}
Output:

42

func (*State) NewAttrs added in v0.2.0

func (s *State) NewAttrs(attrs map[string]*Value) (*Value, error)

NewAttrs returns a Value containing an attrset.

Example
package main

import (
	"fmt"

	"github.com/farcaller/gonix"
)

func main() {
	ctx := gonix.NewContext()
	store, err := gonix.NewStore(ctx, "dummy", nil)
	if err != nil {
		panic(fmt.Errorf("failed to create a store: %v", err))
	}
	state := store.NewState(nil)

	newString := func(str string) *gonix.Value {
		s, err := state.NewString(str)
		if err != nil {
			panic(fmt.Errorf("failed to create a string: %v", err))
		}
		return s
	}

	newInt := func(i int64) *gonix.Value {
		s, err := state.NewInt(i)
		if err != nil {
			panic(fmt.Errorf("failed to create a number: %v", err))
		}
		return s
	}

	as, err := state.NewAttrs(map[string]*gonix.Value{
		"hello":  newString("world"),
		"number": newInt(11),
	})
	if err != nil {
		panic(fmt.Errorf("failed to build an attrset: %v", err))
	}

	fmt.Println(as)
}
Output:

map[hello:world number:11]

func (*State) NewBool added in v0.2.0

func (s *State) NewBool(b bool) (*Value, error)

NewBool returns a Value containing a bool.

Example
package main

import (
	"fmt"

	"github.com/farcaller/gonix"
)

func main() {
	ctx := gonix.NewContext()
	store, err := gonix.NewStore(ctx, "dummy", nil)
	if err != nil {
		panic(fmt.Errorf("failed to create a store: %v", err))
	}
	state := store.NewState(nil)

	v, err := state.NewBool(true)
	if err != nil {
		panic(fmt.Errorf("failed to create a float: %v", err))
	}

	fmt.Println(v)
}
Output:

true

func (*State) NewExternalValue added in v0.2.0

func (state *State) NewExternalValue(val ExternalValueProvider) (*Value, error)

NewExternalValue returns a Value containing an external value.

Example
package main

import (
	"fmt"

	"github.com/farcaller/gonix"
)

type simpleExternal struct{}

func (v *simpleExternal) Print() string {
	return "printed"
}

func (v *simpleExternal) ShowType() string {
	return "simpleexternal"
}
func (v *simpleExternal) TypeOf() string {
	return "simpleexternal"
}

func (v *simpleExternal) CoerceToString(addContext func(string) error, copyMore, copyToStore bool) (string, error) {
	return fmt.Sprintf("coerced with copyMore=%v", copyMore), nil
}

func (v *simpleExternal) Equal(other gonix.ExternalValueProvider) bool {
	return false
}

func (v *simpleExternal) PrintValueAsJSON(strict, copyToStore bool) string {
	return `{ "value" : "simpleexternal" }`
}

func main() {
	ctx := gonix.NewContext()
	store, err := gonix.NewStore(ctx, "dummy", nil)
	if err != nil {
		panic(fmt.Errorf("failed to create a store: %v", err))
	}
	state := store.NewState(nil)

	externalVal, err := state.NewExternalValue(&simpleExternal{})
	if err != nil {
		panic(fmt.Errorf("failed to create an external value: %v", err))
	}

	toStr, err := state.EvalExpr("builtins.toString", ".")
	if err != nil {
		panic(fmt.Errorf("failed to eval: %v", err))
	}
	res, err := state.Call(toStr, externalVal)
	if err != nil {
		panic(fmt.Errorf("failed to call a function: %v", err))
	}

	strInterpolation, err := state.EvalExpr(`v: "${v}"`, ".")
	if err != nil {
		panic(fmt.Errorf("failed to eval: %v", err))
	}
	res2, err := state.Call(strInterpolation, externalVal)
	if err != nil {
		panic(fmt.Errorf("failed to call a function: %v", err))
	}

	fmt.Println(res)
	fmt.Println(res2)
}
Output:

coerced with copyMore=true
coerced with copyMore=false

func (*State) NewFloat added in v0.2.0

func (s *State) NewFloat(f float64) (*Value, error)

NewInt returns a Value containing a float.

Example
package main

import (
	"fmt"

	"github.com/farcaller/gonix"
)

func main() {
	ctx := gonix.NewContext()
	store, err := gonix.NewStore(ctx, "dummy", nil)
	if err != nil {
		panic(fmt.Errorf("failed to create a store: %v", err))
	}
	state := store.NewState(nil)

	v, err := state.NewFloat(3.50)
	if err != nil {
		panic(fmt.Errorf("failed to create a float: %v", err))
	}

	fmt.Println(v)
}
Output:

3.5

func (*State) NewInt added in v0.2.0

func (s *State) NewInt(i int64) (*Value, error)

NewInt returns a Value containing an integer.

Example
package main

import (
	"fmt"

	"github.com/farcaller/gonix"
)

func main() {
	ctx := gonix.NewContext()
	store, err := gonix.NewStore(ctx, "dummy", nil)
	if err != nil {
		panic(fmt.Errorf("failed to create a store: %v", err))
	}
	state := store.NewState(nil)

	v, err := state.NewInt(15)
	if err != nil {
		panic(fmt.Errorf("failed to create an int: %v", err))
	}

	fmt.Println(v)
}
Output:

15

func (*State) NewList added in v0.2.0

func (s *State) NewList(items []*Value) (*Value, error)

NewList returns a Value containing a list of passed items.

Example
package main

import (
	"fmt"

	"github.com/farcaller/gonix"
)

func main() {
	ctx := gonix.NewContext()
	store, err := gonix.NewStore(ctx, "dummy", nil)
	if err != nil {
		panic(fmt.Errorf("failed to create a store: %v", err))
	}
	state := store.NewState(nil)

	newString := func(str string) *gonix.Value {
		s, err := state.NewString(str)
		if err != nil {
			panic(fmt.Errorf("failed to create a string: %v", err))
		}
		return s
	}

	newInt := func(i int64) *gonix.Value {
		s, err := state.NewInt(i)
		if err != nil {
			panic(fmt.Errorf("failed to create a number: %v", err))
		}
		return s
	}

	l, err := state.NewList([]*gonix.Value{
		newString("hello"),
		newString("world"),
		newInt(11),
	})
	if err != nil {
		panic(fmt.Errorf("failed to get the string value: %v", err))
	}

	fmt.Println(l)
}
Output:

[hello world 11]

func (*State) NewNull added in v0.2.0

func (s *State) NewNull() (*Value, error)

NewNull returns a Value containing a null.

Example
package main

import (
	"fmt"

	"github.com/farcaller/gonix"
)

func main() {
	ctx := gonix.NewContext()
	store, err := gonix.NewStore(ctx, "dummy", nil)
	if err != nil {
		panic(fmt.Errorf("failed to create a store: %v", err))
	}
	state := store.NewState(nil)

	s, err := state.NewNull()
	if err != nil {
		panic(fmt.Errorf("failed to create a null: %v", err))
	}

	fmt.Println(s)
}
Output:

<nil>

func (*State) NewPath added in v0.2.0

func (s *State) NewPath(p string) (*Value, error)

NewPath returns a Value containing a path.

Example
package main

import (
	"fmt"

	"github.com/farcaller/gonix"
)

func main() {
	ctx := gonix.NewContext()
	store, err := gonix.NewStore(ctx, "dummy", nil)
	if err != nil {
		panic(fmt.Errorf("failed to create a store: %v", err))
	}
	state := store.NewState(nil)

	s, err := state.NewPath("./.")
	if err != nil {
		panic(fmt.Errorf("failed to create a path: %v", err))
	}

	fmt.Println(s)
}
Output:

./.

func (*State) NewPrimOp added in v0.2.0

func (s *State) NewPrimOp(op *PrimOp) (*Value, error)

NewPrimOp returns a Value containing a PrimOp.

Example
package main

import (
	"fmt"

	"github.com/farcaller/gonix"
)

func main() {
	ctx := gonix.NewContext()
	store, _ := gonix.NewStore(ctx, "dummy", nil)
	state := store.NewState(nil)

	op, _ := gonix.NewPrimOp(
		ctx,
		"helloworlder",
		[]string{"target"},
		"docs",
		func(ctx *gonix.Context, state *gonix.State, args ...*gonix.Value) *gonix.Value {
			v, _ := state.NewString(fmt.Sprintf("hello, %s", args[0]))
			return v
		})
	vop, _ := state.NewPrimOp(op)

	world, _ := state.NewString("world")

	res, err := state.Call(vop, world)
	if err != nil {
		panic(fmt.Errorf("failed to call: %v", err))
	}

	fmt.Println(res)
}
Output:

hello, world

func (*State) NewString added in v0.2.0

func (s *State) NewString(st string) (*Value, error)

NewString returns a Value containing a string.

Example
package main

import (
	"fmt"

	"github.com/farcaller/gonix"
)

func main() {
	ctx := gonix.NewContext()
	store, err := gonix.NewStore(ctx, "dummy", nil)
	if err != nil {
		panic(fmt.Errorf("failed to create a store: %v", err))
	}
	state := store.NewState(nil)

	s, err := state.NewString("hello")
	if err != nil {
		panic(fmt.Errorf("failed to create a string: %v", err))
	}

	fmt.Println(s)
}
Output:

hello

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is the interface to the nix store.

func NewStore

func NewStore(ctx *Context, uri string, params map[string]string) (*Store, error)

NewStore creates a new store. See nix help-stores for details on the store options.

func (*Store) NewState

func (s *Store) NewState(searchPath []string) *State

NewState creates a new execution state.

func (*Store) ParsePath

func (s *Store) ParsePath(path string) (*StorePath, error)

ParsePath parses a path in the nix store.

func (*Store) URI added in v0.2.0

func (s *Store) URI() (string, error)

URI returns the URI of the store.

Example:

uri, err := store.URI()

Output:

"daemon", nil

func (*Store) Version added in v0.2.0

func (s *Store) Version() (string, error)

Version returns the version of the store.

Example:

ver, err := store.Version()

Output:

"2.13.5", nil

type StorePath

type StorePath struct {
	// contains filtered or unexported fields
}

StorePath defines a path in the nix store.

func (*StorePath) Build

func (sp *StorePath) Build() (BuildOutputs, error)

Build builds the store path, returning the realised outputs.

Example
package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/farcaller/gonix"
)

func main() {
	ctx := gonix.NewContext()
	store, err := gonix.NewStore(ctx, "", nil)
	if err != nil {
		panic(fmt.Errorf("failed to create a store: %v", err))
	}
	state := store.NewState(strings.Split(os.Getenv("NIX_PATH"), ":"))

	val, err := state.EvalExpr("(import <nixpkgs> {}).hello.drvPath", ".")
	if err != nil {
		panic(fmt.Errorf("failed to eval: %v", err))
	}

	sp, err := store.ParsePath(val.String())
	if err != nil {
		panic(fmt.Errorf("failed to parse path: %v", err))
	}
	if !sp.Valid() {
		panic(fmt.Errorf("store path isn't valid"))
	}

	outs, err := sp.Build()
	if err != nil {
		panic(fmt.Errorf("failed to build: %v", err))
	}

	for k, _ := range outs {
		fmt.Printf("%s\n", k)
	}
}
Output:

out

func (*StorePath) Valid

func (sp *StorePath) Valid() bool

Valid returns true if the store path is valid for the owning store.

type Value

type Value struct {
	// contains filtered or unexported fields
}

Value is a wrapper around a nix value.

func (*Value) Force

func (v *Value) Force() error

Force forces the evaluation of a Nix value.

func (*Value) ForceDeep added in v0.2.0

func (v *Value) ForceDeep() error

ForceDeep calls Value.Force recursively.

func (*Value) GetAttrs added in v0.2.0

func (v *Value) GetAttrs() (map[string]*Value, error)

GetAttrs returns the attrset value iff the value contains an attrset.

func (*Value) GetBool added in v0.2.0

func (v *Value) GetBool() (bool, error)

GetBool returns the bool value iff the value contains a bool.

func (*Value) GetExternalValue added in v0.2.0

func (v *Value) GetExternalValue() (*ExternalValue, error)

GetExternalValue returns the external value iff the value contains an external value.

func (*Value) GetFloat added in v0.2.0

func (v *Value) GetFloat() (float64, error)

GetFloat returns the float value iff the value contains a float.

func (*Value) GetInt added in v0.2.0

func (v *Value) GetInt() (int64, error)

GetInt returns the int value iff the value contains an int.

func (*Value) GetList added in v0.2.0

func (v *Value) GetList() ([]*Value, error)

GetList returns the list value iff the value contains a list.

func (*Value) GetPath added in v0.2.0

func (v *Value) GetPath() (string, error)

GetPath returns the path value iff the value contains a path.

func (*Value) GetString

func (v *Value) GetString() (string, error)

GetString returns the string value iff the value contains a string.

func (*Value) SetAttrs added in v0.2.0

func (v *Value) SetAttrs(attrs map[string]*Value) error

SetAttrs sets the value to the passed attrset.

func (*Value) SetBool added in v0.2.0

func (v *Value) SetBool(b bool) error

SetBool sets the value to the passed bool.

func (*Value) SetExternalValue added in v0.2.0

func (v *Value) SetExternalValue(ev *ExternalValue) error

SetExternalValue sets the value to the passed external value.

func (*Value) SetFloat added in v0.2.0

func (v *Value) SetFloat(f float64) error

SetFloat sets the value to the passed float.

func (*Value) SetInt added in v0.2.0

func (v *Value) SetInt(i int64) error

func (*Value) SetList added in v0.2.0

func (v *Value) SetList(items []*Value) error

SetList sets the value to the passed list.

func (*Value) SetNull added in v0.2.0

func (v *Value) SetNull() error

SetNull sets the value to null.

func (*Value) SetPath added in v0.2.0

func (v *Value) SetPath(ps string) error

SetPath sets the value to the passed string as a path.

func (*Value) SetPrimOp added in v0.2.0

func (v *Value) SetPrimOp(op *PrimOp) error

SetPrimOp sets the value to the passed PrimOp.

func (*Value) SetString added in v0.2.0

func (v *Value) SetString(s string) error

SetString sets the value to the passed string.

func (Value) String added in v0.2.0

func (v Value) String() string

func (*Value) Type added in v0.2.0

func (v *Value) Type() ValueType

Type returns the nix type stored in this value.

type ValueType added in v0.2.0

type ValueType int

ValueType is the nix type contained in the Value.

const (
	NixTypeThunk ValueType = iota
	NixTypeInt
	NixTypeFloat
	NixTypeBool
	NixTypeString
	NixTypePath
	NixTypeNull
	NixTypeAttrs
	NixTypeList
	NixTypeFunction
	NixTypeExternal
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL