hmdeploy/models/project.go
2025-04-04 12:22:30 +02:00

134 lines
2.6 KiB
Go

package models
import (
"encoding/json"
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"github.com/rs/zerolog/log"
)
const (
MainDir string = ".homeserver"
ComposeFile string = "docker-compose.deploy.yml"
EnvFile string = ".env"
NginxFile = "nginx.conf"
ConfFile = "hmdeploy.json"
)
var ErrProjectConfFile = errors.New("project error")
func getFileInfo(baseDir, filePath string) (fs.FileInfo, error) {
var fInf fs.FileInfo
filePath = filepath.Clean(filePath)
filePath = filepath.Join(baseDir, filePath)
fileAbsPath, err := filepath.Abs(filePath)
if err != nil {
return fInf, fmt.Errorf("%w, file=%s, err=%v", ErrProjectConfFile, fileAbsPath, err)
}
fInf, err = os.Stat(fileAbsPath)
if err != nil {
return fInf, fmt.Errorf(
"%w, unable to stat file=%s, err=%v",
ErrProjectConfFile,
fileAbsPath,
err,
)
}
return fInf, nil
}
// Project handles the details and file informations of your project.
type Project struct {
Name string `json:"name"`
Dir string
ImageName string `json:"image"`
Deps struct {
EnvFile string `json:"env"`
EnvFileInfo fs.FileInfo
ComposeFile string `json:"compose"`
ComposeFileInfo fs.FileInfo
NginxFile string `json:"nginx"`
NginxFileInfo fs.FileInfo
} `json:"dependencies"`
}
func (p *Project) validate() error {
cfs, err := getFileInfo(p.Dir, p.Deps.ComposeFile)
if err != nil {
return err
}
p.Deps.ComposeFileInfo = cfs
if p.Deps.EnvFile != "" {
efs, err := getFileInfo(p.Dir, p.Deps.EnvFile)
if err != nil {
return err
}
p.Deps.EnvFileInfo = efs
} else {
log.Warn().Msg("no .env file provided, hoping one it's set elsewhere...")
}
nfs, err := getFileInfo(p.Dir, p.Deps.NginxFile)
if err != nil {
return err
}
p.Deps.NginxFileInfo = nfs
return nil
}
// ProjectFromDir instantiates a new project from a directory path.
//
// The directory path must refers to the path including the `.homeserver` dir not
// the `.homeserver` path itself.
func ProjectFromDir(dir string) (Project, error) {
var p Project
dir = filepath.Join(dir, MainDir)
p.Dir = dir
content, err := os.ReadFile(filepath.Join(dir, ConfFile))
if err != nil {
return p, fmt.Errorf(
"%w, unable to read conf file=%s, err=%v",
ErrProjectConfFile,
ConfFile,
err,
)
}
if err := json.Unmarshal(content, &p); err != nil {
return p, fmt.Errorf(
"%w, unable to parse conf file=%s, err=%v",
ErrProjectConfFile,
ConfFile,
err,
)
}
if err := p.validate(); err != nil {
return p, fmt.Errorf(
"%w, unable to validate project, name=%s, dir=%s, err=%v",
ErrProjectConfFile,
p.Name,
p.Dir,
err,
)
}
return p, nil
}