Compare commits
2 commits
c5c643197f
...
b2e1cb30cd
Author | SHA1 | Date | |
---|---|---|---|
b2e1cb30cd | |||
ab68d7b954 |
17 changed files with 396 additions and 506 deletions
|
@ -56,4 +56,3 @@ PS2=" -> "
|
||||||
## {{ $command.Description }}
|
## {{ $command.Description }}
|
||||||
{{ $command.Command }}
|
{{ $command.Command }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{ print "" }}
|
|
||||||
|
|
|
@ -193,5 +193,11 @@
|
||||||
"user-dirs.dirs",
|
"user-dirs.dirs",
|
||||||
"user-dirs.locale",
|
"user-dirs.locale",
|
||||||
"zk"
|
"zk"
|
||||||
]
|
],
|
||||||
|
"neovim": {
|
||||||
|
"manage": true,
|
||||||
|
"gitRepoURL": "https://codeflow.dananglin.me.uk/linux-home/nvim.d.git",
|
||||||
|
"gitRef": "746f07efdb203a46a7a02ada987cd97b68fa92d6",
|
||||||
|
"gitRepoPath": "nvim"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,14 +43,6 @@
|
||||||
"Projects"
|
"Projects"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"externalConfigurations": [
|
|
||||||
{
|
|
||||||
"label": "Neovim",
|
|
||||||
"gitRepoURL": "https://codeflow.dananglin.me.uk/linux-home/nvim.d.git",
|
|
||||||
"gitRef": "746f07efdb203a46a7a02ada987cd97b68fa92d6",
|
|
||||||
"gitRepoPath": "nvim"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"git": {
|
"git": {
|
||||||
"gpgSign": false,
|
"gpgSign": false,
|
||||||
"user": {
|
"user": {
|
||||||
|
|
|
@ -6,9 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"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.
|
// BashProfile manages the user's Bash Profile using their configuration and the Bash Profile template.
|
||||||
|
@ -24,27 +22,31 @@ func BashProfile() error {
|
||||||
return fmt.Errorf("unable to get the user's home configuration directory: %w", err)
|
return fmt.Errorf("unable to get the user's home configuration directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := config.NewConfig()
|
config, err := newConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load the configuration: %w", err)
|
return fmt.Errorf("unable to load the configuration: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cfg.BashProfile.Manage {
|
if !config.BashProfile.Manage {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := utilities.RenderTemplate(cfg, bashProfileTemplateFile, managedBashProfile); err != nil {
|
funcMap := template.FuncMap{
|
||||||
|
"env": env,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := renderTemplate(config, bashProfileTemplateFile, managedBashProfile, funcMap); err != nil {
|
||||||
return fmt.Errorf("unable to generate the Bash Profile: %w", err)
|
return fmt.Errorf("unable to generate the Bash Profile: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
filename := cfg.BashProfile.Filename
|
filename := config.BashProfile.Filename
|
||||||
if filename == "" {
|
if filename == "" {
|
||||||
filename = defaultFilename
|
filename = defaultFilename
|
||||||
}
|
}
|
||||||
|
|
||||||
symlinkPath := filepath.Join(homeDirectory, filename)
|
symlinkPath := filepath.Join(homeDirectory, filename)
|
||||||
|
|
||||||
if err := utilities.EnsureSymlink(managedBashProfile, symlinkPath); err != nil {
|
if err := ensureSymlink(managedBashProfile, symlinkPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,26 @@
|
||||||
package utilities
|
//go:build mage
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"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 (
|
||||||
const TemplateExtension string = ".gotmpl"
|
dirModePerm fs.FileMode = 0o700
|
||||||
|
|
||||||
func EnsureDirectory(path string) error {
|
configDir string = "hosts"
|
||||||
|
rootManagedDir string = "managed"
|
||||||
|
rootFilesDir string = "files"
|
||||||
|
rootTemplateDir string = "templates"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ensureDirectory(path string) error {
|
||||||
info, err := os.Stat(path)
|
info, err := os.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
@ -47,7 +50,7 @@ func EnsureDirectory(path string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func EnsureSymlink(source, dest string) error {
|
func ensureSymlink(source, dest string) error {
|
||||||
absolutePathErrorMessageFormat := "unable to get the absolute path to %s: %w"
|
absolutePathErrorMessageFormat := "unable to get the absolute path to %s: %w"
|
||||||
|
|
||||||
absoluteSourcePath, err := filepath.Abs(source)
|
absoluteSourcePath, err := filepath.Abs(source)
|
||||||
|
@ -118,7 +121,7 @@ func EnsureSymlink(source, dest string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ManagedConfigSet(applicationConfigurationList []string) map[string]struct{} {
|
func managedConfigSet(applicationConfigurationList []string) map[string]struct{} {
|
||||||
set := make(map[string]struct{})
|
set := make(map[string]struct{})
|
||||||
|
|
||||||
for _, app := range slices.All(applicationConfigurationList) {
|
for _, app := range slices.All(applicationConfigurationList) {
|
||||||
|
@ -127,32 +130,3 @@ func ManagedConfigSet(applicationConfigurationList []string) map[string]struct{}
|
||||||
|
|
||||||
return set
|
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
|
|
||||||
}
|
|
120
magefiles/config.go
Normal file
120
magefiles/config.go
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
//go:build mage
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type config struct {
|
||||||
|
ManagedConfigurations []string `json:"managedConfigurations"`
|
||||||
|
BashProfile configBashProfile `json:"bashProfile"`
|
||||||
|
Directories configDirectories `json:"directories"`
|
||||||
|
Git configGit `json:"git"`
|
||||||
|
Neovim configNeovim `json:"neovim"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type configDirectories struct {
|
||||||
|
UseDefaultDirectories bool `json:"useDefaultDirectories"`
|
||||||
|
IncludeXDGDirectories bool `json:"includeXDGDirectories"`
|
||||||
|
AdditionalDirectories []string `json:"additionalDirectories"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type configGit struct {
|
||||||
|
GpgSign bool `json:"gpgSign"`
|
||||||
|
User configGitUser `json:"user"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type configGitUser struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
SigningKey string `json:"signingKey"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type configBashProfile struct {
|
||||||
|
Manage bool `json:"manage"`
|
||||||
|
Filename string `json:"filename"`
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type configBashProfileSessionPath struct {
|
||||||
|
Path string `json:"path"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type configBashProfileCommand struct {
|
||||||
|
Command string `json:"command"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type configNeovim struct {
|
||||||
|
Manage bool `json:"manage"`
|
||||||
|
GitRepoURL string `json:"gitRepoURL"`
|
||||||
|
GitRef string `json:"gitRef"`
|
||||||
|
GitRepoPath string `json:"gitRepoPath"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
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 cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func configFilePath() (string, error) {
|
||||||
|
hostname, err := os.Hostname()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("unable to get the machine's hostname: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostnameParts := strings.SplitN(hostname, "-", 3)
|
||||||
|
|
||||||
|
if len(hostnameParts) != 3 {
|
||||||
|
return "", fmt.Errorf("unexpected hostname format")
|
||||||
|
}
|
||||||
|
|
||||||
|
identifier := hostnameParts[1]
|
||||||
|
|
||||||
|
return filepath.Join(configDir, identifier+".json"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultConfig() config {
|
||||||
|
return config{
|
||||||
|
Directories: configDirectories{
|
||||||
|
UseDefaultDirectories: true,
|
||||||
|
IncludeXDGDirectories: true,
|
||||||
|
AdditionalDirectories: []string{},
|
||||||
|
},
|
||||||
|
Git: configGit{
|
||||||
|
GpgSign: false,
|
||||||
|
User: configGitUser{
|
||||||
|
Email: "",
|
||||||
|
Name: "",
|
||||||
|
SigningKey: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ManagedConfigurations: []string{},
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,14 +7,11 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"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.
|
// Directories ensure that the specified home directories are present.
|
||||||
func Directories() error {
|
func Directories() error {
|
||||||
cfg, err := config.NewConfig()
|
config, err := newConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load the configuration: %w", err)
|
return fmt.Errorf("unable to load the configuration: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -26,22 +23,22 @@ func Directories() error {
|
||||||
|
|
||||||
directories := make([]string, 0)
|
directories := make([]string, 0)
|
||||||
|
|
||||||
if cfg.Directories.UseDefaultDirectories{
|
if config.Directories.UseDefaultDirectories{
|
||||||
defaultHomeDirs := homeDirectories(userHome, defaultDirectories())
|
defaultHomeDirs := homeDirectories(userHome, defaultDirectories())
|
||||||
directories = append(directories, defaultHomeDirs...)
|
directories = append(directories, defaultHomeDirs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Directories.IncludeXDGDirectories{
|
if config.Directories.IncludeXDGDirectories{
|
||||||
directories = append(directories, xdgDirectories()...)
|
directories = append(directories, xdgDirectories()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cfg.Directories.AdditionalDirectories) != 0 {
|
if len(config.Directories.AdditionalDirectories) != 0 {
|
||||||
additionalHomeDirs := homeDirectories(userHome, cfg.Directories.AdditionalDirectories)
|
additionalHomeDirs := homeDirectories(userHome, config.Directories.AdditionalDirectories)
|
||||||
directories = append(directories, additionalHomeDirs...)
|
directories = append(directories, additionalHomeDirs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dir := range slices.All(directories) {
|
for _, dir := range slices.All(directories) {
|
||||||
if err := utilities.EnsureDirectory(dir); err != nil {
|
if err := ensureDirectory(dir); err != nil {
|
||||||
return fmt.Errorf("unable to ensure that %s is present: %w", dir, err)
|
return fmt.Errorf("unable to ensure that %s is present: %w", dir, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
//go:build mage
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"slices"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/config"
|
|
||||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/walk"
|
|
||||||
"github.com/magefile/mage/sh"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Externalconfigs downloads and manages neovim configuration from a remote git repository.
|
|
||||||
func Externalconfigs() error {
|
|
||||||
cfg, err := config.NewConfig()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"unable to load the configuration: %w",
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
homeConfigDir, err := os.UserConfigDir()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"unable to get the user's home configuration directory: %w",
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, externalConfig := range slices.All(cfg.ExternalConfigurations) {
|
|
||||||
if err := manageExternalConfig(externalConfig, homeConfigDir); err != nil {
|
|
||||||
return fmt.Errorf("received an error while processing %s: %w", externalConfig.Label, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func manageExternalConfig(cfg config.ExternalConfig, homeConfigDir string) error {
|
|
||||||
clonedRepo, err := cloneNvimConfigRepo(cfg.GitRepoURL, cfg.GitRef)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to clone the git repository: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Git repository cloned to:", clonedRepo)
|
|
||||||
|
|
||||||
validationFunc := func(relativePath string) bool {
|
|
||||||
split := strings.SplitN(relativePath, "/", 2)
|
|
||||||
|
|
||||||
if len(split) < 1 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
rootPath := split[0]
|
|
||||||
|
|
||||||
return rootPath == cfg.GitRepoPath
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = filepath.WalkDir(
|
|
||||||
clonedRepo,
|
|
||||||
walk.CopyFiles(homeConfigDir, clonedRepo, rootManagedDir, validationFunc),
|
|
||||||
); err != nil {
|
|
||||||
return fmt.Errorf("received an error while copying the files: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cloneNvimConfigRepo(repoURL, repoRef string) (string, error) {
|
|
||||||
cloneDir, err := os.MkdirTemp("/tmp", "neovim-config-")
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("unable to create the temporary directory: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
git := sh.RunCmd("git", "-C", cloneDir)
|
|
||||||
|
|
||||||
commands := [][]string{
|
|
||||||
{"init"},
|
|
||||||
{"remote", "add", "origin", repoURL},
|
|
||||||
{"fetch", "origin", repoRef},
|
|
||||||
{"checkout", "FETCH_HEAD"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, command := range slices.All(commands) {
|
|
||||||
if err := git(command...); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.RemoveAll(filepath.Join(cloneDir, ".git")); err != nil {
|
|
||||||
return "", fmt.Errorf("unable to remove the .git folder: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cloneDir, nil
|
|
||||||
}
|
|
|
@ -4,54 +4,81 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/linux-home/manager/magefiles/internal/config"
|
"github.com/magefile/mage/sh"
|
||||||
"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
|
// 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
|
// ensures that they are symlinked correctly to the files in the user's home configuration
|
||||||
// directory.
|
// directory.
|
||||||
func Files() error {
|
func Files() error {
|
||||||
const rootFilesDir string = "files"
|
homeConfigDirectory, err := os.UserConfigDir()
|
||||||
|
|
||||||
homeConfigDir, err := os.UserConfigDir()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to get the user's home configuration directory: %w", err)
|
return fmt.Errorf("unable to get the user's home configuration directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := config.NewConfig()
|
config, err := newConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load the configuration: %w", err)
|
return fmt.Errorf("unable to load the configuration: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
managedConfig := utilities.ManagedConfigSet(cfg.ManagedConfigurations)
|
managedConfig := managedConfigSet(config.ManagedConfigurations)
|
||||||
|
|
||||||
validationFunc := func(relativePath string) bool {
|
if err = filepath.WalkDir(rootFilesDir, manageFilesFunc(homeConfigDirectory, managedConfig)); err != nil {
|
||||||
split := strings.SplitN(relativePath, "/", 2)
|
return fmt.Errorf("received an error while processing the files: %w", err)
|
||||||
|
|
||||||
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
|
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,121 +0,0 @@
|
||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const dir string = "hosts"
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
ManagedConfigurations []string `json:"managedConfigurations"`
|
|
||||||
BashProfile BashProfile `json:"bashProfile"`
|
|
||||||
Directories Directories `json:"directories"`
|
|
||||||
Git Git `json:"git"`
|
|
||||||
ExternalConfigurations []ExternalConfig `json:"externalConfigurations"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Directories struct {
|
|
||||||
UseDefaultDirectories bool `json:"useDefaultDirectories"`
|
|
||||||
IncludeXDGDirectories bool `json:"includeXDGDirectories"`
|
|
||||||
AdditionalDirectories []string `json:"additionalDirectories"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Git struct {
|
|
||||||
GpgSign bool `json:"gpgSign"`
|
|
||||||
User GitUser `json:"user"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GitUser struct {
|
|
||||||
Email string `json:"email"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
SigningKey string `json:"signingKey"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type BashProfile struct {
|
|
||||||
Manage bool `json:"manage"`
|
|
||||||
Filename string `json:"filename"`
|
|
||||||
SessionPaths []BashProfileSessionPath `json:"sessionPaths"`
|
|
||||||
XdgDirectories map[string]string `json:"xdgDirectories"`
|
|
||||||
EnvironmentVariables map[string]string `json:"environmentVariables"`
|
|
||||||
Aliases map[string]string `json:"aliases"`
|
|
||||||
Commands []BashProfileCommand `json:"commands"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type BashProfileSessionPath struct {
|
|
||||||
Path string `json:"path"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type BashProfileCommand struct {
|
|
||||||
Command string `json:"command"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ExternalConfig struct {
|
|
||||||
Label string `json:"label"`
|
|
||||||
GitRepoURL string `json:"gitRepoURL"`
|
|
||||||
GitRef string `json:"gitRef"`
|
|
||||||
GitRepoPath string `json:"gitRepoPath"`
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
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 cfg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func configFilePath() (string, error) {
|
|
||||||
hostname, err := os.Hostname()
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("unable to get the machine's hostname: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
hostnameParts := strings.SplitN(hostname, "-", 3)
|
|
||||||
|
|
||||||
if len(hostnameParts) != 3 {
|
|
||||||
return "", fmt.Errorf("unexpected hostname format")
|
|
||||||
}
|
|
||||||
|
|
||||||
identifier := hostnameParts[1]
|
|
||||||
|
|
||||||
return filepath.Join(dir, identifier+".json"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultConfig() Config {
|
|
||||||
return Config{
|
|
||||||
Directories: Directories{
|
|
||||||
UseDefaultDirectories: true,
|
|
||||||
IncludeXDGDirectories: true,
|
|
||||||
AdditionalDirectories: []string{},
|
|
||||||
},
|
|
||||||
Git: Git{
|
|
||||||
GpgSign: false,
|
|
||||||
User: GitUser{
|
|
||||||
Email: "",
|
|
||||||
Name: "",
|
|
||||||
SigningKey: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ManagedConfigurations: []string{},
|
|
||||||
ExternalConfigurations: []ExternalConfig{},
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
package templatefuncs
|
|
||||||
|
|
||||||
import "os"
|
|
||||||
|
|
||||||
func Env(value string) string {
|
|
||||||
return os.Getenv(value)
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package templatefuncs
|
|
||||||
|
|
||||||
import "text/template"
|
|
||||||
|
|
||||||
func FuncMap() template.FuncMap {
|
|
||||||
return template.FuncMap{
|
|
||||||
"env": Env,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
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,12 +4,10 @@ package main
|
||||||
|
|
||||||
import "github.com/magefile/mage/mg"
|
import "github.com/magefile/mage/mg"
|
||||||
|
|
||||||
const rootManagedDir string = "managed"
|
var Default = Manage
|
||||||
|
|
||||||
var Default = All
|
// Manage runs all the management tasks.
|
||||||
|
func Manage() error {
|
||||||
// All runs all the management tasks.
|
|
||||||
func All() error {
|
|
||||||
mg.Deps(Directories, Files, Templates)
|
mg.Deps(Directories, Files, Templates)
|
||||||
|
|
||||||
return nil
|
return nil
|
81
magefiles/neovim.go
Normal file
81
magefiles/neovim.go
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
//go:build mage
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
"github.com/magefile/mage/sh"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Neovim downloads and manages neovim configuration from a remote git repository.
|
||||||
|
func Neovim() error {
|
||||||
|
config, err := newConfig()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"unable to load the configuration: %w",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !config.Neovim.Manage {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//homeConfigDirectory, err := os.UserConfigDir()
|
||||||
|
//if err != nil {
|
||||||
|
// return fmt.Errorf(
|
||||||
|
// "unable to get the user's home configuration directory: %w",
|
||||||
|
// err,
|
||||||
|
// )
|
||||||
|
//}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// neovimManagedDir = filepath.Join(rootManagedDir, "nvim")
|
||||||
|
// versionLabelFile = filepath.Join(neovimManagedDir, ".managed.version")
|
||||||
|
// neovimConfigDir = filepath.Join(homeConfigDirectory, "nvim")
|
||||||
|
)
|
||||||
|
|
||||||
|
tempLocalRepo, err := cloneNvimConfigRepo(config.Neovim.GitRepoURL, config.Neovim.GitRef)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to clone the git repository: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Git repository cloned to:", tempLocalRepo)
|
||||||
|
|
||||||
|
// defer os.Remove(tempLocalRepo)
|
||||||
|
|
||||||
|
// TODO: copy the files from temp folder to managed folder
|
||||||
|
|
||||||
|
// TODO: add commit/tag ref to .managed.version
|
||||||
|
|
||||||
|
// TODO: symlink all inside managed neovim folder
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cloneNvimConfigRepo(repoURL, repoRef string) (string, error) {
|
||||||
|
cloneDir, err := os.MkdirTemp("/tmp", "neovim-config-")
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("unable to create the temporary directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
git := sh.RunCmd("git", "-C", cloneDir)
|
||||||
|
|
||||||
|
commands := [][]string{
|
||||||
|
{"init"},
|
||||||
|
{"remote", "add", "origin", repoURL},
|
||||||
|
{"fetch", "origin", repoRef},
|
||||||
|
{"checkout", "FETCH_HEAD"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, command := range slices.All(commands) {
|
||||||
|
if err := git(command...); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cloneDir, nil
|
||||||
|
}
|
|
@ -4,59 +4,127 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
"text/template"
|
||||||
"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"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const templateExtension string = ".gotmpl"
|
||||||
|
|
||||||
// Templates generates the configuration files in the managed directory from the templates and
|
// 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
|
// ensures that they the generated files are symlinked correctly to the files in the user's home
|
||||||
// configuration directory.
|
// configuration directory.
|
||||||
func Templates() error {
|
func Templates() error {
|
||||||
const rootTemplateDir string = "templates"
|
|
||||||
|
|
||||||
homeConfigDirectory, err := os.UserConfigDir()
|
homeConfigDirectory, err := os.UserConfigDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to get the user's home configuration directory: %w", err)
|
return fmt.Errorf("unable to get the user's home configuration directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := config.NewConfig()
|
config, err := newConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load the configuration: %w", err)
|
return fmt.Errorf("unable to load the configuration: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
managedConfig := utilities.ManagedConfigSet(cfg.ManagedConfigurations)
|
managedConfig := managedConfigSet(config.ManagedConfigurations)
|
||||||
|
|
||||||
validationFunc := func(relativePath string) bool {
|
if err = filepath.WalkDir(rootTemplateDir, manageTemplatesFunc(homeConfigDirectory, config, managedConfig)); err != nil {
|
||||||
split := strings.SplitN(relativePath, "/", 2)
|
return fmt.Errorf("received an error while processing the templates: %w", err)
|
||||||
|
|
||||||
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
|
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