Beispiel #1
0
// expandTaskSelector expands strings inside task selectors.
func expandTaskSelector(ts taskSelector, exp command.Expansions) (taskSelector, error) {
	newTS := taskSelector{}
	newName, err := exp.ExpandString(ts.Name)
	if err != nil {
		return newTS, fmt.Errorf("expanding name: %v", err)
	}
	newTS.Name = newName
	if v := ts.Variant; v != nil {
		if len(v.matrixSelector) > 0 {
			newMS, err := expandMatrixDefinition(v.matrixSelector, exp)
			if err != nil {
				return newTS, fmt.Errorf("expanding variant: %v", err)
			}
			newTS.Variant = &variantSelector{
				matrixSelector: newMS,
			}
		} else {
			selector, err := exp.ExpandString(v.stringSelector)
			if err != nil {
				return newTS, fmt.Errorf("expanding variant: %v", err)
			}
			newTS.Variant = &variantSelector{
				stringSelector: selector,
			}
		}
	}
	return newTS, nil
}
Beispiel #2
0
func expandString(inputVal reflect.Value, expansions *command.Expansions) error {
	expanded, err := expansions.ExpandString(inputVal.String())
	if err != nil {
		return err
	}
	inputVal.SetString(expanded)
	return nil
}
Beispiel #3
0
// expandStrings expands a slice of strings.
func expandStrings(strings []string, exp command.Expansions) ([]string, error) {
	var expanded []string
	for _, s := range strings {
		newS, err := exp.ExpandString(s)
		if err != nil {
			return nil, err
		}
		expanded = append(expanded, newS)
	}
	return expanded, nil
}
Beispiel #4
0
func (sc *StatsCollector) expandCommands(exp *command.Expansions) {
	expandedCmds := []string{}
	for _, cmd := range sc.Cmds {
		expanded, err := exp.ExpandString(cmd)
		if err != nil {
			sc.logger.Logf(slogger.WARN, "Couldn't expand '%v': %v", cmd, err)
			continue
		}
		expandedCmds = append(expandedCmds, expanded)
	}
	sc.Cmds = expandedCmds
}
Beispiel #5
0
// expandExpansions expands expansion maps.
func expandExpansions(in, exp command.Expansions) (command.Expansions, error) {
	newExp := command.Expansions{}
	for k, v := range in {
		newK, err := exp.ExpandString(k)
		if err != nil {
			return nil, err
		}
		newV, err := exp.ExpandString(v)
		if err != nil {
			return nil, err
		}
		newExp[newK] = newV
	}
	return newExp, nil
}
func TestExpansionsPlugin(t *testing.T) {
	Convey("Should be able to update expansions", t, func() {
		updateCommand := UpdateCommand{
			Updates: []PutCommandParams{
				{
					Key:   "base",
					Value: "eggs",
				},
				{
					Key:    "topping",
					Concat: ",sausage",
				},
			},
		}

		expansions := command.Expansions{}
		expansions.Put("base", "not eggs")
		expansions.Put("topping", "bacon")

		taskConfig := model.TaskConfig{
			Expansions: &expansions,
		}

		updateCommand.ExecuteUpdates(&taskConfig)

		So(expansions.Get("base"), ShouldEqual, "eggs")
		So(expansions.Get("topping"), ShouldEqual, "bacon,sausage")
	})
}
Beispiel #7
0
// Helper function to expand a map. Returns expanded version with
// both keys and values expanded
func expandMap(inputMap reflect.Value, expansions *command.Expansions) error {

	if inputMap.Type().Key().Kind() != reflect.String {
		return fmt.Errorf("input map to expand must have keys of string type")
	}

	// iterate through keys and value, expanding them
	for _, key := range inputMap.MapKeys() {
		expandedKeyString, err := expansions.ExpandString(key.String())
		if err != nil {
			return fmt.Errorf("could not expand key %v: %v", key.String(), err)
		}

		// expand and set new value
		val := inputMap.MapIndex(key)
		expandedVal := reflect.Value{}
		switch val.Type().Kind() {
		case reflect.String:
			expandedValString, err := expansions.ExpandString(val.String())
			if err != nil {
				return fmt.Errorf("could not expand value %v: %v", val.String(), err)
			}
			expandedVal = reflect.ValueOf(expandedValString)
		case reflect.Map:
			if err := expandMap(val, expansions); err != nil {
				return fmt.Errorf("could not expand value %v: %v", val.String(), err)
			}
			expandedVal = val
		default:
			return fmt.Errorf(
				"could not expand value %v: must be string, map, or struct",
				val.String())
		}

		// unset unexpanded key then set expanded key
		inputMap.SetMapIndex(key, reflect.Value{})
		inputMap.SetMapIndex(reflect.ValueOf(expandedKeyString), expandedVal)
	}

	return nil
}
Beispiel #8
0
// expandParserBVTask expands strings inside parserBVTs.
func expandParserBVTask(pbvt parserBVTask, exp command.Expansions) (parserBVTask, error) {
	var err error
	newTask := pbvt
	newTask.Name, err = exp.ExpandString(pbvt.Name)
	if err != nil {
		return parserBVTask{}, fmt.Errorf("expanding name: %v", err)
	}
	newTask.RunOn, err = expandStrings(pbvt.RunOn, exp)
	if err != nil {
		return parserBVTask{}, fmt.Errorf("expanding run_on: %v", err)
	}
	newTask.Distros, err = expandStrings(pbvt.Distros, exp)
	if err != nil {
		return parserBVTask{}, fmt.Errorf("expanding distros: %v", err)
	}
	var newDeps parserDependencies
	for i, d := range pbvt.DependsOn {
		newDep := d
		newDep.Status, err = exp.ExpandString(d.Status)
		if err != nil {
			return parserBVTask{}, fmt.Errorf("expanding depends_on[%v].status: %v", i, err)
		}
		newDep.taskSelector, err = expandTaskSelector(d.taskSelector, exp)
		if err != nil {
			return parserBVTask{}, fmt.Errorf("expanding depends_on[%v]: %v", i, err)
		}
		newDeps = append(newDeps, newDep)
	}
	newTask.DependsOn = newDeps
	var newReqs taskSelectors
	for i, r := range pbvt.Requires {
		newReq, err := expandTaskSelector(r, exp)
		if err != nil {
			return parserBVTask{}, fmt.Errorf("expanding requires[%v]: %v", i, err)
		}
		newReqs = append(newReqs, newReq)
	}
	newTask.Requires = newReqs
	return newTask, nil
}
Beispiel #9
0
// buildMatrixVariant does the heavy lifting of building a matrix variant based on axis information.
// We do this by iterating over all axes and merging the axis value's settings when applicable. Expansions
// are evaluated during this process. Rules are parsed and added to the resulting parserBV for later
// excecution.
func buildMatrixVariant(axes []matrixAxis, mv matrixValue, m *matrix, ase *axisSelectorEvaluator) (*parserBV, error) {
	v := parserBV{
		matrixVal:  mv,
		matrixId:   m.Id,
		Stepback:   m.Stepback,
		BatchTime:  m.BatchTime,
		Modules:    m.Modules,
		RunOn:      m.RunOn,
		Expansions: *command.NewExpansions(mv),
	}
	// we declare a separate expansion map for evaluating the display name
	displayNameExp := command.Expansions{}

	// build up the variant id while iterating through axis values
	idBuf := bytes.Buffer{}
	idBuf.WriteString(m.Id)
	idBuf.WriteString("__")

	// track how many axes we cover, so we know the value is only using real axes
	usedAxes := 0

	// we must iterate over axis definitions to have a consistent ordering for our axis priority
	for _, a := range axes {
		// skip any axes that aren't used in the variant's definition
		if _, ok := mv[a.Id]; !ok {
			continue
		}
		usedAxes++
		axisVal, err := a.find(mv[a.Id])
		if err != nil {
			return nil, err
		}
		if err := v.mergeAxisValue(axisVal); err != nil {
			return nil, fmt.Errorf("processing axis value %v,%v: %v", a.Id, axisVal.Id, err)
		}
		// for display names, fall back to the axis values id so we have *something*
		if axisVal.DisplayName != "" {
			displayNameExp.Put(a.Id, axisVal.DisplayName)
		} else {
			displayNameExp.Put(a.Id, axisVal.Id)
		}

		// append to the variant's name
		idBuf.WriteString(a.Id)
		idBuf.WriteRune('~')
		idBuf.WriteString(axisVal.Id)
		if usedAxes < len(mv) {
			idBuf.WriteRune('_')
		}
	}
	if usedAxes != len(mv) {
		// we could make this error more helpful at the expense of extra complexity
		return nil, fmt.Errorf("cell %v uses undefined axes", mv)
	}
	v.Name = idBuf.String()
	disp, err := displayNameExp.ExpandString(m.DisplayName)
	if err != nil {
		return nil, fmt.Errorf("processing display name: %v", err)
	}
	v.DisplayName = disp

	// add final matrix-level tags and tasks
	if err := v.mergeAxisValue(axisValue{Tags: m.Tags}); err != nil {
		return nil, fmt.Errorf("processing matrix tags: %v", err)
	}
	for _, t := range m.Tasks {
		expTask, err := expandParserBVTask(t, v.Expansions)
		if err != nil {
			return nil, fmt.Errorf("processing task %v: %v", t.Name, err)
		}
		v.Tasks = append(v.Tasks, expTask)
	}

	// evaluate rules for matching matrix values
	for i, rule := range m.Rules {
		r, err := expandRule(rule, v.Expansions)
		if err != nil {
			return nil, fmt.Errorf("processing rule[%v]: %v", i, err)
		}
		matchers, errs := r.If.evaluatedCopies(ase) // we could cache this
		if len(errs) > 0 {
			return nil, fmt.Errorf("evaluating rules for matrix %v: %v", m.Id, errs)
		}
		if matchers.contain(mv) {
			if r.Then.Set != nil {
				if err := v.mergeAxisValue(*r.Then.Set); err != nil {
					return nil, fmt.Errorf("evaluating %v rule %v: %v", m.Id, i, err)
				}
			}
			// we append add/remove task rules internally and execute them
			// during task evaluation, when other tasks are being evaluated.
			if len(r.Then.RemoveTasks) > 0 || len(r.Then.AddTasks) > 0 {
				v.matrixRules = append(v.matrixRules, r.Then)
			}
		}
	}
	return &v, nil
}