checkpoint: implemented managing external config

This commit is contained in:
Dan Anglin 2024-09-14 09:04:10 +01:00
parent 823252fe4d
commit c5c643197f
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
5 changed files with 147 additions and 125 deletions

View file

@ -193,11 +193,5 @@
"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"
}
} }

View file

@ -43,6 +43,14 @@
"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": {

100
magefiles/external.go Normal file
View file

@ -0,0 +1,100 @@
//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
}

View file

@ -1,6 +1,4 @@
//go:build mage package config
package main
import ( import (
"encoding/json" "encoding/json"
@ -10,74 +8,76 @@ import (
"strings" "strings"
) )
type config struct { const dir string = "hosts"
type Config struct {
ManagedConfigurations []string `json:"managedConfigurations"` ManagedConfigurations []string `json:"managedConfigurations"`
BashProfile configBashProfile `json:"bashProfile"` BashProfile BashProfile `json:"bashProfile"`
Directories configDirectories `json:"directories"` Directories Directories `json:"directories"`
Git configGit `json:"git"` Git Git `json:"git"`
Neovim configNeovim `json:"neovim"` ExternalConfigurations []ExternalConfig `json:"externalConfigurations"`
} }
type configDirectories struct { type Directories struct {
UseDefaultDirectories bool `json:"useDefaultDirectories"` UseDefaultDirectories bool `json:"useDefaultDirectories"`
IncludeXDGDirectories bool `json:"includeXDGDirectories"` IncludeXDGDirectories bool `json:"includeXDGDirectories"`
AdditionalDirectories []string `json:"additionalDirectories"` AdditionalDirectories []string `json:"additionalDirectories"`
} }
type configGit struct { type Git struct {
GpgSign bool `json:"gpgSign"` GpgSign bool `json:"gpgSign"`
User configGitUser `json:"user"` User GitUser `json:"user"`
} }
type configGitUser struct { type GitUser struct {
Email string `json:"email"` Email string `json:"email"`
Name string `json:"name"` Name string `json:"name"`
SigningKey string `json:"signingKey"` SigningKey string `json:"signingKey"`
} }
type configBashProfile struct { type BashProfile struct {
Manage bool `json:"manage"` Manage bool `json:"manage"`
Filename string `json:"filename"` Filename string `json:"filename"`
SessionPaths []configBashProfileSessionPath `json:"sessionPaths"` SessionPaths []BashProfileSessionPath `json:"sessionPaths"`
XdgDirectories map[string]string `json:"xdgDirectories"` XdgDirectories map[string]string `json:"xdgDirectories"`
EnvironmentVariables map[string]string `json:"environmentVariables"` EnvironmentVariables map[string]string `json:"environmentVariables"`
Aliases map[string]string `json:"aliases"` Aliases map[string]string `json:"aliases"`
Commands []configBashProfileCommand `json:"commands"` Commands []BashProfileCommand `json:"commands"`
} }
type configBashProfileSessionPath struct { type BashProfileSessionPath struct {
Path string `json:"path"` Path string `json:"path"`
Description string `json:"description"` Description string `json:"description"`
} }
type configBashProfileCommand struct { type BashProfileCommand struct {
Command string `json:"command"` Command string `json:"command"`
Description string `json:"description"` Description string `json:"description"`
} }
type configNeovim struct { type ExternalConfig struct {
Manage bool `json:"manage"` Label string `json:"label"`
GitRepoURL string `json:"gitRepoURL"` GitRepoURL string `json:"gitRepoURL"`
GitRef string `json:"gitRef"` GitRef string `json:"gitRef"`
GitRepoPath string `json:"gitRepoPath"` GitRepoPath string `json:"gitRepoPath"`
} }
func newConfig() (config, error) { func NewConfig() (Config, error) {
cfg := defaultConfig() cfg := defaultConfig()
path, err := configFilePath() path, err := configFilePath()
if err != nil { 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) file, err := os.Open(path)
if err != nil { 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() defer file.Close()
if err = json.NewDecoder(file).Decode(&cfg); err != nil { 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 return cfg, nil
@ -97,24 +97,25 @@ func configFilePath() (string, error) {
identifier := hostnameParts[1] identifier := hostnameParts[1]
return filepath.Join(configDir, identifier+".json"), nil return filepath.Join(dir, identifier+".json"), nil
} }
func defaultConfig() config { func defaultConfig() Config {
return config{ return Config{
Directories: configDirectories{ Directories: Directories{
UseDefaultDirectories: true, UseDefaultDirectories: true,
IncludeXDGDirectories: true, IncludeXDGDirectories: true,
AdditionalDirectories: []string{}, AdditionalDirectories: []string{},
}, },
Git: configGit{ Git: Git{
GpgSign: false, GpgSign: false,
User: configGitUser{ User: GitUser{
Email: "", Email: "",
Name: "", Name: "",
SigningKey: "", SigningKey: "",
}, },
}, },
ManagedConfigurations: []string{}, ManagedConfigurations: []string{},
ExternalConfigurations: []ExternalConfig{},
} }
} }

View file

@ -1,81 +0,0 @@
//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
}