props

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 19, 2022 License: BSD-3-Clause Imports: 17 Imported by: 13

README

props: Go (golang) library for handling Java-style property files and app configuration

This library provides compatibility with Java property files for Go.

It also provides additional features such as property expansion, configuration by convention, and encryption for use as application configuration. The approach is similar to that of the Environment classes of Spring Boot.

Important Types

There are three main types provided:

  • Properties - read and write property files in Java format
  • Expander - replaces property references wrapped by '${}' (or other custom prefix/suffix) at runtime (as found in Ant/Log4J/JSP EL/Spring)
  • Configuration - provides easy configuration by convention, parsing of property values into Go types, and encryption support

The full Java property file format including all comment types, line continuations, key-value separators, unicode escapes, etc. is supported.

Configuration by Convention

The standard convention supported provides for profile and environment specific property files along with command line arguments and environment variables.

Properties are resolved in the following priority order:

  1. Command line arguments
  2. Environment variables
  3. <prefix>-<profile>.properties for the provided prefix and profiles values (in order)
  4. <prefix>.properties for the provided prefix value

The first matching property value found will be returned.

Custom Configuration

The types provided can be included or excluded in any order to create an alternative configuration.

  • Arguments
  • Environment
  • Expander
  • Properties

Combine multiple property source lookups with the Combined type.

Command Line Utility

A command line utility is provided in the cmd directory. This app is used to encrypt, decrypt, or re-encrypt property files or individual values.

Encryption

Encryption is handled by putting a marker prefix ([enc:x]) on encrypted values. The prefix indicates which algorithm was used for encryption and allows for different algorithms to co-exist or be upgraded at different times in the same file.

The standard approach is to update your property file with plaintext values with the [enc:0] prefix, for example:

db.password=[enc:0]$ecr3t!

Then run the encryptFile command from app in the cmd dir to convert the result into an encrypted value:

db.password=[enc:1]<base64 data>

Documentation

Overview

Package props implements handling of property lists and files. It is fully compatible with the Java property file format and also provides additional features such as property expansion, configuration by convention, and encryption for use as application configuration.

See the cmd dir for a helper application to encrypt and decrypt properties in files.

Index

Constants

View Source
const (
	// EncryptNone represents a value that has not yet been encrypted
	EncryptNone = "[enc:0]"
	// EncryptAESGCM represents a value that has been encryped with AES-GCM
	EncryptAESGCM = "[enc:1]"

	// EncryptDefault represents the default encryption algorithm
	EncryptDefault = EncryptAESGCM
)

Variables

This section is empty.

Functions

func Decrypt

func Decrypt(password string, val string) (string, error)

Decrypt returns the plaintext value of a property encrypted with the Encrypt function. If the property does not exist, then the default value will be returned with a nil error. If the property value could not be decrypted, then an error and the default value will be returned.

func Encrypt

func Encrypt(alg, password, value string) (string, error)

Encrypt returns the value encrypted with the provided algorithm in base64 format. If encryption fails, an empty string and error are returned.

Types

type Arguments

type Arguments struct {
	// Prefix provides the common prefix to use when looking for property
	// arguments. If not set, the default of '--' will be used.
	Prefix string
}

Arguments reads properties from the command line arguments. Property arguments are expected to have a common prefix and use key=value format. Other arguments are ignored.

For example, the command:

cmd -a -1 -z --prop.1=a --prop.2=b --prop.3 --log=debug

with a prefix of '--prop.' would have properties "1"="a", "2"="b", and "3"="".

func (*Arguments) Get

func (a *Arguments) Get(key string) (string, bool)

Get retrieves the value of a property from the command line arguments. If the property does not exist, an empty string will be returned. The bool return value indicates whether the property was found.

func (*Arguments) GetDefault

func (e *Arguments) GetDefault(key, defVal string) string

GetDefault retrieves the value of a property from the command line arguments. If the property does not exist, then the default value will be returned.

type Combined

type Combined struct {
	// The property sources to use for lookup in priority order. The first
	// source to have a value for a property will be used.
	Sources []PropertyGetter
}

Combined provides property value lookups across multiple sources.

func (*Combined) Get

func (c *Combined) Get(key string) (string, bool)

Get retrieves the value of a property from the source list. If the source list is empty or none of the sources has the property, an empty string will be returned. The bool return value indicates whether the property was found.

func (*Combined) GetDefault

func (c *Combined) GetDefault(key string, defVal string) string

GetDefault retrieves the value of a property from the source list. If the source list is empty or none of the sources has the property, then the default value will be returned.

type Configuration

type Configuration struct {
	// Props provides the configuration values to retrieve and/or parse.
	Props PropertyGetter

	// DateFormat provides the format string to use when parsing dates as
	// defined in the time package. If blank, the default 2006-01-02 is used.
	DateFormat string
	// StrictBool determines whether bool parsing is strict or not. When true,
	// only "true" and "false" values are considered valid. When false,
	// additional "boolean-like" values are accepted such as 0 and 1. See
	// ParseBool for details.
	StrictBool bool
}

Configuration represents an application's configuration parameters provided by properties.

It can be created directly or through NewConfiguration which provides configuration by convention.

func NewConfiguration

func NewConfiguration(fileSys fs.StatFS, prefix string, profiles ...string) (*Configuration, error)

NewConfiguration creates a Configuration using common conventions.

The returned Configuration uses an Expander to return properties in the following priority order:

  1. Command line arguments
  2. Environment variables
  3. <prefix>-<profile>.properties for the provided prefix and profiles values (in order)
  4. <prefix>.properties for the provided prefix value

The first matching property value found will be returned.

An error will be returned if one of the property files could not be read or parsed.

func (*Configuration) Decrypt

func (c *Configuration) Decrypt(password string, key string, defVal string) (string, error)

Decrypt returns the plaintext value of a property encrypted with the Encrypt function. If the property does not exist, then the default value will be returned with a nil error. If the property value could not be decrypted, then an error and the default value will be returned.

func (*Configuration) Get

func (c *Configuration) Get(key string) (string, bool)

Get retrieves the value of a property. If the property does not exist, an empty string will be returned. The bool return value indicates whether the property was found.

func (*Configuration) GetDefault

func (c *Configuration) GetDefault(key, defVal string) string

GetDefault retrieves the value of a property. If the property does not exist, then the default value will be returned.

func (*Configuration) ParseBool

func (c *Configuration) ParseBool(key string, defVal bool) (bool, error)

ParseBool converts a property value to a bool. If the property does not exist, then the default value will be returned with a nil error. If the property value could not be parsed, then an error and the default value will be returned.

If the StrictBool setting is true, then only "true" and "false" values are able to be converted.

If StrictBool is false (the default), then the following values are converted:

true, t, yes, y, 1, on -> true
false, f, no, n, 0, off -> false

func (*Configuration) ParseByteSize

func (c *Configuration) ParseByteSize(key string, defVal uint64) (uint64, error)

ParseByteSize converts a property value in byte size format to uint64. If the property does not exist, then the default value will be returned with a nil error. If the property value could not be parsed, then an error and the default value will be returned.

The format supported is "<num> <suffix>" where <num> is a numeric value (whole number or decimal) and <suffix> is a byte size unit as listed below. The <suffix> and space between <num> and <suffix> are optional.

The supported suffixes are: (none) - not modified (x 1) k - kilobytes (x 1000) Ki - kibibytes (x 1024) M - megabyte (x 1000^2) Mi - mebibyte (x 1024^2) G - gigabyte (x 1000^3) Gi - gibibyte (x 1024^3) T - terabyte (x 1000^4) Ti - tebibyte (x 1024^4) P - petabyte (x 1000^5) Pi - pebibyte (x 1024^5) E - exabyte (x 1000^6) Ei - exbibyte (x 1024^6)

func (*Configuration) ParseDate

func (c *Configuration) ParseDate(key string, defVal time.Time) (time.Time, error)

ParseDate converts a property value to a Time. If the property does not exist, then the default value will be returned with a nil error. If the property value could not be parsed, then an error and the default value will be returned.

