From c5c643197fe0dd7b5d68ecc3e0a60318ef933617 Mon Sep 17 00:00:00 2001 From: Dan Anglin Date: Sat, 14 Sep 2024 09:04:10 +0100 Subject: [PATCH] checkpoint: implemented managing external config --- hosts/falcon.json | 8 +-- hosts/sparrow.json | 8 +++ magefiles/external.go | 100 ++++++++++++++++++++++++++++ magefiles/internal/config/config.go | 75 +++++++++++---------- magefiles/neovim.go | 81 ---------------------- 5 files changed, 147 insertions(+), 125 deletions(-) create mode 100644 magefiles/external.go delete mode 100644 magefiles/neovim.go diff --git a/hosts/falcon.json b/hosts/falcon.json index 8b58611..4166702 100644 --- a/hosts/falcon.json +++ b/hosts/falcon.json @@ -193,11 +193,5 @@ "user-dirs.dirs", "user-dirs.locale", "zk" - ], - "neovim": { - "manage": true, - "gitRepoURL": "https://codeflow.dananglin.me.uk/linux-home/nvim.d.git", - "gitRef": "746f07efdb203a46a7a02ada987cd97b68fa92d6", - "gitRepoPath": "nvim" - } + ] } diff --git a/hosts/sparrow.json b/hosts/sparrow.json index e7d7e99..809fe4d 100644 --- a/hosts/sparrow.json +++ b/hosts/sparrow.json @@ -43,6 +43,14 @@ "Projects" ] }, + "externalConfigurations": [ + { + "label": "Neovim", + "gitRepoURL": "https://codeflow.dananglin.me.uk/linux-home/nvim.d.git", + "gitRef": "746f07efdb203a46a7a02ada987cd97b68fa92d6", + "gitRepoPath": "nvim" + } + ], "git": { "gpgSign": false, "user": { diff --git a/magefiles/external.go b/magefiles/external.go new file mode 100644 index 0000000..d501be4 --- /dev/null +++ b/magefiles/external.go @@ -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 +} diff --git a/magefiles/internal/config/config.go b/magefiles/internal/config/config.go index c3c2eea..ad35a27 100644 --- a/magefiles/internal/config/config.go +++ b/magefiles/internal/config/config.go @@ -1,6 +1,4 @@ -//go:build mage - -package main +package config import ( "encoding/json" @@ -10,74 +8,76 @@ import ( "strings" ) -type config struct { - ManagedConfigurations []string `json:"managedConfigurations"` - BashProfile configBashProfile `json:"bashProfile"` - Directories configDirectories `json:"directories"` - Git configGit `json:"git"` - Neovim configNeovim `json:"neovim"` +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 configDirectories struct { +type Directories 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 Git struct { + GpgSign bool `json:"gpgSign"` + User GitUser `json:"user"` } -type configGitUser struct { +type GitUser 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 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 configBashProfileSessionPath struct { +type BashProfileSessionPath struct { Path string `json:"path"` Description string `json:"description"` } -type configBashProfileCommand struct { +type BashProfileCommand struct { Command string `json:"command"` Description string `json:"description"` } -type configNeovim struct { - Manage bool `json:"manage"` +type ExternalConfig struct { + Label string `json:"label"` GitRepoURL string `json:"gitRepoURL"` GitRef string `json:"gitRef"` GitRepoPath string `json:"gitRepoPath"` } -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 @@ -97,24 +97,25 @@ func configFilePath() (string, error) { identifier := hostnameParts[1] - return filepath.Join(configDir, identifier+".json"), nil + return filepath.Join(dir, identifier+".json"), nil } -func defaultConfig() config { - return config{ - Directories: configDirectories{ +func defaultConfig() Config { + return Config{ + Directories: Directories{ UseDefaultDirectories: true, IncludeXDGDirectories: true, AdditionalDirectories: []string{}, }, - Git: configGit{ + Git: Git{ GpgSign: false, - User: configGitUser{ + User: GitUser{ Email: "", Name: "", SigningKey: "", }, }, - ManagedConfigurations: []string{}, + ManagedConfigurations: []string{}, + ExternalConfigurations: []ExternalConfig{}, } } diff --git a/magefiles/neovim.go b/magefiles/neovim.go deleted file mode 100644 index b16314d..0000000 --- a/magefiles/neovim.go +++ /dev/null @@ -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 -}