grim/convey

Port from logrus to log/slog
default tip
5 months ago, Elliott Sales de Andrade
c588f9b3f559
Port from logrus to log/slog

This doesn't really take much advantage of structured logging beyond what is already done (`id` and `idColor`), and consequently the log handler does not try to do any handling of anything more than that (i.e., grouping, or arbitrary attributes beyond those defined).

One should maybe have a `Context` available to pass in, but there isn't one, and anyway, the log handler doesn't use it, so I've passed in a `TODO` instead.

Everything else is just normal import/rename changes.

Testing Done:
Ran `go run . run`

Reviewed at https://reviews.imfreedom.org/r/2871/
// Convey
// Copyright 2016-2018 Gary Kramlich <grim@reaperworld.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package environment
import (
"fmt"
"os"
"strings"
)
type envMapper struct {
env []string
}
const (
maxExpandWidth = 100
)
// mapVariable replaces instances of the given name.
func (e *envMapper) mapVariable(name string) string {
// We might have something like $(pwd), in which case we don't want
// to wrap the name in `{}`, which would cause it to be ${}(pwd) and
// cannot be evaluated by a run task.
if name == "" {
return "$"
}
for _, item := range e.env {
if varName, varValue, valueFound := strings.Cut(item, "="); varName == name {
if valueFound {
return varValue
}
return os.Getenv(name)
}
}
return fmt.Sprintf("${%s}", name)
}
// Map will return the value matching a KEY=VAL pair in the given environment.
func Map(key string, env []string) string {
val, _ := Mapper(key, env)
return val
}
// Mapper will replace ${TEMPLATE} patterns in the string with the KEY=VAL pairs
// in the given environment. This function will replace patterns recursively, so
// if VAL has the form ${TEMPLATE}, it will be replaced again.
func Mapper(str string, env []string) (string, error) {
mapper := envMapper{env}
orig := str
last := str
next := os.Expand(last, mapper.mapVariable)
prev := map[string]struct{}{}
for i := 0; i < maxExpandWidth; i++ {
if last == next {
return next, nil
}
if _, ok := prev[next]; ok {
break
}
last = next
next = os.Expand(last, mapper.mapVariable)
prev[last] = struct{}{}
}
return "", fmt.Errorf("infinite environment mapping loop while expanding '%s'", orig)
}
// SliceMapper calls Mapper for each item in a slice and returns a new slice.
func SliceMapper(slice, env []string) ([]string, error) {
mapped := []string{}
for _, template := range slice {
expanded, err := Mapper(template, env)
if err != nil {
return nil, err
}
mapped = append(mapped, expanded)
}
return mapped, nil
}