refactor: reorganise magefiles
Reorganise and refactor the magefiles to make it more manageable and reduce duplication.
This commit is contained in:
parent
5f8ac4b035
commit
a909803b29
12 changed files with 301 additions and 213 deletions
|
@ -56,3 +56,4 @@ PS2=" -> "
|
|||
## {{ $command.Description }}
|
||||
{{ $command.Command }}
|
||||
{{- end -}}
|
||||
{{ print "" }}
|
||||
|
|
|
@ -4,10 +4,12 @@ package main
|
|||
|
||||
import "github.com/magefile/mage/mg"
|
||||
|
||||
var Default = Manage
|
||||
const rootManagedDir string = "managed"
|
||||
|
||||
// Manage runs all the management tasks.
|
||||
func Manage() error {
|
||||
var Default = All
|
||||
|
||||
// All runs all the management tasks.
|
||||
func All() error {
|
||||
mg.Deps(Directories, Files, Templates)
|
||||
|
||||
return nil
|
|
@ -6,7 +6,9 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
|
||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/config"
|
||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/utilities"
|
||||
)
|
||||
|
||||
// BashProfile manages the user's Bash Profile using their configuration and the Bash Profile template.
|
||||
|
@ -22,31 +24,27 @@ func BashProfile() error {
|
|||
return fmt.Errorf("unable to get the user's home configuration directory: %w", err)
|
||||
}
|
||||
|
||||
config, err := newConfig()
|
||||
cfg, err := config.NewConfig()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load the configuration: %w", err)
|
||||
}
|
||||
|
||||
if !config.BashProfile.Manage {
|
||||
if !cfg.BashProfile.Manage {
|
||||
return nil
|
||||
}
|
||||
|
||||
funcMap := template.FuncMap{
|
||||
"env": env,
|
||||
}
|
||||
|
||||
if err := renderTemplate(config, bashProfileTemplateFile, managedBashProfile, funcMap); err != nil {
|
||||
if err := utilities.RenderTemplate(cfg, bashProfileTemplateFile, managedBashProfile); err != nil {
|
||||
return fmt.Errorf("unable to generate the Bash Profile: %w", err)
|
||||
}
|
||||
|
||||
filename := config.BashProfile.Filename
|
||||
filename := cfg.BashProfile.Filename
|
||||
if filename == "" {
|
||||
filename = defaultFilename
|
||||
}
|
||||
|
||||
symlinkPath := filepath.Join(homeDirectory, filename)
|
||||
|
||||
if err := ensureSymlink(managedBashProfile, symlinkPath); err != nil {
|
||||
if err := utilities.EnsureSymlink(managedBashProfile, symlinkPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,14 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
|
||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/config"
|
||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/utilities"
|
||||
)
|
||||
|
||||
// Directories ensure that the specified home directories are present.
|
||||
func Directories() error {
|
||||
config, err := newConfig()
|
||||
cfg, err := config.NewConfig()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load the configuration: %w", err)
|
||||
}
|
||||
|
@ -23,22 +26,22 @@ func Directories() error {
|
|||
|
||||
directories := make([]string, 0)
|
||||
|
||||
if config.Directories.UseDefaultDirectories{
|
||||
if cfg.Directories.UseDefaultDirectories{
|
||||
defaultHomeDirs := homeDirectories(userHome, defaultDirectories())
|
||||
directories = append(directories, defaultHomeDirs...)
|
||||
}
|
||||
|
||||
if config.Directories.IncludeXDGDirectories{
|
||||
if cfg.Directories.IncludeXDGDirectories{
|
||||
directories = append(directories, xdgDirectories()...)
|
||||
}
|
||||
|
||||
if len(config.Directories.AdditionalDirectories) != 0 {
|
||||
additionalHomeDirs := homeDirectories(userHome, config.Directories.AdditionalDirectories)
|
||||
if len(cfg.Directories.AdditionalDirectories) != 0 {
|
||||
additionalHomeDirs := homeDirectories(userHome, cfg.Directories.AdditionalDirectories)
|
||||
directories = append(directories, additionalHomeDirs...)
|
||||
}
|
||||
|
||||
for _, dir := range slices.All(directories) {
|
||||
if err := ensureDirectory(dir); err != nil {
|
||||
if err := utilities.EnsureDirectory(dir); err != nil {
|
||||
return fmt.Errorf("unable to ensure that %s is present: %w", dir, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,81 +4,54 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/magefile/mage/sh"
|
||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/config"
|
||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/utilities"
|
||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/walk"
|
||||
)
|
||||
|
||||
// Files ensure that the configuration files in the managed directory is up to date and
|
||||
// ensures that they are symlinked correctly to the files in the user's home configuration
|
||||
// directory.
|
||||
func Files() error {
|
||||
homeConfigDirectory, err := os.UserConfigDir()
|
||||
const rootFilesDir string = "files"
|
||||
|
||||
homeConfigDir, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get the user's home configuration directory: %w", err)
|
||||
}
|
||||
|
||||
config, err := newConfig()
|
||||
cfg, err := config.NewConfig()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load the configuration: %w", err)
|
||||
}
|
||||
|
||||
managedConfig := managedConfigSet(config.ManagedConfigurations)
|
||||
managedConfig := utilities.ManagedConfigSet(cfg.ManagedConfigurations)
|
||||
|
||||
if err = filepath.WalkDir(rootFilesDir, manageFilesFunc(homeConfigDirectory, managedConfig)); err != nil {
|
||||
return fmt.Errorf("received an error while processing the files: %w", err)
|
||||
validationFunc := func(relativePath string) bool {
|
||||
split := strings.SplitN(relativePath, "/", 2)
|
||||
|
||||
if len(split) < 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
appConfigName := split[0]
|
||||
|
||||
_, exists := managedConfig[appConfigName]
|
||||
|
||||
return exists
|
||||
}
|
||||
|
||||
if err = filepath.WalkDir(
|
||||
rootFilesDir,
|
||||
walk.CopyFiles(homeConfigDir, rootFilesDir, rootManagedDir, validationFunc),
|
||||
); err != nil {
|
||||
return fmt.Errorf("received an error while copying the files: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func manageFilesFunc(homeConfigDirectory string, managedConfig map[string]struct{}) fs.WalkDirFunc {
|
||||
return func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if path == rootFilesDir {
|
||||
return nil
|
||||
}
|
||||
|
||||
relativePath := strings.TrimPrefix(path, rootFilesDir+"/")
|
||||
|
||||
appConfigName := strings.SplitN(relativePath, "/", 2)[0]
|
||||
|
||||
if _, exists := managedConfig[appConfigName]; !exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
managedPath := filepath.Join(rootManagedDir, relativePath)
|
||||
configPath := filepath.Join(homeConfigDirectory, relativePath)
|
||||
|
||||
if d.IsDir() {
|
||||
dirs := []string{managedPath, configPath}
|
||||
|
||||
for _, dir := range slices.All(dirs) {
|
||||
if err := ensureDirectory(dir); err != nil {
|
||||
return fmt.Errorf("unable to ensure the existence of the directory %q: %w", dir, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Println("Processing file:", relativePath)
|
||||
|
||||
if err := sh.Copy(managedPath, path); err != nil {
|
||||
return fmt.Errorf("unable to copy %s to %s: %w", path, managedPath, err)
|
||||
}
|
||||
|
||||
if err := ensureSymlink(managedPath, configPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
//go:build mage
|
||||
|
||||
package main
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -10,66 +8,68 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
const configDir string = "hosts"
|
||||
|
||||
type Config struct {
|
||||
ManagedConfigurations []string `json:"managedConfigurations"`
|
||||
BashProfile configBashProfile `json:"bashProfile"`
|
||||
Directories configDirectories `json:"directories"`
|
||||
Git configGit `json:"git"`
|
||||
BashProfile ConfigBashProfile `json:"bashProfile"`
|
||||
Directories ConfigDirectories `json:"directories"`
|
||||
Git ConfigGit `json:"git"`
|
||||
}
|
||||
|
||||
type configDirectories struct {
|
||||
type ConfigDirectories struct {
|
||||
UseDefaultDirectories bool `json:"useDefaultDirectories"`
|
||||
IncludeXDGDirectories bool `json:"includeXDGDirectories"`
|
||||
AdditionalDirectories []string `json:"additionalDirectories"`
|
||||
}
|
||||
|
||||
type configGit struct {
|
||||
type ConfigGit struct {
|
||||
GpgSign bool `json:"gpgSign"`
|
||||
User configGitUser `json:"user"`
|
||||
User ConfigGitUser `json:"user"`
|
||||
}
|
||||
|
||||
type configGitUser struct {
|
||||
type ConfigGitUser struct {
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
SigningKey string `json:"signingKey"`
|
||||
}
|
||||
|
||||
type configBashProfile struct {
|
||||
type ConfigBashProfile struct {
|
||||
Manage bool `json:"manage"`
|
||||
Filename string `json:"filename"`
|
||||
SessionPaths []configBashProfileSessionPath `json:"sessionPaths"`
|
||||
SessionPaths []ConfigBashProfileSessionPath `json:"sessionPaths"`
|
||||
XdgDirectories map[string]string `json:"xdgDirectories"`
|
||||
EnvironmentVariables map[string]string `json:"environmentVariables"`
|
||||
Aliases map[string]string `json:"aliases"`
|
||||
Commands []configBashProfileCommand `json:"commands"`
|
||||
Commands []ConfigBashProfileCommand `json:"commands"`
|
||||
}
|
||||
|
||||
type configBashProfileSessionPath struct {
|
||||
type ConfigBashProfileSessionPath struct {
|
||||
Path string `json:"path"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type configBashProfileCommand struct {
|
||||
type ConfigBashProfileCommand struct {
|
||||
Command string `json:"command"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func newConfig() (config, error) {
|
||||
func NewConfig() (Config, error) {
|
||||
cfg := defaultConfig()
|
||||
|
||||
path, err := configFilePath()
|
||||
if err != nil {
|
||||
return config{}, fmt.Errorf("unable to calculate the config file path: %w", err)
|
||||
return Config{}, fmt.Errorf("unable to calculate the config file path: %w", err)
|
||||
}
|
||||
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return config{}, fmt.Errorf("unable to open the file: %w", err)
|
||||
return Config{}, fmt.Errorf("unable to open the file: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if err = json.NewDecoder(file).Decode(&cfg); err != nil {
|
||||
return config{}, fmt.Errorf("unable to decode the JSON file: %w", err)
|
||||
return Config{}, fmt.Errorf("unable to decode the JSON file: %w", err)
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
|
@ -92,16 +92,16 @@ func configFilePath() (string, error) {
|
|||
return filepath.Join(configDir, identifier+".json"), nil
|
||||
}
|
||||
|
||||
func defaultConfig() config {
|
||||
return config{
|
||||
Directories: configDirectories{
|
||||
func defaultConfig() Config {
|
||||
return Config{
|
||||
Directories: ConfigDirectories{
|
||||
UseDefaultDirectories: true,
|
||||
IncludeXDGDirectories: true,
|
||||
AdditionalDirectories: []string{},
|
||||
},
|
||||
Git: configGit{
|
||||
Git: ConfigGit{
|
||||
GpgSign: false,
|
||||
User: configGitUser{
|
||||
User: ConfigGitUser{
|
||||
Email: "",
|
||||
Name: "",
|
||||
SigningKey: "",
|
7
magefiles/internal/templatefuncs/env.go
Normal file
7
magefiles/internal/templatefuncs/env.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package templatefuncs
|
||||
|
||||
import "os"
|
||||
|
||||
func Env(value string) string {
|
||||
return os.Getenv(value)
|
||||
}
|
9
magefiles/internal/templatefuncs/templatefuncs.go
Normal file
9
magefiles/internal/templatefuncs/templatefuncs.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package templatefuncs
|
||||
|
||||
import "text/template"
|
||||
|
||||
func FuncMap() template.FuncMap {
|
||||
return template.FuncMap{
|
||||
"env": Env,
|
||||
}
|
||||
}
|
|
@ -1,26 +1,23 @@
|
|||
//go:build mage
|
||||
|
||||
package main
|
||||
package utilities
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/config"
|
||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/templatefuncs"
|
||||
)
|
||||
|
||||
const (
|
||||
dirModePerm fs.FileMode = 0o700
|
||||
const dirModePerm fs.FileMode = 0o700
|
||||
const TemplateExtension string = ".gotmpl"
|
||||
|
||||
configDir string = "hosts"
|
||||
rootManagedDir string = "managed"
|
||||
rootFilesDir string = "files"
|
||||
rootTemplateDir string = "templates"
|
||||
)
|
||||
|
||||
func ensureDirectory(path string) error {
|
||||
func EnsureDirectory(path string) error {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
|
@ -50,7 +47,7 @@ func ensureDirectory(path string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func ensureSymlink(source, dest string) error {
|
||||
func EnsureSymlink(source, dest string) error {
|
||||
absolutePathErrorMessageFormat := "unable to get the absolute path to %s: %w"
|
||||
|
||||
absoluteSourcePath, err := filepath.Abs(source)
|
||||
|
@ -121,7 +118,7 @@ func ensureSymlink(source, dest string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func managedConfigSet(applicationConfigurationList []string) map[string]struct{} {
|
||||
func ManagedConfigSet(applicationConfigurationList []string) map[string]struct{} {
|
||||
set := make(map[string]struct{})
|
||||
|
||||
for _, app := range slices.All(applicationConfigurationList) {
|
||||
|
@ -130,3 +127,32 @@ func managedConfigSet(applicationConfigurationList []string) map[string]struct{}
|
|||
|
||||
return set
|
||||
}
|
||||
|
||||
func RenderTemplate(cfg config.Config, templatePath, managedPath string) error {
|
||||
if !strings.HasSuffix(templatePath, TemplateExtension) {
|
||||
return fmt.Errorf(
|
||||
"the template %s does not have the %q file extension",
|
||||
templatePath,
|
||||
TemplateExtension,
|
||||
)
|
||||
}
|
||||
|
||||
name := filepath.Base(templatePath)
|
||||
|
||||
tmpl, err := template.New(name).Funcs(templatefuncs.FuncMap()).ParseFiles(templatePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create a new template value from %s: %w", templatePath, err)
|
||||
}
|
||||
|
||||
output, err := os.Create(managedPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create %s: %w", managedPath, err)
|
||||
}
|
||||
defer output.Close()
|
||||
|
||||
if err := tmpl.Execute(output, cfg); err != nil {
|
||||
return fmt.Errorf("unable to render the template to %s: %w", managedPath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
64
magefiles/internal/walk/copy_files.go
Normal file
64
magefiles/internal/walk/copy_files.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
package walk
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/utilities"
|
||||
"github.com/magefile/mage/sh"
|
||||
)
|
||||
|
||||
func CopyFiles(
|
||||
homeConfigDirectory string,
|
||||
rootDir string,
|
||||
rootManagedDir string,
|
||||
validationFunc func(string) bool,
|
||||
) fs.WalkDirFunc {
|
||||
return func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if path == rootDir {
|
||||
return nil
|
||||
}
|
||||
|
||||
relativePath := strings.TrimPrefix(path, rootDir+"/")
|
||||
|
||||
if validationFunc != nil {
|
||||
if !validationFunc(relativePath) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
managedPath := filepath.Join(rootManagedDir, relativePath)
|
||||
configPath := filepath.Join(homeConfigDirectory, relativePath)
|
||||
|
||||
if d.IsDir() {
|
||||
dirs := []string{managedPath, configPath}
|
||||
|
||||
for _, dir := range slices.All(dirs) {
|
||||
if err := utilities.EnsureDirectory(dir); err != nil {
|
||||
return fmt.Errorf("unable to ensure the existence of the directory %q: %w", dir, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Println("Processing file:", relativePath)
|
||||
|
||||
if err := sh.Copy(managedPath, path); err != nil {
|
||||
return fmt.Errorf("unable to copy %s to %s: %w", path, managedPath, err)
|
||||
}
|
||||
|
||||
if err := utilities.EnsureSymlink(managedPath, configPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
73
magefiles/internal/walk/render_templates.go
Normal file
73
magefiles/internal/walk/render_templates.go
Normal file
|
@ -0,0 +1,73 @@
|
|||
package walk
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/config"
|
||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/utilities"
|
||||
)
|
||||
|
||||
func RenderTemplates(
|
||||
cfg config.Config,
|
||||
homeConfigDirectory string,
|
||||
rootDir string,
|
||||
rootManagedDir string,
|
||||
validationFunc func(string) bool,
|
||||
) fs.WalkDirFunc {
|
||||
return func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if path == rootDir {
|
||||
return nil
|
||||
}
|
||||
|
||||
relativePath := strings.TrimPrefix(path, rootDir+"/")
|
||||
|
||||
if validationFunc != nil {
|
||||
if !validationFunc(relativePath) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if d.IsDir() {
|
||||
managedDir := filepath.Join(rootManagedDir, relativePath)
|
||||
configDir := filepath.Join(homeConfigDirectory, relativePath)
|
||||
|
||||
dirs := []string{managedDir, configDir}
|
||||
|
||||
for _, dir := range slices.All(dirs) {
|
||||
if err := utilities.EnsureDirectory(dir); err != nil {
|
||||
return fmt.Errorf("unable to ensure the existence of the directory %q: %w", dir, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
managedPath := filepath.Join(rootManagedDir, strings.TrimSuffix(relativePath, utilities.TemplateExtension))
|
||||
configPath := filepath.Join(homeConfigDirectory, strings.TrimSuffix(relativePath, utilities.TemplateExtension))
|
||||
|
||||
fmt.Println("Processing template:", relativePath)
|
||||
|
||||
if err := utilities.RenderTemplate(cfg, path, managedPath); err != nil {
|
||||
return fmt.Errorf(
|
||||
"unable to generate %s from template %s: %w",
|
||||
managedPath,
|
||||
path,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
if err := utilities.EnsureSymlink(managedPath, configPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -4,127 +4,59 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
const templateExtension string = ".gotmpl"
|
||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/config"
|
||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/utilities"
|
||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/walk"
|
||||
)
|
||||
|
||||
// Templates generates the configuration files in the managed directory from the templates and
|
||||
// ensures that they the generated files are symlinked correctly to the files in the user's home
|
||||
// configuration directory.
|
||||
func Templates() error {
|
||||
const rootTemplateDir string = "templates"
|
||||
|
||||
homeConfigDirectory, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get the user's home configuration directory: %w", err)
|
||||
}
|
||||
|
||||
config, err := newConfig()
|
||||
cfg, err := config.NewConfig()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load the configuration: %w", err)
|
||||
}
|
||||
|
||||
managedConfig := managedConfigSet(config.ManagedConfigurations)
|
||||
managedConfig := utilities.ManagedConfigSet(cfg.ManagedConfigurations)
|
||||
|
||||
if err = filepath.WalkDir(rootTemplateDir, manageTemplatesFunc(homeConfigDirectory, config, managedConfig)); err != nil {
|
||||
return fmt.Errorf("received an error while processing the templates: %w", err)
|
||||
validationFunc := func(relativePath string) bool {
|
||||
split := strings.SplitN(relativePath, "/", 2)
|
||||
|
||||
if len(split) < 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
appConfigName := split[0]
|
||||
|
||||
_, exists := managedConfig[appConfigName]
|
||||
|
||||
return exists
|
||||
}
|
||||
|
||||
if err = filepath.WalkDir(
|
||||
rootTemplateDir,
|
||||
walk.RenderTemplates(
|
||||
cfg,
|
||||
homeConfigDirectory,
|
||||
rootTemplateDir,
|
||||
rootManagedDir,
|
||||
validationFunc,
|
||||
),
|
||||
); err != nil {
|
||||
return fmt.Errorf("received an error while rendering the templates: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func manageTemplatesFunc(homeConfigDirectory string, config config, managedConfig map[string]struct{}) fs.WalkDirFunc {
|
||||
funcMap := template.FuncMap{
|
||||
"env": env,
|
||||
}
|
||||
|
||||
return func(templatePath string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if templatePath == rootTemplateDir {
|
||||
return nil
|
||||
}
|
||||
|
||||
relativePath := strings.TrimPrefix(templatePath, rootTemplateDir+"/")
|
||||
|
||||
appConfigName := strings.SplitN(relativePath, "/", 2)[0]
|
||||
|
||||
if _, exists := managedConfig[appConfigName]; !exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
if d.IsDir() {
|
||||
managedDir := filepath.Join(rootManagedDir, relativePath)
|
||||
configDir := filepath.Join(homeConfigDirectory, relativePath)
|
||||
|
||||
dirs := []string{managedDir, configDir}
|
||||
|
||||
for _, dir := range slices.All(dirs) {
|
||||
if err := ensureDirectory(dir); err != nil {
|
||||
return fmt.Errorf("unable to ensure the existence of the directory %q: %w", dir, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(templatePath, templateExtension) {
|
||||
return fmt.Errorf(
|
||||
"the template %s does not have the %q file extension",
|
||||
templatePath,
|
||||
templateExtension,
|
||||
)
|
||||
}
|
||||
|
||||
managedPath := filepath.Join(rootManagedDir, strings.TrimSuffix(relativePath, templateExtension))
|
||||
configPath := filepath.Join(homeConfigDirectory, strings.TrimSuffix(relativePath, templateExtension))
|
||||
|
||||
fmt.Println("Processing template:", relativePath)
|
||||
|
||||
if err := renderTemplate(config, templatePath, managedPath, funcMap); err != nil {
|
||||
return fmt.Errorf(
|
||||
"unable to generate %s from template %s: %w",
|
||||
managedPath,
|
||||
templatePath,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
if err := ensureSymlink(managedPath, configPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func renderTemplate(config config, templatePath, managedPath string, funcMap template.FuncMap) error {
|
||||
name := filepath.Base(templatePath)
|
||||
|
||||
tmpl, err := template.New(name).Funcs(funcMap).ParseFiles(templatePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create a new template value from %s: %w", templatePath, err)
|
||||
}
|
||||
|
||||
output, err := os.Create(managedPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create %s: %w", managedPath, err)
|
||||
}
|
||||
defer output.Close()
|
||||
|
||||
if err := tmpl.Execute(output, config); err != nil {
|
||||
return fmt.Errorf("unable to render the template to %s: %w", managedPath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func env(value string) string {
|
||||
return os.Getenv(value)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue