fix: install versioned default theme state
This commit is contained in:
@@ -12,20 +12,20 @@ CONFIG_MARKER := $(CONFIG_DIR)/.tint-installed-config
|
|||||||
STATE_MARKER := $(CONFIG_DIR)/.tint-installed-state
|
STATE_MARKER := $(CONFIG_DIR)/.tint-installed-state
|
||||||
|
|
||||||
.PHONY: install uninstall
|
.PHONY: install uninstall
|
||||||
install:
|
install: default-state.toml config.toml
|
||||||
@command -v tinty >/dev/null || { echo "tinty is required" >&2; exit 1; }
|
@command -v tinty >/dev/null || { echo "tinty is required" >&2; exit 1; }
|
||||||
@command -v dark-notify >/dev/null || { echo "dark-notify is required" >&2; exit 1; }
|
@command -v dark-notify >/dev/null || { echo "dark-notify is required" >&2; exit 1; }
|
||||||
mkdir -p "$(BIN_DIR)" "$(CONFIG_DIR)" "$(HERDR_DIR)" "$(LAUNCH_AGENT_DIR)" "$(dir $(DARK_NOTIFY_LOG))"
|
mkdir -p "$(BIN_DIR)" "$(CONFIG_DIR)" "$(HERDR_DIR)" "$(LAUNCH_AGENT_DIR)" "$(dir $(DARK_NOTIFY_LOG))"
|
||||||
go build -o "$(BIN_DIR)/tint" .
|
go build -o "$(BIN_DIR)/tint" .
|
||||||
@if [ "$(CURDIR)" != "$(CONFIG_DIR)" ]; then \
|
@set -e; if [ "$(CURDIR)" != "$(CONFIG_DIR)" ]; then \
|
||||||
if [ -e "$(CONFIG_MARKER)" ] || [ ! -e "$(CONFIG_DIR)/config.toml" ]; then \
|
if [ -e "$(CONFIG_MARKER)" ] || [ ! -e "$(CONFIG_DIR)/config.toml" ]; then \
|
||||||
cp config.toml "$(CONFIG_DIR)/config.toml"; \
|
cp config.toml "$(CONFIG_DIR)/config.toml"; \
|
||||||
touch "$(CONFIG_MARKER)"; \
|
touch "$(CONFIG_MARKER)"; \
|
||||||
fi; \
|
fi; \
|
||||||
if [ ! -e "$(CONFIG_DIR)/state.toml" ]; then \
|
fi; \
|
||||||
cp state.toml "$(CONFIG_DIR)/state.toml"; \
|
if [ ! -e "$(CONFIG_DIR)/state.toml" ]; then \
|
||||||
touch "$(STATE_MARKER)"; \
|
cp default-state.toml "$(CONFIG_DIR)/state.toml"; \
|
||||||
fi; \
|
touch "$(STATE_MARKER)"; \
|
||||||
fi
|
fi
|
||||||
@if [ ! -e "$(HERDR_CONFIG)" ]; then \
|
@if [ ! -e "$(HERDR_CONFIG)" ]; then \
|
||||||
touch "$(HERDR_CONFIG)" "$(HERDR_MARKER)"; \
|
touch "$(HERDR_CONFIG)" "$(HERDR_MARKER)"; \
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ The installer:
|
|||||||
|
|
||||||
- Builds `~/.local/bin/tint`.
|
- Builds `~/.local/bin/tint`.
|
||||||
- Installs `config.toml` under `$XDG_CONFIG_HOME/tinted-theming/tinty`, or `~/.config/tinted-theming/tinty` when `XDG_CONFIG_HOME` is unset.
|
- Installs `config.toml` under `$XDG_CONFIG_HOME/tinted-theming/tinty`, or `~/.config/tinted-theming/tinty` when `XDG_CONFIG_HOME` is unset.
|
||||||
- Copies `state.toml` only when no state file already exists.
|
- Copies the versioned `default-state.toml` to the installed `state.toml` only when no state file already exists.
|
||||||
- Creates `~/.config/herdr/config.toml` if needed.
|
- Creates `~/.config/herdr/config.toml` if needed.
|
||||||
- Runs `tinty sync` to download the configured theme repositories.
|
- Runs `tinty sync` to download the configured theme repositories.
|
||||||
- Creates and loads a `dark-notify` LaunchAgent for automatic macOS appearance switching.
|
- Creates and loads a `dark-notify` LaunchAgent for automatic macOS appearance switching.
|
||||||
@@ -180,7 +180,7 @@ After changing or updating the wrapper source:
|
|||||||
make install
|
make install
|
||||||
```
|
```
|
||||||
|
|
||||||
Existing `state.toml` content is preserved.
|
Existing `state.toml` content is preserved. Missing state is recreated from `default-state.toml`, including the bundled named pairs and favorites. The source directory's ignored `state.toml` is personal state and is not used by the installer.
|
||||||
|
|
||||||
## Uninstall
|
## Uninstall
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
[current]
|
||||||
|
light = "base16-swamp-light"
|
||||||
|
dark = "base16-darktooth"
|
||||||
|
|
||||||
|
[[favorites.pairs]]
|
||||||
|
name = "gruvbox-material-medium"
|
||||||
|
dark = "base16-gruvbox-material-dark-medium"
|
||||||
|
light = "base16-gruvbox-material-light-medium"
|
||||||
|
|
||||||
|
[[favorites.pairs]]
|
||||||
|
name = "gruvbox-pale"
|
||||||
|
dark = "base16-gruvbox-dark-pale"
|
||||||
|
light = "base16-gruvbox-light-soft"
|
||||||
|
|
||||||
|
[[favorites.pairs]]
|
||||||
|
name = "swamp"
|
||||||
|
dark = "base16-swamp-dark"
|
||||||
|
light = "base16-swamp-light"
|
||||||
|
|
||||||
|
[favorites]
|
||||||
|
themes = [
|
||||||
|
"base16-0x96f",
|
||||||
|
"base16-arroz-con-dulce",
|
||||||
|
"base16-ascendancy",
|
||||||
|
"base16-atelier-plateau-light",
|
||||||
|
"base16-cacao",
|
||||||
|
"base16-caroline",
|
||||||
|
"base16-chinoiserie-midnight",
|
||||||
|
"base16-corduroy",
|
||||||
|
"base16-cupcake",
|
||||||
|
"base16-darktooth",
|
||||||
|
"base16-embers",
|
||||||
|
"base16-gruvbox-dark-pale",
|
||||||
|
"base16-pastelon-de-amarillos-dark",
|
||||||
|
"base16-precious-light-warm",
|
||||||
|
"base16-rose-pine-dawn",
|
||||||
|
"base16-selenized-light",
|
||||||
|
"base16-swamp-dark",
|
||||||
|
"base16-swamp-light",
|
||||||
|
"base24-ic-orange-ppl",
|
||||||
|
"base24-later-this-evening",
|
||||||
|
"tinted8-gruvbox-dark",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[others.pairs]]
|
||||||
|
name = "amarillos"
|
||||||
|
dark = "base16-pastelon-de-amarillos-dark"
|
||||||
|
light = "base16-pastelon-de-amarillos"
|
||||||
|
|
||||||
|
[[others.pairs]]
|
||||||
|
name = "charcoal"
|
||||||
|
dark = "base16-charcoal-dark"
|
||||||
|
light = "base16-charcoal-light"
|
||||||
|
|
||||||
|
[[others.pairs]]
|
||||||
|
name = "embers"
|
||||||
|
dark = "base16-embers"
|
||||||
|
light = "base16-embers-light"
|
||||||
|
|
||||||
|
[[others.pairs]]
|
||||||
|
name = "gruvbox-material-hard"
|
||||||
|
dark = "base16-gruvbox-material-dark-hard"
|
||||||
|
light = "base16-gruvbox-material-light-hard"
|
||||||
|
|
||||||
|
[[others.pairs]]
|
||||||
|
name = "gruvbox-material-soft"
|
||||||
|
dark = "base16-gruvbox-material-dark-soft"
|
||||||
|
light = "base16-gruvbox-material-light-soft"
|
||||||
|
|
||||||
|
[[others.pairs]]
|
||||||
|
name = "pale-swamp"
|
||||||
|
dark = "base16-gruvbox-dark-pale"
|
||||||
|
light = "base16-swamp-light"
|
||||||
|
|
||||||
|
[others]
|
||||||
|
themes = [
|
||||||
|
"base16-apprentice",
|
||||||
|
"base16-ashes",
|
||||||
|
"base16-atelier-heath",
|
||||||
|
"base16-atelier-heath-light",
|
||||||
|
"base16-black-metal",
|
||||||
|
"base16-black-metal-bathory",
|
||||||
|
"base16-black-metal-khold",
|
||||||
|
"base16-black-metal-mayhem",
|
||||||
|
"base16-chinoiserie-morandi",
|
||||||
|
"base16-corduroy-dark",
|
||||||
|
"base16-da-one-gray",
|
||||||
|
"base16-default-dark",
|
||||||
|
"base16-equilibrium-light",
|
||||||
|
"base16-helios",
|
||||||
|
"base16-kanagawa-dragon",
|
||||||
|
"base16-mezcal",
|
||||||
|
"base16-railscasts",
|
||||||
|
"base16-sandcastle",
|
||||||
|
"base16-tarot",
|
||||||
|
"base16-vesper",
|
||||||
|
"base16-zenbones",
|
||||||
|
"base24-alucard",
|
||||||
|
"base24-earthsong",
|
||||||
|
"base24-flexoki-light",
|
||||||
|
"base24-mountain",
|
||||||
|
"base24-pastelon-de-amarillos",
|
||||||
|
"base24-sleepy-hollow",
|
||||||
|
]
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInstallFromFreshCheckout(t *testing.T) {
|
||||||
|
tmp := t.TempDir()
|
||||||
|
source := filepath.Join(tmp, "source")
|
||||||
|
bin := filepath.Join(tmp, "bin")
|
||||||
|
for _, dir := range []string{source, bin} {
|
||||||
|
if err := os.Mkdir(dir, 0o755); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entries, err := os.ReadDir(".")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, entry := range entries {
|
||||||
|
if !entry.Type().IsRegular() || entry.Name() == "state.toml" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data, err := os.ReadFile(entry.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(filepath.Join(source, entry.Name()), data, 0o644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeExecutable(t, filepath.Join(bin, "tinty"), `#!/bin/sh
|
||||||
|
case "$1" in
|
||||||
|
sync|info) exit 0 ;;
|
||||||
|
apply) printf '%s\n' "$2" >> "$TINTY_LOG" ;;
|
||||||
|
*) exit 2 ;;
|
||||||
|
esac
|
||||||
|
`)
|
||||||
|
for _, name := range []string{"dark-notify", "launchctl"} {
|
||||||
|
writeExecutable(t, filepath.Join(bin, name), "#!/bin/sh\nexit 0\n")
|
||||||
|
}
|
||||||
|
home := filepath.Join(tmp, "home")
|
||||||
|
config := filepath.Join(home, ".config")
|
||||||
|
log := filepath.Join(tmp, "applied")
|
||||||
|
cache, err := exec.Command("go", "env", "GOMODCACHE").Output()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Setenv("GOMODCACHE", strings.TrimSpace(string(cache)))
|
||||||
|
t.Setenv("PATH", bin+":"+os.Getenv("PATH"))
|
||||||
|
t.Setenv("TINTY_LOG", log)
|
||||||
|
install := func() {
|
||||||
|
t.Helper()
|
||||||
|
cmd := exec.Command("make", "install", "HOME="+home, "XDG_CONFIG_HOME="+config)
|
||||||
|
cmd.Dir = source
|
||||||
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
|
t.Fatalf("install failed: %v\n%s", err, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
install()
|
||||||
|
statePath := filepath.Join(config, "tinted-theming", "tinty", "state.toml")
|
||||||
|
value, err := loadState(statePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("fresh install did not provide usable state: %v", err)
|
||||||
|
}
|
||||||
|
cmd := exec.Command(filepath.Join(home, ".local", "bin", "tint"), "swamp")
|
||||||
|
cmd.Env = append(os.Environ(), "TINT_STATE_FILE="+statePath, "TINTY_PAIR_APPEARANCE=dark")
|
||||||
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
|
t.Fatalf("selecting an installed pair failed: %v\n%s", err, output)
|
||||||
|
}
|
||||||
|
if got := strings.TrimSpace(readFile(t, log)); got != "base16-swamp-dark" {
|
||||||
|
t.Fatalf("applied theme = %q, want base16-swamp-dark", got)
|
||||||
|
}
|
||||||
|
value.Current = currentPair{Light: "personal-light", Dark: "personal-dark"}
|
||||||
|
if err := saveState(statePath, value); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
before, err := os.ReadFile(statePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
install()
|
||||||
|
after, err := os.ReadFile(statePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(before, after) {
|
||||||
|
t.Fatal("reinstall overwrote personal state")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user