mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-01 19:18:28 -04:00
dankinstall: add danksearch and dankcalendar as optional deps
This commit is contained in:
@@ -23,6 +23,8 @@ var (
|
|||||||
replaceConfigs []string
|
replaceConfigs []string
|
||||||
replaceConfigsAll bool
|
replaceConfigsAll bool
|
||||||
yes bool
|
yes bool
|
||||||
|
danksearch bool
|
||||||
|
dankcalendar bool
|
||||||
)
|
)
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
@@ -49,6 +51,8 @@ func init() {
|
|||||||
rootCmd.Flags().StringSliceVar(&replaceConfigs, "replace-configs", []string{}, "Deploy only named configs (e.g. niri,ghostty)")
|
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")
|
rootCmd.Flags().BoolVar(&replaceConfigsAll, "replace-configs-all", false, "Deploy and replace all configurations")
|
||||||
rootCmd.Flags().BoolVarP(&yes, "yes", "y", false, "Auto-confirm all prompts")
|
rootCmd.Flags().BoolVarP(&yes, "yes", "y", false, "Auto-confirm all prompts")
|
||||||
|
rootCmd.Flags().BoolVar(&danksearch, "danksearch", false, "Install danksearch and enable its user indexing service")
|
||||||
|
rootCmd.Flags().BoolVar(&dankcalendar, "dankcalendar", false, "Install dankcalendar")
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -74,6 +78,8 @@ func runDankinstall(cmd *cobra.Command, args []string) error {
|
|||||||
"replace-configs",
|
"replace-configs",
|
||||||
"replace-configs-all",
|
"replace-configs-all",
|
||||||
"yes",
|
"yes",
|
||||||
|
"danksearch",
|
||||||
|
"dankcalendar",
|
||||||
}
|
}
|
||||||
var set []string
|
var set []string
|
||||||
for _, name := range headlessOnly {
|
for _, name := range headlessOnly {
|
||||||
@@ -109,6 +115,8 @@ func runHeadless() error {
|
|||||||
ReplaceConfigs: replaceConfigs,
|
ReplaceConfigs: replaceConfigs,
|
||||||
ReplaceConfigsAll: replaceConfigsAll,
|
ReplaceConfigsAll: replaceConfigsAll,
|
||||||
Yes: yes,
|
Yes: yes,
|
||||||
|
DankSearch: danksearch,
|
||||||
|
DankCalendar: dankcalendar,
|
||||||
}
|
}
|
||||||
|
|
||||||
runner := headless.NewRunner(cfg)
|
runner := headless.NewRunner(cfg)
|
||||||
|
|||||||
@@ -886,6 +886,7 @@ func checkOptionalDependencies() []checkResult {
|
|||||||
{"cava", "cava", "Audio visualizer", true},
|
{"cava", "cava", "Audio visualizer", true},
|
||||||
{"khal", "khal", "Calendar events", false},
|
{"khal", "khal", "Calendar events", false},
|
||||||
{"danksearch", "dsearch", "File search", false},
|
{"danksearch", "dsearch", "File search", false},
|
||||||
|
{"dankcalendar", "dcal", "Calendar app", false},
|
||||||
{"fprintd", "fprintd-list", "Fingerprint auth", false},
|
{"fprintd", "fprintd-list", "Fingerprint auth", false},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -119,10 +119,30 @@ func (a *ArchDistribution) DetectDependenciesWithTerminal(ctx context.Context, w
|
|||||||
|
|
||||||
dependencies = append(dependencies, a.detectMatugen())
|
dependencies = append(dependencies, a.detectMatugen())
|
||||||
dependencies = append(dependencies, a.detectDgop())
|
dependencies = append(dependencies, a.detectDgop())
|
||||||
|
dependencies = append(dependencies, a.detectDanksearch())
|
||||||
|
dependencies = append(dependencies, a.detectDankCalendar())
|
||||||
|
|
||||||
return dependencies, nil
|
return dependencies, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *ArchDistribution) detectDanksearch() deps.Dependency {
|
||||||
|
dep := a.BaseDistribution.detectDanksearch()
|
||||||
|
dep.CanToggle = true
|
||||||
|
if a.packageInstalled("dsearch-git") {
|
||||||
|
dep.Variant = deps.VariantGit
|
||||||
|
}
|
||||||
|
return dep
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArchDistribution) detectDankCalendar() deps.Dependency {
|
||||||
|
dep := a.BaseDistribution.detectDankCalendar()
|
||||||
|
dep.CanToggle = true
|
||||||
|
if a.packageInstalled("dankcalendar-git") {
|
||||||
|
dep.Variant = deps.VariantGit
|
||||||
|
}
|
||||||
|
return dep
|
||||||
|
}
|
||||||
|
|
||||||
func (a *ArchDistribution) detectXDGPortal() deps.Dependency {
|
func (a *ArchDistribution) detectXDGPortal() deps.Dependency {
|
||||||
return a.detectPackage("xdg-desktop-portal-gtk", "Desktop integration portal for GTK", a.packageInstalled("xdg-desktop-portal-gtk"))
|
return a.detectPackage("xdg-desktop-portal-gtk", "Desktop integration portal for GTK", a.packageInstalled("xdg-desktop-portal-gtk"))
|
||||||
}
|
}
|
||||||
@@ -199,6 +219,8 @@ func (a *ArchDistribution) GetPackageMappingWithVariants(wm deps.WindowManager,
|
|||||||
"alacritty": {Name: "alacritty", Repository: RepoTypeSystem},
|
"alacritty": {Name: "alacritty", Repository: RepoTypeSystem},
|
||||||
"xdg-desktop-portal-gtk": {Name: "xdg-desktop-portal-gtk", Repository: RepoTypeSystem},
|
"xdg-desktop-portal-gtk": {Name: "xdg-desktop-portal-gtk", Repository: RepoTypeSystem},
|
||||||
"accountsservice": {Name: "accountsservice", Repository: RepoTypeSystem},
|
"accountsservice": {Name: "accountsservice", Repository: RepoTypeSystem},
|
||||||
|
"danksearch": a.getDanksearchMapping(variants["danksearch"]),
|
||||||
|
"dankcalendar": a.getDankCalendarMapping(variants["dankcalendar"]),
|
||||||
}
|
}
|
||||||
|
|
||||||
switch wm {
|
switch wm {
|
||||||
@@ -253,6 +275,20 @@ func (a *ArchDistribution) getMatugenMapping(variant deps.PackageVariant) Packag
|
|||||||
return PackageMapping{Name: "matugen", Repository: RepoTypeSystem}
|
return PackageMapping{Name: "matugen", Repository: RepoTypeSystem}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *ArchDistribution) getDanksearchMapping(variant deps.PackageVariant) PackageMapping {
|
||||||
|
if variant == deps.VariantGit {
|
||||||
|
return PackageMapping{Name: "dsearch-git", Repository: RepoTypeAUR}
|
||||||
|
}
|
||||||
|
return PackageMapping{Name: "dsearch-bin", Repository: RepoTypeAUR}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArchDistribution) getDankCalendarMapping(variant deps.PackageVariant) PackageMapping {
|
||||||
|
if variant == deps.VariantGit {
|
||||||
|
return PackageMapping{Name: "dankcalendar-git", Repository: RepoTypeAUR}
|
||||||
|
}
|
||||||
|
return PackageMapping{Name: "dankcalendar-bin", Repository: RepoTypeAUR}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *ArchDistribution) getDMSMapping(variant deps.PackageVariant) PackageMapping {
|
func (a *ArchDistribution) getDMSMapping(variant deps.PackageVariant) PackageMapping {
|
||||||
if forceDMSGit || variant == deps.VariantGit {
|
if forceDMSGit || variant == deps.VariantGit {
|
||||||
return PackageMapping{Name: "dms-shell-git", Repository: RepoTypeAUR}
|
return PackageMapping{Name: "dms-shell-git", Repository: RepoTypeAUR}
|
||||||
|
|||||||
@@ -107,6 +107,14 @@ func (b *BaseDistribution) detectDgop() deps.Dependency {
|
|||||||
return b.detectCommand("dgop", "Desktop portal management tool")
|
return b.detectCommand("dgop", "Desktop portal management tool")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *BaseDistribution) detectDanksearch() deps.Dependency {
|
||||||
|
return b.detectOptionalPackage("danksearch", "File indexing and search service", b.commandExists("dsearch") || b.commandExists("danksearch"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseDistribution) detectDankCalendar() deps.Dependency {
|
||||||
|
return b.detectOptionalPackage("dankcalendar", "Calendar application", b.commandExists("dcal") || b.commandExists("dankcalendar"))
|
||||||
|
}
|
||||||
|
|
||||||
func (b *BaseDistribution) detectDMS() deps.Dependency {
|
func (b *BaseDistribution) detectDMS() deps.Dependency {
|
||||||
dmsPath := filepath.Join(os.Getenv("HOME"), ".config/quickshell/dms")
|
dmsPath := filepath.Join(os.Getenv("HOME"), ".config/quickshell/dms")
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ func (d *DebianDistribution) DetectDependenciesWithTerminal(ctx context.Context,
|
|||||||
|
|
||||||
dependencies = append(dependencies, d.detectMatugen())
|
dependencies = append(dependencies, d.detectMatugen())
|
||||||
dependencies = append(dependencies, d.detectDgop())
|
dependencies = append(dependencies, d.detectDgop())
|
||||||
|
dependencies = append(dependencies, d.detectDanksearch())
|
||||||
|
dependencies = append(dependencies, d.detectDankCalendar())
|
||||||
|
|
||||||
return dependencies, nil
|
return dependencies, nil
|
||||||
}
|
}
|
||||||
@@ -135,6 +137,8 @@ func (d *DebianDistribution) GetPackageMappingWithVariants(wm deps.WindowManager
|
|||||||
"matugen": {Name: "matugen", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
"matugen": {Name: "matugen", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
||||||
"dgop": {Name: "dgop", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
"dgop": {Name: "dgop", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
||||||
"ghostty": {Name: "ghostty", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
"ghostty": {Name: "ghostty", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
||||||
|
"danksearch": {Name: "danksearch", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
||||||
|
"dankcalendar": {Name: "dankcalendar-git", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
||||||
}
|
}
|
||||||
|
|
||||||
if wm == deps.WindowManagerNiri {
|
if wm == deps.WindowManagerNiri {
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package distros
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetupDsearchService enables the dsearch.service user unit. Enablement failures
|
||||||
|
// are returned for the caller to surface as a non-fatal warning.
|
||||||
|
func SetupDsearchService(ctx context.Context, logf func(string)) error {
|
||||||
|
if logf == nil {
|
||||||
|
logf = func(string) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := runSystemctlUser(ctx, "daemon-reload"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := runSystemctlUser(ctx, "enable", "--now", "dsearch.service"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logf("Enabled dsearch.service")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runSystemctlUser(ctx context.Context, args ...string) error {
|
||||||
|
cmd := exec.CommandContext(ctx, "systemctl", append([]string{"--user"}, args...)...)
|
||||||
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("systemctl --user %v failed: %w: %s", args, err, string(output))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -104,6 +104,8 @@ func (f *FedoraDistribution) DetectDependenciesWithTerminal(ctx context.Context,
|
|||||||
|
|
||||||
dependencies = append(dependencies, f.detectMatugen())
|
dependencies = append(dependencies, f.detectMatugen())
|
||||||
dependencies = append(dependencies, f.detectDgop())
|
dependencies = append(dependencies, f.detectDgop())
|
||||||
|
dependencies = append(dependencies, f.detectDanksearch())
|
||||||
|
dependencies = append(dependencies, f.detectDankCalendar())
|
||||||
|
|
||||||
return dependencies, nil
|
return dependencies, nil
|
||||||
}
|
}
|
||||||
@@ -138,6 +140,8 @@ func (f *FedoraDistribution) GetPackageMappingWithVariants(wm deps.WindowManager
|
|||||||
"matugen": {Name: "matugen", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"},
|
"matugen": {Name: "matugen", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"},
|
||||||
"dms (DankMaterialShell)": f.getDmsMapping(variants["dms (DankMaterialShell)"]),
|
"dms (DankMaterialShell)": f.getDmsMapping(variants["dms (DankMaterialShell)"]),
|
||||||
"dgop": {Name: "dgop", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"},
|
"dgop": {Name: "dgop", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"},
|
||||||
|
"danksearch": {Name: "danksearch", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"},
|
||||||
|
"dankcalendar": {Name: "dankcalendar-git", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"},
|
||||||
}
|
}
|
||||||
|
|
||||||
switch wm {
|
switch wm {
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ func (g *GentooDistribution) DetectDependenciesWithTerminal(ctx context.Context,
|
|||||||
|
|
||||||
dependencies = append(dependencies, g.detectMatugen())
|
dependencies = append(dependencies, g.detectMatugen())
|
||||||
dependencies = append(dependencies, g.detectDgop())
|
dependencies = append(dependencies, g.detectDgop())
|
||||||
|
dependencies = append(dependencies, g.detectDanksearch())
|
||||||
|
|
||||||
return dependencies, nil
|
return dependencies, nil
|
||||||
}
|
}
|
||||||
@@ -171,6 +172,7 @@ func (g *GentooDistribution) GetPackageMappingWithVariants(wm deps.WindowManager
|
|||||||
"matugen": {Name: "x11-misc/matugen", Repository: RepoTypeGURU, AcceptKeywords: archKeyword},
|
"matugen": {Name: "x11-misc/matugen", Repository: RepoTypeGURU, AcceptKeywords: archKeyword},
|
||||||
"dms (DankMaterialShell)": g.getDmsMapping(),
|
"dms (DankMaterialShell)": g.getDmsMapping(),
|
||||||
"dgop": {Name: "gui-apps/dgop", Repository: RepoTypeGURU, AcceptKeywords: archKeyword},
|
"dgop": {Name: "gui-apps/dgop", Repository: RepoTypeGURU, AcceptKeywords: archKeyword},
|
||||||
|
"danksearch": {Name: "gui-apps/danksearch", Repository: RepoTypeGURU, AcceptKeywords: archKeyword},
|
||||||
}
|
}
|
||||||
|
|
||||||
switch wm {
|
switch wm {
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ func (o *OpenSUSEDistribution) DetectDependenciesWithTerminal(ctx context.Contex
|
|||||||
|
|
||||||
dependencies = append(dependencies, o.detectMatugen())
|
dependencies = append(dependencies, o.detectMatugen())
|
||||||
dependencies = append(dependencies, o.detectDgop())
|
dependencies = append(dependencies, o.detectDgop())
|
||||||
|
dependencies = append(dependencies, o.detectDanksearch())
|
||||||
|
dependencies = append(dependencies, o.detectDankCalendar())
|
||||||
|
|
||||||
return dependencies, nil
|
return dependencies, nil
|
||||||
}
|
}
|
||||||
@@ -129,6 +131,8 @@ func (o *OpenSUSEDistribution) GetPackageMappingWithVariants(wm deps.WindowManag
|
|||||||
"ghostty": {Name: "ghostty", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
"ghostty": {Name: "ghostty", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
||||||
"matugen": {Name: "matugen", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
"matugen": {Name: "matugen", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
||||||
"dgop": {Name: "dgop", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
"dgop": {Name: "dgop", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
||||||
|
"danksearch": {Name: "danksearch", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
||||||
|
"dankcalendar": {Name: "dankcalendar-git", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
||||||
}
|
}
|
||||||
|
|
||||||
switch wm {
|
switch wm {
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ func (u *UbuntuDistribution) DetectDependenciesWithTerminal(ctx context.Context,
|
|||||||
|
|
||||||
dependencies = append(dependencies, u.detectMatugen())
|
dependencies = append(dependencies, u.detectMatugen())
|
||||||
dependencies = append(dependencies, u.detectDgop())
|
dependencies = append(dependencies, u.detectDgop())
|
||||||
|
dependencies = append(dependencies, u.detectDanksearch())
|
||||||
|
dependencies = append(dependencies, u.detectDankCalendar())
|
||||||
|
|
||||||
return dependencies, nil
|
return dependencies, nil
|
||||||
}
|
}
|
||||||
@@ -124,6 +126,8 @@ func (u *UbuntuDistribution) GetPackageMappingWithVariants(wm deps.WindowManager
|
|||||||
"matugen": {Name: "matugen", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"},
|
"matugen": {Name: "matugen", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"},
|
||||||
"dgop": {Name: "dgop", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"},
|
"dgop": {Name: "dgop", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"},
|
||||||
"ghostty": {Name: "ghostty", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"},
|
"ghostty": {Name: "ghostty", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"},
|
||||||
|
"danksearch": {Name: "danksearch", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"},
|
||||||
|
"dankcalendar": {Name: "dankcalendar-git", Repository: RepoTypePPA, RepoURL: "ppa:avengemedia/danklinux"},
|
||||||
}
|
}
|
||||||
|
|
||||||
switch wm {
|
switch wm {
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ func (v *VoidDistribution) DetectDependenciesWithTerminal(ctx context.Context, w
|
|||||||
|
|
||||||
dependencies = append(dependencies, v.detectMatugen())
|
dependencies = append(dependencies, v.detectMatugen())
|
||||||
dependencies = append(dependencies, v.detectDgop())
|
dependencies = append(dependencies, v.detectDgop())
|
||||||
|
dependencies = append(dependencies, v.detectDanksearch())
|
||||||
|
dependencies = append(dependencies, v.detectDankCalendar())
|
||||||
|
|
||||||
return dependencies, nil
|
return dependencies, nil
|
||||||
}
|
}
|
||||||
@@ -176,6 +178,8 @@ func (v *VoidDistribution) GetPackageMappingWithVariants(wm deps.WindowManager,
|
|||||||
"dms (DankMaterialShell)": v.getDmsMapping(variants["dms (DankMaterialShell)"]),
|
"dms (DankMaterialShell)": v.getDmsMapping(variants["dms (DankMaterialShell)"]),
|
||||||
"dms-greeter": {Name: "dms-greeter", Repository: RepoTypeXBPS, RepoURL: VoidDMSRepo},
|
"dms-greeter": {Name: "dms-greeter", Repository: RepoTypeXBPS, RepoURL: VoidDMSRepo},
|
||||||
"dgop": {Name: "dgop", Repository: RepoTypeXBPS, RepoURL: VoidDankLinuxRepo},
|
"dgop": {Name: "dgop", Repository: RepoTypeXBPS, RepoURL: VoidDankLinuxRepo},
|
||||||
|
"danksearch": {Name: "danksearch", Repository: RepoTypeXBPS, RepoURL: VoidDankLinuxRepo},
|
||||||
|
"dankcalendar": {Name: "dankcalendar", Repository: RepoTypeXBPS, RepoURL: VoidDankLinuxRepo},
|
||||||
}
|
}
|
||||||
|
|
||||||
switch wm {
|
switch wm {
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ type Config struct {
|
|||||||
ReplaceConfigs []string // specific configs to deploy (e.g. "niri", "ghostty")
|
ReplaceConfigs []string // specific configs to deploy (e.g. "niri", "ghostty")
|
||||||
ReplaceConfigsAll bool // deploy/replace all configurations
|
ReplaceConfigsAll bool // deploy/replace all configurations
|
||||||
Yes bool
|
Yes bool
|
||||||
|
DankSearch bool // install danksearch and enable its user service
|
||||||
|
DankCalendar bool // install dankcalendar
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runner orchestrates unattended (headless) installation.
|
// Runner orchestrates unattended (headless) installation.
|
||||||
@@ -214,6 +216,11 @@ func (r *Runner) Run() error {
|
|||||||
return fmt.Errorf("package installation failed: %w", err)
|
return fmt.Errorf("package installation failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useSystemd := true
|
||||||
|
if distroConfig, exists := distros.Registry[osInfo.Distribution.ID]; exists && distroConfig.Family == distros.FamilyVoid {
|
||||||
|
useSystemd = false
|
||||||
|
}
|
||||||
|
|
||||||
// 9. Greeter setup (if dms-greeter was included)
|
// 9. Greeter setup (if dms-greeter was included)
|
||||||
if !disabledItems["dms-greeter"] && r.depExists(dependencies, "dms-greeter") {
|
if !disabledItems["dms-greeter"] && r.depExists(dependencies, "dms-greeter") {
|
||||||
compositorName := "niri"
|
compositorName := "niri"
|
||||||
@@ -231,15 +238,24 @@ func (r *Runner) Run() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 9b. danksearch service setup (if danksearch was included)
|
||||||
|
if useSystemd && !disabledItems["danksearch"] && r.depExists(dependencies, "danksearch") {
|
||||||
|
fmt.Fprintln(os.Stdout, "Enabling danksearch service...")
|
||||||
|
logFunc := func(line string) {
|
||||||
|
r.log(line)
|
||||||
|
fmt.Fprintf(os.Stdout, " danksearch: %s\n", line)
|
||||||
|
}
|
||||||
|
if err := distros.SetupDsearchService(context.Background(), logFunc); err != nil {
|
||||||
|
// Non-fatal, matching greeter behavior
|
||||||
|
fmt.Fprintf(os.Stderr, "Warning: danksearch service setup issue (non-fatal): %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 10. Deploy configurations
|
// 10. Deploy configurations
|
||||||
fmt.Fprintln(os.Stdout, "Deploying configurations...")
|
fmt.Fprintln(os.Stdout, "Deploying configurations...")
|
||||||
r.log("Starting configuration deployment")
|
r.log("Starting configuration deployment")
|
||||||
|
|
||||||
deployer := config.NewConfigDeployer(r.logChan)
|
deployer := config.NewConfigDeployer(r.logChan)
|
||||||
useSystemd := true
|
|
||||||
if distroConfig, exists := distros.Registry[osInfo.Distribution.ID]; exists && distroConfig.Family == distros.FamilyVoid {
|
|
||||||
useSystemd = false
|
|
||||||
}
|
|
||||||
results, err := deployer.DeployConfigurationsSelectiveWithReinstallsAndSystemd(
|
results, err := deployer.DeployConfigurationsSelectiveWithReinstallsAndSystemd(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
wm,
|
wm,
|
||||||
@@ -272,19 +288,31 @@ func (r *Runner) Run() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// buildDisabledItems computes the set of dependencies that should be skipped
|
// buildDisabledItems computes the set of dependencies that should be skipped
|
||||||
// during installation, applying the --include-deps and --exclude-deps filters.
|
// during installation. Optional components are opt-in (disabled by default),
|
||||||
// dms-greeter is disabled by default (opt-in), matching TUI behavior.
|
// then re-enabled by the dedicated flags and --include-deps.
|
||||||
func (r *Runner) buildDisabledItems(dependencies []deps.Dependency) (map[string]bool, error) {
|
func (r *Runner) buildDisabledItems(dependencies []deps.Dependency) (map[string]bool, error) {
|
||||||
disabledItems := make(map[string]bool)
|
disabledItems := make(map[string]bool)
|
||||||
|
|
||||||
// dms-greeter is opt-in (disabled by default), matching TUI behavior
|
|
||||||
for i := range dependencies {
|
for i := range dependencies {
|
||||||
if dependencies[i].Name == "dms-greeter" {
|
if !dependencies[i].Required {
|
||||||
disabledItems["dms-greeter"] = true
|
disabledItems[dependencies[i].Name] = true
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dedicated flags resolve before include/exclude
|
||||||
|
if r.cfg.DankSearch {
|
||||||
|
if !r.depExists(dependencies, "danksearch") {
|
||||||
|
return nil, fmt.Errorf("--danksearch: not available on this distribution")
|
||||||
|
}
|
||||||
|
delete(disabledItems, "danksearch")
|
||||||
|
}
|
||||||
|
if r.cfg.DankCalendar {
|
||||||
|
if !r.depExists(dependencies, "dankcalendar") {
|
||||||
|
return nil, fmt.Errorf("--dankcalendar: not available on this distribution")
|
||||||
|
}
|
||||||
|
delete(disabledItems, "dankcalendar")
|
||||||
|
}
|
||||||
|
|
||||||
// Process --include-deps (enable items that are disabled by default)
|
// Process --include-deps (enable items that are disabled by default)
|
||||||
for _, name := range r.cfg.IncludeDeps {
|
for _, name := range r.cfg.IncludeDeps {
|
||||||
name = strings.TrimSpace(name)
|
name = strings.TrimSpace(name)
|
||||||
|
|||||||
@@ -342,17 +342,21 @@ func TestConfigReplaceConfigsStoredCorrectly(t *testing.T) {
|
|||||||
|
|
||||||
func TestBuildDisabledItems(t *testing.T) {
|
func TestBuildDisabledItems(t *testing.T) {
|
||||||
dependencies := []deps.Dependency{
|
dependencies := []deps.Dependency{
|
||||||
{Name: "niri", Status: deps.StatusInstalled},
|
{Name: "niri", Status: deps.StatusInstalled, Required: true},
|
||||||
{Name: "ghostty", Status: deps.StatusMissing},
|
{Name: "ghostty", Status: deps.StatusMissing, Required: true},
|
||||||
{Name: "dms (DankMaterialShell)", Status: deps.StatusInstalled},
|
{Name: "dms (DankMaterialShell)", Status: deps.StatusInstalled, Required: true},
|
||||||
{Name: "dms-greeter", Status: deps.StatusMissing},
|
{Name: "dms-greeter", Status: deps.StatusMissing},
|
||||||
{Name: "waybar", Status: deps.StatusMissing},
|
{Name: "danksearch", Status: deps.StatusMissing},
|
||||||
|
{Name: "dankcalendar", Status: deps.StatusMissing},
|
||||||
|
{Name: "waybar", Status: deps.StatusMissing, Required: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
includeDeps []string
|
includeDeps []string
|
||||||
excludeDeps []string
|
excludeDeps []string
|
||||||
|
dankSearch bool
|
||||||
|
dankCalendar bool
|
||||||
deps []deps.Dependency // nil means use the shared fixture
|
deps []deps.Dependency // nil means use the shared fixture
|
||||||
wantErr bool
|
wantErr bool
|
||||||
errContains string // substring expected in error message
|
errContains string // substring expected in error message
|
||||||
@@ -360,19 +364,20 @@ func TestBuildDisabledItems(t *testing.T) {
|
|||||||
wantEnabled []string // dep names that should NOT be in disabledItems (extra check)
|
wantEnabled []string // dep names that should NOT be in disabledItems (extra check)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "no flags set, dms-greeter disabled by default",
|
name: "no flags set, optional deps disabled by default",
|
||||||
wantDisabled: []string{"dms-greeter"},
|
wantDisabled: []string{"dms-greeter", "danksearch", "dankcalendar"},
|
||||||
wantEnabled: []string{"niri", "ghostty", "waybar"},
|
wantEnabled: []string{"niri", "ghostty", "waybar"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "include dms-greeter enables it",
|
name: "include dms-greeter enables it",
|
||||||
includeDeps: []string{"dms-greeter"},
|
includeDeps: []string{"dms-greeter"},
|
||||||
wantEnabled: []string{"dms-greeter"},
|
wantEnabled: []string{"dms-greeter"},
|
||||||
|
wantDisabled: []string{"danksearch", "dankcalendar"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "exclude a regular dep",
|
name: "exclude a regular dep",
|
||||||
excludeDeps: []string{"waybar"},
|
excludeDeps: []string{"waybar"},
|
||||||
wantDisabled: []string{"dms-greeter", "waybar"},
|
wantDisabled: []string{"dms-greeter", "danksearch", "dankcalendar", "waybar"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "include unknown dep returns error",
|
name: "include unknown dep returns error",
|
||||||
@@ -399,24 +404,53 @@ func TestBuildDisabledItems(t *testing.T) {
|
|||||||
wantDisabled: []string{"dms-greeter"},
|
wantDisabled: []string{"dms-greeter"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "whitespace entries are skipped",
|
name: "whitespace entries are skipped",
|
||||||
includeDeps: []string{" ", "dms-greeter"},
|
includeDeps: []string{" ", "dms-greeter"},
|
||||||
wantEnabled: []string{"dms-greeter"},
|
wantEnabled: []string{"dms-greeter"},
|
||||||
|
wantDisabled: []string{"danksearch", "dankcalendar"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no dms-greeter in deps, nothing disabled by default",
|
name: "no optional deps present, nothing disabled by default",
|
||||||
deps: []deps.Dependency{
|
deps: []deps.Dependency{
|
||||||
{Name: "niri", Status: deps.StatusInstalled},
|
{Name: "niri", Status: deps.StatusInstalled, Required: true},
|
||||||
},
|
},
|
||||||
wantEnabled: []string{"niri"},
|
wantEnabled: []string{"niri"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "danksearch flag enables it",
|
||||||
|
dankSearch: true,
|
||||||
|
wantEnabled: []string{"danksearch"},
|
||||||
|
wantDisabled: []string{"dms-greeter", "dankcalendar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dankcalendar flag enables it",
|
||||||
|
dankCalendar: true,
|
||||||
|
wantEnabled: []string{"dankcalendar"},
|
||||||
|
wantDisabled: []string{"dms-greeter", "danksearch"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "danksearch flag when unavailable errors",
|
||||||
|
dankSearch: true,
|
||||||
|
deps: []deps.Dependency{{Name: "niri", Status: deps.StatusInstalled, Required: true}},
|
||||||
|
wantErr: true,
|
||||||
|
errContains: "--danksearch",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dankcalendar flag when unavailable errors",
|
||||||
|
dankCalendar: true,
|
||||||
|
deps: []deps.Dependency{{Name: "niri", Status: deps.StatusInstalled, Required: true}},
|
||||||
|
wantErr: true,
|
||||||
|
errContains: "--dankcalendar",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := NewRunner(Config{
|
r := NewRunner(Config{
|
||||||
IncludeDeps: tt.includeDeps,
|
IncludeDeps: tt.includeDeps,
|
||||||
ExcludeDeps: tt.excludeDeps,
|
ExcludeDeps: tt.excludeDeps,
|
||||||
|
DankSearch: tt.dankSearch,
|
||||||
|
DankCalendar: tt.dankCalendar,
|
||||||
})
|
})
|
||||||
d := tt.deps
|
d := tt.deps
|
||||||
if d == nil {
|
if d == nil {
|
||||||
|
|||||||
@@ -139,6 +139,18 @@ func (m Model) deployConfigurations() tea.Cmd {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m Model) optionalDepSelected(name string) bool {
|
||||||
|
if m.disabledItems[name] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, dep := range m.dependencies {
|
||||||
|
if dep.Name == name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (m Model) useSystemdConfig() bool {
|
func (m Model) useSystemdConfig() bool {
|
||||||
if m.osInfo == nil {
|
if m.osInfo == nil {
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -28,6 +28,21 @@ func (m Model) viewDetectingDeps() string {
|
|||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func partitionOptionalLast(dependencies []deps.Dependency) []deps.Dependency {
|
||||||
|
ordered := make([]deps.Dependency, 0, len(dependencies))
|
||||||
|
for _, dep := range dependencies {
|
||||||
|
if dep.Required {
|
||||||
|
ordered = append(ordered, dep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, dep := range dependencies {
|
||||||
|
if !dep.Required {
|
||||||
|
ordered = append(ordered, dep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ordered
|
||||||
|
}
|
||||||
|
|
||||||
func (m Model) viewDependencyReview() string {
|
func (m Model) viewDependencyReview() string {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
|
|
||||||
@@ -39,7 +54,15 @@ func (m Model) viewDependencyReview() string {
|
|||||||
b.WriteString("\n\n")
|
b.WriteString("\n\n")
|
||||||
|
|
||||||
if len(m.dependencies) > 0 {
|
if len(m.dependencies) > 0 {
|
||||||
|
optionalHeaderShown := false
|
||||||
for i, dep := range m.dependencies {
|
for i, dep := range m.dependencies {
|
||||||
|
if !dep.Required && !optionalHeaderShown {
|
||||||
|
b.WriteString("\n")
|
||||||
|
b.WriteString(m.styles.Subtle.Render("Optional (space to enable)"))
|
||||||
|
b.WriteString("\n")
|
||||||
|
optionalHeaderShown = true
|
||||||
|
}
|
||||||
|
|
||||||
var status string
|
var status string
|
||||||
var reinstallMarker string
|
var reinstallMarker string
|
||||||
var variantMarker string
|
var variantMarker string
|
||||||
@@ -82,8 +105,13 @@ func (m Model) viewDependencyReview() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
note := ""
|
note := ""
|
||||||
if dep.Name == "dms-greeter" {
|
switch dep.Name {
|
||||||
|
case "dms-greeter":
|
||||||
note = m.styles.Subtle.Render(" (selection replaces your current display manager)")
|
note = m.styles.Subtle.Render(" (selection replaces your current display manager)")
|
||||||
|
case "danksearch":
|
||||||
|
note = m.styles.Subtle.Render(" (file search; enables dsearch.service)")
|
||||||
|
case "dankcalendar":
|
||||||
|
note = m.styles.Subtle.Render(" (autostart managed in dankcalendar settings)")
|
||||||
}
|
}
|
||||||
|
|
||||||
var line string
|
var line string
|
||||||
@@ -120,13 +148,13 @@ func (m Model) updateDetectingDepsState(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
m.err = depsMsg.err
|
m.err = depsMsg.err
|
||||||
m.state = StateError
|
m.state = StateError
|
||||||
} else {
|
} else {
|
||||||
m.dependencies = depsMsg.deps
|
m.dependencies = partitionOptionalLast(depsMsg.deps)
|
||||||
// dms-greeter is opt-in skipped by default
|
// Optional components are opt-in, skipped by default
|
||||||
for _, dep := range depsMsg.deps {
|
for _, dep := range m.dependencies {
|
||||||
if dep.Name == "dms-greeter" {
|
if dep.Required {
|
||||||
m.disabledItems["dms-greeter"] = true
|
continue
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
m.disabledItems[dep.Name] = true
|
||||||
}
|
}
|
||||||
m.state = StateDependencyReview
|
m.state = StateDependencyReview
|
||||||
}
|
}
|
||||||
@@ -231,14 +259,7 @@ func (m Model) installPackages() tea.Cmd {
|
|||||||
for msg := range installerProgressChan {
|
for msg := range installerProgressChan {
|
||||||
// Run optional greeter setup
|
// Run optional greeter setup
|
||||||
if msg.Phase == distros.PhaseComplete && msg.IsComplete && msg.Error == nil {
|
if msg.Phase == distros.PhaseComplete && msg.IsComplete && msg.Error == nil {
|
||||||
greeterSelected := false
|
if m.optionalDepSelected("dms-greeter") {
|
||||||
for _, dep := range m.dependencies {
|
|
||||||
if dep.Name == "dms-greeter" && !m.disabledItems["dms-greeter"] {
|
|
||||||
greeterSelected = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if greeterSelected {
|
|
||||||
compositorName := "niri"
|
compositorName := "niri"
|
||||||
switch m.selectedWindowManager() {
|
switch m.selectedWindowManager() {
|
||||||
case deps.WindowManagerHyprland:
|
case deps.WindowManagerHyprland:
|
||||||
@@ -265,6 +286,28 @@ func (m Model) installPackages() tea.Cmd {
|
|||||||
logOutput: fmt.Sprintf("⚠ Greeter auto-setup warning (non-fatal): %v", err),
|
logOutput: fmt.Sprintf("⚠ Greeter auto-setup warning (non-fatal): %v", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if m.useSystemdConfig() && m.optionalDepSelected("danksearch") {
|
||||||
|
m.packageProgressChan <- packageInstallProgressMsg{
|
||||||
|
progress: 0.97,
|
||||||
|
step: "Enabling danksearch service...",
|
||||||
|
logOutput: "Setting up dsearch.service...",
|
||||||
|
}
|
||||||
|
dsearchLogFunc := func(line string) {
|
||||||
|
m.packageProgressChan <- packageInstallProgressMsg{
|
||||||
|
progress: 0.97,
|
||||||
|
step: "Enabling danksearch service...",
|
||||||
|
logOutput: line,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := distros.SetupDsearchService(context.Background(), dsearchLogFunc); err != nil {
|
||||||
|
m.packageProgressChan <- packageInstallProgressMsg{
|
||||||
|
progress: 0.98,
|
||||||
|
step: "danksearch service warning",
|
||||||
|
logOutput: fmt.Sprintf("danksearch service setup warning (non-fatal): %v", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tuiMsg := packageInstallProgressMsg{
|
tuiMsg := packageInstallProgressMsg{
|
||||||
|
|||||||
Reference in New Issue
Block a user