The format used is provided by the DateFormat setting and follows the format defined in time.Layout. If none is set, the default of 2006-01-02 is used.

func (*Configuration) ParseDuration

func (c *Configuration) ParseDuration(key string, defVal time.Duration) (time.Duration, error)

ParseDuration converts a property value to a Duration. If the property does not exist, then the default value will be returned with a nil error. If the property value could not be parsed, then an error and the default value will be returned.

The format used is the same as time.ParseDuration.

func (*Configuration) ParseFloat

func (c *Configuration) ParseFloat(key string, defVal float64) (float64, error)

ParseFloat converts a property value to a float64. If the property does not exist, then the default value will be returned with a nil error. If the property value could not be parsed, then an error and the default value will be returned.

func (*Configuration) ParseInt

func (c *Configuration) ParseInt(key string, defVal int) (int, error)

ParseInt converts a property value to an int. If the property does not exist, then the default value will be returned with a nil error. If the property value could not be parsed, then an error and the default value will be returned.

func (*Configuration) ParseSize

func (c *Configuration) ParseSize(key string, defVal float64) (float64, error)

ParseSize converts a property value with a metric size suffix to float64. If the property does not exist, then the default value will be returned with a nil error. If the property value could not be parsed, then an error and the default value will be returned.

The format supported is "<num> <suffix>" where <num> is a numeric value (whole number or decimal) and <suffix> is a size unit as listed below. The <suffix> and the space between <num> and <suffix> are optional.

The supported suffixes are: Y - yotta (10^24) Z - zetta (10^21) E - exa (10^18) P - peta (10^15) T - tera (10^12) G - giga (10^9) M - mega (10^6) k - kilo (10^3) h - hecto (10^2) da - deca (10^1) (none) - not modified (x 1) d - deci (10^-1) c - centi (10^-2) m - milli (10^-3) u - micro (10^-6) n - nano (10^-9) p - pico (10^-12) f - femto (10^-15) a - atto (10^-18) z - zepto (10^-21) y - yocto (10^-23)

type Environment

type Environment struct {
	// Normalize indicates that key values should be converted to POSIX-style
	// environment variable names.
	//
	// If true, key values passed to Get and GetDefault will be converted to:
	// - Uppercase
	// - Alphanumeric (as per ASCII)
	// - All non-alphanumeric characters replaced with underscore '_'
	//
	// For example, 'foo.bar.baz' would become 'FOO_BAR_BAZ' and
	// '$my-test#val_1' would become '_MY_TEST_VAL_1'.
	Normalize bool
}

Environment reads properties from the OS environment.

func (*Environment) Get

func (e *Environment) Get(key string) (string, bool)

Get retrieves the value of a property from the environment. If the env var does not exist, an empty string will be returned. The bool return value indicates whether the property was found.

func (*Environment) GetDefault

func (e *Environment) GetDefault(key, defVal string) string

GetDefault retrieves the value of a property from the environment. If the env var does not exist, then the default value will be returned.

type Expander

type Expander struct {
	// Prefix indicates the start of a property expansion.
	Prefix string
	// Suffix indicates the end of a property expansion.
	Suffix string
	// Limit the nesting depth; <= 0 allows for unlimited nesting
	Limit int
	// Source provides the properties to use for expansion
	Source PropertyGetter
}

Expander represents a property set that interprets special character sequences in property values as references to other property values for replacement.

For example, the following properties:

color.alert = red
color.info = blue
color.text = black

css.alert = border: 1px solid ${color.alert}; color: ${color.text};
css.info = border: 1px solid ${color.info}; color: ${color.text};

Would result in the following values:

"css.alert": "border: 1px solid red; color: black;"
"css.info":  "border: 1px solid blue; color: black;"

Nested and recursive property expansions are permitted. If a property value does not exist, the property reference will be left unchanged.

func NewExpander

func NewExpander(source PropertyGetter) *Expander

NewExpander creates an empty property set with the default expansion Prefix "${" and Suffix "}".

