<commit_before>package narcissus

import (
	"fmt"
	"reflect"
	"strings"
)

// Write writes a structure pointer to the Augeas tree
func (n *Narcissus) Write(val interface{}) error {
	ref, err := structRef(val)
	if err != nil {
		return fmt.Errorf("invalid interface: %v", err)
	}

	path, err := getPath(ref)
	if err != nil {
		return fmt.Errorf("undefined path: %v", err)
	}

	return n.writeStruct(ref, path)
}

func (n *Narcissus) writeStruct(ref reflect.Value, path string) error {
	refType := ref.Type()
	for i := 0; i < refType.NumField(); i++ {
		if refType.Field(i).Name == "augeasPath" {
			// Ignore the special `augeasPath` field
			continue
		}
		err := n.writeField(ref.Field(i), refType.Field(i), path)
		if err != nil {
			return fmt.Errorf("failed to write field %s: %v", refType.Field(i).Name, err)
		}
	}

	return nil
}

func (n *Narcissus) writeField(field reflect.Value, fieldType reflect.StructField, path string) error {
	fieldPath := fmt.Sprintf("%s/%s", path, fieldType.Tag.Get("path"))
	if field.Kind() == reflect.Slice {
		return n.writeSliceField(field, fieldType, path, fieldPath)
	} else if field.Kind() == reflect.Map {
		return n.writeMapField(field, fieldType, path, fieldPath)
	}
	return n.writeSimpleField(field, fieldPath, fieldType.Tag)
}

func (n *Narcissus) writeSimpleField(field reflect.Value, fieldPath string, tag reflect.StructTag) error {
	aug := n.Augeas
	// There might be a better way to convert, but that does it
	value := fmt.Sprintf("%v", field.Interface())

	if tag.Get("value-from") == "label" {
		return nil
	}

	// FIXME: use omitempty for that
	if value == "" {
		return nil
	}

	err := aug.Set(fieldPath, value)
	return err
}

func (n *Narcissus) writeSliceField(field reflect.Value, fieldType reflect.StructField, path, fieldPath string) error {
	for i := 0; i < field.Len(); i++ {
		value := field.Index(i)
		var p string
		if fieldType.Tag.Get("type") == "seq" {
			p = fmt.Sprintf("%s/%v", path, i+1)
		} else {
			p = fmt.Sprintf("%s[%v]", fieldPath, i+1)
		}
		if value.Kind() == reflect.Struct {
			err := n.writeStruct(value, p)
			if err != nil {
				return fmt.Errorf("failed to write slice struct value: %v", err)
			}
		} else {
			err := n.writeSimpleField(value, p, fieldType.Tag)
			if err != nil {
				return fmt.Errorf("failed to write slice value: %v", err)
			}
		}<commit_msg>Create base node for slices<commit_after>package narcissus

import (
	"fmt"
	"reflect"
	"strings"
)

// Write writes a structure pointer to the Augeas tree
func (n *Narcissus) Write(val interface{}) error {
	ref, err := structRef(val)
	if err != nil {
		return fmt.Errorf("invalid interface: %v", err)
	}

	path, err := getPath(ref)
	if err != nil {
		return fmt.Errorf("undefined path: %v", err)
	}

	return n.writeStruct(ref, path)
}

func (n *Narcissus) writeStruct(ref reflect.Value, path string) error {
	refType := ref.Type()
	for i := 0; i < refType.NumField(); i++ {
		if refType.Field(i).Name == "augeasPath" {
			// Ignore the special `augeasPath` field
			continue
		}
		err := n.writeField(ref.Field(i), refType.Field(i), path)
		if err != nil {
			return fmt.Errorf("failed to write field %s: %v", refType.Field(i).Name, err)
		}
	}

	return nil
}

func (n *Narcissus) writeField(field reflect.Value, fieldType reflect.StructField, path string) error {
	fieldPath := fmt.Sprintf("%s/%s", path, fieldType.Tag.Get("path"))
	if field.Kind() == reflect.Slice {
		return n.writeSliceField(field, fieldType, path, fieldPath)
	} else if field.Kind() == reflect.Map {
		return n.writeMapField(field, fieldType, path, fieldPath)
	}
	return n.writeSimpleField(field, fieldPath, fieldType.Tag)
}

func (n *Narcissus) writeSimpleField(field reflect.Value, fieldPath string, tag reflect.StructTag) error {
	aug := n.Augeas
	// There might be a better way to convert, but that does it
	value := fmt.Sprintf("%v", field.Interface())

	if tag.Get("value-from") == "label" {
		return nil
	}

	// FIXME: use omitempty for that
	if value == "" {
		return nil
	}

	err := aug.Set(fieldPath, value)
	return err
}

func (n *Narcissus) writeSliceField(field reflect.Value, fieldType reflect.StructField, path, fieldPath string) error {
	for i := 0; i < field.Len(); i++ {
		value := field.Index(i)
		var p string
		if fieldType.Tag.Get("type") == "seq" {
			p = fmt.Sprintf("%s/%v", path, i+1)
		} else {
			p = fmt.Sprintf("%s[%v]", fieldPath, i+1)
		}
		// Create base node
		err := n.Augeas.Clear(p)
		if err != nil {
			return fmt.Errorf("failed to create base path for slice: %v", err)
		}
		if value.Kind() == reflect.Struct {
			err := n.writeStruct(value, p)
			if err != nil {
				return fmt.Errorf("failed to write slice struct value: %v", err)
			}
		} else {
			err := n.writeSimpleField(value, p, fieldType.Tag)
			if err != nil {
				return fmt.Errorf("failed to write slice value: %v", err)
			}
		}
{'fraction_non_alphanumeric': 0.15413146507315062, 'fraction_numerical': 0.00164846486709252, 'mean_word_length': 3.703488372093023, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, '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': '2414739', 'n_tokens_mistral': 1828, 'n_tokens_neox': 1707, 'n_words': 498}