Skip to content

Commit

Permalink
1.1.3
Browse files Browse the repository at this point in the history
  • Loading branch information
lburgess-acxiom committed Nov 21, 2022
1 parent 94e7456 commit ead2815
Show file tree
Hide file tree
Showing 9 changed files with 202 additions and 42 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ vendor

# don't accidentally commit a build of main
boilr
boilr-mac
*.tgz
boilr.rb
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
.PHONY: help
.DEFAULT_GOAL := help

VERSION := 1.1.2
SHA256SUM_MAC=$(shell sha256sum boilr-${VERSION}-darwin_amd6.tgz | cut -d' ' -f1 2>&1)
VERSION := 1.1.3
SHA256SUM_MAC=$(shell sha256sum boilr-${VERSION}-darwin_amd64.tgz | cut -d' ' -f1 2>&1)

define FORMULA
class Boilr < Formula
Expand Down Expand Up @@ -39,7 +39,7 @@ precommit-run: ## run all pre-commit hooks
build-mac: ## build the boilr executable
@go mod tidy
@go build
@tar czf boilr-${VERSION}-darwin_amd6.tgz ./boilr
@tar czf boilr-${VERSION}-darwin_amd64.tgz ./boilr
@mv boilr boilr-mac

build-linux: ## build the boilr executable
Expand Down
12 changes: 12 additions & 0 deletions boilr.rb.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class Boilr < Formula
desc "Boilerplate template manager that generates files or directories from template repositories"
homepage "https://github.com/solaegis/boilr"
url "https://github.com/solaegis/boilr/releases/download/v${VERIONS}/boilr-${VERSION}-darwin_amd64.tgz"
version "1.1.1"
sha256 "$(sha256sum boilr-mac | cut -d' ' -f1)"

def install
bin.install "boilr"
end
end

2 changes: 1 addition & 1 deletion pkg/boilr/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const (
AppName = "boilr"

// Version of the application
Version = "1.1.2"
Version = "1.1.3"

// ConfigDirPath is the configuration directory of the application
ConfigDirPath = ".config/boilr"
Expand Down
2 changes: 2 additions & 0 deletions pkg/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ func Run() {

Use.PersistentFlags().BoolP("use-defaults", "f", false, "Uses default values in project.json instead of prompting the user")
Use.PersistentFlags().StringP("log-level", "l", "error", "log-level for output")
Use.PersistentFlags().StringP("use-file", "i", "", "Json file used to get custom values")
Use.PersistentFlags().StringP("json-file", "j", "", "Json file to create using prompt inputs")
Template.AddCommand(Use)

Template.AddCommand(Validate)
Expand Down
62 changes: 62 additions & 0 deletions pkg/cmd/use.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
Expand All @@ -12,6 +13,7 @@ import (
"github.com/solaegis/boilr/pkg/template"
"github.com/solaegis/boilr/pkg/util/exit"
"github.com/solaegis/boilr/pkg/util/osutil"
"github.com/solaegis/boilr/pkg/util/templateinput"
"github.com/solaegis/boilr/pkg/util/validate"
)

Expand Down Expand Up @@ -64,6 +66,16 @@ var Use = &cli.Command{
exit.Fatal(fmt.Errorf("use: %s", err))
}

contextFile := GetStringFlag(cmd, "use-file")
if contextFile != "" {

err := tmpl.CachaedValuesFromJson(contextFile)
if err != nil {
exit.Fatal(fmt.Errorf("error reading values value frrom %s", contextFile))
}
tmpl.UseDefaultValues()
}

if shouldUseDefaults := GetBoolFlag(cmd, "use-defaults"); shouldUseDefaults {
tmpl.UseDefaultValues()
}
Expand Down Expand Up @@ -98,6 +110,56 @@ var Use = &cli.Command{
exit.Fatal(fmt.Errorf("use: %v", err))
}

// store promted inputs in a json file
jsonFile := GetStringFlag(cmd, "json-file")
if jsonFile != "" {
file, err := json.MarshalIndent(templateinput.UserInput, "", " ")
if err != nil {
exit.Fatal(fmt.Errorf("use: %v", err))
}
if err := ioutil.WriteFile(jsonFile, file, 0644); err != nil {
exit.Fatal(fmt.Errorf("use: %v", err))
}
}

if contextFile != "" {
f, err := os.Open(contextFile)
if err != nil {
if os.IsNotExist(err) {
fmt.Println("could not find ", contextFile, " Please fix the error and run the boilr again.")
exit.Fatal(fmt.Errorf("use: %v", err))
}
fmt.Println("could not read ", contextFile, " Please fix the error and run the boilr again.")
exit.Fatal(fmt.Errorf("use: %v", err))
}
defer f.Close()
buf, err := ioutil.ReadAll(f)
if err != nil {
fmt.Println("could not read ", contextFile, " Please fix the error and run the boilr again.")
exit.Fatal(fmt.Errorf("use: %v", err))
}
var contextFileJson map[string]interface{}
if err := json.Unmarshal(buf, &contextFileJson); err != nil {
fmt.Println("could not read ", contextFile, " as a Joson. Please fix the error and run the boilr again.")
exit.Fatal(fmt.Errorf("use: %v", err))
}
returnError := false
for k, _ := range templateinput.UsedKeys {
if _, ok := contextFileJson[k]; !ok {
returnError = true
fmt.Printf(`
********************************************************************************************************************
boilr used project.json value for key %s. Please define the key and value in %s
********************************************************************************************************************`,
k, contextFile)
}
}
if returnError {
fmt.Println()
exit.Fatal(fmt.Errorf("Missing values in %s, please review the file", contextFile))
}
}

exit.OK("Successfully executed the project template %v in %v", tmplName, targetDir)
},
}
22 changes: 21 additions & 1 deletion pkg/prompt/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strconv"
"strings"

