STENCIL

  • Docs
  • GitHub
Star

What's on this Page

  • Step 1: Create a Native Extension
  • Step 2: Using in a Test Module
  • Step 3: Running the Test Module
GETTING STARTED

Native Extension Quick Start

Create a native extension and use it in an application

This quick start assumes you’re familiar with stencil and module usage already. If you aren’t be sure to go through the reference documentation or the other quick starts here before proceeding. You’ve been warned!

What is a Native Extension?

Native extensions are special module types that don’t use go-templates to integrate with stencil. Instead they expose template functions written in another language that can be called by stencil templates.

How to create a Native Extension

This quick start will focus on creating a Go native extension. While other languages may work as well, there currently is no official documentation or support for those languages (if you’re interested in another language please contribute it back!).

Step 1: Create a Native Extension

Much like a module we’re going to use the [stencil create module] command to create a native extension.

create-module.sh
mkdir helloworld; cd helloworld
stencil create module --native-extension github.com/yourorg/helloworld

However, instead of using the templates/ directory we’re going to create a plugin/ directory.

setup-dirs.sh
rm templates; mkdir plugin

Now that we’ve created the plugin/ directory we’re going to created a simple plugin.go file that’ll implement the Implementation interface and prints helloWorld when the helloWorld function is called.

package main

import (
"fmt"

	"github.com/getoutreach/stencil/pkg/extensions/apiv1"
	"github.com/sirupsen/logrus"
)

// _ is a compile time assertion to ensure we implement
// the Implementation interface
var _ apiv1.Implementation = &TestPlugin{}

type TestPlugin struct{}

func (tp *TestPlugin) GetConfig() (*apiv1.Config, error) {
	return &apiv1.Config{}, nil
}

func (tp *TestPlugin) ExecuteTemplateFunction(t *apiv1.TemplateFunctionExec) (interface{}, error) {
	if t.Name == "helloWorld" {
		return "helloWorld"
	}

  return nil, nil
}

func (tp *TestPlugin) GetTemplateFunctions() ([]*apiv1.TemplateFunction, error) {
	return []*apiv1.TemplateFunction{
		{
			Name: "helloWorld",
		},
	}, nil
}

func helloWorld() (interface{}, error) {
	fmt.Println("👋 from the test plugin")
	return "hello from a plugin!", nil
}

func main() {
	err := apiv1.NewExtensionImplementation(&TestPlugin{})
	if err != nil {
		logrus.WithError(err).Fatal("failed to start extension")
	}
}

Now lets run make to create the binary at bin/plugin so we can consume it in a test application.

Step 2: Using in a Test Module

Let’s create a testmodule to consume the native extension.

create-test-module.sh
mkdir testmodule; cd testmodule
stencil create module github.com/yourorg/testmodule

Now let’s create a hello.txt.tpl that consumes the helloWorld function.

hello.txt.tpl
{{ extensions.Call "github.com/yourorg/helloworld" "helloWorld" }}

Ensure that the manifest.yaml for this module consumes the native extension:

name: testmodule
modules:
  - name: github.com/yourorg/helloworld

Step 3: Running the Test Module

Now, in order to test the native extension and the module consuming it we’ll need to create a test application.

mkdir testapp; cd testapp
cat > service.yaml <<EOF
name: testapp
modules:
- name: github.com/yourorg/testmodule
replacements:
	# Note: Replace these directories with their actual paths. This assumes they're
	# right behind our application in the directory tree.
  github.com/yourorg/helloworld: ../helloworld
  github.com/yourorg/testmodule: ../testmodule

Now, if we run stencil we should get a hello.txt file in our test application.

testapp ❯ stencil
INFO[0000] stencil v1.14.2
INFO[0000] Fetching dependencies
INFO[0002]  -> github.com/yourorg/helloworld local
INFO[0002] Loading native extensions
INFO[0002] Rendering templates
INFO[0002] Writing template(s) to disk
INFO[0002]   -> Created hello.txt

testapp ❯ cat hello.txt
helloWorld

Success! 🎉

Reflection

To reflect, we’ve created a hello.txt.tpl file that calls the helloWorld function in the native extension we implemented.

Releasing is all handled by the templates in stencil-base and stencil-template-base that were created when you ran stencil create

See Also

  • Module Quick Start
  • Quick Start
  • About Stencil
    • What is Stencil?
    • License
  • Getting Started
    • Get Started Overview
    • Install Stencil
    • Quick Start
    • Module Quick Start
    • Native Extension Quick Start
  • Reference Docs
    • Reference Docs Overview
    • Stencil Modules Overview
    • Native Extensions
    • Template Module
    • Service Manifest
  • Functions
    • Functions Quick Reference
    • file.Block
    • file.Create
    • file.Delete
    • file.Path
    • file.RemoveAll
    • file.SetContents
    • file.SetPath
    • file.Skip
    • file.Static
    • stencil.AddToModuleHook
    • stencil.ApplyTemplate
    • stencil.Arg
    • stencil.Args
    • stencil.Exists
    • stencil.GetGlobal
    • stencil.GetModuleHook
    • stencil.ReadBlocks
    • stencil.ReadFile
    • stencil.SetGlobal
  • CLI
    • Commands Quick Reference
    • stencil
    • stencil create
    • stencil create module
    • stencil describe
    • stencil docs
    • stencil docs generate
    • stencil updater
    • stencil updater get-channel
    • stencil updater get-channels
    • stencil updater list-releases
    • stencil updater rollback
    • stencil updater set-channel
    • stencil updater status
    • stencil updater use
  • Contribute
    • Contribute to Stencil
    • Development
    • Documentation
  • Maintenance
Last updated: June 1, 2022: docs: fix indentation, remove code usage (#99) (a596617)
Improve this page
By the Stencil Authors
Hugo Logo
  • File an Issue
  • Get Help
  • Docs
  • GitHub
  • About Stencil
  • Getting Started
  • Reference Docs
  • Functions
  • CLI
  • Contribute
  • Maintenance