123 lines
2.7 KiB
Go
123 lines
2.7 KiB
Go
package manifest
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/BurntSushi/toml"
|
|
|
|
"gitea.lclr.dev/AI/mcp-framework/update"
|
|
)
|
|
|
|
const DefaultFile = "mcp.toml"
|
|
|
|
type File struct {
|
|
Update Update `toml:"update"`
|
|
}
|
|
|
|
type Update struct {
|
|
SourceName string `toml:"source_name"`
|
|
BaseURL string `toml:"base_url"`
|
|
LatestReleaseURL string `toml:"latest_release_url"`
|
|
TokenHeader string `toml:"token_header"`
|
|
TokenEnvNames []string `toml:"token_env_names"`
|
|
}
|
|
|
|
func Find(startDir string) (string, error) {
|
|
dir := strings.TrimSpace(startDir)
|
|
if dir == "" {
|
|
wd, err := os.Getwd()
|
|
if err != nil {
|
|
return "", fmt.Errorf("resolve working directory: %w", err)
|
|
}
|
|
dir = wd
|
|
}
|
|
|
|
absDir, err := filepath.Abs(dir)
|
|
if err != nil {
|
|
return "", fmt.Errorf("resolve manifest search path %q: %w", dir, err)
|
|
}
|
|
|
|
for {
|
|
path := filepath.Join(absDir, DefaultFile)
|
|
info, err := os.Stat(path)
|
|
switch {
|
|
case err == nil:
|
|
if info.IsDir() {
|
|
return "", fmt.Errorf("manifest path %q is a directory", path)
|
|
}
|
|
return path, nil
|
|
case !errors.Is(err, os.ErrNotExist):
|
|
return "", fmt.Errorf("stat manifest %q: %w", path, err)
|
|
}
|
|
|
|
parent := filepath.Dir(absDir)
|
|
if parent == absDir {
|
|
return "", fmt.Errorf("find manifest %q from %q: %w", DefaultFile, dir, os.ErrNotExist)
|
|
}
|
|
absDir = parent
|
|
}
|
|
}
|
|
|
|
func Load(path string) (File, error) {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return File{}, fmt.Errorf("read manifest %s: %w", path, err)
|
|
}
|
|
|
|
var file File
|
|
if err := toml.Unmarshal(data, &file); err != nil {
|
|
return File{}, fmt.Errorf("parse manifest %s: %w", path, err)
|
|
}
|
|
|
|
file.normalize()
|
|
return file, nil
|
|
}
|
|
|
|
func LoadDefault(startDir string) (File, string, error) {
|
|
path, err := Find(startDir)
|
|
if err != nil {
|
|
return File{}, "", err
|
|
}
|
|
|
|
file, err := Load(path)
|
|
if err != nil {
|
|
return File{}, "", err
|
|
}
|
|
|
|
return file, path, nil
|
|
}
|
|
|
|
func (f *File) normalize() {
|
|
f.Update.normalize()
|
|
}
|
|
|
|
func (u *Update) normalize() {
|
|
u.SourceName = strings.TrimSpace(u.SourceName)
|
|
u.BaseURL = strings.TrimRight(strings.TrimSpace(u.BaseURL), "/")
|
|
u.LatestReleaseURL = strings.TrimSpace(u.LatestReleaseURL)
|
|
u.TokenHeader = strings.TrimSpace(u.TokenHeader)
|
|
|
|
envNames := u.TokenEnvNames[:0]
|
|
for _, envName := range u.TokenEnvNames {
|
|
if trimmed := strings.TrimSpace(envName); trimmed != "" {
|
|
envNames = append(envNames, trimmed)
|
|
}
|
|
}
|
|
u.TokenEnvNames = envNames
|
|
}
|
|
|
|
func (u Update) ReleaseSource() update.ReleaseSource {
|
|
u.normalize()
|
|
|
|
return update.ReleaseSource{
|
|
Name: u.SourceName,
|
|
BaseURL: u.BaseURL,
|
|
LatestReleaseURL: u.LatestReleaseURL,
|
|
TokenHeader: u.TokenHeader,
|
|
TokenEnvNames: append([]string(nil), u.TokenEnvNames...),
|
|
}
|
|
}
|