Skip to content

Commit

Permalink
Added support for file-inclusion.
Browse files Browse the repository at this point in the history
This allows three forms of file-inclusion:

* Literal/Complete file inclusion.
* Include lines from a file that match a regexp.
* Include lines between two regular expressions.

This closes #17
  • Loading branch information
skx committed Jun 29, 2020
1 parent a0689d4 commit fa79495
Showing 1 changed file with 111 additions and 7 deletions.
118 changes: 111 additions & 7 deletions cmd_env_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"io/ioutil"
"os"
"regexp"
"strings"
"text/template"

Expand All @@ -24,11 +25,15 @@ func (et *envTemplateCommand) Info() (string, string) {
Details:
This command is a slight reworking of the standard 'envsubst' command,
which might not be available upon systems by default.
which might not be available upon systems by default, along with extra
support for file-inclusion (which supports the inclusion of other files,
along with extra behavior such as 'grep' and inserting regions of files
between matches of a start/end pair of regular expressions).
The intention is that you can substitute environmental variables into
simple (golang) template-files.
The basic use-case of this sub-command is to allow substituting
environmental variables into simple (golang) template-files.
However there are extra facilities, as noted above.
Examples:
Expand All @@ -51,18 +56,38 @@ and process variables. For example splitting $PATH into parts:
{{$k}} {{$v}}
{{end}}
Inclusion Examples:
The basic case of including a file could be handled like so:
Before
{{include "/etc/passwd"}}
After
You can also include only lines matching a particular regular
expression:
{{grep "/etc/passwd" "^(root|nobody):"}}
Or lines between a pair of marker (regular expressions):
{{between "/etc/passwd" "^root" "^bin"}}
NOTE: Using 'between' includes the lines that match too, not just the region
between them. If you regard this as a bug please file an issue.
`

}

// Execute is invoked if the user specifies `with-lock` as the subcommand.
// Execute is invoked if the user specifies `env-template` as the subcommand.
func (et *envTemplateCommand) Execute(args []string) int {

//
// Ensure we have an argument
//
if len(args) < 1 {
fmt.Printf("You must specify the template to expand\n")
fmt.Printf("You must specify the template to expand.\n")
return 1
}

Expand All @@ -88,13 +113,92 @@ func (et *envTemplateCommand) expandFile(path string) error {
}

//
// Define a helper-function that users can call to get
// the variables they've set.
// Define a helper-function that are available within the
// templates we process.
//
funcMap := template.FuncMap{
"between": func(in string, begin string, end string) string {

// Read the named file.
dat, err := ioutil.ReadFile(in)

if err != nil {
return fmt.Sprintf("error reading %s: %s", in, err.Error())
}

// temporary holder
res := []string{}

// found the open?
var found bool

// for each line
for _, line := range strings.Split(string(dat), "\n") {

// in the section we care about?
matched, err := regexp.MatchString(begin, line)
if err != nil {
return fmt.Sprintf("error matching %s: %s", begin, err.Error())
}

// if we matched add the line
if matched || found {
res = append(res, line)
}

// if we matched, or we're in a match
// then skip
if matched {
found = true
continue
}

// are we closing a match?
if found {
matched, err := regexp.MatchString(end, line)
if err != nil {
return fmt.Sprintf("error matching %s: %s", end, err.Error())
}

if matched {
found = false
}
}
}
return strings.Join(res, "\n")

},
"env": func(s string) string {
return (os.Getenv(s))
},
"grep": func(in string, pattern string) string {

dat, err := ioutil.ReadFile(in)

if err != nil {
return fmt.Sprintf("error reading %s: %s", in, err.Error())
}

res := []string{}
for _, line := range strings.Split(string(dat), "\n") {
matched, err := regexp.MatchString(pattern, line)
if err != nil {
return fmt.Sprintf("error matching %s: %s", pattern, err.Error())
}
if matched {
res = append(res, line)
}
}
return strings.Join(res, "\n")

},
"include": func(in string) string {
dat, err := ioutil.ReadFile(in)
if err != nil {
return fmt.Sprintf("error reading %s: %s", in, err.Error())
}
return (string(dat))
},
"split": func(in string, delim string) []string {
return strings.Split(in, delim)
},
Expand Down

0 comments on commit fa79495

Please sign in to comment.