"github.com/solaegis/boilr/pkg/util/templateinput"
"github.com/solaegis/boilr/pkg/util/tlog"
)

Expand Down Expand Up @@ -136,13 +137,32 @@ func New(fieldName string, defval interface{}) func() interface{} {
if err != nil {
tlog.Warn(err.Error())
}

cachedValue, err = prompt.EvaluateChoice(choice)
if err != nil {
tlog.Warn(err.Error())
}
templateinput.UserInput[fieldName] = cachedValue
}

return cachedValue
}
}

func CachedValue(value string, defval interface{}, key string) func() interface{} {
prompt := Func(defval)

var cachedValue interface{}
return func() interface{} {
if cachedValue == nil {
msg := prompt.PromptMessage(value)
tlog.Prompt(msg, defval)
var err error
cachedValue, err = prompt.EvaluateChoice(value)
if err != nil {
tlog.Warn(err.Error())
}
}
templateinput.UsedKeys[key] = cachedValue
return cachedValue
}
}
112 changes: 75 additions & 37 deletions pkg/template/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ type Interface interface {
// If used, the template will execute using default values.
UseDefaultValues()

// If used, the template will execute using CachaedValuesFromJson.
CachaedValuesFromJson(string) error

// Returns the metadata of the template.
Info() Metadata
}
Expand All @@ -38,7 +41,6 @@ func Get(path string) (Interface, error) {
if err != nil {
return nil, err
}

// TODO make context optional
ctxt, err := func(fname string) (map[string]interface{}, error) {
f, err := os.Open(fname)
Expand Down Expand Up @@ -88,71 +90,107 @@ func Get(path string) (Interface, error) {
}()

return &dirTemplate{
Context: ctxt,
FuncMap: FuncMap,
Path: filepath.Join(absPath, boilr.TemplateDirName),
Context: ctxt,
FuncMap: FuncMap,
Path: filepath.Join(absPath, boilr.TemplateDirName),

Metadata: md,
}, err
}

type dirTemplate struct {
Path string
Context map[string]interface{}
FuncMap template.FuncMap
Metadata Metadata
Path string
Context map[string]interface{}
StoredContext map[string]interface{}
FuncMap template.FuncMap
Metadata Metadata

alignment string
ShouldUseDefaults bool
}

func (t *dirTemplate) CachaedValuesFromJson(path string) error {
absPath, err := filepath.Abs(path)

if err != nil {
return err
}
fmt.Println(absPath)
// TODO make context optional
ctxt, err := func(fname string) (map[string]interface{}, error) {
f, err := os.Open(fname)
if err != nil {
if os.IsNotExist(err) {
fmt.Println("Not Found ->", fname)
return nil, nil
}
return nil, err
}
defer f.Close()
buf, err := ioutil.ReadAll(f)
if err != nil {
return nil, err
}
var metadata map[string]interface{}
if err := json.Unmarshal(buf, &metadata); err != nil {
return nil, err
}
return metadata, nil
}(absPath)
t.StoredContext = ctxt
return nil
}

func (t *dirTemplate) UseDefaultValues() {
t.ShouldUseDefaults = true
}

func (t *dirTemplate) BindPrompts() {
for s, v := range t.Context {
if m, ok := v.(map[string]interface{}); ok {
advancedMode := prompt.New(s, false)

for k, v2 := range m {
if t.ShouldUseDefaults {
t.FuncMap[k] = func() interface{} {
// load all variables from project.json and stored.json.
// order of list is importanat as we want to use variable functions from t.StoredContext
// it is importanat that all variable functions should be avaliable before template execution
// otherwise you will get an error like - panic: template: <file_name>: function "<variable>" not defined

contextList := []map[string]interface{}{t.Context, t.StoredContext}
for _, ctx := range contextList {
for s, v := range ctx {
if m, ok := v.(map[string]interface{}); ok {
advancedMode := prompt.New(s, false)

for k, v2 := range m {
if t.ShouldUseDefaults {
switch v2 := v2.(type) {
// First is the default value if it's a slice
case []interface{}:
return v2[0]
t.FuncMap[k] = prompt.CachedValue(fmt.Sprintf("%v", v2[0]), v2[0], k)
default:
t.FuncMap[k] = prompt.CachedValue(fmt.Sprintf("%v", v2), v2, k)
}
} else {
v, p := v2, prompt.New(k, v2)

return v2
}
} else {
v, p := v2, prompt.New(k, v2)
t.FuncMap[k] = func() interface{} {
if val := advancedMode().(bool); val {
return p()
}

t.FuncMap[k] = func() interface{} {
if val := advancedMode().(bool); val {
return p()
return v
}

return v
}
}
}

continue
}
continue
}

if t.ShouldUseDefaults {
t.FuncMap[s] = func() interface{} {
if t.ShouldUseDefaults {
switch v := v.(type) {
// First is the default value if it's a slice
case []interface{}:
return v[0]
t.FuncMap[s] = prompt.CachedValue(fmt.Sprintf("%v", v[0]), v[0], s)
default:
t.FuncMap[s] = prompt.CachedValue(fmt.Sprintf("%v", v), v, s)
}

return v
} else {
t.FuncMap[s] = prompt.New(s, v)
}
} else {
t.FuncMap[s] = prompt.New(s, v)
}
}
}
Expand Down
23 changes: 23 additions & 0 deletions pkg/util/templateinput/templateinput.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package templateinput

func init() {
UserInput.Init()
UsedKeys.Init()
}

type set map[string]interface{}

var UserInput set

func (s *set) Init() {
*s = make(map[string]interface{})
}

// store keys used during boilr execution
type s map[string]interface{}

var UsedKeys s

func (s *s) Init() {
*s = make(map[string]interface{})
}

0 comments on commit ead2815

Please sign in to comment.