package utils import ( "bytes" "fmt" "github.com/sirupsen/logrus" "html/template" "io" "net/http" "os" "os/exec" "path/filepath" "strings" "time" ) // CalculateSelectOptionsIndex рассчитывает индекс первой и последней опции для отображения в поле выбора func CalculateSelectOptionsIndex(focus, visibleCount, optionsCount int) (int, int) { //Если количество отображаемых больше, чем есть количество опций на самом деле, //то меняем количество опций для отображения на количество опций. if visibleCount > optionsCount { visibleCount = optionsCount } //Количество объектов сверху и снизу half := visibleCount / 2 //Индекс первой опции для показа в списке start := focus - half //Если индекс меньше 0, то фиксируем его на первой if start < 0 { start = 0 } //Индекс последней опции для показа в списке end := start + visibleCount //Если индекс больше, чем количество опций для вывода, //то фиксируем его на последней опции. //Производим перерасчет индекса первой опции if end > optionsCount { end = optionsCount start = end - visibleCount if start < 0 { start = 0 } } return start, end } func RenderFileTemplate(source, target string, vars map[string]interface{}) error { if source == "" || target == "" { return fmt.Errorf("source или target пустые") } var data []byte var err error if strings.HasPrefix(source, "http") { resp, err := http.Get(source) if err != nil { return fmt.Errorf("ошибка получения данных файла по адресу %s, err : %v", source, err) } defer resp.Body.Close() data, err = io.ReadAll(resp.Body) } else { data, err = os.ReadFile(source) } if err != nil { return fmt.Errorf("ошибка чтения данных файла %s, err: %v", source, err) } tmpl, err := template.New("").Parse(string(data)) if err != nil { return fmt.Errorf("ошибка формирования шаблона строки: %v", err) } var rendered bytes.Buffer if err = tmpl.Execute(&rendered, vars); err != nil { return fmt.Errorf("ошибка подстановки значений в шаблон") } if _, err = os.Stat(target); err == nil { backup := target + ".bak" + time.Now().Format("20060102-150405") if cpErr := CopyFile(target, backup); cpErr != nil { logrus.Warnf("Не удалось создать бекап: %v", cpErr) } else { logrus.Infof("Бекап %s создан", backup) } } if err = os.MkdirAll(filepath.Dir(target), 0755); err != nil { return fmt.Errorf("ошибка создания директории для файла %s, err: %v", target, err) } if err = os.WriteFile(target, rendered.Bytes(), 0644); err != nil { return fmt.Errorf("ошибка записи в файл %s, err: %v", target, err) } return nil } func RenderTemplate(tmpl string, data map[string]interface{}) (string, error) { if tmpl == "" { return "", nil } t, err := template.New("").Parse(tmpl) if err != nil { return "", fmt.Errorf("ошибка формирования шаблона строки: %v", err) } var buf bytes.Buffer if err = t.Execute(&buf, data); err != nil { return "", fmt.Errorf("ошибка подстановки значений в шаблон: %v", err) } return buf.String(), nil } func RunCommand(cmdStr, runAs string) error { if cmdStr == "" { return nil } var cmd *exec.Cmd if runAs != "" && runAs != "root" { cmd = exec.Command("su", "-c", cmdStr, runAs) } else { cmd = exec.Command("bach", "-c", cmdStr) } output, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("ошибка команды: %v\nВывод: %s", err, string(output)) } return nil } // CopyFile копирование файла в новое место func CopyFile(src, dst string) error { in, err := os.Open(src) if err != nil { return err } defer in.Close() out, err := os.Create(dst) if err != nil { return err } defer out.Close() _, err = io.Copy(out, in) return err }