package hugo import ( "context" "fmt" "gopkg.in/yaml.v3" "lmika.dev/lmika/hugo-cms/models" "log" "os" "os/exec" "path/filepath" ) type Provider struct { stagingDir string previewDir string scratchDir string } func New(stagingDir, previewDir, scratchDir string) (*Provider, error) { return &Provider{ stagingDir: stagingDir, previewDir: previewDir, scratchDir: scratchDir, }, 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) } return filepath.Join(p.stagingDir, site.Name, string(what)) } 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 if err := exec.CommandContext(ctx, "hugo", "new", "site", "--config=hugo.yaml", p.SiteStagingDir(site, BaseSiteDir)).Run(); err != nil { return err } return nil } func (p *Provider) PreviewSite(ctx context.Context, site models.Site) (outDir string, err error) { previewTarget := models.PublishTarget{ URL: fmt.Sprintf("http://localhost:3000/preview/%s", site.Name), } 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)) if err != nil { return "", err } outDir, err = filepath.Abs(filepath.Join(dir, site.Name)) if err != nil { return "", err } if err := os.MkdirAll(outDir, 0755); err != nil { return "", err } cmd := exec.CommandContext(ctx, "hugo", "--source", baseSiteDir, "--destination", outDir, "--config", filepath.Join(baseSiteDir, configFile), "--baseURL", target.URL) cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout if err := cmd.Run(); err != nil { return "", err } return outDir, nil } func (p *Provider) ReconfigureSite(ctx context.Context, configBase string, site models.Site) error { hugoCfg := hugoConfig{ Title: site.Title, LanguageCode: "en", Theme: site.Theme, CanonifyURLs: configBase == "hugoPreview", Markup: hugoConfigMarkup{ Goldmark: hugoGoldmarkConfig{ Renderer: hugoGoldmarkRendererConfig{ Unsafe: true, }, }, }, } ymlBytes, err := yaml.Marshal(hugoCfg) if err != nil { return err } if err := os.WriteFile(filepath.Join(p.SiteStagingDir(site, BaseSiteDir), configBase+".yaml"), ymlBytes, 0644); err != nil { return err } 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 { return err } } return nil }