<commit_before>package jobspec

import (
	"fmt"
	"time"

	multierror "github.com/hashicorp/go-multierror"
	"github.com/hashicorp/hcl"
	"github.com/hashicorp/hcl/hcl/ast"
	"github.com/hashicorp/nomad/api"
	"github.com/hashicorp/nomad/helper"
	"github.com/mitchellh/mapstructure"
)

func parseTasks(result *[]*api.Task, list *ast.ObjectList) error {
	list = list.Children()
	if len(list.Items) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	seen := make(map[string]struct{})
	for _, item := range list.Items {
		n := item.Keys[0].Token.Value().(string)

		// Make sure we haven't already found this
		if _, ok := seen[n]; ok {
			return fmt.Errorf("task '%s' defined more than once", n)
		}
		seen[n] = struct{}{}

		t, err := parseTask(item)
		if err != nil {
			return multierror.Prefix(err, fmt.Sprintf("'%s',", n))
		}

		t.Name = n

		*result = append(*result, t)
	}

	return nil
}

func parseTask(item *ast.ObjectItem) (*api.Task, error) {
	// We need this later
	var listVal *ast.ObjectList
	if ot, ok := item.Val.(*ast.ObjectType); ok {
		listVal = ot.List
	} else {
		return nil, fmt.Errorf("should be an object")
	}

	// Check for invalid keys
	valid := []string{
		"artifact",
		"config",
		"constraint",
		"affinity",
		"dispatch_payload",
		"driver",
		"env",
		"kill_timeout",
		"leader",
		"logs",
		"meta",
		"resources",
		"service",
		"shutdown_delay",
		"template",
		"user",
		"vault",
		"kill_signal",
		"kind",
		"volume_mount",
	}
	if err := helper.CheckHCLKeys(listVal, valid); err != nil {
		return nil, err
	}

	var m map[string]interface{}
	if err := hcl.DecodeObject(&m, item.Val); err != nil {
		return nil, err
	}
	delete(m, "artifact")
	delete(m, "config")
	delete(m, "constraint")
	delete(m, "affinity")
	delete(m, "dispatch_payload")
	delete(m, "env")
	delete(m, "logs")
	delete(m, "meta")
	delete(m, "resources")
	delete(m, "service")
	delete(m, "template")
	delete(m, "vault")
	delete(m, "volume_mount")

	// Build the task
	var t api.Task
	dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
		DecodeHook:       mapstructure.StringToTimeDurationHookFunc(),
		WeaklyTypedInput: true,
		Result:           &t,
	})

	if err != nil {
		return nil, err
	}
	if err := dec.Decode(m); err != nil {
		return nil, err
	}

	// If we have env, then parse them
	if o := listVal.Filter("env"); len(o.Items) > 0 {
		for _, o := range o.Elem().Items {
			var m map[string]interface{}
			if err := hcl.DecodeObject(&m, o.Val); err != nil {
				return nil, err
			}
			if err := mapstructure.WeakDecode(m, &t.Env); err != nil {
				return nil, err
			}
		}
	}

	if o := listVal.Filter("service"); len(o.Items) > 0 {
		services, err := parseServices(o)
		if err != nil {
			return nil, err
		}

		t.Services = services
	}

	// If we have config, then parse that
	if o := listVal.Filter("config"); len(o.Items) > 0 {
		for _, o := range o.Elem().Items {
			var m map[string]interface{}
			if err := hcl.DecodeObject(&m, o.Val); err != nil {
				return nil, err
			}

			if err := mapstructure.WeakDecode(m, &t.Config); err != nil {
				return nil, err
			}
		}
	}

	// Parse constraints
	if o := listVal.Filter("constraint"); len(o.Items) > 0 {
		if err := parseConstraints(&t.Constraints, o); err != nil {
			return nil, multierror.Prefix(err, "constraint ->")
		}
	}

	// Parse affinities
	if o := listVal.Filter("affinity"); len(o.Items) > 0 {
		if err := parseAffinities(&t.Affinities, o); err != nil {
			return nil, multierror.Prefix(err, "affinity ->")
		}
	}

	// Parse out meta fields. These are in HCL as a list so we need
	// to iterate over them and merge them.
	if metaO := listVal.Filter("meta"); len(metaO.Items) > 0 {
		for _, o := range metaO.Elem().Items {
			var m map[string]interface{}
			if err := hcl.DecodeObject(&m, o.Val); err != nil {
				return nil, err
			}
			if err := mapstructure.WeakDecode(m, &t.Meta); err != nil {
				return nil, err
			}
		}
	}

	// Parse volume mounts
	if o := listVal.Filter("volume_mount"); len(o.Items) > 0 {
		if err := parseVolumeMounts(&t.VolumeMounts, o); err != nil {
			return multierror.Prefix(err, fmt.Sprintf(
				"'%s', volume_mount ->", n))
		}
	}

	// If we have resources, then parse that
	if o := listVal.Filter("resources"); len(o.Items) > 0 {
		var r api.Resources<commit_msg>fixup rebase<commit_after>package jobspec

import (
	"fmt"
	"time"

	multierror "github.com/hashicorp/go-multierror"
	"github.com/hashicorp/hcl"
	"github.com/hashicorp/hcl/hcl/ast"
	"github.com/hashicorp/nomad/api"
	"github.com/hashicorp/nomad/helper"
	"github.com/mitchellh/mapstructure"
)

func parseTasks(result *[]*api.Task, list *ast.ObjectList) error {
	list = list.Children()
	if len(list.Items) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	seen := make(map[string]struct{})
	for _, item := range list.Items {
		n := item.Keys[0].Token.Value().(string)

		// Make sure we haven't already found this
		if _, ok := seen[n]; ok {
			return fmt.Errorf("task '%s' defined more than once", n)
		}
		seen[n] = struct{}{}

		t, err := parseTask(item)
		if err != nil {
			return multierror.Prefix(err, fmt.Sprintf("'%s',", n))
		}

		t.Name = n

		*result = append(*result, t)
	}

	return nil
}

func parseTask(item *ast.ObjectItem) (*api.Task, error) {
	// We need this later
	var listVal *ast.ObjectList
	if ot, ok := item.Val.(*ast.ObjectType); ok {
		listVal = ot.List
	} else {
		return nil, fmt.Errorf("should be an object")
	}

	// Check for invalid keys
	valid := []string{
		"artifact",
		"config",
		"constraint",
		"affinity",
		"dispatch_payload",
		"driver",
		"env",
		"kill_timeout",
		"leader",
		"logs",
		"meta",
		"resources",
		"service",
		"shutdown_delay",
		"template",
		"user",
		"vault",
		"kill_signal",
		"kind",
		"volume_mount",
	}
	if err := helper.CheckHCLKeys(listVal, valid); err != nil {
		return nil, err
	}

	var m map[string]interface{}
	if err := hcl.DecodeObject(&m, item.Val); err != nil {
		return nil, err
	}
	delete(m, "artifact")
	delete(m, "config")
	delete(m, "constraint")
	delete(m, "affinity")
	delete(m, "dispatch_payload")
	delete(m, "env")
	delete(m, "logs")
	delete(m, "meta")
	delete(m, "resources")
	delete(m, "service")
	delete(m, "template")
	delete(m, "vault")
	delete(m, "volume_mount")

	// Build the task
	var t api.Task
	dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
		DecodeHook:       mapstructure.StringToTimeDurationHookFunc(),
		WeaklyTypedInput: true,
		Result:           &t,
	})

	if err != nil {
		return nil, err
	}
	if err := dec.Decode(m); err != nil {
		return nil, err
	}

	// If we have env, then parse them
	if o := listVal.Filter("env"); len(o.Items) > 0 {
		for _, o := range o.Elem().Items {
			var m map[string]interface{}
			if err := hcl.DecodeObject(&m, o.Val); err != nil {
				return nil, err
			}
			if err := mapstructure.WeakDecode(m, &t.Env); err != nil {
				return nil, err
			}
		}
	}

	if o := listVal.Filter("service"); len(o.Items) > 0 {
		services, err := parseServices(o)
		if err != nil {
			return nil, err
		}

		t.Services = services
	}

	// If we have config, then parse that
	if o := listVal.Filter("config"); len(o.Items) > 0 {
		for _, o := range o.Elem().Items {
			var m map[string]interface{}
			if err := hcl.DecodeObject(&m, o.Val); err != nil {
				return nil, err
			}

			if err := mapstructure.WeakDecode(m, &t.Config); err != nil {
				return nil, err
			}
		}
	}

	// Parse constraints
	if o := listVal.Filter("constraint"); len(o.Items) > 0 {
		if err := parseConstraints(&t.Constraints, o); err != nil {
			return nil, multierror.Prefix(err, "constraint ->")
		}
	}

	// Parse affinities
	if o := listVal.Filter("affinity"); len(o.Items) > 0 {
		if err := parseAffinities(&t.Affinities, o); err != nil {
			return nil, multierror.Prefix(err, "affinity ->")
		}
	}

	// Parse out meta fields. These are in HCL as a list so we need
	// to iterate over them and merge them.
	if metaO := listVal.Filter("meta"); len(metaO.Items) > 0 {
		for _, o := range metaO.Elem().Items {
			var m map[string]interface{}
			if err := hcl.DecodeObject(&m, o.Val); err != nil {
				return nil, err
			}
			if err := mapstructure.WeakDecode(m, &t.Meta); err != nil {
				return nil, err
			}
		}
	}

	// Parse volume mounts
	if o := listVal.Filter("volume_mount"); len(o.Items) > 0 {
		if err := parseVolumeMounts(&t.VolumeMounts, o); err != nil {
			return nil, multierror.Prefix(err, "volume_mount ->")
		}
	}

	// If we have resources, then parse that
	if o := listVal.Filter("resources"); len(o.Items) > 0 {
		var r api.Resources
{'fraction_non_alphanumeric': 0.16877686142409107, 'fraction_numerical': 0.0023231501916598906, 'mean_word_length': 3.251851851851852, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 25, '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': '6052761', 'n_tokens_mistral': 3469, 'n_tokens_neox': 3140, 'n_words': 838}