package utils import ( "bubble/types" "fmt" "github.com/charmbracelet/bubbles/textinput" "github.com/expr-lang/expr" "github.com/sirupsen/logrus" "os/exec" "reflect" "regexp" "strconv" "strings" ) // userRE - с начала строки, делит все по знаку двоеточия, берется первые 3 группы, пример user_name:x:1000: var userRE = regexp.MustCompile(`^([^:]+):[^:]*:([0-9]+):`) // ComputeValue вычисляет значение для поля compute. func ComputeValue(computeExpr string, app *types.PackageApplication) (interface{}, error) { if computeExpr == "" { return nil, nil } env := ParamsForCompute(app) options := append([]expr.Option{ expr.Env(env), expr.AsKind(reflect.String), // по умолчанию строка, если не указано иное expr.AllowUndefinedVariables(), }, DefineExprCustomFunctions()...) program, err := expr.Compile(computeExpr, options...) if err != nil { return nil, fmt.Errorf("ошибка компиляции compute: %v", err) } result, err := expr.Run(program, env) if err != nil { return nil, fmt.Errorf("ошибка выполнения compute: %v", err) } return result, nil } // Recompute производит перерасчет всех полей func Recompute(app *types.PackageApplication) { for i := range app.Sections { section := &app.Sections[i] for j := range section.Fields { field := §ion.Fields[j] if field.FieldType == "compute" && field.Compute != "" { value, err := ComputeValue(field.Compute, app) if err != nil { value = fmt.Sprintf("Ошибка вычисления: %v", err) } field.Variable.Value = value } } } } // CheckCondition проверяет равно ли переданное условие func CheckCondition(condition string, app *types.PackageApplication) bool { if condition == "" { return true } result, err := expr.Eval(condition, ParamsForCondition(app)) if err != nil { logrus.Errorf("Ошибка в условии '%s': %v", condition, err) return false } boolResult, ok := result.(bool) if !ok { logrus.Warnf("Условие '%s' не вернуло bool, а %T: %v", condition, result, result) return false } return boolResult } // IsParent проверяет, является ли указанная переменная условием для поля или секции func IsParent(variableName string, sections []types.Section) bool { for _, section := range sections { for _, parent := range section.Parent { if parent == variableName { return true } } for _, field := range section.Fields { for _, parent := range field.Parent { if parent == variableName { return true } } } } return false } // IsMultiField проверяет переменную на использование несколькими полями. func IsMultiField(variableName string, applicationSections []types.Section) bool { var count int for _, section := range applicationSections { for _, field := range section.Fields { if field.Name == variableName { count++ } } } return count > 1 } // SpecialValueHandle получаем необычные значения полей func SpecialValueHandle(special string) interface{} { specialValue := strings.Split(special, "code:")[1] switch specialValue { case "users": return GetSystemUsers() } return true } // GetSystemUsers получение списка обычных пользователей в системе func GetSystemUsers() []string { //результат выполнения команды читающей файл passwd output, _ := exec.Command("getent", "passwd").Output() //массив строк разделенных новой строкой lines := strings.Split(string(output), "\n") var users []string for _, line := range lines { //линия совпадает с регулярным выражением if matches := userRE.FindStringSubmatch(line); len(matches) == 3 { //идентификатор больше или равен 1000, uid обычного пользователя в системе if uid, _ := strconv.Atoi(matches[2]); uid >= 1000 { users = append(users, matches[1]) } } } return users } // ValidateCheckField создает функцию типа types.BoolValidateFunc для проверки значения bool полей func ValidateCheckField(fieldName, variableName string, validations []types.FieldValidate, app *types.PackageApplication) types.BoolValidateFunc { if len(validations) == 0 { return nil } return func(checked bool) error { env := ParamsForCompute(app) env[variableName] = checked options := append([]expr.Option{ expr.Env(env), expr.AllowUndefinedVariables(), }, DefineExprCustomFunctions()...) for _, validate := range validations { program, err := expr.Compile(validate.Rule, options...) prefix := fmt.Sprintf("Валидация поля %s,", fieldName) if err != nil { msg := fmt.Errorf("ошибка компиляции правила: %s, err: %v", validate.Rule, err) logrus.Errorf("%s %v", prefix, msg) return msg } result, err := expr.Run(program, env) if err != nil { msg := fmt.Errorf("ошибка выполнения правила: %s, err: %v", validate.Rule, err) logrus.Errorf("%s %v", prefix, msg) return msg } if boolValue, ok := result.(bool); ok && !boolValue { return fmt.Errorf("%s", validate.Message) } else if !ok { msg := fmt.Errorf("возвращаемое значение правила: %s не булево", validate.Rule) logrus.Errorf("%s %v", prefix, msg) return msg } } return nil } } // ValidateField создает функцию типа textinput.ValidateFunc для проверки значения text полей func ValidateField(fieldName, variableName string, validations []types.FieldValidate, app *types.PackageApplication) textinput.ValidateFunc { if len(validations) == 0 { return nil } return func(text string) error { env := ParamsForCompute(app) env[variableName] = text options := append([]expr.Option{ expr.Env(env), expr.AllowUndefinedVariables(), }, DefineExprCustomFunctions()...) for _, validate := range validations { program, err := expr.Compile(validate.Rule, options...) prefix := fmt.Sprintf("Валидация поля %s,", fieldName) if err != nil { msg := fmt.Errorf("ошибка компиляции правила: %s, err: %v", validate.Rule, err) logrus.Errorf("%s %v", prefix, msg) return msg } result, err := expr.Run(program, env) if err != nil { msg := fmt.Errorf("ошибка выполнения правила: %s, err: %v", validate.Rule, err) logrus.Errorf("%s %v", prefix, msg) return msg } if boolValue, ok := result.(bool); ok && !boolValue { return fmt.Errorf("%s", validate.Message) } else if !ok { msg := fmt.Errorf("возвращаемое значение правила: %s не булево", validate.Rule) logrus.Errorf("%s %v", prefix, msg) return msg } } return nil } }