func (*Expander) Get

func (e *Expander) Get(key string) (string, bool)

Get retrieves the value of a property with all property references expanded. If the property does not exist, an empty string will be returned. The bool return value indicates whether the property was found.

func (*Expander) GetDefault

func (e *Expander) GetDefault(key, defVal string) string

GetDefault retrieves the value of a property with all property references expanded. If the property does not exist, the default value will be returned with all its property references expanded.

type Properties

type Properties struct {
	// contains filtered or unexported fields
}

Properties represents a set of key-value pairs.

func NewProperties

func NewProperties() *Properties

NewProperties creates a new, empty property set.

func Read

func Read(r io.Reader) (*Properties, error)

Read creates a new property set and fills it with the contents of a file. See Load for the supported file format.

func (*Properties) Clear

func (p *Properties) Clear()

Clear removes all key-value pairs.

func (*Properties) Get

func (p *Properties) Get(key string) (string, bool)

Get retrieves the value of a property. If the property does not exist, an empty string will be returned.

func (*Properties) GetDefault

func (p *Properties) GetDefault(key, defVal string) string

GetDefault retrieves the value of a property. If the property does not exist, then the default value will be returned.

func (*Properties) Load

func (p *Properties) Load(r io.Reader) error

Load reads the contents of a property file. Existing properties will be retained. The contents of the file will override any existing properties with matching keys.

File Format

The supported property file format follows the Java conventions. Each line of the file represents a key-value pair. Keys and values may be separated by '=', ':', or whitespace. Comments are indicated by a leading '#' or '!' character.

Encoding

Java property files require an ISO 8859-1 encoding, but this package will also accept files encoded in UTF-8.

Escapes

The escape character is '\'; valid escapes are '\f', '\n', '\r', '\t', and UTF-16 escapes in the format "\uXXXX" where each "X" is a hexadecimal digit. Invalid escapes are replaced with the escaped character only, so '\A' will result in 'A'. (This is useful for escaping the key separator or comment characters.) Invalid UTF-16 escapes will be replaced with the Unicode replacement character U+FFFD.

Spanning Lines

To create a key or value that spans multiple lines, end the line with '\' followed by a newline. All leading whitespace on the next line will be ignored and not included in the key or value, allowing for indentation of continued lines.

Sample File

This is a sample property file:

# env.properties
! for dev environment
site.url = http://localhost:8180/

# database
db.host:localhost
db.port:5432
db.user:devdb

# email
email.from dev@example.com
email.to   me@example.org

email.welcome  Subject: Welcome! \
			  Thank you. Now: \
			  \t Feat 1 \
			  \t Feat 2 \
			  Enjoy!

# reporting
rpt\ newline=\u000a
rpt\ list\ bullet=\u2022

Loading this file would result in the following properties:

"site.url":        "http://localhost:8180/"
"db.host":         "localhost"
"db.port":         "5432"
"db.user":         "devdb"
"email.from":      "dev@example.com"
"email.to":        "me@example.org"
"email.welcome":   "Subject: Welcome! \nThank you. Now: \n\tFeat 1 \n..."
"rpt newline":     "\n"
"rpt list bullet": "•"

func (*Properties) Names

func (p *Properties) Names() []string

Names returns the keys for all properties in the set.

func (*Properties) Set

func (p *Properties) Set(key, val string)

Set adds or changes the value of a property.

func (*Properties) Write

func (p *Properties) Write(w io.Writer) error

Write saves the property set to a file. The output will be in "key=value" format, with appropriate characters escaped. See Load for more details on the file format.

Note: if the property set was loaded from a file, the formatting and comments from the original file will not be retained in the output file.

type PropertyGetter

type PropertyGetter interface {
	// Get retrieves the value of a property. If the property does not exist, an
	// empty string will be returned. The bool return value indicates whether
	// the property was found.
	Get(key string) (string, bool)

	// GetDefault retrieves the value of a property. If the property does not
	// exist, then the default value will be returned.
	GetDefault(key, defVal string) string
}

PropertyGetter represents a source for looking up property values.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL