200 lines
3.8 KiB
Go
200 lines
3.8 KiB
Go
package models
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"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")
|
|
|
|
type filepathOption struct {
|
|
isDir bool
|
|
}
|
|
|
|
type fnFilepathOption func(*filepathOption)
|
|
|
|
func IsDir() fnFilepathOption {
|
|
return func(fo *filepathOption) {
|
|
fo.isDir = true
|
|
}
|
|
}
|
|
|
|
func getFilepath(baseDir, filePath string, options ...fnFilepathOption) (string, error) {
|
|
var opts filepathOption
|
|
for _, opt := range options {
|
|
opt(&opts)
|
|
}
|
|
|
|
if !filepath.IsAbs(filePath) {
|
|
filePath = filepath.Join(baseDir, filePath)
|
|
filePath, err := filepath.Abs(filePath) //nolint: govet
|
|
if err != nil {
|
|
return filePath, fmt.Errorf(
|
|
"%w, file=%s, err=%v",
|
|
ErrProjectConfFile,
|
|
filePath,
|
|
err,
|
|
)
|
|
}
|
|
}
|
|
|
|
fileInfo, err := os.Stat(filePath)
|
|
if err != nil {
|
|
return filePath, fmt.Errorf(
|
|
"%w, file=%s, err=%v",
|
|
ErrProjectConfFile,
|
|
filePath,
|
|
err,
|
|
)
|
|
}
|
|
|
|
if fileInfo.IsDir() && !opts.isDir {
|
|
return filePath, fmt.Errorf(
|
|
"%w, file=%s, err=%s",
|
|
ErrProjectConfFile,
|
|
filePath,
|
|
"must be a file",
|
|
)
|
|
}
|
|
|
|
if !fileInfo.IsDir() && opts.isDir {
|
|
return filePath, fmt.Errorf(
|
|
"%w, file=%s, err=%s",
|
|
ErrProjectConfFile,
|
|
filePath,
|
|
"must be a dir",
|
|
)
|
|
}
|
|
|
|
return filePath, nil
|
|
}
|
|
|
|
// Project handles the details and file informations of your project.
|
|
type Project struct {
|
|
Name string `json:"name"`
|
|
Dir string
|
|
Deps struct {
|
|
Swarm struct {
|
|
EnvFile string `json:"env"`
|
|
ComposeFile string `json:"compose"`
|
|
} `json:"swarm"`
|
|
Nginx struct {
|
|
Conf string `json:"conf"`
|
|
Assets string `json:"assets"`
|
|
}
|
|
} `json:"dependencies"`
|
|
ImageNames []string `json:"images"`
|
|
}
|
|
|
|
func (p *Project) validate() error {
|
|
if compf := p.Deps.Swarm.ComposeFile; compf != "" {
|
|
cpath, err := getFilepath(p.Dir, compf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
p.Deps.Swarm.ComposeFile = cpath
|
|
} else {
|
|
log.Warn().Msg("no docker-compose file provided, Swarm deployment discards")
|
|
}
|
|
|
|
if env := p.Deps.Swarm.EnvFile; env != "" {
|
|
epath, err := getFilepath(p.Dir, env)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
p.Deps.Swarm.EnvFile = epath
|
|
}
|
|
|
|
if conf := p.Deps.Nginx.Conf; conf != "" {
|
|
npath, err := getFilepath(p.Dir, conf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
p.Deps.Nginx.Conf = npath
|
|
}
|
|
|
|
if assets := p.Deps.Nginx.Assets; assets != "" {
|
|
apath, err := getFilepath(p.Dir, assets, IsDir())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
p.Deps.Nginx.Assets = apath
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p Project) GetComposePath() string {
|
|
return p.Deps.Swarm.ComposeFile
|
|
}
|
|
|
|
func (p Project) GetEnvPath() string {
|
|
return p.Deps.Swarm.EnvFile
|
|
}
|
|
|
|
func (p Project) GetNginxConfPath() string {
|
|
return p.Deps.Nginx.Conf
|
|
}
|
|
|
|
func (p Project) GetNginxAssetsPath() string {
|
|
return p.Deps.Nginx.Assets
|
|
}
|
|
|
|
// 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
|
|
}
|