distros: dux packaging rebrand sweep

Port 2.0
This commit is contained in:
purian23 committed 2026-10-30 07:32:31 -04:00
1 parent 095d1c6fd5
commit 40a129c9d6
16 files changed
+253 -101

No files matched your search

+11 -11
View File
@@ -14,16 +14,16 @@ import (
var greeterCmd = &cobra.Command{
Use: "greeter",
Short: "Deprecated: moved to the standalone dms-greeter binary",
Long: "The greeter has moved to the standalone dms-greeter package.\nThis command forwards to 'dms-greeter' when it is installed.",
Long: "The greeter has moved to the standalone dux-greeter package.\nThis command forwards to 'dms-greeter' when it is installed.",
DisableFlagParsing: true,
SilenceUsage: true,
RunE: func(_ *cobra.Command, args []string) error {
binary, err := exec.LookPath("dms-greeter")
if err != nil {
return fmt.Errorf("'dms greeter' has moved to the standalone dms-greeter package.\n %s", greeterPackageInstallHint())
return fmt.Errorf("'dms greeter' has moved to the standalone dux-greeter package.\n %s", greeterPackageInstallHint())
}
if isLegacyWrapperScript(binary) {
return fmt.Errorf("'dms greeter' has moved to the standalone dms-greeter package; %s is the old wrapper script.\n %s", binary, greeterPackageInstallHint())
return fmt.Errorf("'dms greeter' has moved to the standalone dux-greeter package; %s is the old wrapper script.\n %s", binary, greeterPackageInstallHint())
}
fmt.Fprintln(os.Stderr, "warning: 'dms greeter' is deprecated; use 'dms-greeter' directly")
return syscall.Exec(binary, append([]string{"dms-greeter"}, args...), os.Environ())
@@ -50,11 +50,11 @@ func isLegacyWrapperScript(path string) bool {
func greeterPackageInstallHint() string {
osInfo, err := distros.GetOSInfo()
if err != nil {
return "Install package: dms-greeter"
return "Install package: dux-greeter"
}
config, exists := distros.Registry[osInfo.Distribution.ID]
if !exists {
return "Install package: dms-greeter"
return "Install package: dux-greeter"
}
if config.ID == "pika" {
@@ -63,19 +63,19 @@ func greeterPackageInstallHint() string {
switch config.Family {
case distros.FamilyDebian:
return "Install with 'sudo apt install dms-greeter' (requires Dux Labs OBS repo — see " + site.Docs + "/dms-greeter/installation#debian)"
return "Install with 'sudo apt install dux-greeter' (requires Dux Labs OBS repo — see " + site.Docs + "/dms-greeter/installation#debian)"
case distros.FamilySUSE:
return "Install with 'sudo zypper install dms-greeter' (requires Dux Labs OBS repo — see " + site.Docs + "/dms-greeter/installation#opensuse--derivatives)"
return "Install with 'sudo zypper install dux-greeter' (requires Dux Labs OBS repo — see " + site.Docs + "/dms-greeter/installation#opensuse--derivatives)"
case distros.FamilyUbuntu:
repo := greeterRepoURL(config)
return fmt.Sprintf("Install with 'sudo apt install dms-greeter' (requires %s: sudo add-apt-repository %s)", repo, repo)
return fmt.Sprintf("Install with 'sudo apt install dux-greeter' (requires %s: sudo add-apt-repository %s)", repo, repo)
case distros.FamilyFedora:
return fmt.Sprintf("Install with 'sudo dnf install dms-greeter' (requires COPR: sudo dnf copr enable %s)", greeterRepoURL(config))
return fmt.Sprintf("Install with 'sudo dnf install dux-greeter' (requires COPR: sudo dnf copr enable %s)", greeterRepoURL(config))
case distros.FamilyArch:
return "Install from AUR with 'paru -S dux-greeter-bin' or 'yay -S dux-greeter-bin'"
case distros.FamilyVoid:
return "Install with 'sudo xbps-install -S dms-greeter' (requires DMS XBPS repo: echo 'repository=" + distros.VoidDepsRepo + "' | sudo tee /etc/xbps.d/dux.conf)"
return "Install with 'sudo xbps-install -S dux-greeter' (requires DMS XBPS repo: echo 'repository=" + distros.VoidDepsRepo + "' | sudo tee /etc/xbps.d/dux.conf)"
default:
return "Install the dms-greeter package for your distribution"
return "Install the dux-greeter package for your distribution"
}
}
+33
View File
@@ -113,6 +113,39 @@ func (b *BaseDistribution) detectDankCalendar() deps.Dependency {
return b.detectOptionalPackage("dankcalendar", "Calendar application", b.commandExists("dcal") || b.commandExists("dankcalendar"))
}
// renamedPackages maps distro packages to their pre-rename names. rpm -q, dpkg-query and xbps-query
// ignore Provides, so hosts that have not upgraded since the rename only match the old name.
var renamedPackages = map[string]string{
"dux-greeter": "dms-greeter",
"dux-greeter-git": "dms-greeter-git",
"dux-search": "danksearch",
"dux-calendar": "dankcalendar",
"dux-calendar-git": "dankcalendar-git",
"dux-gop": "dgop",
}
func installedName(installed func(string) bool, pkg string) (string, bool) {
if installed(pkg) {
return pkg, true
}
if old, ok := renamedPackages[pkg]; ok && installed(old) {
return old, true
}
return "", false
}
func (b *BaseDistribution) detectGreeterPackage(installed func(string) bool) deps.Dependency {
_, gitInstalled := installedName(installed, "dux-greeter-git")
_, stableInstalled := installedName(installed, "dux-greeter")
dep := b.detectOptionalPackage("dms-greeter", "Dux Shell greetd greeter", gitInstalled || stableInstalled)
return withGitVariant(dep, gitInstalled)
}
func (b *BaseDistribution) detectCalendarPackage(installed func(string) bool) deps.Dependency {
_, gitInstalled := installedName(installed, "dux-calendar-git")
return withGitVariant(b.detectDankCalendar(), gitInstalled)
}
func withGitVariant(dep deps.Dependency, gitInstalled bool) deps.Dependency {
dep.CanToggle = true
if gitInstalled {
+54
View File
@@ -3,6 +3,7 @@ package distros
import (
"os"
"path/filepath"
"strings"
"testing"
"github.com/duxlabs-dev/dux-shell/core/internal/deps"
@@ -73,3 +74,56 @@ func TestParseHyprlandVersion(t *testing.T) {
}
}
}
func TestDetectGreeterPackageAcceptsOldNames(t *testing.T) {
cases := []struct {
installed string
wantInstalled bool
wantVariant deps.PackageVariant
}{
{"", false, deps.VariantStable},
{"dms-greeter", true, deps.VariantStable},
{"dux-greeter", true, deps.VariantStable},
{"dms-greeter-git", true, deps.VariantGit},
{"dux-greeter-git", true, deps.VariantGit},
}
for _, tc := range cases {
dep := NewBaseDistribution(nil).detectGreeterPackage(func(p string) bool { return p == tc.installed })
if (dep.Status == deps.StatusInstalled) != tc.wantInstalled || dep.Variant != tc.wantVariant {
t.Errorf("%q installed: status %v variant %v, want installed=%v variant %v", tc.installed, dep.Status, dep.Variant, tc.wantInstalled, tc.wantVariant)
}
}
}
func TestDetectCalendarPackageAcceptsOldNames(t *testing.T) {
for installed, want := range map[string]deps.PackageVariant{
"": deps.VariantStable,
"dankcalendar-git": deps.VariantGit,
"dux-calendar-git": deps.VariantGit,
} {
dep := NewBaseDistribution(nil).detectCalendarPackage(func(p string) bool { return p == installed })
if dep.Variant != want {
t.Errorf("%q installed: variant %v, want %v", installed, dep.Variant, want)
}
}
}
func TestRenamedPackagesInstallNewNames(t *testing.T) {
cases := map[string]Distribution{
"fedora": NewFedoraDistribution(Registry["fedora"], nil),
"opensuse": NewOpenSUSEDistribution(Registry["opensuse-tumbleweed"], nil),
"debian": NewDebianDistribution(Registry["debian"], nil),
"ubuntu": NewUbuntuDistribution(Registry["ubuntu"], nil),
"void": NewVoidDistribution(Registry["void"], nil),
}
for id, d := range cases {
for _, variant := range []deps.PackageVariant{deps.VariantStable, deps.VariantGit} {
packages := d.GetPackageMappingWithVariants(deps.WindowManagerNiri, map[string]deps.PackageVariant{"dms-greeter": variant, "dankcalendar": variant})
for dep, want := range map[string]string{"dms-greeter": "dux-greeter", "danksearch": "dux-search", "dankcalendar": "dux-calendar"} {
if got := strings.TrimSuffix(packages[dep].Name, "-git"); got != want {
t.Errorf("%s %s (%v) installs %q, want %q", id, dep, variant, packages[dep].Name, want)
}
}
}
}
}
+5 -11
View File
@@ -62,7 +62,7 @@ func (d *DebianDistribution) DetectDependenciesWithTerminal(ctx context.Context,
dependencies = append(dependencies, d.detectGit())
dependencies = append(dependencies, d.detectWindowManager(wm))
dependencies = append(dependencies, d.detectQuickshell())
dependencies = append(dependencies, d.detectDMSGreeter())
dependencies = append(dependencies, d.detectGreeterPackage(d.packageInstalled))
dependencies = append(dependencies, d.detectXDGPortal())
dependencies = append(dependencies, d.detectAccountsService())
@@ -77,7 +77,7 @@ func (d *DebianDistribution) DetectDependenciesWithTerminal(ctx context.Context,
dependencies = append(dependencies, d.detectMatugen())
dependencies = append(dependencies, d.detectDanksearch())
dependencies = append(dependencies, withGitVariant(d.detectDankCalendar(), d.packageInstalled("dankcalendar-git")))
dependencies = append(dependencies, d.detectCalendarPackage(d.packageInstalled))
return dependencies, nil
}
@@ -94,12 +94,6 @@ func (d *DebianDistribution) detectAccountsService() deps.Dependency {
return d.detectPackage("accountsservice", "D-Bus interface for user account query and manipulation", d.packageInstalled("accountsservice"))
}
func (d *DebianDistribution) detectDMSGreeter() deps.Dependency {
gitInstalled := d.packageInstalled("dms-greeter-git")
dep := d.detectOptionalPackage("dms-greeter", "Dux Shell greetd greeter", gitInstalled || d.packageInstalled("dms-greeter"))
return withGitVariant(dep, gitInstalled)
}
func (d *DebianDistribution) packageInstalled(pkg string) bool {
return debianPackageInstalledPrecisely(pkg)
}
@@ -159,11 +153,11 @@ func (d *DebianDistribution) GetPackageMappingWithVariants(wm deps.WindowManager
// DMS packages from OBS with variant support
"dms (Dux Shell)": d.getDmsMapping(variants["dms (Dux Shell)"]),
"quickshell": d.getQuickshellMapping(variants["quickshell"]),
"dms-greeter": variantMapping("dms-greeter", variants["dms-greeter"], RepoTypeOBS, obsDeps),
"dms-greeter": variantMapping("dux-greeter", variants["dms-greeter"], RepoTypeOBS, obsDeps),
"matugen": {Name: "matugen", Repository: RepoTypeOBS, RepoURL: obsDeps},
"ghostty": {Name: "ghostty", Repository: RepoTypeOBS, RepoURL: obsDeps},
"danksearch": {Name: "danksearch", Repository: RepoTypeOBS, RepoURL: obsDeps},
"dankcalendar": variantMapping("dankcalendar", variants["dankcalendar"], RepoTypeOBS, obsDeps),
"danksearch": {Name: "dux-search", Repository: RepoTypeOBS, RepoURL: obsDeps},
"dankcalendar": variantMapping("dux-calendar", variants["dankcalendar"], RepoTypeOBS, obsDeps),
}
if wm == deps.WindowManagerNiri {
+61 -13
View File
@@ -2,10 +2,13 @@ package distros
import (
"context"
"encoding/json"
"fmt"
"maps"
"os/exec"
"slices"
"strings"
"sync"
"github.com/duxlabs-dev/dux-shell/core/internal/deps"
"github.com/duxlabs-dev/dux-shell/core/internal/privesc"
@@ -53,7 +56,8 @@ type FedoraDistribution struct {
*ManualPackageInstaller
config DistroConfig
rpmInstalled func(pkg string) bool
rpmInstalled func(pkg string) bool
ostreeRequested func() []string
}
func NewFedoraDistribution(config DistroConfig, logChan chan<- string) *FedoraDistribution {
@@ -106,7 +110,7 @@ func (f *FedoraDistribution) DetectDependenciesWithTerminal(ctx context.Context,
}
dependencies = append(dependencies, wmDep)
dependencies = append(dependencies, f.detectQuickshell())
dependencies = append(dependencies, f.detectDMSGreeter())
dependencies = append(dependencies, f.detectGreeterPackage(f.packageInstalled))
dependencies = append(dependencies, f.detectXDGPortal())
dependencies = append(dependencies, f.detectAccountsService())
@@ -128,7 +132,7 @@ func (f *FedoraDistribution) DetectDependenciesWithTerminal(ctx context.Context,
dependencies = append(dependencies, f.detectMatugen())
dependencies = append(dependencies, f.detectDanksearch())
dependencies = append(dependencies, withGitVariant(f.detectDankCalendar(), f.packageInstalled("dankcalendar-git")))
dependencies = append(dependencies, f.detectCalendarPackage(f.packageInstalled))
return dependencies, nil
}
@@ -294,11 +298,11 @@ func (f *FedoraDistribution) GetPackageMappingWithVariants(wm deps.WindowManager
// COPR packages
"quickshell": f.getQuickshellMapping(variants["quickshell"]),
"dms-greeter": variantMapping("dms-greeter", variants["dms-greeter"], RepoTypeCOPR, coprDeps),
"dms-greeter": variantMapping("dux-greeter", variants["dms-greeter"], RepoTypeCOPR, coprDeps),
"matugen": {Name: "matugen", Repository: RepoTypeCOPR, RepoURL: coprDeps},
"dms (Dux Shell)": f.getDmsMapping(variants["dms (Dux Shell)"]),
"danksearch": {Name: "danksearch", Repository: RepoTypeCOPR, RepoURL: coprDeps},
"dankcalendar": variantMapping("dankcalendar", variants["dankcalendar"], RepoTypeCOPR, coprDeps),
"danksearch": {Name: "dux-search", Repository: RepoTypeCOPR, RepoURL: coprDeps},
"dankcalendar": variantMapping("dux-calendar", variants["dankcalendar"], RepoTypeCOPR, coprDeps),
}
switch wm {
@@ -381,12 +385,6 @@ func (f *FedoraDistribution) detectAccountsService() deps.Dependency {
}
}
func (f *FedoraDistribution) detectDMSGreeter() deps.Dependency {
gitInstalled := f.packageInstalled("dms-greeter-git")
dep := f.detectOptionalPackage("dms-greeter", "Dux Shell greetd greeter", gitInstalled || f.packageInstalled("dms-greeter"))
return withGitVariant(dep, gitInstalled)
}
func (f *FedoraDistribution) getPrerequisites() []string {
return []string{
"dnf-plugins-core",
@@ -829,6 +827,44 @@ func (f *FedoraDistribution) coprRepoFileCommand(repo string) string {
coprRepoFile(repo), owner, project, chroot, owner, project, chroot)
}
// rpm-ostree status runs over D-Bus and the layer view rebuilds its commands on every render.
var rpmOstreeRequested = sync.OnceValue(func() []string {
out, err := exec.Command("rpm-ostree", "status", "--json").Output()
if err != nil {
return nil
}
var status struct {
Deployments []struct {
Requested []string `json:"requested-packages"`
} `json:"deployments"`
}
if json.Unmarshal(out, &status) != nil || len(status.Deployments) == 0 {
return nil
}
return status.Deployments[0].Requested
})
func (f *FedoraDistribution) layeredRequests() map[string]bool {
list := f.ostreeRequested
if list == nil {
list = rpmOstreeRequested
}
requested := map[string]bool{}
for _, name := range list() {
requested[name] = true
}
return requested
}
// layeredName is what --uninstall must name: the request, which may still be the pre-rename name
// even when its Provides already resolved to the renamed package.
func layeredName(requested map[string]bool, pkg string) string {
if old, ok := renamedPackages[pkg]; ok && !requested[pkg] && requested[old] {
return old
}
return pkg
}
// Shown to the user, never run. Terra-only packages have no rpm-ostree path.
func (f *FedoraDistribution) LayerCommands(dependencies []deps.Dependency, wm deps.WindowManager, reinstallFlags, disabledFlags map[string]bool) []string {
var commands []string
@@ -837,6 +873,7 @@ func (f *FedoraDistribution) LayerCommands(dependencies []deps.Dependency, wm de
if skip == nil {
skip = map[string]bool{}
}
requested := f.layeredRequests()
// rpm-ostree refuses to install what is already layered, so a reinstall mark only means a variant switch.
for _, dep := range dependencies {
if !reinstallFlags[dep.Name] || skip[dep.Name] || dep.Status != deps.StatusInstalled {
@@ -847,7 +884,7 @@ func (f *FedoraDistribution) LayerCommands(dependencies []deps.Dependency, wm de
skip[dep.Name] = true
continue
}
uninstall = append(uninstall, swap.From.Name)
uninstall = append(uninstall, layeredName(requested, swap.From.Name))
if swap.From.Name == swap.To.Name && swap.From.Repository == RepoTypeCOPR {
var files []string
for _, repo := range coprAliases(swap.From.RepoURL) {
@@ -871,6 +908,17 @@ func (f *FedoraDistribution) LayerCommands(dependencies []deps.Dependency, wm de
commands = append(commands, "echo priority=1 | sudo tee -a "+coprRepoFile("yalter/niri-git"))
}
}
// A request keeps its old name forever and resolves by name before Provides, ignoring Obsoletes.
for _, name := range slices.Sorted(maps.Keys(renamedPackages)) {
old := renamedPackages[name]
if !requested[old] || slices.Contains(uninstall, old) {
continue
}
uninstall = append(uninstall, old)
if !requested[name] && !slices.Contains(pkgs, name) {
pkgs = append(pkgs, name)
}
}
for _, dep := range dependencies {
if dep.Status == deps.StatusNeedsUpdate && !disabledFlags[dep.Name] {
commands = append(commands, "sudo rpm-ostree upgrade")
+28 -1
View File
@@ -137,6 +137,7 @@ func TestApplyImmutableDetection(t *testing.T) {
func TestFedoraLayerCommands(t *testing.T) {
f := NewFedoraDistribution(Registry["fedora"], nil)
f.ostreeRequested = func() []string { return nil }
dependencies := []deps.Dependency{
{Name: "dms (Dux Shell)", Status: deps.StatusMissing},
{Name: "niri", Status: deps.StatusMissing, Variant: deps.VariantGit},
@@ -180,6 +181,7 @@ func TestFedoraLayerCommandsSwapVariants(t *testing.T) {
f := NewFedoraDistribution(Registry["fedora"], nil)
installed := map[string]bool{"dms-greeter": true, "dms": true}
f.rpmInstalled = func(pkg string) bool { return installed[pkg] }
f.ostreeRequested = func() []string { return []string{"dms", "dms-greeter"} }
orig := installedFromCOPR
installedFromCOPR = func(pkg, repo string) bool { return pkg == "dms" && repo == "duxlabs/dms-git" }
t.Cleanup(func() { installedFromCOPR = orig })
@@ -194,7 +196,7 @@ func TestFedoraLayerCommandsSwapVariants(t *testing.T) {
for _, want := range []string{
"sudo rm -f /etc/yum.repos.d/_copr:copr.fedorainfracloud.org:duxlabs:dms-git.repo /etc/yum.repos.d/_copr:copr.fedorainfracloud.org:avengemedia:dms-git.repo",
"sudo rpm-ostree install dms dms-greeter-git --uninstall dms dms-greeter",
"sudo rpm-ostree install dms dux-greeter-git --uninstall dms dms-greeter",
} {
if !strings.Contains(got, want) {
t.Fatalf("missing %q in:\n%s", want, got)
@@ -205,6 +207,31 @@ func TestFedoraLayerCommandsSwapVariants(t *testing.T) {
}
}
func TestFedoraLayerCommandsRenamedRequests(t *testing.T) {
cases := []struct {
name string
rpm string
requested []string
want string
}{
{"old package and request", "dms-greeter", []string{"dms-greeter", "danksearch"}, "sudo rpm-ostree install dux-greeter-git dux-search --uninstall dms-greeter danksearch"},
{"old request resolved through Provides", "dux-greeter", []string{"dms-greeter"}, "sudo rpm-ostree install dux-greeter-git --uninstall dms-greeter"},
{"new request", "dux-greeter", []string{"dux-greeter"}, "sudo rpm-ostree install dux-greeter-git --uninstall dux-greeter"},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
f := NewFedoraDistribution(Registry["fedora"], nil)
f.rpmInstalled = func(pkg string) bool { return pkg == tc.rpm }
f.ostreeRequested = func() []string { return tc.requested }
dependencies := []deps.Dependency{{Name: "dms-greeter", Status: deps.StatusInstalled, Variant: deps.VariantGit, CanToggle: true}}
got := strings.Join(f.LayerCommands(dependencies, deps.WindowManagerNiri, map[string]bool{"dms-greeter": true}, nil), "\n")
if !strings.Contains(got, tc.want) {
t.Fatalf("missing %q in:\n%s", tc.want, got)
}
})
}
}
func TestApplyImmutableDetectionReadsVariant(t *testing.T) {
dir := t.TempDir()
if err := os.WriteFile(filepath.Join(dir, "dms"), []byte("#!/bin/sh\necho 'dms (git) v2.0.0-5333'\n"), 0o755); err != nil {
+5 -11
View File
@@ -75,7 +75,7 @@ func (o *OpenSUSEDistribution) DetectDependenciesWithTerminal(ctx context.Contex
dependencies = append(dependencies, o.detectGit())
dependencies = append(dependencies, o.detectWindowManager(wm))
dependencies = append(dependencies, o.detectQuickshell())
dependencies = append(dependencies, o.detectDMSGreeter())
dependencies = append(dependencies, o.detectGreeterPackage(o.packageInstalled))
dependencies = append(dependencies, o.detectXDGPortal())
dependencies = append(dependencies, o.detectAccountsService())
@@ -92,7 +92,7 @@ func (o *OpenSUSEDistribution) DetectDependenciesWithTerminal(ctx context.Contex
dependencies = append(dependencies, o.detectMatugen())
dependencies = append(dependencies, o.detectDanksearch())
dependencies = append(dependencies, withGitVariant(o.detectDankCalendar(), o.packageInstalled("dankcalendar-git")))
dependencies = append(dependencies, o.detectCalendarPackage(o.packageInstalled))
return dependencies, nil
}
@@ -196,12 +196,6 @@ func obsZypperRepoURL(repo, dist string) string {
return obsBaseURL(repo, dist) + "/" + repo + ".repo"
}
func (o *OpenSUSEDistribution) detectDMSGreeter() deps.Dependency {
gitInstalled := o.packageInstalled("dms-greeter-git")
dep := o.detectOptionalPackage("dms-greeter", "Dux Shell greetd greeter", gitInstalled || o.packageInstalled("dms-greeter"))
return withGitVariant(dep, gitInstalled)
}
func (o *OpenSUSEDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping {
return o.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant))
}
@@ -218,11 +212,11 @@ func (o *OpenSUSEDistribution) GetPackageMappingWithVariants(wm deps.WindowManag
// DMS packages from OBS
"dms (Dux Shell)": o.getDmsMapping(variants["dms (Dux Shell)"]),
"quickshell": o.getQuickshellMapping(variants["quickshell"]),
"dms-greeter": variantMapping("dms-greeter", variants["dms-greeter"], RepoTypeOBS, obsDeps),
"dms-greeter": variantMapping("dux-greeter", variants["dms-greeter"], RepoTypeOBS, obsDeps),
"ghostty": {Name: "ghostty", Repository: RepoTypeOBS, RepoURL: obsDeps},
"matugen": {Name: "matugen", Repository: RepoTypeOBS, RepoURL: obsDeps},
"danksearch": {Name: "danksearch", Repository: RepoTypeOBS, RepoURL: obsDeps},
"dankcalendar": variantMapping("dankcalendar", variants["dankcalendar"], RepoTypeOBS, obsDeps),
"danksearch": {Name: "dux-search", Repository: RepoTypeOBS, RepoURL: obsDeps},
"dankcalendar": variantMapping("dux-calendar", variants["dankcalendar"], RepoTypeOBS, obsDeps),
}
switch wm {
+5 -11
View File
@@ -70,7 +70,7 @@ func (u *UbuntuDistribution) DetectDependenciesWithTerminal(ctx context.Context,
dependencies = append(dependencies, u.detectGit())
dependencies = append(dependencies, u.detectWindowManager(wm))
dependencies = append(dependencies, u.detectQuickshell())
dependencies = append(dependencies, u.detectDMSGreeter())
dependencies = append(dependencies, u.detectGreeterPackage(u.packageInstalled))
dependencies = append(dependencies, u.detectXDGPortal())
dependencies = append(dependencies, u.detectAccountsService())
@@ -87,7 +87,7 @@ func (u *UbuntuDistribution) DetectDependenciesWithTerminal(ctx context.Context,
dependencies = append(dependencies, u.detectMatugen())
dependencies = append(dependencies, u.detectDanksearch())
dependencies = append(dependencies, withGitVariant(u.detectDankCalendar(), u.packageInstalled("dankcalendar-git")))
dependencies = append(dependencies, u.detectCalendarPackage(u.packageInstalled))
return dependencies, nil
}
@@ -104,12 +104,6 @@ func (u *UbuntuDistribution) detectAccountsService() deps.Dependency {
return u.detectPackage("accountsservice", "D-Bus interface for user account query and manipulation", u.packageInstalled("accountsservice"))
}
func (u *UbuntuDistribution) detectDMSGreeter() deps.Dependency {
gitInstalled := u.packageInstalled("dms-greeter-git")
dep := u.detectOptionalPackage("dms-greeter", "Dux Shell greetd greeter", gitInstalled || u.packageInstalled("dms-greeter"))
return withGitVariant(dep, gitInstalled)
}
func (u *UbuntuDistribution) packageInstalled(pkg string) bool {
return debianPackageInstalledPrecisely(pkg)
}
@@ -190,11 +184,11 @@ func (u *UbuntuDistribution) GetPackageMappingWithVariants(wm deps.WindowManager
// DMS packages from PPAs
"dms (Dux Shell)": u.getDmsMapping(variants["dms (Dux Shell)"]),
"quickshell": u.getQuickshellMapping(variants["quickshell"]),
"dms-greeter": variantMapping("dms-greeter", variants["dms-greeter"], RepoTypePPA, ppaDeps),
"dms-greeter": variantMapping("dux-greeter", variants["dms-greeter"], RepoTypePPA, ppaDeps),
"matugen": {Name: "matugen", Repository: RepoTypePPA, RepoURL: ppaDeps},
"ghostty": {Name: "ghostty", Repository: RepoTypePPA, RepoURL: ppaDeps},
"danksearch": {Name: "danksearch", Repository: RepoTypePPA, RepoURL: ppaDeps},
"dankcalendar": variantMapping("dankcalendar", variants["dankcalendar"], RepoTypePPA, ppaDeps),
"danksearch": {Name: "dux-search", Repository: RepoTypePPA, RepoURL: ppaDeps},
"dankcalendar": variantMapping("dux-calendar", variants["dankcalendar"], RepoTypePPA, ppaDeps),
}
switch wm {
+14 -5
View File
@@ -20,6 +20,7 @@ type VariantSwap struct {
type VariantSwapper interface {
InstalledVariant(stable, git PackageMapping) (deps.PackageVariant, bool)
SwapVariants(ctx context.Context, swaps []VariantSwap, sudoPassword string, progressChan chan<- InstallProgressMsg) error
packageInstalled(pkg string) bool
}
type SwapStatus int
@@ -53,18 +54,26 @@ func PlanVariantSwap(d Distribution, wm deps.WindowManager, dep string, target d
case current == target:
return VariantSwap{}, SwapAlreadyOnTarget
case target == deps.VariantGit:
return VariantSwap{Dep: dep, From: stable, To: git}, SwapNeeded
return VariantSwap{Dep: dep, From: installedAs(swapper, stable), To: git}, SwapNeeded
default:
return VariantSwap{Dep: dep, From: git, To: stable}, SwapNeeded
return VariantSwap{Dep: dep, From: installedAs(swapper, git), To: stable}, SwapNeeded
}
}
// installedAs names the package the remove step must target, which is the old name on hosts not yet upgraded past a rename.
func installedAs(swapper VariantSwapper, m PackageMapping) PackageMapping {
if name, ok := installedName(swapper.packageInstalled, m.Name); ok {
m.Name = name
}
return m
}
// installedVariantByName works when the two variants ship under different package names.
func installedVariantByName(installed func(string) bool, stable, git PackageMapping) (deps.PackageVariant, bool) {
switch {
case installed(packageBaseName(git.Name)):
if _, ok := installedName(installed, packageBaseName(git.Name)); ok {
return deps.VariantGit, true
case installed(packageBaseName(stable.Name)):
}
if _, ok := installedName(installed, packageBaseName(stable.Name)); ok {
return deps.VariantStable, true
}
return deps.VariantStable, false
+13 -8
View File
@@ -15,13 +15,15 @@ type swapFake struct {
func (f *swapFake) GetPackageMappingWithVariants(_ deps.WindowManager, variants map[string]deps.PackageVariant) map[string]PackageMapping {
return map[string]PackageMapping{
"dms-greeter": variantMapping("dms-greeter", variants["dms-greeter"], RepoTypeCOPR, "duxlabs/dux-repo"),
"dms-greeter": variantMapping("dux-greeter", variants["dms-greeter"], RepoTypeCOPR, "duxlabs/dux-repo"),
"matugen": {Name: "matugen", Repository: RepoTypeSystem},
}
}
func (f *swapFake) packageInstalled(pkg string) bool { return f.installed[pkg] }
func (f *swapFake) InstalledVariant(stable, git PackageMapping) (deps.PackageVariant, bool) {
return installedVariantByName(func(p string) bool { return f.installed[p] }, stable, git)
return installedVariantByName(f.packageInstalled, stable, git)
}
func (f *swapFake) SwapVariants(_ context.Context, swaps []VariantSwap, _ string, _ chan<- InstallProgressMsg) error {
@@ -38,9 +40,12 @@ func TestPlanVariantSwap(t *testing.T) {
want SwapStatus
from, to string
}{
{"stable to git", "dms-greeter", "dms-greeter", deps.VariantGit, SwapNeeded, "dms-greeter", "dms-greeter-git"},
{"git to stable", "dms-greeter", "dms-greeter-git", deps.VariantStable, SwapNeeded, "dms-greeter-git", "dms-greeter"},
{"already on target", "dms-greeter", "dms-greeter-git", deps.VariantGit, SwapAlreadyOnTarget, "", ""},
{"stable to git", "dms-greeter", "dux-greeter", deps.VariantGit, SwapNeeded, "dux-greeter", "dux-greeter-git"},
{"git to stable", "dms-greeter", "dux-greeter-git", deps.VariantStable, SwapNeeded, "dux-greeter-git", "dux-greeter"},
{"stable to git from the pre-rename package", "dms-greeter", "dms-greeter", deps.VariantGit, SwapNeeded, "dms-greeter", "dux-greeter-git"},
{"git to stable from the pre-rename package", "dms-greeter", "dms-greeter-git", deps.VariantStable, SwapNeeded, "dms-greeter-git", "dux-greeter"},
{"already on target", "dms-greeter", "dux-greeter-git", deps.VariantGit, SwapAlreadyOnTarget, "", ""},
{"already on target under the pre-rename name", "dms-greeter", "dms-greeter-git", deps.VariantGit, SwapAlreadyOnTarget, "", ""},
{"not installed", "dms-greeter", "", deps.VariantGit, SwapNotInstalled, "", ""},
{"same mapping both ways", "matugen", "matugen", deps.VariantGit, SwapNoVariant, "", ""},
}
@@ -56,7 +61,7 @@ func TestPlanVariantSwap(t *testing.T) {
}
func TestSwapReinstalledVariantsSkipsSwappedDeps(t *testing.T) {
d := &swapFake{installed: map[string]bool{"dms-greeter": true}}
d := &swapFake{installed: map[string]bool{"dux-greeter": true}}
dependencies := []deps.Dependency{
{Name: "dms-greeter", Status: deps.StatusInstalled, Variant: deps.VariantGit},
{Name: "matugen", Status: deps.StatusInstalled},
@@ -68,8 +73,8 @@ func TestSwapReinstalledVariantsSkipsSwappedDeps(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if len(d.swapped) != 1 || d.swapped[0].To.Name != "dms-greeter-git" {
t.Fatalf("swapped = %+v, want only dms-greeter → dms-greeter-git", d.swapped)
if len(d.swapped) != 1 || d.swapped[0].To.Name != "dux-greeter-git" {
t.Fatalf("swapped = %+v, want only dux-greeter → dux-greeter-git", d.swapped)
}
if !skip["dms-greeter"] || skip["matugen"] {
t.Fatalf("skip = %v, want the swapped greeter skipped and matugen reinstalled", skip)
+4 -10
View File
@@ -69,7 +69,7 @@ func (v *VoidDistribution) DetectDependenciesWithTerminal(ctx context.Context, w
dependencies = append(dependencies, v.detectGit())
dependencies = append(dependencies, v.detectWindowManager(wm))
dependencies = append(dependencies, v.detectQuickshell())
dependencies = append(dependencies, v.detectDMSGreeter())
dependencies = append(dependencies, v.detectGreeterPackage(v.packageInstalled))
dependencies = append(dependencies, v.detectXDGPortal())
dependencies = append(dependencies, v.detectAccountsService())
dependencies = append(dependencies, v.detectDBus())
@@ -129,12 +129,6 @@ func (v *VoidDistribution) detectXDGPortal() deps.Dependency {
return v.detectPackage("xdg-desktop-portal-gtk", "Desktop integration portal for GTK", v.packageInstalled("xdg-desktop-portal-gtk"))
}
func (v *VoidDistribution) detectDMSGreeter() deps.Dependency {
gitInstalled := v.packageInstalled("dms-greeter-git")
dep := v.detectOptionalPackage("dms-greeter", "Dux Shell greetd greeter", gitInstalled || v.packageInstalled("dms-greeter"))
return withGitVariant(dep, gitInstalled)
}
func (v *VoidDistribution) detectAccountsService() deps.Dependency {
return v.detectPackage("accountsservice", "D-Bus interface for user account query and manipulation", v.packageInstalled("accountsservice"))
}
@@ -318,9 +312,9 @@ func (v *VoidDistribution) GetPackageMappingWithVariants(wm deps.WindowManager,
"quickshell": {Name: "quickshell", Repository: RepoTypeSystem},
"matugen": {Name: "matugen", Repository: RepoTypeSystem},
"dms (Dux Shell)": v.getDmsMapping(variants["dms (Dux Shell)"]),
"dms-greeter": variantMapping("dms-greeter", variants["dms-greeter"], RepoTypeXBPS, VoidDepsRepo),
"danksearch": {Name: "danksearch", Repository: RepoTypeXBPS, RepoURL: VoidDepsRepo},
"dankcalendar": {Name: "dankcalendar", Repository: RepoTypeXBPS, RepoURL: VoidDepsRepo},
"dms-greeter": variantMapping("dux-greeter", variants["dms-greeter"], RepoTypeXBPS, VoidDepsRepo),
"danksearch": {Name: "dux-search", Repository: RepoTypeXBPS, RepoURL: VoidDepsRepo},
"dankcalendar": {Name: "dux-calendar", Repository: RepoTypeXBPS, RepoURL: VoidDepsRepo},
}
switch wm {
@@ -43,12 +43,12 @@ bash.x86_64 5.2.40-1.fc41 updates`,
},
{
name: "one package offered by two repos is reported once",
input: `dms-greeter.x86_64 1.5.1-1.fc44 copr:copr.fedorainfracloud.org:avengemedia:danklinux
dms-greeter.x86_64 1.5.1-1.fc44 coprdep:copr.fedorainfracloud.org:avengemedia:danklinux`,
input: `dux-greeter.x86_64 1.5.1-1.fc44 copr:copr.fedorainfracloud.org:avengemedia:danklinux
dux-greeter.x86_64 1.5.1-1.fc44 coprdep:copr.fedorainfracloud.org:avengemedia:danklinux`,
backendID: "dnf5",
installed: map[string]string{"dms-greeter": "1.5.0-1.fc44"},
installed: map[string]string{"dux-greeter": "1.5.0-1.fc44"},
want: []Package{
{Name: "dms-greeter.x86_64", Repo: RepoSystem, Backend: "dnf5", FromVersion: "1.5.0-1.fc44", ToVersion: "1.5.1-1.fc44"},
{Name: "dux-greeter.x86_64", Repo: RepoSystem, Backend: "dnf5", FromVersion: "1.5.0-1.fc44", ToVersion: "1.5.1-1.fc44"},
},
},
{
+5 -5
View File
@@ -245,10 +245,10 @@ dms-git)
dms)
GIT_REPO="duxlabs-dev/dux-shell"
;;
danksearch)
dux-search)
GIT_REPO="duxlabs-dev/dux-search"
;;
dgop)
dux-gop)
GIT_REPO="duxlabs-dev/dux-gop"
;;
esac
@@ -540,8 +540,8 @@ fi
# Handle packages that need pre-built binaries downloaded
cd "$WORK_PACKAGE_DIR"
case "$PACKAGE_NAME" in
danksearch)
info "Downloading pre-built binaries for danksearch..."
dux-search)
info "Downloading pre-built binaries for dux-search..."
VERSION=$(dpkg-parsechangelog -S Version | sed 's/-[^-]*$//' | sed 's/ppa[0-9]*$//')
if [ ! -f "dsearch-amd64" ]; then
@@ -568,7 +568,7 @@ danksearch)
fi
fi
;;
dgop)
dux-gop)
if [ ! -f "dgop" ]; then
warn "dgop binary not found - should be committed to repo"
fi
+1 -1
View File
@@ -452,7 +452,7 @@ if [ "$KEEP_BUILDS" = "false" ]; then
done
case "$PACKAGE_NAME" in
danksearch)
dux-search)
if [ -f "$PACKAGE_DIR/dsearch-amd64" ]; then
rm -f "$PACKAGE_DIR/dsearch-amd64"
REMOVED=$((REMOVED + 1))
+9 -9
View File
@@ -5,8 +5,8 @@ XBPS templates for Dux Shell on [Void Linux](https://voidlinux.org).
| Package | Source repo | Template |
| --- | --- | --- |
| `dms` | Dux Shell | [`srcpkgs/dms/template`](srcpkgs/dms/template) |
| `dgop` | duxlabs-dev/dux-gop | maintained in the **dux-repo** repo (`distro/void/srcpkgs/dgop`) |
| `danksearch` | duxlabs-dev/dux-search | maintained in the **dux-repo** repo (`distro/void/srcpkgs/danksearch`) |
| `dux-gop` | duxlabs-dev/dux-gop | maintained in the **dux-repo** repo (`distro/void/srcpkgs/dux-gop`) |
| `dux-search` | duxlabs-dev/dux-search | maintained in the **dux-repo** repo (`distro/void/srcpkgs/dux-search`) |
All build from source.
@@ -18,7 +18,7 @@ This is a DMS maintained repo for VoidLinux until these packages are officially
We serve both stable release and development packages from Cloudflare R2 at
`void.duxlabs.dev`: `dms` and `dms-git` from `dms/current`, their dependencies
and `dms-greeter` from `dux-repo/current`.
and `dux-greeter` from `dux-repo/current`.
> **Repository migration:** the former GitHub Pages repositories will be
> frozen for 14 days at cutover. Their retirement date will be announced when
@@ -59,14 +59,14 @@ checkout at `srcpkgs/<pkg>/template` to build or submit it.
## Dependencies
Installing `dms` automatically pulls in `quickshell`, `accountsservice`, `dgop`,
Installing `dms` automatically pulls in `quickshell`, `accountsservice`, `dux-gop`,
`matugen` (which drives the Material You theming), `dbus`, `elogind`, and
`mesa-dri` (GL drivers, required for compositors to render).
The rest are optional, install whichever features you want:
| Package | Enables |
| --- | --- |
| `danksearch` | launcher / filesystem search |
| `dux-search` | launcher / filesystem search |
| `cava` | audio visualiser widget |
| `qt6-multimedia` | system sound feedback |
| `qt6ct` | Qt app theming |
@@ -81,16 +81,16 @@ The rest are optional, install whichever features you want:
Inside a `void-packages` checkout (symlink or copy these `srcpkgs/<pkg>` dirs in):
```sh
# build the dependency packages first (dms requires dgop)
./xbps-src pkg dgop
./xbps-src pkg danksearch
# build the dependency packages first (dms requires dux-gop)
./xbps-src pkg dux-gop
./xbps-src pkg dux-search
./xbps-src pkg dms
# lint (xlint ships in the xtools package)
xlint srcpkgs/dms/template
# install the built packages
sudo xbps-install --repository=hostdir/binpkgs dms dgop
sudo xbps-install --repository=hostdir/binpkgs dms dux-gop
```
## Running the shell
+1 -1
View File
@@ -223,7 +223,7 @@ Item {
root.greeterStatusText = root.greeterStatusText + "\n\nstderr:\n" + err;
return;
}
var failure = I18n.tr("Failed to run '%1'. Ensure the %2 package is installed.", "greeter status error, %1 is a command, %2 a package name").arg("dms-greeter status").arg("dms-greeter") + " " + I18n.tr("(exit %1)", "process exit code").arg(exitCode);
var failure = I18n.tr("Failed to run '%1'. Ensure the %2 package is installed.", "greeter status error, %1 is a command, %2 a package name").arg("dms-greeter status").arg("dux-greeter") + " " + I18n.tr("(exit %1)", "process exit code").arg(exitCode);
if (out !== "")
failure = failure + "\n\n" + out;
if (err !== "")