mirror of
https://github.com/ollama/ollama.git
synced 2026-03-11 12:22:13 -05:00
100 lines
2.2 KiB
Go
100 lines
2.2 KiB
Go
package config
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
)
|
|
|
|
func readJSONFile(path string) (map[string]any, error) {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var result map[string]any
|
|
if err := json.Unmarshal(data, &result); err != nil {
|
|
return nil, err
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func copyFile(src, dst string) error {
|
|
info, err := os.Stat(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
data, err := os.ReadFile(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.WriteFile(dst, data, info.Mode().Perm())
|
|
}
|
|
|
|
func backupDir() string {
|
|
return filepath.Join(os.TempDir(), "ollama-backups")
|
|
}
|
|
|
|
func backupToTmp(srcPath string) (string, error) {
|
|
dir := backupDir()
|
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
backupPath := filepath.Join(dir, fmt.Sprintf("%s.%d", filepath.Base(srcPath), time.Now().Unix()))
|
|
if err := copyFile(srcPath, backupPath); err != nil {
|
|
return "", err
|
|
}
|
|
return backupPath, nil
|
|
}
|
|
|
|
// writeWithBackup writes data to path via temp file + rename, backing up any existing file first
|
|
func writeWithBackup(path string, data []byte) error {
|
|
var backupPath string
|
|
// backup must be created before any writes to the target file
|
|
if existingContent, err := os.ReadFile(path); err == nil {
|
|
if !bytes.Equal(existingContent, data) {
|
|
backupPath, err = backupToTmp(path)
|
|
if err != nil {
|
|
return fmt.Errorf("backup failed: %w", err)
|
|
}
|
|
}
|
|
} else if !os.IsNotExist(err) {
|
|
return fmt.Errorf("read existing file: %w", err)
|
|
}
|
|
|
|
dir := filepath.Dir(path)
|
|
tmp, err := os.CreateTemp(dir, ".tmp-*")
|
|
if err != nil {
|
|
return fmt.Errorf("create temp failed: %w", err)
|
|
}
|
|
tmpPath := tmp.Name()
|
|
|
|
if _, err := tmp.Write(data); err != nil {
|
|
_ = tmp.Close()
|
|
_ = os.Remove(tmpPath)
|
|
return fmt.Errorf("write failed: %w", err)
|
|
}
|
|
if err := tmp.Sync(); err != nil {
|
|
_ = tmp.Close()
|
|
_ = os.Remove(tmpPath)
|
|
return fmt.Errorf("sync failed: %w", err)
|
|
}
|
|
if err := tmp.Close(); err != nil {
|
|
_ = os.Remove(tmpPath)
|
|
return fmt.Errorf("close failed: %w", err)
|
|
}
|
|
|
|
if err := os.Rename(tmpPath, path); err != nil {
|
|
_ = os.Remove(tmpPath)
|
|
if backupPath != "" {
|
|
_ = copyFile(backupPath, path)
|
|
}
|
|
return fmt.Errorf("rename failed: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|