GoSetup-bubble/setup/utils/utils.go

147 lines
5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}
// RenderFileTemplate создает целевой файл на основе файла источника с подставленными значениями в нем
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
}
// RenderTemplate формирует строку с подставленными параметрами
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
}
// RunCommand запускает выполнение переданной команды от указанного лица
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("bash", "-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
}