Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: template support #42

Merged
merged 1 commit into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkgmgr/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Config struct {
ConfigDir string
CacheDir string
Logger *slog.Logger
Template *Template
}

func NewDefaultConfig() (Config, error) {
Expand Down
90 changes: 80 additions & 10 deletions pkgmgr/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,22 @@ type Package struct {
}

func (p Package) install(cfg Config, context string) error {
// Update template vars
pkgName := fmt.Sprintf("%s-%s-%s", p.Name, p.Version, context)
cfg.Template = cfg.Template.WithVars(
map[string]any{
"Package": map[string]any{
"Name": pkgName,
"ShortName": p.Name,
"Version": p.Version,
},
"DataDir": filepath.Join(
cfg.ConfigDir,
"data",
pkgName,
),
},
)
// Run pre-flight checks
for _, installStep := range p.InstallSteps {
// Make sure only one install method is specified per install step
Expand Down Expand Up @@ -117,15 +132,64 @@ func (p *PackageInstallStepDocker) preflight(cfg Config, pkgName string) error {

func (p *PackageInstallStepDocker) install(cfg Config, pkgName string) error {
containerName := fmt.Sprintf("%s-%s", pkgName, p.ContainerName)
extraVars := map[string]any{
"Container": map[string]any{
"Name": containerName,
},
}
tmpImage, err := cfg.Template.Render(p.Image, extraVars)
if err != nil {
return err
}
tmpEnv := make(map[string]string)
for k, v := range p.Env {
tmplVal, err := cfg.Template.Render(v, extraVars)
if err != nil {
return err
}
tmpEnv[k] = tmplVal
}
var tmpCommand []string
for _, cmd := range p.Command {
tmpCmd, err := cfg.Template.Render(cmd, extraVars)
if err != nil {
return err
}
tmpCommand = append(tmpCommand, tmpCmd)
}
var tmpArgs []string
for _, arg := range p.Args {
tmpArg, err := cfg.Template.Render(arg, extraVars)
if err != nil {
return err
}
tmpArgs = append(tmpArgs, tmpArg)
}
var tmpBinds []string
for _, bind := range p.Binds {
tmpBind, err := cfg.Template.Render(bind, extraVars)
if err != nil {
return err
}
tmpBinds = append(tmpBinds, tmpBind)
}
var tmpPorts []string
for _, port := range p.Ports {
tmpPort, err := cfg.Template.Render(port, extraVars)
if err != nil {
return err
}
tmpPorts = append(tmpPorts, tmpPort)
}
svc := DockerService{
logger: cfg.Logger,
ContainerName: containerName,
Image: p.Image,
Env: p.Env,
Command: p.Command,
Args: p.Args,
Binds: p.Binds,
Ports: p.Ports,
Image: tmpImage,
Env: tmpEnv,
Command: tmpCommand,
Args: tmpArgs,
Binds: tmpBinds,
Ports: tmpPorts,
}
if err := svc.Create(); err != nil {
return err
Expand Down Expand Up @@ -156,17 +220,19 @@ func (p *PackageInstallStepDocker) uninstall(cfg Config, pkgName string) error {
type PackageInstallStepFile struct {
Filename string `yaml:"filename"`
Content string `yaml:"content"`
Template bool `yaml:"template"`
Mode fs.FileMode `yaml:"mode,omitempty"`
}

func (p *PackageInstallStepFile) install(cfg Config, pkgName string) error {
// TODO: add templating support
tmpFilePath, err := cfg.Template.Render(p.Filename, nil)
if err != nil {
return err
}
filePath := filepath.Join(
cfg.ConfigDir,
"data",
pkgName,
p.Filename,
tmpFilePath,
)
parentDir := filepath.Dir(filePath)
if err := os.MkdirAll(parentDir, fs.ModePerm); err != nil {
Expand All @@ -176,7 +242,11 @@ func (p *PackageInstallStepFile) install(cfg Config, pkgName string) error {
if p.Mode > 0 {
fileMode = p.Mode
}
if err := os.WriteFile(filePath, []byte(p.Content), fileMode); err != nil {
tmpContent, err := cfg.Template.Render(p.Content, nil)
if err != nil {
return err
}
if err := os.WriteFile(filePath, []byte(tmpContent), fileMode); err != nil {
return err
}
cfg.Logger.Debug(fmt.Sprintf("wrote file %s", filePath))
Expand Down
23 changes: 19 additions & 4 deletions pkgmgr/pkgmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,28 @@ func (p *PackageManager) init() error {
}
// TODO: replace this with syncing a repo and reading from disk
p.availablePackages = append(p.availablePackages, RegistryPackages...)
// TODO: remove me
if err := p.state.Save(); err != nil {
return err
}
// Setup templating
p.initTemplate()
return nil
}

func (p *PackageManager) initTemplate() {
activeContextName, activeContext := p.ActiveContext()
tmplVars := map[string]any{
"Context": map[string]any{
"Name": activeContextName,
"Network": activeContext.Network,
},
}
tmpConfig := p.config
if tmpConfig.Template == nil {
tmpConfig.Template = NewTemplate(tmplVars)
} else {
tmpConfig.Template = tmpConfig.Template.WithVars(tmplVars)
}
p.config = tmpConfig
}

func (p *PackageManager) AvailablePackages() []Package {
return p.availablePackages[:]
}
Expand Down
9 changes: 5 additions & 4 deletions pkgmgr/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,20 @@ var RegistryPackages = []Package{
ContainerName: "cardano-node",
Image: "ghcr.io/blinklabs-io/cardano-node:8.7.3",
Env: map[string]string{
"NETWORK": "preview",
"NETWORK": "{{ .Context.Network }}",
"CARDANO_NODE_SOCKET_PATH": "/ipc/node.socket",
},
Ports: []string{
"3001:3001",
},
},
},
{
// TODO: turn this into a template
File: &PackageInstallStepFile{
Filename: "test-cardano-cli",
Filename: "cardano-cli",
// TODO: figure out how to get network magic for named network
Content: `#!/bin/bash
docker exec -ti cardano-node-8.7.3-cardano-node cardano-cli $@
docker exec -ti {{ .Package.Name }}-cardano-node cardano-cli $@
`,
},
},
Expand Down
70 changes: 70 additions & 0 deletions pkgmgr/template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2024 Blink Labs Software
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package pkgmgr

import (
"bytes"
"text/template"
)

type Template struct {
tmpl *template.Template
baseVars map[string]any
}

func NewTemplate(baseVars map[string]any) *Template {
return &Template{
tmpl: template.New("main"),
baseVars: baseVars,
}
}

func (t *Template) Render(tmplBody string, extraVars map[string]any) (string, error) {
// Build our vars
tmpVars := map[string]any{}
for k, v := range t.baseVars {
tmpVars[k] = v
}
for k, v := range extraVars {
tmpVars[k] = v
}
// Parse template body
tmpl, err := t.tmpl.Parse(tmplBody)
if err != nil {
return "", err
}
// Render template
outBuffer := bytes.NewBuffer(nil)
if err := tmpl.Execute(outBuffer, tmpVars); err != nil {
return "", err
}
return outBuffer.String(), nil
}

// WithVars creates a copy of the Template with the extra variables added to the original base variables
func (t *Template) WithVars(extraVars map[string]any) *Template {
tmpVars := map[string]any{}
for k, v := range t.baseVars {
tmpVars[k] = v
}
for k, v := range extraVars {
tmpVars[k] = v
}
tmpl := &Template{
tmpl: template.New("main"),
baseVars: tmpVars,
}
return tmpl
}