From 5a458468c48474183ae646555ce05af4c65162c2 Mon Sep 17 00:00:00 2001 From: JDKamalakar Date: Fri, 14 Aug 2026 07:35:37 +0530 Subject: [PATCH 1/3] feat: add option for non interactive install via install script --- core/README.md | 26 +++++--- core/cmd/dankinstall/main.go | 51 ++++++++++++++- core/install.sh | 12 ++-- core/internal/headless/runner.go | 91 ++++++++++++++++++++++++++- core/internal/headless/runner_test.go | 48 ++++++++++++-- 5 files changed, 206 insertions(+), 22 deletions(-) diff --git a/core/README.md b/core/README.md index ea07a91cf..db9b54c13 100644 --- a/core/README.md +++ b/core/README.md @@ -155,18 +155,30 @@ curl -fsSL https://install.danklinux.com | sh **Headless (unattended):** -Headless mode requires cached sudo credentials. Run `sudo -v` first: +Headless mode requires cached credentials or passwordless privilege escalation (sudo/doas/run0): ```bash -sudo -v && curl -fsSL https://install.danklinux.com | sh -s -- -c niri -t ghostty -y -sudo -v && curl -fsSL https://install.danklinux.com | sh -s -- -c hyprland -t kitty --include-deps dms-greeter -y +curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c niri -t ghostty -p sudo -y +curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c hyprland -t kitty --wm-git --quickshell-git -a -y +curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c mango -t alacritty --git --danksearch --dankcalendar -y ``` | Flag | Short | Description | |------|-------|-------------| -| `--compositor ` | `-c` | Compositor/WM to install (required for headless) | -| `--term ` | `-t` | Terminal emulator (required for headless) | -| `--include-deps ` | | Enable optional dependencies (e.g. `dms-greeter`) | +| `--compositor ` | `-c` | Compositor/WM to install (required for headless) | +| `--term ` | `-t` | Terminal emulator (required for headless) | +| `--privesc ` | `-p` | Explicit privilege escalation tool | +| `--wm-git` | | Use git/development version of selected window manager | +| `--quickshell-git` | | Use git/development version of quickshell | +| `--dms-git` | | Use git/development version of DankMaterialShell | +| `--git` / `--git-all` | | Use git/development versions for all supported components | +| `--git-deps ` | | Specify dependencies to install git versions of | +| `--all` / `--all-features` | `-a` | Install all optional features and dependencies | +| `--no-features` | | Skip all optional features and dependencies | +| `--dms-greeter` / `--greeter` | | Install dms-greeter optional package | +| `--danksearch` | | Install danksearch and enable user indexing service | +| `--dankcalendar` | | Install dankcalendar package | +| `--include-deps ` | | Enable specific optional dependencies | | `--exclude-deps ` | | Skip specific dependencies | | `--replace-configs ` | | Replace specific configuration files (mutually exclusive with `--replace-configs-all`) | | `--replace-configs-all` | | Replace all configuration files (mutually exclusive with `--replace-configs`) | @@ -174,7 +186,7 @@ sudo -v && curl -fsSL https://install.danklinux.com | sh -s -- -c hyprland -t ki Headless mode requires `--yes` to proceed; without it, the installer exits with an error. Configuration files are not replaced by default unless `--replace-configs` or `--replace-configs-all` is specified. -`dms-greeter` is disabled by default; use `--include-deps dms-greeter` to enable it. +Use `--all` / `-a` to automatically enable all optional packages (`dms-greeter`, `danksearch`, `dankcalendar`). When no flags are provided, `dankinstall` launches the interactive TUI. diff --git a/core/cmd/dankinstall/main.go b/core/cmd/dankinstall/main.go index 389992ab1..60fb1c578 100644 --- a/core/cmd/dankinstall/main.go +++ b/core/cmd/dankinstall/main.go @@ -18,6 +18,15 @@ var Version = "dev" var ( compositor string term string + privescTool string + wmGit bool + quickshellGit bool + dmsGit bool + gitAll bool + gitDeps []string + allFeatures bool + noFeatures bool + dmsGreeter bool includeDeps []string excludeDeps []string replaceConfigs []string @@ -35,8 +44,7 @@ var rootCmd = &cobra.Command{ Without flags, it launches an interactive TUI. Providing either --compositor or --term activates headless (unattended) mode, which requires both flags. -Headless mode requires cached sudo credentials. Run 'sudo -v' beforehand, or -configure passwordless sudo for your user.`, +Headless mode requires cached credentials or passwordless privilege escalation.`, Args: cobra.NoArgs, RunE: runDankinstall, SilenceErrors: true, @@ -46,7 +54,19 @@ configure passwordless sudo for your user.`, func init() { rootCmd.Flags().StringVarP(&compositor, "compositor", "c", "", "Compositor/WM to install: niri, hyprland, or mango (enables headless mode)") rootCmd.Flags().StringVarP(&term, "term", "t", "", "Terminal emulator to install: ghostty, kitty, or alacritty (enables headless mode)") - rootCmd.Flags().StringSliceVar(&includeDeps, "include-deps", []string{}, "Optional deps to enable (e.g. dms-greeter)") + rootCmd.Flags().StringVarP(&privescTool, "privesc", "p", "", "Privilege escalation tool: sudo, doas, or run0") + rootCmd.Flags().BoolVar(&wmGit, "wm-git", false, "Use git/development version of selected window manager") + rootCmd.Flags().BoolVar(&quickshellGit, "quickshell-git", false, "Use git/development version of quickshell") + rootCmd.Flags().BoolVar(&dmsGit, "dms-git", false, "Use git/development version of DankMaterialShell") + rootCmd.Flags().BoolVar(&gitAll, "git-all", false, "Use git/development versions for all supported components") + rootCmd.Flags().BoolVar(&gitAll, "git", false, "Use git/development versions for all supported components (alias for --git-all)") + rootCmd.Flags().StringSliceVar(&gitDeps, "git-deps", []string{}, "Comma-separated list of dependencies to use git versions for") + rootCmd.Flags().BoolVarP(&allFeatures, "all-features", "a", false, "Install all optional features and dependencies") + rootCmd.Flags().BoolVar(&allFeatures, "all", false, "Install all optional features and dependencies (alias for --all-features)") + rootCmd.Flags().BoolVar(&noFeatures, "no-features", false, "Skip all optional features and dependencies") + rootCmd.Flags().BoolVar(&dmsGreeter, "dms-greeter", false, "Install dms-greeter optional package") + rootCmd.Flags().BoolVar(&dmsGreeter, "greeter", false, "Install dms-greeter optional package (alias for --dms-greeter)") + rootCmd.Flags().StringSliceVar(&includeDeps, "include-deps", []string{}, "Optional deps to enable (e.g. dms-greeter, danksearch)") rootCmd.Flags().StringSliceVar(&excludeDeps, "exclude-deps", []string{}, "Deps to skip during installation") rootCmd.Flags().StringSliceVar(&replaceConfigs, "replace-configs", []string{}, "Deploy only named configs (e.g. niri,ghostty)") rootCmd.Flags().BoolVar(&replaceConfigsAll, "replace-configs-all", false, "Deploy and replace all configurations") @@ -73,6 +93,18 @@ func runDankinstall(cmd *cobra.Command, args []string) error { if !headlessMode { // Reject headless-only flags when running in TUI mode. headlessOnly := []string{ + "privesc", + "wm-git", + "quickshell-git", + "dms-git", + "git-all", + "git", + "git-deps", + "all-features", + "all", + "no-features", + "dms-greeter", + "greeter", "include-deps", "exclude-deps", "replace-configs", @@ -107,9 +139,22 @@ func runHeadless() error { return fmt.Errorf("--term is required for headless mode (ghostty, kitty, or alacritty)") } + if allFeatures && noFeatures { + return fmt.Errorf("cannot specify both --all-features/--all and --no-features") + } + cfg := headless.Config{ Compositor: compositor, Terminal: term, + PrivescTool: privescTool, + WMGit: wmGit, + QuickshellGit: quickshellGit, + DMSGit: dmsGit, + GitAll: gitAll, + GitDeps: gitDeps, + AllFeatures: allFeatures, + NoFeatures: noFeatures, + DmsGreeter: dmsGreeter, IncludeDeps: includeDeps, ExcludeDeps: excludeDeps, ReplaceConfigs: replaceConfigs, diff --git a/core/install.sh b/core/install.sh index baca5881b..103524a2e 100755 --- a/core/install.sh +++ b/core/install.sh @@ -35,11 +35,13 @@ aarch64) ;; esac +REPO_SLUG="${DMS_REPO:-JDKamalakar/DankMaterialShell}" + # Get the latest release version -LATEST_VERSION=$(curl -s https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') +LATEST_VERSION=$(curl -s "https://api.github.com/repos/${REPO_SLUG}/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') if [ -z "$LATEST_VERSION" ]; then - printf "%bError: Could not fetch latest version%b\n" "$RED" "$NC" + printf "%bError: Could not fetch latest version from %s%b\n" "$RED" "$REPO_SLUG" "$NC" exit 1 fi @@ -51,8 +53,8 @@ cd "$TEMP_DIR" || exit 1 # Download the gzipped binary and its checksum printf "%bDownloading installer...%b\n" "$GREEN" "$NC" -curl -L "https://github.com/AvengeMedia/DankMaterialShell/releases/download/$LATEST_VERSION/dankinstall-$ARCH.gz" -o "installer.gz" -curl -L "https://github.com/AvengeMedia/DankMaterialShell/releases/download/$LATEST_VERSION/dankinstall-$ARCH.gz.sha256" -o "expected.sha256" +curl -L "https://github.com/${REPO_SLUG}/releases/download/$LATEST_VERSION/dankinstall-$ARCH.gz" -o "installer.gz" +curl -L "https://github.com/${REPO_SLUG}/releases/download/$LATEST_VERSION/dankinstall-$ARCH.gz.sha256" -o "expected.sha256" # Get the expected checksum EXPECTED_CHECKSUM=$(awk '{print $1}' expected.sha256) @@ -79,7 +81,7 @@ chmod +x installer # Execute the installer printf "%bRunning installer...%b\n" "$GREEN" "$NC" -./installer +./installer "$@" # Cleanup cd - >/dev/null diff --git a/core/internal/headless/runner.go b/core/internal/headless/runner.go index e5f664c3e..cf7fba391 100644 --- a/core/internal/headless/runner.go +++ b/core/internal/headless/runner.go @@ -34,8 +34,17 @@ var orderedConfigNames = []string{"niri", "hyprland", "ghostty", "kitty", "alacr // Config holds all CLI parameters for unattended installation. type Config struct { - Compositor string // "niri" or "hyprland" - Terminal string // "ghostty", "kitty", or "alacritty" + Compositor string // "niri", "hyprland", or "mango" + Terminal string // "ghostty", "kitty", or "alacritty" + PrivescTool string // "sudo", "doas", or "run0" + WMGit bool // install git version of selected window manager + QuickshellGit bool // install git version of quickshell + DMSGit bool // install git version of DMS + GitAll bool // install git version of all supported components + GitDeps []string // specific dependencies to force git version + AllFeatures bool // enable all optional features + NoFeatures bool // disable all optional features + DmsGreeter bool // install dms-greeter IncludeDeps []string ExcludeDeps []string ReplaceConfigs []string // specific configs to deploy (e.g. "niri", "ghostty") @@ -68,6 +77,18 @@ func (r *Runner) GetLogChan() <-chan string { func (r *Runner) Run() error { r.log("Starting headless installation") + if r.cfg.PrivescTool != "" { + tool := privesc.Tool(strings.ToLower(r.cfg.PrivescTool)) + switch tool { + case privesc.ToolSudo, privesc.ToolDoas, privesc.ToolRun0: + if err := privesc.SetTool(tool); err != nil { + return fmt.Errorf("failed to set privilege escalation tool %q: %w", r.cfg.PrivescTool, err) + } + default: + return fmt.Errorf("invalid --privesc value %q: must be 'sudo', 'doas', or 'run0'", r.cfg.PrivescTool) + } + } + // 1. Parse compositor and terminal selections wm, err := r.parseWindowManager() if err != nil { @@ -112,6 +133,8 @@ func (r *Runner) Run() error { return fmt.Errorf("dependency detection failed: %w", err) } + r.applyGitVariants(dependencies) + // 5. Apply include/exclude filters and build the disabled-items map. // Headless mode does not currently collect any explicit reinstall selections, // so keep reinstallItems nil instead of constructing an always-empty map. @@ -283,12 +306,70 @@ func (r *Runner) Run() error { return nil } +// applyGitVariants sets VariantGit on dependencies matching git flags or --git-deps. +func (r *Runner) applyGitVariants(dependencies []deps.Dependency) { + gitDepsMap := make(map[string]bool) + for _, raw := range r.cfg.GitDeps { + for _, item := range strings.Split(raw, ",") { + item = strings.TrimSpace(strings.ToLower(item)) + if item != "" { + gitDepsMap[item] = true + } + } + } + + wmName := strings.ToLower(r.cfg.Compositor) + + for i := range dependencies { + depNameLower := strings.ToLower(dependencies[i].Name) + isWM := depNameLower == wmName + isQuickshell := depNameLower == "quickshell" + isDMS := strings.HasPrefix(depNameLower, "dms") && strings.Contains(depNameLower, "dankmaterialshell") + + shouldUseGit := r.cfg.GitAll || + (isWM && (r.cfg.WMGit || gitDepsMap[depNameLower])) || + (isQuickshell && (r.cfg.QuickshellGit || gitDepsMap["quickshell"])) || + (isDMS && (r.cfg.DMSGit || gitDepsMap["dms"] || gitDepsMap["dms (dankmaterialshell)"])) || + gitDepsMap[depNameLower] + + if shouldUseGit && dependencies[i].CanToggle { + dependencies[i].Variant = deps.VariantGit + } + } +} + // buildDisabledItems computes the set of dependencies that should be skipped // during installation. Optional components are opt-in (disabled by default), // then re-enabled by the dedicated flags and --include-deps. func (r *Runner) buildDisabledItems(dependencies []deps.Dependency) (map[string]bool, error) { disabledItems := make(map[string]bool) + if r.cfg.AllFeatures { + for _, name := range r.cfg.ExcludeDeps { + name = strings.TrimSpace(name) + if name == "" { + continue + } + if !r.depExists(dependencies, name) { + return nil, fmt.Errorf("--exclude-deps: unknown dependency %q", name) + } + if name == "dms (DankMaterialShell)" { + return nil, fmt.Errorf("--exclude-deps: cannot exclude required package %q", name) + } + disabledItems[name] = true + } + return disabledItems, nil + } + + if r.cfg.NoFeatures { + for i := range dependencies { + if !dependencies[i].Required { + disabledItems[dependencies[i].Name] = true + } + } + return disabledItems, nil + } + for i := range dependencies { if !dependencies[i].Required { disabledItems[dependencies[i].Name] = true @@ -308,6 +389,12 @@ func (r *Runner) buildDisabledItems(dependencies []deps.Dependency) (map[string] } delete(disabledItems, "dankcalendar") } + if r.cfg.DmsGreeter { + if !r.depExists(dependencies, "dms-greeter") { + return nil, fmt.Errorf("--dms-greeter: not available on this distribution") + } + delete(disabledItems, "dms-greeter") + } // Process --include-deps (enable items that are disabled by default) for _, name := range r.cfg.IncludeDeps { diff --git a/core/internal/headless/runner_test.go b/core/internal/headless/runner_test.go index d667644e5..be8494e23 100644 --- a/core/internal/headless/runner_test.go +++ b/core/internal/headless/runner_test.go @@ -442,6 +442,16 @@ func TestBuildDisabledItems(t *testing.T) { wantErr: true, errContains: "--dankcalendar", }, + { + name: "allFeatures enables all optional features", + allFeatures: true, + wantEnabled: []string{"dms-greeter", "danksearch", "dankcalendar"}, + }, + { + name: "noFeatures disables all optional features", + noFeatures: true, + wantDisabled: []string{"dms-greeter", "danksearch", "dankcalendar"}, + }, } for _, tt := range tests { @@ -451,6 +461,8 @@ func TestBuildDisabledItems(t *testing.T) { ExcludeDeps: tt.excludeDeps, DankSearch: tt.dankSearch, DankCalendar: tt.dankCalendar, + AllFeatures: tt.allFeatures, + NoFeatures: tt.noFeatures, }) d := tt.deps if d == nil { @@ -483,11 +495,37 @@ func TestBuildDisabledItems(t *testing.T) { t.Errorf("expected %q to NOT be disabled, but it is", name) } } - - // If wantDisabled is empty, the map should have length 0 - if len(tt.wantDisabled) == 0 && len(got) != 0 { - t.Errorf("expected empty disabledItems map, got %v", got) - } }) } } + +func TestApplyGitVariants(t *testing.T) { + r := NewRunner(Config{ + Compositor: "niri", + WMGit: true, + QuickshellGit: true, + GitDeps: []string{"matugen"}, + }) + + dependencies := []deps.Dependency{ + {Name: "niri", Variant: deps.VariantStable, CanToggle: true}, + {Name: "quickshell", Variant: deps.VariantStable, CanToggle: true}, + {Name: "matugen", Variant: deps.VariantStable, CanToggle: true}, + {Name: "ghostty", Variant: deps.VariantStable, CanToggle: false}, + } + + r.applyGitVariants(dependencies) + + if dependencies[0].Variant != deps.VariantGit { + t.Errorf("expected niri variant to be VariantGit, got %v", dependencies[0].Variant) + } + if dependencies[1].Variant != deps.VariantGit { + t.Errorf("expected quickshell variant to be VariantGit, got %v", dependencies[1].Variant) + } + if dependencies[2].Variant != deps.VariantGit { + t.Errorf("expected matugen variant to be VariantGit, got %v", dependencies[2].Variant) + } + if dependencies[3].Variant != deps.VariantStable { + t.Errorf("expected ghostty variant to stay VariantStable (CanToggle=false), got %v", dependencies[3].Variant) + } +} From 8607a27308b13c4020c3102f1dddd36d8aba5691 Mon Sep 17 00:00:00 2001 From: JDKamalakar Date: Fri, 14 Aug 2026 07:39:52 +0530 Subject: [PATCH 2/3] docs: add installer command-line flag reference and usage guide --- install_script_flags.md | 123 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 install_script_flags.md diff --git a/install_script_flags.md b/install_script_flags.md new file mode 100644 index 000000000..9a36f7254 --- /dev/null +++ b/install_script_flags.md @@ -0,0 +1,123 @@ +# DankMaterialShell Installer (`dankinstall`) Flag Reference & Combinations + +This document provides a comprehensive guide and full list of command-line flags and combinations for headless (unattended) automated installation of **DankMaterialShell** via `dankinstall` or `install.sh`. + +--- + +## 1. Complete Flag Reference + +| Flag | Short | Input Values / Type | Description | +| :--- | :--- | :--- | :--- | +| `--compositor` | `-c` | `niri`, `hyprland`, `mango` | Compositor / Window Manager (Required for headless mode). | +| `--term` | `-t` | `ghostty`, `kitty`, `alacritty` | Terminal emulator to install (Required for headless mode). | +| `--privesc` | `-p` | `sudo`, `doas`, `run0` | Explicit privilege escalation tool. | +| `--yes` | `-y` | Boolean | Required for headless mode - auto-confirms installation without prompts. | +| `--all` / `--all-features` | `-a` | Boolean | Enables all optional packages (`dms-greeter`, `danksearch`, `dankcalendar`). | +| `--no-features` | | Boolean | Skips all optional packages and features. | +| `--wm-git` | | Boolean | Installs the git/development release of the selected window manager. | +| `--quickshell-git` | | Boolean | Installs the git/development release of Quickshell. | +| `--dms-git` | | Boolean | Installs the git/development release of DankMaterialShell. | +| `--git` / `--git-all` | | Boolean | Forces git/development versions for all supported components. | +| `--git-deps` | | Comma-separated list | Forces git versions for specific dependencies (e.g. `niri,quickshell`). | +| `--dms-greeter` / `--greeter` | | Boolean | Installs the `dms-greeter` optional component. | +| `--danksearch` | | Boolean | Installs `danksearch` and enables its background file indexing service. | +| `--dankcalendar` | | Boolean | Installs `dankcalendar` optional package. | +| `--include-deps` | | Comma-separated list | Explicit list of optional dependencies to enable. | +| `--exclude-deps` | | Comma-separated list | Dependencies to exclude/skip during installation. | +| `--replace-configs` | | Comma-separated list | Deploy/overwrite specific configs (e.g. `niri,ghostty`). | +| `--replace-configs-all` | | Boolean | Deploy/overwrite all configuration files. | + +--- + +## 2. Core Compositor & Terminal Matrix + +Headless mode requires both `--compositor` (`-c`) and `--term` (`-t`), plus `--yes` (`-y`). + +| # | Compositor | Terminal | Execution Command Example | +| :--- | :--- | :--- | :--- | +| 1 | `niri` | `ghostty` | `dankinstall -c niri -t ghostty -y` | +| 2 | `niri` | `kitty` | `dankinstall -c niri -t kitty -y` | +| 3 | `niri` | `alacritty` | `dankinstall -c niri -t alacritty -y` | +| 4 | `hyprland` | `ghostty` | `dankinstall -c hyprland -t ghostty -y` | +| 5 | `hyprland` | `kitty` | `dankinstall -c hyprland -t kitty -y` | +| 6 | `hyprland` | `alacritty` | `dankinstall -c hyprland -t alacritty -y` | +| 7 | `mango` | `ghostty` | `dankinstall -c mango -t ghostty -y` | +| 8 | `mango` | `kitty` | `dankinstall -c mango -t kitty -y` | +| 9 | `mango` | `alacritty` | `dankinstall -c mango -t alacritty -y` | + +--- + +## 3. Privilege Escalation Combinations + +Choose your preferred escalation backend using `--privesc` (`-p`). + +```bash +# 1. Standard sudo escalation +curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c niri -t ghostty -p sudo -y + +# 2. OpenBSD doas escalation +curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c hyprland -t kitty -p doas -y + +# 3. systemd run0 escalation +curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c mango -t alacritty -p run0 -y +``` + +--- + +## 4. Git vs. Stable Variant Combinations + +Control whether components install stable or bleeding-edge (git) releases. + +| Category | Description | Command Combination | +| :--- | :--- | :--- | +| **All Git Releases** | Force git builds for WM, Quickshell, DMS & companions | `dankinstall -c niri -t ghostty --git -y` | +| **WM Git Only** | Bleeding-edge WM with stable DMS & Quickshell | `dankinstall -c hyprland -t kitty --wm-git -y` | +| **Quickshell Git Only** | Bleeding-edge Quickshell backend | `dankinstall -c niri -t ghostty --quickshell-git -y` | +| **DMS Git Only** | Development version of DMS shell | `dankinstall -c niri -t ghostty --dms-git -y` | +| **WM + Quickshell Git** | Git WM and Quickshell | `dankinstall -c niri -t ghostty --wm-git --quickshell-git -y` | +| **Targeted Git List** | Specific packages via comma list | `dankinstall -c niri -t ghostty --git-deps niri,quickshell,matugen -y` | + +--- + +## 5. Feature Toggles & Package Combinations + +| Goal | Description | Command Combination | +| :--- | :--- | :--- | +| **Full Installation** | Install all optional features & services | `dankinstall -c niri -t ghostty -a -y` | +| **Minimal / Core Only** | Skip all optional features | `dankinstall -c niri -t ghostty --no-features -y` | +| **DankSearch Only** | Enable search indexer service | `dankinstall -c niri -t ghostty --danksearch -y` | +| **Calendar Only** | Enable calendar package | `dankinstall -c niri -t ghostty --dankcalendar -y` | +| **Greeter Only** | Enable login greeter | `dankinstall -c niri -t ghostty --greeter -y` | +| **Search + Calendar** | Enable search & calendar | `dankinstall -c niri -t ghostty --danksearch --dankcalendar -y` | +| **Include Specific List** | Enable specific items | `dankinstall -c niri -t ghostty --include-deps dms-greeter,danksearch -y` | +| **Exclude Specific Item** | Exclude unwanted package | `dankinstall -c niri -t ghostty -a --exclude-deps dms-greeter -y` | + +--- + +## 6. Config Deployment Combinations + +| Goal | Command Combination | +| :--- | :--- | +| **Deploy All Configs** | `dankinstall -c niri -t ghostty --replace-configs-all -y` | +| **Deploy WM Config Only** | `dankinstall -c niri -t ghostty --replace-configs niri -y` | +| **Deploy Terminal Config Only** | `dankinstall -c niri -t ghostty --replace-configs ghostty -y` | +| **Deploy WM + Terminal Config** | `dankinstall -c niri -t ghostty --replace-configs niri,ghostty -y` | + +--- + +## 7. Real-World Deployment Recipes + +### Minimal Production Deployment (Niri + Ghostty) +```bash +curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c niri -t ghostty -p sudo --no-features -y +``` + +### Full Workstation Deployment (Hyprland + Kitty + All Features + Configs) +```bash +curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c hyprland -t kitty -p sudo -a --replace-configs-all -y +``` + +### Bleeding-Edge Developer Setup (Mango + Alacritty + All Git Versions) +```bash +curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c mango -t alacritty -p doas --git -a -y +``` From ad11d16a1925e463418f2a42aef8b8b7412f8e82 Mon Sep 17 00:00:00 2001 From: JDKamalakar Date: Sun, 16 Aug 2026 20:32:16 +0530 Subject: [PATCH 3/3] refactor: simplify git dependency management by removing individual flags and updating the installation repository source. --- core/README.md | 13 ++- core/cmd/dankinstall/main.go | 18 ---- core/install.sh | 2 +- core/internal/headless/runner.go | 87 ++++++++---------- core/internal/headless/runner_test.go | 29 ++++-- install_script_flags.md | 123 -------------------------- 6 files changed, 66 insertions(+), 206 deletions(-) delete mode 100644 install_script_flags.md diff --git a/core/README.md b/core/README.md index db9b54c13..d44344c94 100644 --- a/core/README.md +++ b/core/README.md @@ -158,9 +158,9 @@ curl -fsSL https://install.danklinux.com | sh Headless mode requires cached credentials or passwordless privilege escalation (sudo/doas/run0): ```bash -curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c niri -t ghostty -p sudo -y -curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c hyprland -t kitty --wm-git --quickshell-git -a -y -curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c mango -t alacritty --git --danksearch --dankcalendar -y +curl -fsSL https://install.danklinux.com | sh -s -- -c niri -t ghostty -p sudo -y +curl -fsSL https://install.danklinux.com | sh -s -- -c hyprland -t kitty --git-deps niri,quickshell -a -y +curl -fsSL https://install.danklinux.com | sh -s -- -c mango -t alacritty --git --danksearch --dankcalendar -y ``` | Flag | Short | Description | @@ -168,14 +168,11 @@ curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/maste | `--compositor ` | `-c` | Compositor/WM to install (required for headless) | | `--term ` | `-t` | Terminal emulator (required for headless) | | `--privesc ` | `-p` | Explicit privilege escalation tool | -| `--wm-git` | | Use git/development version of selected window manager | -| `--quickshell-git` | | Use git/development version of quickshell | -| `--dms-git` | | Use git/development version of DankMaterialShell | | `--git` / `--git-all` | | Use git/development versions for all supported components | -| `--git-deps ` | | Specify dependencies to install git versions of | +| `--git-deps ` | | Specify dependencies to install git versions of (e.g. `niri,quickshell`) | | `--all` / `--all-features` | `-a` | Install all optional features and dependencies | | `--no-features` | | Skip all optional features and dependencies | -| `--dms-greeter` / `--greeter` | | Install dms-greeter optional package | +| `--dms-greeter` | | Install dms-greeter optional package | | `--danksearch` | | Install danksearch and enable user indexing service | | `--dankcalendar` | | Install dankcalendar package | | `--include-deps ` | | Enable specific optional dependencies | diff --git a/core/cmd/dankinstall/main.go b/core/cmd/dankinstall/main.go index 60fb1c578..f527c0f3c 100644 --- a/core/cmd/dankinstall/main.go +++ b/core/cmd/dankinstall/main.go @@ -19,9 +19,6 @@ var ( compositor string term string privescTool string - wmGit bool - quickshellGit bool - dmsGit bool gitAll bool gitDeps []string allFeatures bool @@ -55,9 +52,6 @@ func init() { rootCmd.Flags().StringVarP(&compositor, "compositor", "c", "", "Compositor/WM to install: niri, hyprland, or mango (enables headless mode)") rootCmd.Flags().StringVarP(&term, "term", "t", "", "Terminal emulator to install: ghostty, kitty, or alacritty (enables headless mode)") rootCmd.Flags().StringVarP(&privescTool, "privesc", "p", "", "Privilege escalation tool: sudo, doas, or run0") - rootCmd.Flags().BoolVar(&wmGit, "wm-git", false, "Use git/development version of selected window manager") - rootCmd.Flags().BoolVar(&quickshellGit, "quickshell-git", false, "Use git/development version of quickshell") - rootCmd.Flags().BoolVar(&dmsGit, "dms-git", false, "Use git/development version of DankMaterialShell") rootCmd.Flags().BoolVar(&gitAll, "git-all", false, "Use git/development versions for all supported components") rootCmd.Flags().BoolVar(&gitAll, "git", false, "Use git/development versions for all supported components (alias for --git-all)") rootCmd.Flags().StringSliceVar(&gitDeps, "git-deps", []string{}, "Comma-separated list of dependencies to use git versions for") @@ -65,7 +59,6 @@ func init() { rootCmd.Flags().BoolVar(&allFeatures, "all", false, "Install all optional features and dependencies (alias for --all-features)") rootCmd.Flags().BoolVar(&noFeatures, "no-features", false, "Skip all optional features and dependencies") rootCmd.Flags().BoolVar(&dmsGreeter, "dms-greeter", false, "Install dms-greeter optional package") - rootCmd.Flags().BoolVar(&dmsGreeter, "greeter", false, "Install dms-greeter optional package (alias for --dms-greeter)") rootCmd.Flags().StringSliceVar(&includeDeps, "include-deps", []string{}, "Optional deps to enable (e.g. dms-greeter, danksearch)") rootCmd.Flags().StringSliceVar(&excludeDeps, "exclude-deps", []string{}, "Deps to skip during installation") rootCmd.Flags().StringSliceVar(&replaceConfigs, "replace-configs", []string{}, "Deploy only named configs (e.g. niri,ghostty)") @@ -94,9 +87,6 @@ func runDankinstall(cmd *cobra.Command, args []string) error { // Reject headless-only flags when running in TUI mode. headlessOnly := []string{ "privesc", - "wm-git", - "quickshell-git", - "dms-git", "git-all", "git", "git-deps", @@ -104,7 +94,6 @@ func runDankinstall(cmd *cobra.Command, args []string) error { "all", "no-features", "dms-greeter", - "greeter", "include-deps", "exclude-deps", "replace-configs", @@ -139,17 +128,10 @@ func runHeadless() error { return fmt.Errorf("--term is required for headless mode (ghostty, kitty, or alacritty)") } - if allFeatures && noFeatures { - return fmt.Errorf("cannot specify both --all-features/--all and --no-features") - } - cfg := headless.Config{ Compositor: compositor, Terminal: term, PrivescTool: privescTool, - WMGit: wmGit, - QuickshellGit: quickshellGit, - DMSGit: dmsGit, GitAll: gitAll, GitDeps: gitDeps, AllFeatures: allFeatures, diff --git a/core/install.sh b/core/install.sh index 103524a2e..0863d0d44 100755 --- a/core/install.sh +++ b/core/install.sh @@ -35,7 +35,7 @@ aarch64) ;; esac -REPO_SLUG="${DMS_REPO:-JDKamalakar/DankMaterialShell}" +REPO_SLUG="${DMS_REPO:-AvengeMedia/DankMaterialShell}" # Get the latest release version LATEST_VERSION=$(curl -s "https://api.github.com/repos/${REPO_SLUG}/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') diff --git a/core/internal/headless/runner.go b/core/internal/headless/runner.go index cf7fba391..b7c8fbc75 100644 --- a/core/internal/headless/runner.go +++ b/core/internal/headless/runner.go @@ -37,9 +37,6 @@ type Config struct { Compositor string // "niri", "hyprland", or "mango" Terminal string // "ghostty", "kitty", or "alacritty" PrivescTool string // "sudo", "doas", or "run0" - WMGit bool // install git version of selected window manager - QuickshellGit bool // install git version of quickshell - DMSGit bool // install git version of DMS GitAll bool // install git version of all supported components GitDeps []string // specific dependencies to force git version AllFeatures bool // enable all optional features @@ -78,14 +75,8 @@ func (r *Runner) Run() error { r.log("Starting headless installation") if r.cfg.PrivescTool != "" { - tool := privesc.Tool(strings.ToLower(r.cfg.PrivescTool)) - switch tool { - case privesc.ToolSudo, privesc.ToolDoas, privesc.ToolRun0: - if err := privesc.SetTool(tool); err != nil { - return fmt.Errorf("failed to set privilege escalation tool %q: %w", r.cfg.PrivescTool, err) - } - default: - return fmt.Errorf("invalid --privesc value %q: must be 'sudo', 'doas', or 'run0'", r.cfg.PrivescTool) + if err := privesc.SetTool(privesc.Tool(strings.ToLower(r.cfg.PrivescTool))); err != nil { + return fmt.Errorf("failed to set privilege escalation tool %q: %w", r.cfg.PrivescTool, err) } } @@ -133,7 +124,9 @@ func (r *Runner) Run() error { return fmt.Errorf("dependency detection failed: %w", err) } - r.applyGitVariants(dependencies) + if err := r.applyGitVariants(dependencies); err != nil { + return err + } // 5. Apply include/exclude filters and build the disabled-items map. // Headless mode does not currently collect any explicit reinstall selections, @@ -307,7 +300,7 @@ func (r *Runner) Run() error { } // applyGitVariants sets VariantGit on dependencies matching git flags or --git-deps. -func (r *Runner) applyGitVariants(dependencies []deps.Dependency) { +func (r *Runner) applyGitVariants(dependencies []deps.Dependency) error { gitDepsMap := make(map[string]bool) for _, raw := range r.cfg.GitDeps { for _, item := range strings.Split(raw, ",") { @@ -318,62 +311,54 @@ func (r *Runner) applyGitVariants(dependencies []deps.Dependency) { } } - wmName := strings.ToLower(r.cfg.Compositor) - - for i := range dependencies { - depNameLower := strings.ToLower(dependencies[i].Name) - isWM := depNameLower == wmName - isQuickshell := depNameLower == "quickshell" - isDMS := strings.HasPrefix(depNameLower, "dms") && strings.Contains(depNameLower, "dankmaterialshell") - - shouldUseGit := r.cfg.GitAll || - (isWM && (r.cfg.WMGit || gitDepsMap[depNameLower])) || - (isQuickshell && (r.cfg.QuickshellGit || gitDepsMap["quickshell"])) || - (isDMS && (r.cfg.DMSGit || gitDepsMap["dms"] || gitDepsMap["dms (dankmaterialshell)"])) || - gitDepsMap[depNameLower] + for target := range gitDepsMap { + found := false + for i := range dependencies { + depNameLower := strings.ToLower(dependencies[i].Name) + if depNameLower == target || (target == "dms" && depNameLower == "dms (dankmaterialshell)") { + found = true + if !dependencies[i].CanToggle { + return fmt.Errorf("--git-deps: dependency %q does not support git variant", dependencies[i].Name) + } + dependencies[i].Variant = deps.VariantGit + } + } + if !found { + return fmt.Errorf("--git-deps: unknown dependency %q", target) + } + } - if shouldUseGit && dependencies[i].CanToggle { - dependencies[i].Variant = deps.VariantGit + if r.cfg.GitAll { + for i := range dependencies { + if dependencies[i].CanToggle { + dependencies[i].Variant = deps.VariantGit + } } } + + return nil } // buildDisabledItems computes the set of dependencies that should be skipped // during installation. Optional components are opt-in (disabled by default), // then re-enabled by the dedicated flags and --include-deps. func (r *Runner) buildDisabledItems(dependencies []deps.Dependency) (map[string]bool, error) { - disabledItems := make(map[string]bool) - - if r.cfg.AllFeatures { - for _, name := range r.cfg.ExcludeDeps { - name = strings.TrimSpace(name) - if name == "" { - continue - } - if !r.depExists(dependencies, name) { - return nil, fmt.Errorf("--exclude-deps: unknown dependency %q", name) - } - if name == "dms (DankMaterialShell)" { - return nil, fmt.Errorf("--exclude-deps: cannot exclude required package %q", name) - } - disabledItems[name] = true - } - return disabledItems, nil + if r.cfg.AllFeatures && r.cfg.NoFeatures { + return nil, fmt.Errorf("cannot specify both --all-features/--all and --no-features") } - if r.cfg.NoFeatures { + disabledItems := make(map[string]bool) + + if !r.cfg.AllFeatures { for i := range dependencies { if !dependencies[i].Required { disabledItems[dependencies[i].Name] = true } } - return disabledItems, nil } - for i := range dependencies { - if !dependencies[i].Required { - disabledItems[dependencies[i].Name] = true - } + if r.cfg.NoFeatures { + return disabledItems, nil } // Dedicated flags resolve before include/exclude diff --git a/core/internal/headless/runner_test.go b/core/internal/headless/runner_test.go index be8494e23..6cd568f83 100644 --- a/core/internal/headless/runner_test.go +++ b/core/internal/headless/runner_test.go @@ -452,6 +452,13 @@ func TestBuildDisabledItems(t *testing.T) { noFeatures: true, wantDisabled: []string{"dms-greeter", "danksearch", "dankcalendar"}, }, + { + name: "both allFeatures and noFeatures set returns error", + allFeatures: true, + noFeatures: true, + wantErr: true, + errContains: "cannot specify both --all-features/--all and --no-features", + }, } for _, tt := range tests { @@ -501,10 +508,8 @@ func TestBuildDisabledItems(t *testing.T) { func TestApplyGitVariants(t *testing.T) { r := NewRunner(Config{ - Compositor: "niri", - WMGit: true, - QuickshellGit: true, - GitDeps: []string{"matugen"}, + Compositor: "niri", + GitDeps: []string{"niri", "quickshell", "matugen"}, }) dependencies := []deps.Dependency{ @@ -514,7 +519,9 @@ func TestApplyGitVariants(t *testing.T) { {Name: "ghostty", Variant: deps.VariantStable, CanToggle: false}, } - r.applyGitVariants(dependencies) + if err := r.applyGitVariants(dependencies); err != nil { + t.Fatalf("applyGitVariants unexpected error: %v", err) + } if dependencies[0].Variant != deps.VariantGit { t.Errorf("expected niri variant to be VariantGit, got %v", dependencies[0].Variant) @@ -528,4 +535,16 @@ func TestApplyGitVariants(t *testing.T) { if dependencies[3].Variant != deps.VariantStable { t.Errorf("expected ghostty variant to stay VariantStable (CanToggle=false), got %v", dependencies[3].Variant) } + + // Test unknown dependency in --git-deps returns error + rErr := NewRunner(Config{GitDeps: []string{"nonexistent"}}) + if err := rErr.applyGitVariants(dependencies); err == nil { + t.Error("expected error for unknown git dependency, got nil") + } + + // Test non-togglable dependency in --git-deps returns error + rCantToggle := NewRunner(Config{GitDeps: []string{"ghostty"}}) + if err := rCantToggle.applyGitVariants(dependencies); err == nil { + t.Error("expected error for non-togglable git dependency, got nil") + } } diff --git a/install_script_flags.md b/install_script_flags.md deleted file mode 100644 index 9a36f7254..000000000 --- a/install_script_flags.md +++ /dev/null @@ -1,123 +0,0 @@ -# DankMaterialShell Installer (`dankinstall`) Flag Reference & Combinations - -This document provides a comprehensive guide and full list of command-line flags and combinations for headless (unattended) automated installation of **DankMaterialShell** via `dankinstall` or `install.sh`. - ---- - -## 1. Complete Flag Reference - -| Flag | Short | Input Values / Type | Description | -| :--- | :--- | :--- | :--- | -| `--compositor` | `-c` | `niri`, `hyprland`, `mango` | Compositor / Window Manager (Required for headless mode). | -| `--term` | `-t` | `ghostty`, `kitty`, `alacritty` | Terminal emulator to install (Required for headless mode). | -| `--privesc` | `-p` | `sudo`, `doas`, `run0` | Explicit privilege escalation tool. | -| `--yes` | `-y` | Boolean | Required for headless mode - auto-confirms installation without prompts. | -| `--all` / `--all-features` | `-a` | Boolean | Enables all optional packages (`dms-greeter`, `danksearch`, `dankcalendar`). | -| `--no-features` | | Boolean | Skips all optional packages and features. | -| `--wm-git` | | Boolean | Installs the git/development release of the selected window manager. | -| `--quickshell-git` | | Boolean | Installs the git/development release of Quickshell. | -| `--dms-git` | | Boolean | Installs the git/development release of DankMaterialShell. | -| `--git` / `--git-all` | | Boolean | Forces git/development versions for all supported components. | -| `--git-deps` | | Comma-separated list | Forces git versions for specific dependencies (e.g. `niri,quickshell`). | -| `--dms-greeter` / `--greeter` | | Boolean | Installs the `dms-greeter` optional component. | -| `--danksearch` | | Boolean | Installs `danksearch` and enables its background file indexing service. | -| `--dankcalendar` | | Boolean | Installs `dankcalendar` optional package. | -| `--include-deps` | | Comma-separated list | Explicit list of optional dependencies to enable. | -| `--exclude-deps` | | Comma-separated list | Dependencies to exclude/skip during installation. | -| `--replace-configs` | | Comma-separated list | Deploy/overwrite specific configs (e.g. `niri,ghostty`). | -| `--replace-configs-all` | | Boolean | Deploy/overwrite all configuration files. | - ---- - -## 2. Core Compositor & Terminal Matrix - -Headless mode requires both `--compositor` (`-c`) and `--term` (`-t`), plus `--yes` (`-y`). - -| # | Compositor | Terminal | Execution Command Example | -| :--- | :--- | :--- | :--- | -| 1 | `niri` | `ghostty` | `dankinstall -c niri -t ghostty -y` | -| 2 | `niri` | `kitty` | `dankinstall -c niri -t kitty -y` | -| 3 | `niri` | `alacritty` | `dankinstall -c niri -t alacritty -y` | -| 4 | `hyprland` | `ghostty` | `dankinstall -c hyprland -t ghostty -y` | -| 5 | `hyprland` | `kitty` | `dankinstall -c hyprland -t kitty -y` | -| 6 | `hyprland` | `alacritty` | `dankinstall -c hyprland -t alacritty -y` | -| 7 | `mango` | `ghostty` | `dankinstall -c mango -t ghostty -y` | -| 8 | `mango` | `kitty` | `dankinstall -c mango -t kitty -y` | -| 9 | `mango` | `alacritty` | `dankinstall -c mango -t alacritty -y` | - ---- - -## 3. Privilege Escalation Combinations - -Choose your preferred escalation backend using `--privesc` (`-p`). - -```bash -# 1. Standard sudo escalation -curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c niri -t ghostty -p sudo -y - -# 2. OpenBSD doas escalation -curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c hyprland -t kitty -p doas -y - -# 3. systemd run0 escalation -curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c mango -t alacritty -p run0 -y -``` - ---- - -## 4. Git vs. Stable Variant Combinations - -Control whether components install stable or bleeding-edge (git) releases. - -| Category | Description | Command Combination | -| :--- | :--- | :--- | -| **All Git Releases** | Force git builds for WM, Quickshell, DMS & companions | `dankinstall -c niri -t ghostty --git -y` | -| **WM Git Only** | Bleeding-edge WM with stable DMS & Quickshell | `dankinstall -c hyprland -t kitty --wm-git -y` | -| **Quickshell Git Only** | Bleeding-edge Quickshell backend | `dankinstall -c niri -t ghostty --quickshell-git -y` | -| **DMS Git Only** | Development version of DMS shell | `dankinstall -c niri -t ghostty --dms-git -y` | -| **WM + Quickshell Git** | Git WM and Quickshell | `dankinstall -c niri -t ghostty --wm-git --quickshell-git -y` | -| **Targeted Git List** | Specific packages via comma list | `dankinstall -c niri -t ghostty --git-deps niri,quickshell,matugen -y` | - ---- - -## 5. Feature Toggles & Package Combinations - -| Goal | Description | Command Combination | -| :--- | :--- | :--- | -| **Full Installation** | Install all optional features & services | `dankinstall -c niri -t ghostty -a -y` | -| **Minimal / Core Only** | Skip all optional features | `dankinstall -c niri -t ghostty --no-features -y` | -| **DankSearch Only** | Enable search indexer service | `dankinstall -c niri -t ghostty --danksearch -y` | -| **Calendar Only** | Enable calendar package | `dankinstall -c niri -t ghostty --dankcalendar -y` | -| **Greeter Only** | Enable login greeter | `dankinstall -c niri -t ghostty --greeter -y` | -| **Search + Calendar** | Enable search & calendar | `dankinstall -c niri -t ghostty --danksearch --dankcalendar -y` | -| **Include Specific List** | Enable specific items | `dankinstall -c niri -t ghostty --include-deps dms-greeter,danksearch -y` | -| **Exclude Specific Item** | Exclude unwanted package | `dankinstall -c niri -t ghostty -a --exclude-deps dms-greeter -y` | - ---- - -## 6. Config Deployment Combinations - -| Goal | Command Combination | -| :--- | :--- | -| **Deploy All Configs** | `dankinstall -c niri -t ghostty --replace-configs-all -y` | -| **Deploy WM Config Only** | `dankinstall -c niri -t ghostty --replace-configs niri -y` | -| **Deploy Terminal Config Only** | `dankinstall -c niri -t ghostty --replace-configs ghostty -y` | -| **Deploy WM + Terminal Config** | `dankinstall -c niri -t ghostty --replace-configs niri,ghostty -y` | - ---- - -## 7. Real-World Deployment Recipes - -### Minimal Production Deployment (Niri + Ghostty) -```bash -curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c niri -t ghostty -p sudo --no-features -y -``` - -### Full Workstation Deployment (Hyprland + Kitty + All Features + Configs) -```bash -curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c hyprland -t kitty -p sudo -a --replace-configs-all -y -``` - -### Bleeding-Edge Developer Setup (Mango + Alacritty + All Git Versions) -```bash -curl -fsSL https://raw.githubusercontent.com/JDKamalakar/DankMaterialShell/master/core/install.sh | sh -s -- -c mango -t alacritty -p doas --git -a -y -```