2025-01-26 22:26:15 +00:00
|
|
|
package hugo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2025-02-01 04:36:35 +00:00
|
|
|
"gopkg.in/yaml.v3"
|
2025-01-27 10:48:40 +00:00
|
|
|
"lmika.dev/lmika/hugo-cms/models"
|
2025-01-26 22:26:15 +00:00
|
|
|
"log"
|
2025-02-18 10:26:24 +00:00
|
|
|
"net/url"
|
2025-01-26 22:26:15 +00:00
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Provider struct {
|
2025-02-18 10:26:24 +00:00
|
|
|
stagingDir string
|
|
|
|
previewDir string
|
|
|
|
previewBaseURL *url.URL
|
|
|
|
scratchDir string
|
2025-01-26 22:26:15 +00:00
|
|
|
}
|
|
|
|
|
2025-02-18 10:26:24 +00:00
|
|
|
func New(stagingDir, previewBaseURL, previewDir, scratchDir string) (*Provider, error) {
|
|
|
|
baseURL, err := url.Parse(previewBaseURL)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2025-01-26 22:26:15 +00:00
|
|
|
return &Provider{
|
2025-02-18 10:26:24 +00:00
|
|
|
stagingDir: stagingDir,
|
|
|
|
previewBaseURL: baseURL,
|
|
|
|
previewDir: previewDir,
|
|
|
|
scratchDir: scratchDir,
|
2025-01-26 22:26:15 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Provider) SiteStagingDir(site models.Site, what SiteDir) string {
|
|
|
|
switch what {
|
|
|
|
case BaseSiteDir:
|
|
|
|
return filepath.Join(p.stagingDir, site.Name)
|
|
|
|
case ThemeSiteDir:
|
|
|
|
return filepath.Join(p.stagingDir, site.Name, "themes", site.Theme)
|
|
|
|
}
|
2025-01-27 03:23:54 +00:00
|
|
|
return filepath.Join(p.stagingDir, site.Name, string(what))
|
2025-01-26 22:26:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Provider) NewSite(ctx context.Context, site models.Site) error {
|
|
|
|
log.Printf(" .. %v", p.SiteStagingDir(site, BaseSiteDir))
|
|
|
|
if err := os.MkdirAll(p.SiteStagingDir(site, BaseSiteDir), 0755); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the new site
|
2025-02-01 04:36:35 +00:00
|
|
|
if err := exec.CommandContext(ctx, "hugo", "new", "site",
|
|
|
|
"--config=hugo.yaml",
|
|
|
|
p.SiteStagingDir(site, BaseSiteDir)).Run(); err != nil {
|
2025-01-26 22:26:15 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2025-02-17 10:41:36 +00:00
|
|
|
func (p *Provider) PreviewSite(ctx context.Context, site models.Site) (outDir string, err error) {
|
2025-02-18 10:26:24 +00:00
|
|
|
previewURL, err := p.previewBaseURL.Parse("preview/" + site.Name)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2025-02-17 10:41:36 +00:00
|
|
|
previewTarget := models.PublishTarget{
|
2025-02-18 10:26:24 +00:00
|
|
|
URL: previewURL.String(),
|
2025-01-27 04:45:53 +00:00
|
|
|
}
|
|
|
|
|
2025-02-17 10:41:36 +00:00
|
|
|
return p.publishSiteAt(ctx, p.previewDir, site, previewTarget, "hugoPreview.yaml")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Provider) PublishSite(ctx context.Context, site models.Site, target models.PublishTarget) (outDir string, err error) {
|
|
|
|
return p.publishSiteAt(ctx, p.scratchDir, site, target, "hugo.yaml")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Provider) publishSiteAt(ctx context.Context, dir string, site models.Site, target models.PublishTarget, configFile string) (outDir string, err error) {
|
|
|
|
baseSiteDir, err := filepath.Abs(p.SiteStagingDir(site, BaseSiteDir))
|
2025-01-27 04:45:53 +00:00
|
|
|
if err != nil {
|
2025-02-17 10:41:36 +00:00
|
|
|
return "", err
|
2025-01-27 04:45:53 +00:00
|
|
|
}
|
|
|
|
|
2025-02-17 10:41:36 +00:00
|
|
|
outDir, err = filepath.Abs(filepath.Join(dir, site.Name))
|
2025-01-27 04:45:53 +00:00
|
|
|
if err != nil {
|
2025-02-17 10:41:36 +00:00
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := os.MkdirAll(outDir, 0755); err != nil {
|
|
|
|
return "", err
|
2025-01-27 04:45:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cmd := exec.CommandContext(ctx, "hugo",
|
2025-02-17 10:41:36 +00:00
|
|
|
"--source", baseSiteDir,
|
2025-01-27 04:45:53 +00:00
|
|
|
"--destination", outDir,
|
2025-02-18 10:26:24 +00:00
|
|
|
"--quiet",
|
2025-02-17 10:41:36 +00:00
|
|
|
"--config", filepath.Join(baseSiteDir, configFile),
|
2025-01-27 04:45:53 +00:00
|
|
|
"--baseURL", target.URL)
|
|
|
|
cmd.Stderr = os.Stderr
|
|
|
|
cmd.Stdout = os.Stdout
|
|
|
|
|
|
|
|
if err := cmd.Run(); err != nil {
|
2025-02-17 10:41:36 +00:00
|
|
|
return "", err
|
2025-01-27 04:45:53 +00:00
|
|
|
}
|
2025-02-17 10:41:36 +00:00
|
|
|
return outDir, nil
|
2025-01-27 04:45:53 +00:00
|
|
|
}
|
|
|
|
|
2025-02-18 10:26:24 +00:00
|
|
|
func (p *Provider) ReconfigureSite(ctx context.Context, isPreviewConfig bool, configBase string, site models.Site) error {
|
2025-02-01 04:36:35 +00:00
|
|
|
hugoCfg := hugoConfig{
|
2025-02-01 22:54:30 +00:00
|
|
|
Title: site.Title,
|
2025-02-01 04:36:35 +00:00
|
|
|
LanguageCode: "en",
|
|
|
|
Theme: site.Theme,
|
|
|
|
Markup: hugoConfigMarkup{
|
|
|
|
Goldmark: hugoGoldmarkConfig{
|
|
|
|
Renderer: hugoGoldmarkRendererConfig{
|
|
|
|
Unsafe: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2025-02-18 10:26:24 +00:00
|
|
|
if isPreviewConfig {
|
|
|
|
hugoCfg.CanonifyURLs = true
|
|
|
|
}
|
|
|
|
|
2025-02-01 04:36:35 +00:00
|
|
|
ymlBytes, err := yaml.Marshal(hugoCfg)
|
|
|
|
if err != nil {
|
2025-01-26 22:26:15 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2025-02-17 10:41:36 +00:00
|
|
|
if err := os.WriteFile(filepath.Join(p.SiteStagingDir(site, BaseSiteDir), configBase+".yaml"), ymlBytes, 0644); err != nil {
|
2025-01-26 22:26:15 +00:00
|
|
|
return err
|
|
|
|
}
|
2025-02-01 04:36:35 +00:00
|
|
|
|
2025-02-17 10:41:36 +00:00
|
|
|
if _, err := os.Stat(filepath.Join(p.SiteStagingDir(site, BaseSiteDir), configBase+".toml")); err == nil {
|
|
|
|
if err := os.Remove(filepath.Join(p.SiteStagingDir(site, BaseSiteDir), configBase+".toml")); err != nil {
|
2025-02-01 04:36:35 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-26 22:26:15 +00:00
|
|
|
return nil
|
|
|
|
}
|