Dan Anglin
2402833b1a
This commit updates the scope of this project to manage the files and directories within my home directory. The Makefile and helper bash scripts are now replaced with mage targets so that the home directory is now managed with Mage. The state of the home directory is managed using a JSON configuration for each machine host. The manager is a set of mage targets to manage various aspects of the home directory. At the moment the manager can: - ensure specified directories are present within the home directory. - ensure application configuration files are up-to-date and have the correct symlinks within the user's home configuration directory. - manages the user's bash profile (a.k.a bashrc) file. Other notable changes: - The X11 xinitrc is removed because it is not currently used and won't be used for the forseeable future as we slowly move to Wayland. - All bashrc configurations are now defined in one file and is now fully managed by the manager. - The dunst configuration is currently removed but will make a comeback. - The ansible configuration is removed as it is no longer used. - The logrotate configuration is updated and now generated from a template. - Added configuration for the foot terminal. - Added configuration for the River window manager.
132 lines
2.9 KiB
Go
132 lines
2.9 KiB
Go
//go:build mage
|
|
|
|
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"slices"
|
|
)
|
|
|
|
const (
|
|
dirModePerm fs.FileMode = 0o700
|
|
|
|
configDir string = "hosts"
|
|
rootManagedDir string = "managed"
|
|
rootFilesDir string = "files"
|
|
rootTemplateDir string = "templates"
|
|
)
|
|
|
|
func ensureDirectory(path string) error {
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
if err := os.Mkdir(path, dirModePerm); err != nil {
|
|
return fmt.Errorf("unable to create the directory: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf(
|
|
"received an unexpected error after attempting to get the directory information: %w",
|
|
err,
|
|
)
|
|
}
|
|
|
|
if !info.IsDir() {
|
|
return errors.New("the path exists but it is not a directory")
|
|
}
|
|
|
|
if info.Mode().Perm() != dirModePerm {
|
|
if err := os.Chmod(path, dirModePerm); err != nil {
|
|
return fmt.Errorf("unable to update the directory's mode to %d: %w", dirModePerm, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func ensureSymlink(source, dest string) error {
|
|
absolutePathErrorMessageFormat := "unable to get the absolute path to %s: %w"
|
|
|
|
absoluteSourcePath, err := filepath.Abs(source)
|
|
if err != nil {
|
|
return fmt.Errorf(absolutePathErrorMessageFormat, source, err)
|
|
}
|
|
|
|
absoluteDestPath, err := filepath.Abs(dest)
|
|
if err != nil {
|
|
return fmt.Errorf(absolutePathErrorMessageFormat, dest, err)
|
|
}
|
|
|
|
destInfo, err := os.Lstat(absoluteDestPath)
|
|
if err != nil {
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
fmt.Printf("Linking %s to %s\n", absoluteDestPath, absoluteSourcePath)
|
|
|
|
if err := os.Symlink(absoluteSourcePath, absoluteDestPath); err != nil {
|
|
return fmt.Errorf(
|
|
"unable to symlink %s to %s: %w",
|
|
absoluteDestPath,
|
|
absoluteSourcePath,
|
|
err,
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("unable to get the file info for %s: %w", absoluteDestPath, err)
|
|
}
|
|
|
|
if destInfo.Mode().Type() != fs.ModeSymlink {
|
|
return fmt.Errorf("the path %s exists but it is not a symlink", absoluteDestPath)
|
|
}
|
|
|
|
destLinksTo, err := filepath.EvalSymlinks(absoluteDestPath)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to evaluate the symlink %s: %w", absoluteDestPath, err)
|
|
}
|
|
|
|
if destLinksTo == absoluteSourcePath {
|
|
return nil
|
|
}
|
|
|
|
fmt.Printf(
|
|
"%s should link back to %s but instead links back to %s\n",
|
|
absoluteDestPath,
|
|
absoluteSourcePath,
|
|
destLinksTo,
|
|
)
|
|
|
|
fmt.Println("Recreating:", absoluteDestPath)
|
|
|
|
if err := os.Remove(absoluteDestPath); err != nil {
|
|
return fmt.Errorf("unable to remove %s: %w", absoluteDestPath, err)
|
|
}
|
|
|
|
if err := os.Symlink(absoluteSourcePath, absoluteDestPath); err != nil {
|
|
return fmt.Errorf(
|
|
"unable to symlink %s to %s: %w",
|
|
absoluteDestPath,
|
|
absoluteSourcePath,
|
|
err,
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func managedConfigSet(applicationConfigurationList []string) map[string]struct{} {
|
|
set := make(map[string]struct{})
|
|
|
|
for _, app := range slices.All(applicationConfigurationList) {
|
|
set[app] = struct{}{}
|
|
}
|
|
|
|
return set
|
|
}
|