<commit_before>package config

import (
	"flag"
	"fmt"
	"gnd.la/form/input"
	"gnd.la/log"
	"gnd.la/signal"
	"gnd.la/util"
	"gnd.la/util/textutil"
	"gnd.la/util/types"
	"io"
	"os"
	"reflect"
	"strconv"
	"strings"
)

const DefaultName = "app.conf"

var (
	defaultFilename = util.RelativePath(DefaultName)
	configName      *string
)

type fieldValue struct {
	Value reflect.Value
	Tag   reflect.StructTag
}

type fieldMap map[string]*fieldValue

func (f fieldMap) Append(name string, value reflect.Value, tag reflect.StructTag) error {
	if _, ok := f[name]; ok {
		return fmt.Errorf("duplicate field name %q", name)
	}
	f[name] = &fieldValue{value, tag}
	return nil
}

type varMap map[string]interface{}

// SetDefaultFilename changes the default filename used by Parse().
func SetDefaultFilename(name string) {
	defaultFilename = name
}

// DefaultFilename returns the default config filename used by Parse().
// It might changed by calling SetDefaultFilename() or overriden using
// the -config command line flag (the latter, of present, takes precendence).
// The initial value is app.conf in the same directory as the application
// binary.
func DefaultFilename() string {
	return defaultFilename
}

// Filename returns the filename used by Parse(). If the -config command
// line flag was provided, it returns its value. Otherwise, it returns
// DefaultFilename().
func Filename() string {
	if configName == nil || *configName == "" {
		return defaultFilename
	}
	return *configName
}

func fileParameterName(name string) string {
	return util.CamelCaseToLower(name, "_")
}

func flagParameterName(name string) string {
	return util.CamelCaseToLower(name, "-")
}

func parseValue(v reflect.Value, raw string) error {
	switch v.Type().Kind() {
	case reflect.Bool:
		value, err := strconv.ParseBool(raw)
		if err != nil {
			return err
		}
		v.SetBool(value)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		value, err := strconv.ParseInt(raw, 10, 64)
		if err != nil {
			return err
		}
		v.SetInt(int64(value))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		value, err := strconv.ParseUint(raw, 10, 64)
		if err != nil {
			return err
		}
		v.SetUint(uint64(value))
	case reflect.Float32, reflect.Float64:
		value, err := strconv.ParseFloat(raw, 64)
		if err != nil {
			return err
		}
		v.SetFloat(value)
	case reflect.String:
		v.SetString(raw)
	case reflect.Slice:
		fields, err := textutil.SplitFields(raw, ",")
		if err != nil {
			return fmt.Errorf("error splitting values: %s", err)
		}
		count := len(fields)
		v.Set(reflect.MakeSlice(v.Type(), count, count))
		for ii, f := range fields {
			if err := input.Parse(f, v.Index(ii).Addr().Interface()); err != nil {
				return fmt.Errorf("error parsing field at index %d: %s", ii, err)
			}
		}
	case reflect.Map:
		fields, err := textutil.SplitFields(raw, ",")
		if err != nil {
			return fmt.Errorf("error splitting values: %s", err)
		}
		v.Set(reflect.MakeMap(v.Type()))
		ktyp := v.Type().Key()
		etyp := v.Type().Elem()
		for ii, field := range fields {
			subFields, err := textutil.SplitFields(field, "=")
			if err != nil {
				return fmt.Errorf("error splitting key-value %q: %s", field, err)
			}
			k := reflect.New(ktyp)
			if err := input.Parse(subFields[0], k.Interface()); err != nil {
				return fmt.Errorf("error parsing key at index %d: %s", ii, err)
			}
			elem := reflect.New(etyp)
			if len(subFields) > 0 {
				if err := input.Parse(subFields[1], elem.Interface()); err != nil {
					return fmt.Errorf("error parsing value at index %d: %s", ii, err)
				}
			}
			v.SetMapIndex(k.Elem(), elem.Elem())<commit_msg>Return an error when a map field is missing the = symbol<commit_after>package config

import (
	"flag"
	"fmt"
	"gnd.la/form/input"
	"gnd.la/log"
	"gnd.la/signal"
	"gnd.la/util"
	"gnd.la/util/textutil"
	"gnd.la/util/types"
	"io"
	"os"
	"reflect"
	"strconv"
	"strings"
)

const DefaultName = "app.conf"

var (
	defaultFilename = util.RelativePath(DefaultName)
	configName      *string
)

type fieldValue struct {
	Value reflect.Value
	Tag   reflect.StructTag
}

type fieldMap map[string]*fieldValue

func (f fieldMap) Append(name string, value reflect.Value, tag reflect.StructTag) error {
	if _, ok := f[name]; ok {
		return fmt.Errorf("duplicate field name %q", name)
	}
	f[name] = &fieldValue{value, tag}
	return nil
}

type varMap map[string]interface{}

// SetDefaultFilename changes the default filename used by Parse().
func SetDefaultFilename(name string) {
	defaultFilename = name
}

// DefaultFilename returns the default config filename used by Parse().
// It might changed by calling SetDefaultFilename() or overriden using
// the -config command line flag (the latter, of present, takes precendence).
// The initial value is app.conf in the same directory as the application
// binary.
func DefaultFilename() string {
	return defaultFilename
}

// Filename returns the filename used by Parse(). If the -config command
// line flag was provided, it returns its value. Otherwise, it returns
// DefaultFilename().
func Filename() string {
	if configName == nil || *configName == "" {
		return defaultFilename
	}
	return *configName
}

func fileParameterName(name string) string {
	return util.CamelCaseToLower(name, "_")
}

func flagParameterName(name string) string {
	return util.CamelCaseToLower(name, "-")
}

func parseValue(v reflect.Value, raw string) error {
	switch v.Type().Kind() {
	case reflect.Bool:
		value, err := strconv.ParseBool(raw)
		if err != nil {
			return err
		}
		v.SetBool(value)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		value, err := strconv.ParseInt(raw, 10, 64)
		if err != nil {
			return err
		}
		v.SetInt(int64(value))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		value, err := strconv.ParseUint(raw, 10, 64)
		if err != nil {
			return err
		}
		v.SetUint(uint64(value))
	case reflect.Float32, reflect.Float64:
		value, err := strconv.ParseFloat(raw, 64)
		if err != nil {
			return err
		}
		v.SetFloat(value)
	case reflect.String:
		v.SetString(raw)
	case reflect.Slice:
		fields, err := textutil.SplitFields(raw, ",")
		if err != nil {
			return fmt.Errorf("error splitting values: %s", err)
		}
		count := len(fields)
		v.Set(reflect.MakeSlice(v.Type(), count, count))
		for ii, f := range fields {
			if err := input.Parse(f, v.Index(ii).Addr().Interface()); err != nil {
				return fmt.Errorf("error parsing field at index %d: %s", ii, err)
			}
		}
	case reflect.Map:
		fields, err := textutil.SplitFields(raw, ",")
		if err != nil {
			return fmt.Errorf("error splitting values: %s", err)
		}
		v.Set(reflect.MakeMap(v.Type()))
		ktyp := v.Type().Key()
		etyp := v.Type().Elem()
		for ii, field := range fields {
			subFields, err := textutil.SplitFields(field, "=")
			if err != nil {
				return fmt.Errorf("error splitting key-value %q: %s", field, err)
			}
			k := reflect.New(ktyp)
			if err := input.Parse(subFields[0], k.Interface()); err != nil {
				return fmt.Errorf("error parsing key at index %d: %s", ii, err)
			}
			elem := reflect.New(etyp)
			if len(subFields) < 2 {
				return fmt.Errorf("invalid map field %q", field)
			}
			if err := input.Parse(subFields[1], elem.Interface()); err != nil {
				return fmt.Errorf("error parsing value at index %d: %s", ii, err)
			}
			v.SetMapIndex(k.Elem(), elem.Elem())
{'fraction_non_alphanumeric': 0.14206766410567462, 'fraction_numerical': 0.009435233859010649, 'mean_word_length': 3.7503201024327786, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7411951', 'n_tokens_mistral': 2729, 'n_tokens_neox': 2506, 'n_words': 727}