Rename packages
This commit is contained in:
parent
49b8760527
commit
ef1243ea39
47 changed files with 524 additions and 369 deletions
117
pkg/envreader/envreader.go
Normal file
117
pkg/envreader/envreader.go
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// Package envreader
|
||||
package envreader
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Scanner is a scanner for environment files.
|
||||
// To create a new scanner use [NewScanner].
|
||||
//
|
||||
// It scans through a reader and reads environment variables from it.
|
||||
// Reads may be internally buffered.
|
||||
//
|
||||
// An environment variable is of the form:
|
||||
// KEY=VALUE
|
||||
// on a separate line.
|
||||
// Keys and values are case-sensitive and may contain anything except for newline characters.
|
||||
// Spaces around key and value are trimmed using [strings.TrimSpace].
|
||||
// Keys may not contain an '='.
|
||||
// Lines not containing a '=' (e.g. blank lines) and those starting with '#' and '//' are ignored.
|
||||
//
|
||||
// To advance the scanner to the next key, value pair use [Scan].
|
||||
// To get the current (key, value) pair, use [Data].
|
||||
//
|
||||
// A typical use-case of a scanner is as follows:
|
||||
//
|
||||
// scanner := NewScanner(r)
|
||||
// for scanner.Scan() {
|
||||
// // process any data ....
|
||||
// fmt.Println(scanner.Data())
|
||||
// }
|
||||
// if err := scanner.Err(); err != nil {
|
||||
// // handle errors
|
||||
// }
|
||||
//
|
||||
// For the common use case of reading a set of distinct keys from a file see [ReadAll].
|
||||
type Scanner struct {
|
||||
s *bufio.Scanner
|
||||
|
||||
// current key and value
|
||||
key string
|
||||
value string
|
||||
}
|
||||
|
||||
// NewScanner creates a new scanner from the underlying Reader
|
||||
func NewScanner(r io.Reader) *Scanner {
|
||||
return &Scanner{
|
||||
s: bufio.NewScanner(r),
|
||||
}
|
||||
}
|
||||
|
||||
// Scanner advances the scanner until the next KEY=VALUE pair.
|
||||
//
|
||||
// If there are no more values left (e.g. the underlying reader returned io.EOF)
|
||||
// or when an unexpected error occured, returns false.
|
||||
//
|
||||
// A caller should always check Err() to see if there was an error.
|
||||
func (scanner *Scanner) Scan() bool {
|
||||
var found bool
|
||||
for scanner.s.Scan() {
|
||||
// check that we don't have an empty or comment only line
|
||||
tokens := strings.TrimSpace(scanner.s.Text())
|
||||
if len(tokens) == 0 || tokens[0] == '#' || strings.HasPrefix(tokens, "//") {
|
||||
continue
|
||||
}
|
||||
|
||||
// check that we have a 'key=value' pair
|
||||
scanner.key, scanner.value, found = strings.Cut(tokens, "=")
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
// got a key = value
|
||||
scanner.key = strings.TrimSpace(scanner.key)
|
||||
scanner.value = strings.TrimSpace(scanner.value)
|
||||
return true
|
||||
}
|
||||
|
||||
// nothing found
|
||||
scanner.key = ""
|
||||
scanner.value = ""
|
||||
return false
|
||||
}
|
||||
|
||||
// Data reads the current value from the scanner.
|
||||
// When Scan() has not been called, or returned false, returns two empty strings.
|
||||
func (scanner Scanner) Data() (key, value string) {
|
||||
return scanner.key, scanner.value
|
||||
}
|
||||
|
||||
// Err returns any error that occured on the underlying read.
|
||||
//
|
||||
// When no error occured, or the underlying read is io.EOF, returns nil.
|
||||
func (scanner Scanner) Err() error {
|
||||
return scanner.s.Err()
|
||||
}
|
||||
|
||||
// ReadAll creates a new [Scanner], and then reads all key/value pairs from r.
|
||||
// If a key occurs more than once, only the last value is set in the returned map.
|
||||
func ReadAll(r io.Reader) (values map[string]string, err error) {
|
||||
scanner := NewScanner(r)
|
||||
|
||||
// read and store all values
|
||||
values = make(map[string]string)
|
||||
for scanner.Scan() {
|
||||
key, value := scanner.Data()
|
||||
values[key] = value
|
||||
}
|
||||
|
||||
// check if there was an error!
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
42
pkg/envreader/envreader_test.go
Normal file
42
pkg/envreader/envreader_test.go
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Package envreader
|
||||
package envreader
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ExampleNewScanner() {
|
||||
scanner := NewScanner(strings.NewReader(`
|
||||
lines without an equal sign are ignored
|
||||
|
||||
// this line is a comment, even with an = sign
|
||||
KEY=VALUE
|
||||
|
||||
# this is also a comment =
|
||||
spaces in keys = spaces in values
|
||||
multiple=equal=signs
|
||||
CaSe = SenSitiVe
|
||||
empty value=
|
||||
=empty key
|
||||
`))
|
||||
|
||||
for scanner.Scan() {
|
||||
key, value := scanner.Data()
|
||||
fmt.Printf("%q %q\n", key, value)
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
fmt.Println(scanner.Err())
|
||||
} else {
|
||||
fmt.Println("no error")
|
||||
}
|
||||
|
||||
// Output: "KEY" "VALUE"
|
||||
// "spaces in keys" "spaces in values"
|
||||
// "multiple" "equal=signs"
|
||||
// "CaSe" "SenSitiVe"
|
||||
// "empty value" ""
|
||||
// "" "empty key"
|
||||
// no error
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue