193 lines
4.5 KiB
Go
193 lines
4.5 KiB
Go
package gluaenv
|
|
|
|
import (
|
|
"github.com/yuin/gopher-lua"
|
|
"os"
|
|
"bufio"
|
|
"strings"
|
|
"errors"
|
|
)
|
|
|
|
func Loader(L *lua.LState) int {
|
|
tb := L.NewTable()
|
|
L.SetFuncs(tb, map[string]lua.LGFunction{
|
|
"set": envSet,
|
|
"get": envGet,
|
|
"loadfile": envLoadFile,
|
|
})
|
|
L.Push(tb)
|
|
|
|
return 1
|
|
}
|
|
|
|
func envSet(L *lua.LState) int {
|
|
// same github.com/yuin/gopher-lua/oslib.go
|
|
err := os.Setenv(L.CheckString(1), L.CheckString(2))
|
|
if err != nil {
|
|
L.Push(lua.LNil)
|
|
L.Push(lua.LString(err.Error()))
|
|
return 2
|
|
} else {
|
|
L.Push(lua.LTrue)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
func envGet(L *lua.LState) int {
|
|
// same github.com/yuin/gopher-lua/oslib.go
|
|
v := os.Getenv(L.CheckString(1))
|
|
if len(v) == 0 {
|
|
L.Push(lua.LNil)
|
|
} else {
|
|
L.Push(lua.LString(v))
|
|
}
|
|
return 1
|
|
}
|
|
|
|
func envLoadFile(L *lua.LState) int {
|
|
if err := loadFile(L.CheckString(1)); err != nil {
|
|
L.Push(lua.LNil)
|
|
L.Push(lua.LString(err.Error()))
|
|
return 2
|
|
} else {
|
|
L.Push(lua.LTrue)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
// loadFile' s code is highly inspired by https://github.com/joho/godotenv/blob/master/godotenv.go
|
|
//Copyright (c) 2013 John Barton
|
|
//
|
|
//MIT License
|
|
//
|
|
//Permission is hereby granted, free of charge, to any person obtaining
|
|
//a copy of this software and associated documentation files (the
|
|
//"Software"), to deal in the Software without restriction, including
|
|
//without limitation the rights to use, copy, modify, merge, publish,
|
|
//distribute, sublicense, and/or sell copies of the Software, and to
|
|
//permit persons to whom the Software is furnished to do so, subject to
|
|
//the following conditions:
|
|
//
|
|
//The above copyright notice and this permission notice shall be
|
|
//included in all copies or substantial portions of the Software.
|
|
//
|
|
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
//MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
//NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
//LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
//OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
//WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
func loadFile(filename string) error {
|
|
envMap, err := readFile(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for key, value := range envMap {
|
|
os.Setenv(key, value)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func readFile(filename string) (envMap map[string]string, err error) {
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
envMap = make(map[string]string)
|
|
|
|
var lines []string
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
lines = append(lines, scanner.Text())
|
|
}
|
|
|
|
for _, fullLine := range lines {
|
|
if !isIgnoredLine(fullLine) {
|
|
key, value, err := parseLine(fullLine)
|
|
|
|
if err == nil {
|
|
envMap[key] = value
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func parseLine(line string) (key string, value string, err error) {
|
|
if len(line) == 0 {
|
|
err = errors.New("zero length string")
|
|
return
|
|
}
|
|
|
|
// ditch the comments (but keep quoted hashes)
|
|
if strings.Contains(line, "#") {
|
|
segmentsBetweenHashes := strings.Split(line, "#")
|
|
quotesAreOpen := false
|
|
var segmentsToKeep []string
|
|
for _, segment := range segmentsBetweenHashes {
|
|
if strings.Count(segment, "\"") == 1 || strings.Count(segment, "'") == 1 {
|
|
if quotesAreOpen {
|
|
quotesAreOpen = false
|
|
segmentsToKeep = append(segmentsToKeep, segment)
|
|
} else {
|
|
quotesAreOpen = true
|
|
}
|
|
}
|
|
|
|
if len(segmentsToKeep) == 0 || quotesAreOpen {
|
|
segmentsToKeep = append(segmentsToKeep, segment)
|
|
}
|
|
}
|
|
|
|
line = strings.Join(segmentsToKeep, "#")
|
|
}
|
|
|
|
// now split key from value
|
|
splitString := strings.SplitN(line, "=", 2)
|
|
|
|
if len(splitString) != 2 {
|
|
// try yaml mode!
|
|
splitString = strings.SplitN(line, ":", 2)
|
|
}
|
|
|
|
if len(splitString) != 2 {
|
|
err = errors.New("Can't separate key from value")
|
|
return
|
|
}
|
|
|
|
// Parse the key
|
|
key = splitString[0]
|
|
if strings.HasPrefix(key, "export") {
|
|
key = strings.TrimPrefix(key, "export")
|
|
}
|
|
key = strings.Trim(key, " ")
|
|
|
|
// Parse the value
|
|
value = splitString[1]
|
|
// trim
|
|
value = strings.Trim(value, " ")
|
|
|
|
// check if we've got quoted values
|
|
if strings.Count(value, "\"") == 2 || strings.Count(value, "'") == 2 {
|
|
// pull the quotes off the edges
|
|
value = strings.Trim(value, "\"'")
|
|
|
|
// expand quotes
|
|
value = strings.Replace(value, "\\\"", "\"", -1)
|
|
// expand newlines
|
|
value = strings.Replace(value, "\\n", "\n", -1)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func isIgnoredLine(line string) bool {
|
|
trimmedLine := strings.Trim(line, " \n\t")
|
|
return len(trimmedLine) == 0 || strings.HasPrefix(trimmedLine, "#")
|
|
} |