diff --git a/flake.lock b/flake.lock
index bd5ce21..79c6345 100644
--- a/flake.lock
+++ b/flake.lock
@@ -3,19 +3,19 @@
"DankMaterialShell": {
"inputs": {
"dgop": "dgop",
- "dms-cli": [
- "dms-cli"
- ],
"nixpkgs": [
"nixpkgs"
+ ],
+ "quickshell": [
+ "quickshell"
]
},
"locked": {
- "lastModified": 1762812757,
- "narHash": "sha256-VPmzq5tYJIwIV9LQyn+wCiNRHiVHO8wrqoM7pz6LVPs=",
+ "lastModified": 1765916864,
+ "narHash": "sha256-mXKYRVK5YndrvgbIKCyz4BRuLkyEqgceF/djXmA6cD8=",
"owner": "AvengeMedia",
"repo": "DankMaterialShell",
- "rev": "37a10bd453da057fb4e69cf600c413eb4467bd72",
+ "rev": "672754b0b5efd9e61ea8080c40614ad3b4fd5dbf",
"type": "github"
},
"original": {
@@ -45,28 +45,28 @@
"base16-fish": {
"flake": false,
"locked": {
- "lastModified": 1754405784,
- "narHash": "sha256-l9xHIy+85FN+bEo6yquq2IjD1rSg9fjfjpyGP1W8YXo=",
+ "lastModified": 1765809053,
+ "narHash": "sha256-XCUQLoLfBJ8saWms2HCIj4NEN+xNsWBlU1NrEPcQG4s=",
"owner": "tomyun",
"repo": "base16-fish",
- "rev": "23ae20a0093dca0d7b39d76ba2401af0ccf9c561",
+ "rev": "86cbea4dca62e08fb7fd83a70e96472f92574782",
"type": "github"
},
"original": {
"owner": "tomyun",
"repo": "base16-fish",
- "rev": "23ae20a0093dca0d7b39d76ba2401af0ccf9c561",
+ "rev": "86cbea4dca62e08fb7fd83a70e96472f92574782",
"type": "github"
}
},
"base16-helix": {
"flake": false,
"locked": {
- "lastModified": 1752979451,
- "narHash": "sha256-0CQM+FkYy0fOO/sMGhOoNL80ftsAzYCg9VhIrodqusM=",
+ "lastModified": 1760703920,
+ "narHash": "sha256-m82fGUYns4uHd+ZTdoLX2vlHikzwzdu2s2rYM2bNwzw=",
"owner": "tinted-theming",
"repo": "base16-helix",
- "rev": "27cf1e66e50abc622fb76a3019012dc07c678fac",
+ "rev": "d646af9b7d14bff08824538164af99d0c521b185",
"type": "github"
},
"original": {
@@ -104,11 +104,11 @@
]
},
"locked": {
- "lastModified": 1761645416,
- "narHash": "sha256-wTQzbbQ6XHtvNJVuhJj+ytZDRyNtwUKbrIfIvMvKNfQ=",
+ "lastModified": 1763308703,
+ "narHash": "sha256-O9Y+Wer8wOh+N+4kcCK5p/VLrXyX+ktk0/s3HdZvJzk=",
"owner": "numtide",
"repo": "blueprint",
- "rev": "633af1961cae8e02bc6195e6e599a6b09bf75217",
+ "rev": "5a9bba070f801d63e2af3c9ef00b86b212429f4f",
"type": "github"
},
"original": {
@@ -125,11 +125,11 @@
]
},
"locked": {
- "lastModified": 1762435535,
- "narHash": "sha256-QhzRn7pYN35IFpKjjxJAj3GPJECuC+VLhoGem3ezycc=",
+ "lastModified": 1762835999,
+ "narHash": "sha256-UykYGrGFOFTmDpKTLNxj1wvd1gbDG4TkqLNSbV0TYwk=",
"owner": "AvengeMedia",
"repo": "dgop",
- "rev": "6cf638dde818f9f8a2e26d0243179c43cb3458d7",
+ "rev": "799301991cd5dcea9b64245f9d500dcc76615653",
"type": "github"
},
"original": {
@@ -159,31 +159,14 @@
"type": "github"
}
},
- "dms-cli": {
- "inputs": {
- "nixpkgs": [
- "nixpkgs"
- ]
- },
- "locked": {
- "lastModified": 1,
- "narHash": "sha256-P6oitdXzD2nZKaF7USVDZr7+5sRa6ja8m6TGB50w4GI=",
- "path": "./nix/inputs/dms-cli",
- "type": "path"
- },
- "original": {
- "path": "./nix/inputs/dms-cli",
- "type": "path"
- }
- },
"firefox-gnome-theme": {
"flake": false,
"locked": {
- "lastModified": 1758112371,
- "narHash": "sha256-lizRM2pj6PHrR25yimjyFn04OS4wcdbc38DCdBVa2rk=",
+ "lastModified": 1764724327,
+ "narHash": "sha256-OkFLrD3pFR952TrjQi1+Vdj604KLcMnkpa7lkW7XskI=",
"owner": "rafaelmardojai",
"repo": "firefox-gnome-theme",
- "rev": "0909cfe4a2af8d358ad13b20246a350e14c2473d",
+ "rev": "66b7c635763d8e6eb86bd766de5a1e1fbfcc1047",
"type": "github"
},
"original": {
@@ -197,11 +180,11 @@
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
- "lastModified": 1762440070,
- "narHash": "sha256-xxdepIcb39UJ94+YydGP221rjnpkDZUlykKuF54PsqI=",
+ "lastModified": 1765835352,
+ "narHash": "sha256-XswHlK/Qtjasvhd1nOa1e8MgZ8GS//jBoTqWtrS1Giw=",
"owner": "hercules-ci",
"repo": "flake-parts",
- "rev": "26d05891e14c88eb4a5d5bee659c0db5afb609d8",
+ "rev": "a34fae9c08a15ad73f295041fec82323541400a9",
"type": "github"
},
"original": {
@@ -250,18 +233,20 @@
"gnome-shell": {
"flake": false,
"locked": {
- "lastModified": 1748186689,
- "narHash": "sha256-UaD7Y9f8iuLBMGHXeJlRu6U1Ggw5B9JnkFs3enZlap0=",
+ "host": "gitlab.gnome.org",
+ "lastModified": 1764524476,
+ "narHash": "sha256-bTmNn3Q4tMQ0J/P0O5BfTQwqEnCiQIzOGef9/aqAZvk=",
"owner": "GNOME",
"repo": "gnome-shell",
- "rev": "8c88f917db0f1f0d80fa55206c863d3746fa18d0",
- "type": "github"
+ "rev": "c0e1ad9f0f703fd0519033b8f46c3267aab51a22",
+ "type": "gitlab"
},
"original": {
+ "host": "gitlab.gnome.org",
"owner": "GNOME",
- "ref": "48.2",
+ "ref": "gnome-49",
"repo": "gnome-shell",
- "type": "github"
+ "type": "gitlab"
}
},
"home-manager": {
@@ -271,11 +256,11 @@
]
},
"locked": {
- "lastModified": 1762787259,
- "narHash": "sha256-t2U/GLLXHa2+kJkwnFNRVc2fEJ/lUfyZXBE5iKzJdcs=",
+ "lastModified": 1765860045,
+ "narHash": "sha256-7Lxp/PfOy4h3QIDtmWG/EgycaswqRSkDX4DGtet14NE=",
"owner": "nix-community",
"repo": "home-manager",
- "rev": "37a3d97f2873e0f68711117c34d04b7c7ead8f4e",
+ "rev": "09de9577d47d8bffb11c449b6a3d24e32ac16c99",
"type": "github"
},
"original": {
@@ -326,11 +311,11 @@
"treefmt-nix": "treefmt-nix"
},
"locked": {
- "lastModified": 1762744937,
- "narHash": "sha256-37twpZntKS1NOPDSULAyaUPMCyrvw2vhcyYd1bMT40E=",
+ "lastModified": 1765855572,
+ "narHash": "sha256-FJLnGdUnJWp7H3cJN9Kycv1XIUQKj+LgHFCv2EKQdN8=",
"owner": "nix-community",
"repo": "nixos-facter",
- "rev": "bfc460a1df6056f97152252bc45c3668b584e068",
+ "rev": "56e45023f7daae906362496a99ad2e62e0fd127a",
"type": "github"
},
"original": {
@@ -341,11 +326,11 @@
},
"nixos-facter-modules": {
"locked": {
- "lastModified": 1762264948,
- "narHash": "sha256-iaRf6n0KPl9hndnIft3blm1YTAyxSREV1oX0MFZ6Tk4=",
+ "lastModified": 1765442039,
+ "narHash": "sha256-k3lYQ+A1F7aTz8HnlU++bd9t/x/NP2A4v9+x6opcVg0=",
"owner": "nix-community",
"repo": "nixos-facter-modules",
- "rev": "fa695bff9ec37fd5bbd7ee3181dbeb5f97f53c96",
+ "rev": "9dd775ee92de63f14edd021d59416e18ac2c00f1",
"type": "github"
},
"original": {
@@ -356,11 +341,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1762596750,
- "narHash": "sha256-rXXuz51Bq7DHBlfIjN7jO8Bu3du5TV+3DSADBX7/9YQ=",
+ "lastModified": 1765779637,
+ "narHash": "sha256-KJ2wa/BLSrTqDjbfyNx70ov/HdgNBCBBSQP3BIzKnv4=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "b6a8526db03f735b89dd5ff348f53f752e7ddc8e",
+ "rev": "1306659b587dc277866c7b69eb97e5f07864d8c4",
"type": "github"
},
"original": {
@@ -372,11 +357,11 @@
},
"nixpkgs-lib": {
"locked": {
- "lastModified": 1761765539,
- "narHash": "sha256-b0yj6kfvO8ApcSE+QmA6mUfu8IYG6/uU28OFn4PaC8M=",
+ "lastModified": 1765674936,
+ "narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
- "rev": "719359f4562934ae99f5443f20aa06c2ffff91fc",
+ "rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85",
"type": "github"
},
"original": {
@@ -397,11 +382,11 @@
]
},
"locked": {
- "lastModified": 1758998580,
- "narHash": "sha256-VLx0z396gDCGSiowLMFz5XRO/XuNV+4EnDYjdJhHvUk=",
+ "lastModified": 1764773531,
+ "narHash": "sha256-mCBl7MD1WZ7yCG6bR9MmpPO2VydpNkWFgnslJRIT1YU=",
"owner": "nix-community",
"repo": "NUR",
- "rev": "ba8d9c98f5f4630bcb0e815ab456afd90c930728",
+ "rev": "1d9616689e98beded059ad0384b9951e967a17fa",
"type": "github"
},
"original": {
@@ -417,11 +402,11 @@
]
},
"locked": {
- "lastModified": 1761897390,
- "narHash": "sha256-er4gYrIoThYLjlsOMTysoRfn67d1Gci+ZpqDrtQxrA0=",
+ "lastModified": 1764663772,
+ "narHash": "sha256-sHqLmm0wAt3PC4vczJeBozI1/f4rv9yp3IjkClHDXDs=",
"owner": "quickshell-mirror",
"repo": "quickshell",
- "rev": "fc704e6b5d445899a1565955268c91942a4f263f",
+ "rev": "26531fc46ef17e9365b03770edd3fb9206fcb460",
"type": "github"
},
"original": {
@@ -433,7 +418,6 @@
"root": {
"inputs": {
"DankMaterialShell": "DankMaterialShell",
- "dms-cli": "dms-cli",
"flake-parts": "flake-parts",
"home-manager": "home-manager",
"nixos-facter": "nixos-facter",
@@ -466,11 +450,11 @@
"tinted-zed": "tinted-zed"
},
"locked": {
- "lastModified": 1762264356,
- "narHash": "sha256-QVfC53Ri+8n3e7Ujx9kq6all3+TLBRRPRnc6No5qY5w=",
+ "lastModified": 1765897595,
+ "narHash": "sha256-NgTRxiEC5y96zrhdBygnY+mSzk5FWMML39PcRGVJmxg=",
"owner": "nix-community",
"repo": "stylix",
- "rev": "647bb8dd96a206a1b79c4fd714affc88b409e10b",
+ "rev": "e6829552d4bb659ebab00f08c61d8c62754763f3",
"type": "github"
},
"original": {
@@ -545,11 +529,11 @@
"tinted-schemes": {
"flake": false,
"locked": {
- "lastModified": 1757716333,
- "narHash": "sha256-d4km8W7w2zCUEmPAPUoLk1NlYrGODuVa3P7St+UrqkM=",
+ "lastModified": 1763914658,
+ "narHash": "sha256-Hju0WtMf3iForxtOwXqGp3Ynipo0EYx1AqMKLPp9BJw=",
"owner": "tinted-theming",
"repo": "schemes",
- "rev": "317a5e10c35825a6c905d912e480dfe8e71c7559",
+ "rev": "0f6be815d258e435c9b137befe5ef4ff24bea32c",
"type": "github"
},
"original": {
@@ -561,11 +545,11 @@
"tinted-tmux": {
"flake": false,
"locked": {
- "lastModified": 1757811970,
- "narHash": "sha256-n5ZJgmzGZXOD9pZdAl1OnBu3PIqD+X3vEBUGbTi4JiI=",
+ "lastModified": 1764465359,
+ "narHash": "sha256-lbSVPqLEk2SqMrnpvWuKYGCaAlfWFMA6MVmcOFJjdjE=",
"owner": "tinted-theming",
"repo": "tinted-tmux",
- "rev": "d217ba31c846006e9e0ae70775b0ee0f00aa6b1e",
+ "rev": "edf89a780e239263cc691a987721f786ddc4f6aa",
"type": "github"
},
"original": {
@@ -577,11 +561,11 @@
"tinted-zed": {
"flake": false,
"locked": {
- "lastModified": 1757811247,
- "narHash": "sha256-4EFOUyLj85NRL3OacHoLGEo0wjiRJzfsXtR4CZWAn6w=",
+ "lastModified": 1764464512,
+ "narHash": "sha256-rCD/pAhkMdCx6blsFwxIyvBJbPZZ1oL2sVFrH07lmqg=",
"owner": "tinted-theming",
"repo": "base16-zed",
- "rev": "824fe0aacf82b3c26690d14e8d2cedd56e18404e",
+ "rev": "907dbba5fb8cf69ebfd90b00813418a412d0a29a",
"type": "github"
},
"original": {
@@ -598,11 +582,11 @@
]
},
"locked": {
- "lastModified": 1762410071,
- "narHash": "sha256-aF5fvoZeoXNPxT0bejFUBXeUjXfHLSL7g+mjR/p5TEg=",
+ "lastModified": 1762938485,
+ "narHash": "sha256-AlEObg0syDl+Spi4LsZIBrjw+snSVU4T8MOeuZJUJjM=",
"owner": "numtide",
"repo": "treefmt-nix",
- "rev": "97a30861b13c3731a84e09405414398fbf3e109f",
+ "rev": "5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index c74d462..3d12c8c 100644
--- a/flake.nix
+++ b/flake.nix
@@ -6,16 +6,8 @@
DankMaterialShell = {
url = "github:AvengeMedia/DankMaterialShell";
- inputs = {
- nixpkgs.follows = "nixpkgs";
- dms-cli.follows = "dms-cli";
- };
- };
-
- dms-cli = {
- url = "path:./nix/inputs/dms-cli";
-
inputs.nixpkgs.follows = "nixpkgs";
+ inputs.quickshell.follows = "quickshell";
};
home-manager = {
diff --git a/hosts/laptop/configuration.nix b/hosts/laptop/configuration.nix
index 9d28af3..3d9b151 100644
--- a/hosts/laptop/configuration.nix
+++ b/hosts/laptop/configuration.nix
@@ -14,6 +14,8 @@
# Use the latest xanmod kernel, mainly for the Clear Linux patches
boot.kernelPackages = pkgs.linuxPackages_xanmod_latest;
+ hardware.openrazer.enable = true;
+
services = {
# NTP daemon that's more suitable for laptops
chrony.enable = true;
diff --git a/modules/home-manager/my/programs/dms/config.nix b/modules/home-manager/my/programs/dms/config.nix
index efd9b8a..e382ef9 100644
--- a/modules/home-manager/my/programs/dms/config.nix
+++ b/modules/home-manager/my/programs/dms/config.nix
@@ -14,8 +14,7 @@ let
system = pkgs.stdenv.hostPlatform.system;
dgop = inputDms.inputs.dgop.packages.${system}.default;
- dms = inputDms.packages.${system}.default;
- dms-cli = inputDms.inputs.dms-cli.packages.${system}.default;
+ dms-shell = inputDms.packages.${system}.dms-shell;
quickshell = inputQs.packages.${system}.default;
# DankMaterialShell's `wallpaperFillMode` option requires sentence casing
@@ -32,7 +31,7 @@ in {
config = lib.mkIf cfg.enable {
home.packages = [
dgop
- dms-cli
+ dms-shell
] ++ (with pkgs; [
# Needed for brightness functionality
brightnessctl
@@ -78,7 +77,7 @@ in {
package = quickshell;
configs = {
- dms = "${dms}/etc/xdg/quickshell/dms";
+ dms = "${dms-shell}/share/quickshell/dms";
};
};
@@ -105,7 +104,7 @@ in {
"--dereference --no-preserve=all " +
"${config.xdg.configHome}/DankMaterialShell/default-settings.json " +
"${config.xdg.configHome}/DankMaterialShell/settings.json";
- ExecStart = "${lib.getExe dms-cli} run";
+ ExecStart = "${lib.getExe dms-shell} run --session";
Restart = "on-failure";
};
diff --git a/modules/shared/hardware/openrazer/config/home-manager.nix b/modules/shared/hardware/openrazer/config/home-manager.nix
new file mode 100644
index 0000000..398e6d6
--- /dev/null
+++ b/modules/shared/hardware/openrazer/config/home-manager.nix
@@ -0,0 +1,38 @@
+{
+ nixosConfig,
+ lib,
+ pkgs,
+ ...
+}:
+let
+ cfg = nixosConfig.hardware.openrazer;
+in {
+ config = lib.mkIf cfg.enable {
+ home.packages = with pkgs; [
+ polychromatic
+ ];
+
+ # NOTE: I am not saving `~/.local/share/openrazer` because this only
+ # contains logs. Logs are not necessary to see unless there's a problem,
+ # and I can look at them during the problematic run.
+ my.persist.directories = [
+ {
+ # Stores the downloaded images of Razer devices for the UI.
+ path = "~/.cache/polychromatic";
+ unique = false;
+ }
+ {
+ # DPI and polling rate are saved here, in `persistence.conf`.
+ path = "~/.config/openrazer";
+ unique = true;
+ }
+ {
+ # Various UI settings, and the DPI stages (I think?).
+ #
+ # TODO: is this necessary to store?
+ path = "~/.config/polychromatic";
+ unique = true;
+ }
+ ];
+ };
+}
\ No newline at end of file
diff --git a/modules/shared/nix/config/nixos/default.nix b/modules/shared/nix/config/nixos/default.nix
index e4a2c3b..38d0679 100644
--- a/modules/shared/nix/config/nixos/default.nix
+++ b/modules/shared/nix/config/nixos/default.nix
@@ -166,7 +166,7 @@ in {
# Some interesting features.
# "fetch-closures"
- "no-url-literals"
+ #"no-url-literals" # gone from Lix 2.94
"pipe-operator"
];
}
diff --git a/nix/inputs/dms-cli/.github/workflows/pr.yml b/nix/inputs/dms-cli/.github/workflows/pr.yml
deleted file mode 100644
index 9d1c1cc..0000000
--- a/nix/inputs/dms-cli/.github/workflows/pr.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-name: Pull Request
-
-on:
- pull_request:
- branches: [ master ]
-
-jobs:
- test:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
-
- - name: Set up Go
- uses: actions/setup-go@v5
- with:
- go-version: '1.23'
-
- - name: Format check
- run: |
- if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then
- echo "The following files are not formatted:"
- gofmt -s -l .
- exit 1
- fi
-
- - name: Test
- run: go test -v ./...
-
- - name: Build
- run: go build -v ./...
diff --git a/nix/inputs/dms-cli/.github/workflows/release.yml b/nix/inputs/dms-cli/.github/workflows/release.yml
deleted file mode 100644
index 8770936..0000000
--- a/nix/inputs/dms-cli/.github/workflows/release.yml
+++ /dev/null
@@ -1,169 +0,0 @@
-name: Release
-
-on:
- push:
- tags:
- - 'v*'
-
-permissions:
- contents: write
-
-concurrency:
- group: release-${{ github.ref_name }}
- cancel-in-progress: true
-
-jobs:
- build:
- runs-on: ubuntu-latest
- strategy:
- matrix:
- arch: [amd64, arm64]
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Set up Go
- uses: actions/setup-go@v5
- with:
- go-version-file: ./go.mod
-
- - name: Run tests
- run: go test -v ./...
-
- - name: Build dankinstall (${{ matrix.arch }})
- env:
- GOOS: linux
- CGO_ENABLED: 0
- GOARCH: ${{ matrix.arch }}
- run: |
- set -eux
- cd cmd/dankinstall
- go build -trimpath -ldflags "-s -w -X main.Version=${GITHUB_REF#refs/tags/}" \
- -o ../../dankinstall-${{ matrix.arch }}
- cd ../..
- gzip -9 -k dankinstall-${{ matrix.arch }}
- sha256sum dankinstall-${{ matrix.arch }}.gz > dankinstall-${{ matrix.arch }}.gz.sha256
-
- - name: Build dms (${{ matrix.arch }})
- env:
- GOOS: linux
- CGO_ENABLED: 0
- GOARCH: ${{ matrix.arch }}
- run: |
- set -eux
- cd cmd/dms
- go build -trimpath -ldflags "-s -w -X main.Version=${GITHUB_REF#refs/tags/}" \
- -o ../../dms-${{ matrix.arch }}
- cd ../..
- gzip -9 -k dms-${{ matrix.arch }}
- sha256sum dms-${{ matrix.arch }}.gz > dms-${{ matrix.arch }}.gz.sha256
-
- - name: Build dms-distropkg (${{ matrix.arch }})
- env:
- GOOS: linux
- CGO_ENABLED: 0
- GOARCH: ${{ matrix.arch }}
- run: |
- set -eux
- cd cmd/dms
- go build -trimpath -tags distro_binary -ldflags "-s -w -X main.Version=${GITHUB_REF#refs/tags/}" \
- -o ../../dms-distropkg-${{ matrix.arch }}
- cd ../..
- gzip -9 -k dms-distropkg-${{ matrix.arch }}
- sha256sum dms-distropkg-${{ matrix.arch }}.gz > dms-distropkg-${{ matrix.arch }}.gz.sha256
-
- - name: Upload artifacts (${{ matrix.arch }})
- uses: actions/upload-artifact@v4
- with:
- name: release-assets-${{ matrix.arch }}
- path: |
- dankinstall-${{ matrix.arch }}.gz
- dankinstall-${{ matrix.arch }}.gz.sha256
- dms-${{ matrix.arch }}.gz
- dms-${{ matrix.arch }}.gz.sha256
- dms-distropkg-${{ matrix.arch }}.gz
- dms-distropkg-${{ matrix.arch }}.gz.sha256
- if-no-files-found: error
-
- update-flake-version:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
- fetch-depth: 0
-
- - name: Update flake.nix version
- run: |
- set -euo pipefail
-
- version="${GITHUB_REF#refs/tags/}"
- version="${version#v}"
- echo "Updating flake.nix to version: $version"
-
- # Update version in flake.nix
- sed -i "s/version = \"[^\"]*\"/version = \"$version\"/" flake.nix
-
- git config user.name "github-actions[bot]"
- git config user.email "github-actions[bot]@users.noreply.github.com"
-
- if ! git diff --quiet flake.nix; then
- git add flake.nix
- git commit -m "flake: bump version to $version"
-
- # Push to master (or main, depending on your default branch)
- git push origin HEAD:master || git push origin HEAD:main
- echo "Pushed flake.nix version update to master"
- else
- echo "No version changes needed"
- fi
-
- release:
- runs-on: ubuntu-latest
- needs: build
- steps:
- - name: Download all artifacts
- uses: actions/download-artifact@v4
- with:
- pattern: release-assets-*
- merge-multiple: true
- path: ./_dist
-
- - name: Create/Update GitHub Release (single run)
- uses: softprops/action-gh-release@v2
- with:
- tag_name: ${{ github.ref_name }}
- name: Release ${{ github.ref_name }}
- body: |
- ## Danklinux Release
-
- This release includes binaries for:
- - Linux AMD64
- - Linux ARM64
-
- ### Installation
-
- ```bash
- curl -fsSL https://raw.githubusercontent.com/AvengeMedia/danklinux/master/install.sh | sh
- ```
- files: _dist/**
- draft: false
- prerelease: ${{ contains(github.ref_name, '-') }}
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Notify DankMaterialShell to create release and mirror assets (single run)
- uses: peter-evans/repository-dispatch@v3
- with:
- token: ${{ secrets.SHELL_REPO_PAT }}
- repository: AvengeMedia/DankMaterialShell
- event-type: dms_release
- client-payload: >-
- {
- "tag": "${{ github.ref_name }}",
- "dms_repo": "${{ github.repository }}"
- }
diff --git a/nix/inputs/dms-cli/.github/workflows/update-vendor-hash.yml b/nix/inputs/dms-cli/.github/workflows/update-vendor-hash.yml
deleted file mode 100644
index e5c6b4f..0000000
--- a/nix/inputs/dms-cli/.github/workflows/update-vendor-hash.yml
+++ /dev/null
@@ -1,89 +0,0 @@
-name: Update Vendor Hash
-
-on:
- push:
- paths:
- - "go.mod"
- - "go.sum"
- branches:
- - master
-
-jobs:
- update-vendor-hash:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Install Nix
- uses: cachix/install-nix-action@v31
-
- - name: Update vendorHash in flake.nix
- run: |
- set -euo pipefail
-
- # Try to build and capture the expected hash from error message
- echo "Attempting nix build to get new vendorHash..."
- if output=$(nix build .#dms-cli 2>&1); then
- echo "Build succeeded, no hash update needed"
- exit 0
- fi
-
- # Extract the expected hash from the error message
- new_hash=$(echo "$output" | grep -oP "got:\s+\K\S+" | head -n1)
-
- if [ -z "$new_hash" ]; then
- echo "Could not extract new vendorHash from build output"
- echo "Build output:"
- echo "$output"
- exit 1
- fi
-
- echo "New vendorHash: $new_hash"
-
- # Get current hash from flake.nix
- current_hash=$(grep -oP 'vendorHash = "\K[^"]+' flake.nix)
- echo "Current vendorHash: $current_hash"
-
- if [ "$current_hash" = "$new_hash" ]; then
- echo "vendorHash is already up to date"
- exit 0
- fi
-
- # Update the hash in flake.nix
- sed -i "s|vendorHash = \"$current_hash\"|vendorHash = \"$new_hash\"|" flake.nix
-
- # Verify the build works with the new hash
- echo "Verifying build with new vendorHash..."
- nix build .#dms-cli
-
- echo "vendorHash updated successfully!"
-
- - name: Commit and push vendorHash update
- run: |
- set -euo pipefail
-
- if ! git diff --quiet flake.nix; then
- git config user.name "github-actions[bot]"
- git config user.email "github-actions[bot]@users.noreply.github.com"
-
- git add flake.nix
- git commit -m "flake: update vendorHash for go.mod changes"
-
- for attempt in 1 2 3; do
- if git push; then
- echo "Successfully pushed vendorHash update"
- exit 0
- fi
- echo "Push attempt $attempt failed, pulling and retrying..."
- git pull --rebase
- sleep $((attempt*2))
- done
-
- echo "Failed to push after retries" >&2
- exit 1
- else
- echo "No changes to flake.nix"
- fi
diff --git a/nix/inputs/dms-cli/.gitignore b/nix/inputs/dms-cli/.gitignore
deleted file mode 100644
index 8edad49..0000000
--- a/nix/inputs/dms-cli/.gitignore
+++ /dev/null
@@ -1,36 +0,0 @@
-# If you prefer the allow list template instead of the deny list, see community template:
-# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
-#
-# Binaries for programs and plugins
-*.exe
-*.exe~
-*.dll
-*.so
-*.dylib
-
-# Test binary, built with `go test -c`
-*.test
-
-# Code coverage profiles and other test artifacts
-*.out
-coverage.*
-*.coverprofile
-profile.cov
-
-# Dependency directories (remove the comment below to include it)
-# vendor/
-
-# Go workspace file
-go.work
-go.work.sum
-
-# env file
-.env
-
-# Editor/IDE
-# .idea/
-# .vscode/
-
-bin/
-dankinstall
-/dms
diff --git a/nix/inputs/dms-cli/.mockery.yml b/nix/inputs/dms-cli/.mockery.yml
deleted file mode 100644
index a526387..0000000
--- a/nix/inputs/dms-cli/.mockery.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-with-expecter: true
-dir: "internal/mocks/{{.InterfaceDirRelative}}"
-mockname: "Mock{{.InterfaceName}}"
-outpkg: "{{.PackageName}}"
-packages:
- github.com/Wifx/gonetworkmanager/v2:
- interfaces:
- NetworkManager:
- Device:
- DeviceWireless:
- AccessPoint:
- Connection:
- Settings:
- ActiveConnection:
- IP4Config:
- net:
- interfaces:
- Conn:
- github.com/AvengeMedia/danklinux/internal/plugins:
- interfaces:
- GitClient:
- github.com/godbus/dbus/v5:
- interfaces:
- BusObject:
- github.com/AvengeMedia/danklinux/internal/server/brightness:
- config:
- dir: "internal/mocks/brightness"
- outpkg: mocks_brightness
- interfaces:
- DBusConn:
- github.com/AvengeMedia/danklinux/internal/server/network:
- config:
- dir: "internal/mocks/network"
- outpkg: mocks_network
- interfaces:
- Backend:
- github.com/AvengeMedia/danklinux/internal/server/cups:
- config:
- dir: "internal/mocks/cups"
- outpkg: mocks_cups
- interfaces:
- CUPSClientInterface:
diff --git a/nix/inputs/dms-cli/CONTRIBUTING_DISTRO.md b/nix/inputs/dms-cli/CONTRIBUTING_DISTRO.md
deleted file mode 100644
index e70713b..0000000
--- a/nix/inputs/dms-cli/CONTRIBUTING_DISTRO.md
+++ /dev/null
@@ -1,211 +0,0 @@
-# Adding New Linux Distributions
-
-This guide explains how to add support for new Linux distributions to the dankdots installer using the new consolidated architecture.
-
-## Architecture Overview
-
-The codebase uses a simple, consolidated approach where each distribution is completely self-contained:
-
-- **All-in-One** (`internal/distros/{distro}.go`) - Complete distribution implementation
-- **Auto-Registration** - Distributions register themselves via `init()` functions
-- **Shared Base** - Common functionality inherited from `BaseDistribution`
-
-## Adding Support
-
-### Method 1: Use Existing Implementation (Derivatives)
-
-For distros that are derivatives (like CachyOS being Arch-based), you can register them to use an existing implementation.
-
-**Example: Adding CachyOS (Arch-based)**
-
-```go
-// internal/distros/arch.go - add to the init function
-func init() {
- Register("arch", "#1793D1", func(config DistroConfig, logChan chan<- string) Distribution {
- return NewArchDistribution(config, logChan)
- })
- Register("cachyos", "#318CE7", func(config DistroConfig, logChan chan<- string) Distribution {
- return NewArchDistribution(config, logChan) // CachyOS uses Arch implementation but different color
- })
-}
-```
-
-That's it! CachyOS now uses Arch's detection and installation logic.
-
-**Example: Adding Ubuntu derivatives**
-
-```go
-// internal/distros/ubuntu.go (after you create it)
-func init() {
- Register("ubuntu", "#E95420", func(config DistroConfig, logChan chan<- string) Distribution {
- return NewUbuntuDistribution(config, logChan)
- })
- Register("kubuntu", "#0079C1", func(config DistroConfig, logChan chan<- string) Distribution {
- return NewUbuntuDistribution(config, logChan) // Kubuntu uses Ubuntu implementation but different color
- })
- Register("xubuntu", "#2F5BEA", func(config DistroConfig, logChan chan<- string) Distribution {
- return NewUbuntuDistribution(config, logChan) // Xubuntu uses Ubuntu implementation but different color
- })
- Register("pop", "#48B9C7", func(config DistroConfig, logChan chan<- string) Distribution {
- return NewUbuntuDistribution(config, logChan) // Pop!_OS uses Ubuntu implementation but different color
- })
-}
-```
-
-### Method 2: Create New Implementation
-
-For entirely new distribution families, create a complete implementation:
-
-**Example: Adding openSUSE**
-
-Create `internal/distros/opensuse.go`:
-
-```go
-package distros
-
-import (
- "context"
- "os/exec"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
- "github.com/AvengeMedia/danklinux/internal/installer"
-)
-
-func init() {
- Register("opensuse-leap", "#73BA25", func(config DistroConfig, logChan chan<- string) Distribution {
- return NewOpenSUSEDistribution(config, logChan)
- })
- Register("opensuse-tumbleweed", "#73BA25", func(config DistroConfig, logChan chan<- string) Distribution {
- return NewOpenSUSEDistribution(config, logChan)
- })
-}
-
-type OpenSUSEDistribution struct {
- *BaseDistribution
- *ManualPackageInstaller
- config DistroConfig
-}
-
-func NewOpenSUSEDistribution(config DistroConfig, logChan chan<- string) *OpenSUSEDistribution {
- base := NewBaseDistribution(logChan)
- return &OpenSUSEDistribution{
- BaseDistribution: base,
- ManualPackageInstaller: &ManualPackageInstaller{BaseDistribution: base},
- config: config,
- }
-}
-
-func (o *OpenSUSEDistribution) GetID() string {
- return o.config.ID
-}
-
-func (o *OpenSUSEDistribution) GetColorHex() string {
- return o.config.ColorHex
-}
-
-func (o *OpenSUSEDistribution) GetPackageManager() PackageManagerType {
- return PackageManagerZypper
-}
-
-func (o *OpenSUSEDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping {
- return map[string]PackageMapping{
- "git": {Name: "git", Repository: RepoTypeSystem},
- "ghostty": {Name: "ghostty", Repository: RepoTypeManual}, // Build from source
- "kitty": {Name: "kitty", Repository: RepoTypeSystem},
- // ... map all required packages to openSUSE equivalents
- }
-}
-
-func (o *OpenSUSEDistribution) DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error) {
- return o.DetectDependenciesWithTerminal(ctx, wm, deps.TerminalGhostty)
-}
-
-func (o *OpenSUSEDistribution) DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error) {
- var dependencies []deps.Dependency
-
- // Use base methods for common functionality
- dependencies = append(dependencies, o.detectDMS())
- dependencies = append(dependencies, o.detectSpecificTerminal(terminal))
- dependencies = append(dependencies, o.detectGit())
- // ... add openSUSE-specific detection
-
- return dependencies, nil
-}
-
-func (o *OpenSUSEDistribution) InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, progressChan chan<- installer.InstallProgressMsg) error {
- // Implement installation logic using zypper
- // Use o.InstallManualPackages() for source builds
- return nil
-}
-
-func (o *OpenSUSEDistribution) InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- installer.InstallProgressMsg) error {
- // Install build tools, enable repositories, etc.
- return nil
-}
-
-func (o *OpenSUSEDistribution) packageInstalled(pkg string) bool {
- cmd := exec.Command("rpm", "-q", pkg)
- err := cmd.Run()
- return err == nil
-}
-```
-
-## Repository Types
-
-The system supports these repository types:
-
-- `RepoTypeSystem` - Main system repository (zypper, apt, dnf, pacman)
-- `RepoTypeAUR` - Arch User Repository
-- `RepoTypeCOPR` - Fedora COPR
-- `RepoTypePPA` - Ubuntu PPA
-- `RepoTypeManual` - Build from source
-
-## Package Manager Support
-
-To add a new package manager, add it to `internal/distros/interface.go`:
-
-```go
-const (
- PackageManagerPacman PackageManagerType = "pacman"
- PackageManagerDNF PackageManagerType = "dnf"
- PackageManagerAPT PackageManagerType = "apt"
- PackageManagerZypper PackageManagerType = "zypper"
- PackageManagerPortage PackageManagerType = "portage" // Add new ones here
-)
-```
-
-## Testing Your Implementation
-
-1. Build: `go build -o dankdots ./cmd/main.go`
-2. Test on target distribution
-3. Verify all packages detect and install correctly
-4. Test both window managers (Hyprland, Niri)
-5. Test both terminals (Ghostty, Kitty)
-
-## Detection Process
-
-The system automatically detects supported distributions by:
-
-1. Reading `/etc/os-release` for the `ID` field
-2. Looking up the ID in the distribution registry
-3. Creating an instance using the registered constructor function
-
-No hardcoded lists to maintain - everything is driven by the registry!
-
-## Benefits of New Architecture
-
-- ✅ **Single file per distro** - All logic in one place
-- ✅ **Auto-registration** - No factory methods to update
-- ✅ **Shared functionality** - Inherit common features
-- ✅ **No duplication** - Manual builds and fonts are shared
-- ✅ **Easy derivatives** - One line to support a new derivative
-
-## Contributing
-
-1. Fork the repository
-2. Create your distribution file in `internal/distros/`
-3. Test thoroughly on your target distribution
-4. Submit a pull request with example output
-
-The maintainers will review and provide feedback. Thank you for expanding dankdots support!
\ No newline at end of file
diff --git a/nix/inputs/dms-cli/LICENSE b/nix/inputs/dms-cli/LICENSE
deleted file mode 100644
index d8152be..0000000
--- a/nix/inputs/dms-cli/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2025 Avenge Media LLC
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/nix/inputs/dms-cli/Makefile b/nix/inputs/dms-cli/Makefile
deleted file mode 100644
index 119fd79..0000000
--- a/nix/inputs/dms-cli/Makefile
+++ /dev/null
@@ -1,157 +0,0 @@
-BINARY_NAME=dms
-BINARY_NAME_INSTALL=dankinstall
-SOURCE_DIR=cmd/dms
-SOURCE_DIR_INSTALL=cmd/dankinstall
-BUILD_DIR=bin
-PREFIX ?= /usr/local
-INSTALL_DIR=$(PREFIX)/bin
-
-GO=go
-GOFLAGS=-ldflags="-s -w"
-
-# Version and build info
-VERSION=$(shell git describe --tags --always 2>/dev/null || echo "dev")
-BUILD_TIME=$(shell date -u '+%Y-%m-%d_%H:%M:%S')
-COMMIT=$(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
-
-BUILD_LDFLAGS=-ldflags='-s -w -X main.Version=$(VERSION) -X main.buildTime=$(BUILD_TIME) -X main.commit=$(COMMIT)'
-
-# Architecture to build for dist target (amd64, arm64, or all)
-ARCH ?= all
-
-.PHONY: all build dankinstall dist clean install install-all install-dankinstall uninstall uninstall-all uninstall-dankinstall install-config uninstall-config test fmt vet deps help
-
-# Default target
-all: build
-
-# Build the main binary (dms)
-build:
- @echo "Building $(BINARY_NAME)..."
- @mkdir -p $(BUILD_DIR)
- CGO_ENABLED=0 $(GO) build $(BUILD_LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME) ./$(SOURCE_DIR)
- @echo "Build complete: $(BUILD_DIR)/$(BINARY_NAME)"
-
-dankinstall:
- @echo "Building $(BINARY_NAME_INSTALL)..."
- @mkdir -p $(BUILD_DIR)
- CGO_ENABLED=0 $(GO) build $(BUILD_LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME_INSTALL) ./$(SOURCE_DIR_INSTALL)
- @echo "Build complete: $(BUILD_DIR)/$(BINARY_NAME_INSTALL)"
-
-# Build distro binaries for amd64 and arm64 (Linux only, no update/greeter support)
-dist:
-ifeq ($(ARCH),all)
- @echo "Building $(BINARY_NAME) for distribution (amd64 and arm64)..."
- @mkdir -p $(BUILD_DIR)
- @echo "Building for linux/amd64..."
- CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GO) build -tags distro_binary $(BUILD_LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-amd64 ./$(SOURCE_DIR)
- @echo "Building for linux/arm64..."
- CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $(GO) build -tags distro_binary $(BUILD_LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 ./$(SOURCE_DIR)
- @echo "Distribution builds complete:"
- @echo " $(BUILD_DIR)/$(BINARY_NAME)-linux-amd64"
- @echo " $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64"
-else
- @echo "Building $(BINARY_NAME) for distribution ($(ARCH))..."
- @mkdir -p $(BUILD_DIR)
- @echo "Building for linux/$(ARCH)..."
- CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) $(GO) build -tags distro_binary $(BUILD_LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME)-linux-$(ARCH) ./$(SOURCE_DIR)
- @echo "Distribution build complete:"
- @echo " $(BUILD_DIR)/$(BINARY_NAME)-linux-$(ARCH)"
-endif
-
-build-all: build dankinstall
-
-install: build
- @echo "Installing $(BINARY_NAME) to $(INSTALL_DIR)..."
- @install -D -m 755 $(BUILD_DIR)/$(BINARY_NAME) $(INSTALL_DIR)/$(BINARY_NAME)
- @echo "Installation complete"
-
-install-all: build-all
- @echo "Installing $(BINARY_NAME) to $(INSTALL_DIR)..."
- @install -D -m 755 $(BUILD_DIR)/$(BINARY_NAME) $(INSTALL_DIR)/$(BINARY_NAME)
- @echo "Installing $(BINARY_NAME_INSTALL) to $(INSTALL_DIR)..."
- @install -D -m 755 $(BUILD_DIR)/$(BINARY_NAME_INSTALL) $(INSTALL_DIR)/$(BINARY_NAME_INSTALL)
- @echo "Installation complete"
-
-install-dankinstall: dankinstall
- @echo "Installing $(BINARY_NAME_INSTALL) to $(INSTALL_DIR)..."
- @install -D -m 755 $(BUILD_DIR)/$(BINARY_NAME_INSTALL) $(INSTALL_DIR)/$(BINARY_NAME_INSTALL)
- @echo "Installation complete"
-
-uninstall:
- @echo "Uninstalling $(BINARY_NAME) from $(INSTALL_DIR)..."
- @rm -f $(INSTALL_DIR)/$(BINARY_NAME)
- @echo "Uninstall complete"
-
-uninstall-all:
- @echo "Uninstalling $(BINARY_NAME) from $(INSTALL_DIR)..."
- @rm -f $(INSTALL_DIR)/$(BINARY_NAME)
- @echo "Uninstalling $(BINARY_NAME_INSTALL) from $(INSTALL_DIR)..."
- @rm -f $(INSTALL_DIR)/$(BINARY_NAME_INSTALL)
- @echo "Uninstall complete"
-
-uninstall-dankinstall:
- @echo "Uninstalling $(BINARY_NAME_INSTALL) from $(INSTALL_DIR)..."
- @rm -f $(INSTALL_DIR)/$(BINARY_NAME_INSTALL)
- @echo "Uninstall complete"
-
-clean:
- @echo "Cleaning build artifacts..."
- @rm -rf $(BUILD_DIR)
- @echo "Clean complete"
-
-test:
- @echo "Running tests..."
- $(GO) test -v ./...
-
-fmt:
- @echo "Formatting Go code..."
- $(GO) fmt ./...
-
-vet:
- @echo "Running go vet..."
- $(GO) vet ./...
-
-deps:
- @echo "Updating dependencies..."
- $(GO) mod tidy
- $(GO) mod download
-
-dev:
- @echo "Building $(BINARY_NAME) for development..."
- @mkdir -p $(BUILD_DIR)
- $(GO) build -o $(BUILD_DIR)/$(BINARY_NAME) ./$(SOURCE_DIR)
- @echo "Development build complete: $(BUILD_DIR)/$(BINARY_NAME)"
-
-check-go:
- @echo "Checking Go version..."
- @go version | grep -E "go1\.(2[2-9]|[3-9][0-9])" > /dev/null || (echo "ERROR: Go 1.22 or higher required" && exit 1)
- @echo "Go version OK"
-
-version: check-go
- @echo "Version: $(VERSION)"
- @echo "Build Time: $(BUILD_TIME)"
- @echo "Commit: $(COMMIT)"
-
-help:
- @echo "Available targets:"
- @echo " all - Build the main binary (dms) (default)"
- @echo " build - Build the main binary (dms)"
- @echo " dankinstall - Build dankinstall binary"
- @echo " dist - Build dms for linux amd64/arm64 (no update/greeter)"
- @echo " Use ARCH=amd64 or ARCH=arm64 to build only one"
- @echo " build-all - Build both binaries"
- @echo " install - Install dms to $(INSTALL_DIR)"
- @echo " install-all - Install both dms and dankinstall to $(INSTALL_DIR)"
- @echo " install-dankinstall - Install only dankinstall to $(INSTALL_DIR)"
- @echo " uninstall - Remove dms from $(INSTALL_DIR)"
- @echo " uninstall-all - Remove both binaries from $(INSTALL_DIR)"
- @echo " uninstall-dankinstall - Remove only dankinstall from $(INSTALL_DIR)"
- @echo " clean - Clean build artifacts"
- @echo " test - Run tests"
- @echo " fmt - Format Go code"
- @echo " vet - Run go vet"
- @echo " deps - Update dependencies"
- @echo " dev - Build with debug info"
- @echo " check-go - Check Go version compatibility"
- @echo " version - Show version information"
- @echo " help - Show this help message"
diff --git a/nix/inputs/dms-cli/README.md b/nix/inputs/dms-cli/README.md
deleted file mode 100644
index ee74a5c..0000000
--- a/nix/inputs/dms-cli/README.md
+++ /dev/null
@@ -1,274 +0,0 @@
-
-
-
-
-
- ### dms CLI & Backend + dankinstall
-
-[](https://danklinux.com/docs)
-[](https://github.com/AvengeMedia/danklinux/releases)
-[](https://github.com/AvengeMedia/danklinux/blob/master/LICENSE)
-
-
-
----
-
-A monorepo for dankinstall and dms (cli+go backend), a modern desktop suite for Wayland compositors.
-
-**[Full documentation →](https://danklinux.com/docs)**
-
-- **dms** DankMaterialShell (cli + go backend)
- - The backend side of dms, provides APIs for the desktop and a management CLI.
- - Shared dbus connection for networking (NetworkManager, iwd), loginctl, accountsservice, cups, and other interfaces.
- - Implements wayland protocols
- - wlr-gamma-control-unstable-v1 (for night mode/gamma control)
- - dwl-ipc-unstable-v2 (for dwl/MangoWC integration)
- - Exposes a json API over unix socket for interaction with these interfaces
- - Provides plugin management APIs for the shell
- - CUPS integration for printer management
- - Optionally provides `update` interface - depending on build inputs.
- - This is intended to be disabled when packaged as part of distribution packages.
-- **dankinstall** Installs the Dank Linux suite for [niri](https://github.com/YaLTeR/niri) and/or [Hyprland](https://hypr.land)
- - Features the [DankMaterialShell](https://github.com/AvengeMedia/DankMaterialShell)
- - Which features a complete desktop experience with wallpapers, auto theming, notifications, lock screen, etc.
- - Offers up solid out of the box configurations as usable, featured starting points.
- - Can be installed if you already have niri/Hyprland configured
- - Will allow you to keep your existing config, or replace with Dank ones (existing configs always backed up though)
-
-# dms cli & backend
-
-A part of the DankMaterialShell, that is provided by this repository. It is written in GO, and exposes a suite of APIs over unix socket that interface with dbus via [godbus](https://github.com/godbus/dbus) and also the plugin system.
-
-**Backend** (all exposed over a unix socket json API):
-
-- **dbus**
- - networking - full integration with pluggable backends - NetworkManager, iwd
- - bluez - integration with a pairing agent
- - loginctl - creates sleep inhibitor, integrates lock before suspend, signals for lock/unlock
- - accountsservice - suite of user profile APIs - name, email, profile picture, etc.
- - cups - printer management and configuration
-- **dms plugins**
- - APIs to browse, install, update, and search available plugins
-- **wayland**
- - Implements [wlr-gamma-control-unstable-v1](https://wayland.app/protocols/wlr-gamma-control-unstable-v1)
- - Essentially, provides auto or manual gamma control similar to a tool like [gammastep](https://gitlab.com/chinstrap/gammastep) or [wlsunset](https://github.com/kennylevinsen/wlsunset)
- - Implements dwl-ipc-unstable-v2
- - For dwl (tested with MangoWC) integration
-
-*run `dms debug-srv` to run the socket service in standalone mode, and see a list of available APIs*
-
-**cli**
-
-- manage process: run, restart, kill
-- IPC with dms: toggle launcher, notification popup, etc.
-- plugins: install/browse/search (use plugin IDs like `dms plugins install myPlugin`)
-- update (some builds): Update DMS and dependencies, (disabled for Arch AUR and Fedora copr installs, as it is handled by pacman/dnf)
-- greeter (some builds): Install the dms greetd greeter (on arch/fedora it is disabled in favor of OS packages)
-
-## Build & Install
-
-To build the dms CLI (Requires Go 1.24+):
-
-### For distribution package maintainers
-
-This produces a build without the `update` or `greeter` functionality, which are intended for manual installation.
-
-```bash
-make dist
-```
-
-Produces `bin/dms-linux-amd64` and `bin/dms-linux-arm64`
-
-### Manual Install
-
-```bash
-# Installs to /usr/local/bin/dms
-make && sudo make install
-```
-
-### Wayland Protocol Bindings
-
-The gamma control functionality uses Wayland protocol bindings generated from the protocol XML definition. To regenerate the Go bindings from `internal/proto/xml/wlr-gamma-control-unstable-v1.xml`:
-
-```bash
-go install github.com/rajveermalviya/go-wayland/cmd/go-wayland-scanner@latest
-go-wayland-scanner -i internal/proto/xml/wlr-gamma-control-unstable-v1.xml \
- -pkg wlr_gamma_control -o internal/proto/wlr_gamma_control/gamma_control.go
-```
-
-This is only needed if modifying the protocol or updating to a newer version.
-
-# Dank Linux/dankinstall
-
-Installs compositor, dms, terminal, and some optional dependencies - along with a default compositor & terminal configuration.
-
-## Quickstart
-
-```bash
-curl -fsSL https://install.danklinux.com | sh
-```
-
-*Alternatively, download the latest [release](https://github.com/AvengeMedia/danklinux/releases)*
-
-## Supported Distributions
-
-**Note on Greeter**: dankinstall does not install a greeter automatically.
-- To install the dms greeter, run `dms greeter install` after installation.
-- Then you can disable any existing greeter, if present, and run `sudo systemctl enable --now greetd`
-
-### Arch Linux & Derivatives
-
-**Supported:** Arch, ArchARM, Archcraft, CachyOS, EndeavourOS, Manjaro
-
-**Special Notes:**
-- Uses native `pacman` for system packages
-- AUR packages are built manually using `makepkg` (no AUR helper dependency)
-- **Recommendations**
- - Use NetworkManager to manage networking
- - If using archinstall, you can choose `minimal` for profile, and `NetworkManager` under networking.
-
-**Package Sources:**
-| Package | Source | Notes |
-|---------|---------|-------|
-| System packages (git, jq, etc.) | Official repos | Via `pacman` |
-| quickshell | AUR | Built from source |
-| matugen | AUR (`matugen-bin`) | Pre-compiled binary |
-| dgop | AUR | Built from source |
-| niri | Official repos (`niri`) | Latest niri |
-| hyprland | Official repos | Available in Extra repository |
-| DankMaterialShell | Manual | Git clone to `~/.config/quickshell/dms` |
-
-### Fedora & Derivatives
-
-**Supported:** Fedora, Nobara, Fedora Asahi Remix
-
-**Special Notes:**
-- Requires `dnf-plugins-core` for COPR repository support
-- Automatically enables required COPR repositories
-- All COPR repos are enabled with automatic acceptance
-- **Editions** dankinstall is tested on "Workstation Edition", but probably works fine on any fedora flavor. Report issues if anything doesn't work.
-- [Fedora Asahi Remix](https://asahilinux.org/fedora/) hasn't been tested, but presumably it should work fine as all of the dependencies should provide arm64 variants.
-
-**Package Sources:**
-| Package | Source | Notes |
-|---------|---------|-------|
-| System packages | Official repos | Via `dnf` |
-| quickshell | COPR | `avengemedia/danklinux` |
-| matugen | COPR | `avengemedia/danklinux` |
-| dgop | Manual | Built from source with Go |
-| cliphist | COPR | `avengemedia/danklinux` |
-| ghostty | COPR | `avengemedia/danklinux` |
-| hyprland | COPR | `solopasha/hyprland` |
-| niri | COPR | `yalter/niri` |
-| DankMaterialShell | COPR | `avengemedia/dms` |
-
-### Ubuntu
-
-**Supported:** Ubuntu 25.04+
-
-**Special Notes:**
-- Requires PPA support via `software-properties-common`
-- Go installed from PPA for building manual packages
-- Most packages require manual building due to limited repository availability
- - This means the install can be quite slow, as many need to be compiled from source.
- - niri is packages as a `.deb` so it can be managed via `apt`
-- Automatic PPA repository addition and package list updates
-
-**Package Sources:**
-| Package | Source | Notes |
-|---------|---------|-------|
-| System packages | Official repos | Via `apt` |
-| quickshell | Manual | Built from source with cmake |
-| matugen | Manual | Built from source with Go |
-| dgop | Manual | Built from source with Go |
-| hyprland | PPA | `ppa:cppiber/hyprland` |
-| hyprpicker | PPA | `ppa:cppiber/hyprland` |
-| niri | Manual | Built from source with Rust |
-| Go compiler | PPA | `ppa:longsleep/golang-backports` |
-| DankMaterialShell | Manual | Git clone to `~/.config/quickshell/dms` |
-
-### Debian
-
-**Supported:** Debian 13+ (Trixie)
-
-**Special Notes:**
-- **niri only** - Debian does not support Hyprland currently, only niri.
-- Most packages require manual building due to limited repository availability
- - This means the install can be quite slow, as many need to be compiled from source.
- - niri is packages as a `.deb` so it can be managed via `apt`
-
-**Package Sources:**
-| Package | Source | Notes |
-|---------|---------|-------|
-| System packages | Official repos | Via `apt` |
-| quickshell | Manual | Built from source with cmake |
-| matugen | Manual | Built from source with Go |
-| dgop | Manual | Built from source with Go |
-| niri | Manual | Built from source with Rust |
-| DankMaterialShell | Manual | Git clone to `~/.config/quickshell/dms` |
-
-### openSUSE Tumbleweed
-
-**Special Notes:**
-- Most packages available in standard repos, minimal manual building required
-- quickshell and matugen require building from source
-
-**Package Sources:**
-| Package | Source | Notes |
-|---------|---------|-------|
-| System packages (git, jq, etc.) | Official repos | Via `zypper` |
-| hyprland | Official repos | Available in standard repos |
-| niri | Official repos | Available in standard repos |
-| xwayland-satellite | Official repos | For niri X11 app support |
-| ghostty | Official repos | Latest terminal emulator |
-| kitty, alacritty | Official repos | Alternative terminals |
-| grim, slurp, hyprpicker | Official repos | Wayland screenshot utilities |
-| wl-clipboard | Official repos | Via `wl-clipboard` package |
-| cliphist | Official repos | Clipboard manager |
-| quickshell | Manual | Built from source with cmake + openSUSE flags |
-| matugen | Manual | Built from source with Rust |
-| dgop | Manual | Built from source with Go |
-| DankMaterialShell | Manual | Git clone to `~/.config/quickshell/dms` |
-
-### NixOS (Not supported by Dank Linux, but with Flake)
-
-NixOS users should use the [dms flake](https://github.com/AvengeMedia/DankMaterialShell/tree/master?tab=readme-ov-file#nixos---via-home-manager)
-
-## Manual Package Building
-
-The installer handles manual package building for packages not available in repositories:
-
-### quickshell (Ubuntu, Debian, openSUSE)
-- Built from source using cmake
-- Requires Qt6 development libraries
-- Automatically handles build dependencies
-- **openSUSE:** Uses special CFLAGS with rpm optflags and wayland include path
-
-### matugen (Ubuntu, Debian, Fedora, openSUSE)
-- Built from Rust source
-- Requires cargo and rust toolchain
-- Installed to `/usr/local/bin`
-
-### dgop (All distros)
-- Built from Go source
-- Simple dependency-free build
-- Installed to `/usr/local/bin`
-
-### niri (Ubuntu, Debian)
-- Built from Rust source
-- Requires cargo and rust toolchain
-- Complex build with multiple dependencies
-
-## Commands
-
-### dankinstall
-Main installer with interactive TUI for initial setup
-
-### dms
-Management interface for DankMaterialShell:
-- `dms` - Interactive management TUI
-- `dms run` - Start interactive shell
-- `dms run -d` - Start shell as daemon
-- `dms restart` - Restart running DMS shell
-- `dms kill` - Kill running DMS shell processes
-- `dms ipc ` - Send IPC commands to running shell
\ No newline at end of file
diff --git a/nix/inputs/dms-cli/assets/dank.svg b/nix/inputs/dms-cli/assets/dank.svg
deleted file mode 100644
index 3ce27f7..0000000
--- a/nix/inputs/dms-cli/assets/dank.svg
+++ /dev/null
@@ -1,46 +0,0 @@
-
\ No newline at end of file
diff --git a/nix/inputs/dms-cli/assets/danklogo.svg b/nix/inputs/dms-cli/assets/danklogo.svg
deleted file mode 100644
index 1ee6d51..0000000
--- a/nix/inputs/dms-cli/assets/danklogo.svg
+++ /dev/null
@@ -1,113 +0,0 @@
-
-
-
-
diff --git a/nix/inputs/dms-cli/cmd/dms/commands_brightness.go b/nix/inputs/dms-cli/cmd/dms/commands_brightness.go
deleted file mode 100644
index f2535cc..0000000
--- a/nix/inputs/dms-cli/cmd/dms/commands_brightness.go
+++ /dev/null
@@ -1,303 +0,0 @@
-package main
-
-import (
- "fmt"
- "strings"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/AvengeMedia/danklinux/internal/server/brightness"
- "github.com/spf13/cobra"
-)
-
-var brightnessCmd = &cobra.Command{
- Use: "brightness",
- Short: "Control device brightness",
- Long: "Control brightness for backlight and LED devices (use --ddc to include DDC/I2C monitors)",
-}
-
-var brightnessListCmd = &cobra.Command{
- Use: "list",
- Short: "List all brightness devices",
- Long: "List all available brightness devices with their current values",
- Run: runBrightnessList,
-}
-
-var brightnessSetCmd = &cobra.Command{
- Use: "set ",
- Short: "Set brightness for a device",
- Long: "Set brightness percentage (0-100) for a specific device",
- Args: cobra.ExactArgs(2),
- Run: runBrightnessSet,
-}
-
-var brightnessGetCmd = &cobra.Command{
- Use: "get ",
- Short: "Get brightness for a device",
- Long: "Get current brightness percentage for a specific device",
- Args: cobra.ExactArgs(1),
- Run: runBrightnessGet,
-}
-
-func init() {
- brightnessListCmd.Flags().Bool("ddc", false, "Include DDC/I2C monitors (slower)")
- brightnessSetCmd.Flags().Bool("ddc", false, "Include DDC/I2C monitors (slower)")
- brightnessSetCmd.Flags().Bool("exponential", false, "Use exponential brightness scaling")
- brightnessSetCmd.Flags().Float64("exponent", 1.2, "Exponent for exponential scaling (default 1.2)")
- brightnessGetCmd.Flags().Bool("ddc", false, "Include DDC/I2C monitors (slower)")
-
- brightnessCmd.SetHelpTemplate(`{{.Long}}
-
-Usage:
- {{.UseLine}}{{if .HasAvailableSubCommands}}
-
-Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
- {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
-
-Flags:
-{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
-
-Global Flags:
-{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}
-
-Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
- {{rpad .Name .NamePadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
-
-Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
-`)
-
- brightnessListCmd.SetHelpTemplate(`{{.Long}}
-
-Usage:
- {{.UseLine}}{{if .HasAvailableLocalFlags}}
-
-Flags:
-{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
-
-Global Flags:
-{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}
-`)
-
- brightnessSetCmd.SetHelpTemplate(`{{.Long}}
-
-Usage:
- {{.UseLine}}{{if .HasAvailableLocalFlags}}
-
-Flags:
-{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
-
-Global Flags:
-{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}
-`)
-
- brightnessGetCmd.SetHelpTemplate(`{{.Long}}
-
-Usage:
- {{.UseLine}}{{if .HasAvailableLocalFlags}}
-
-Flags:
-{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
-
-Global Flags:
-{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}
-`)
-
- brightnessCmd.AddCommand(brightnessListCmd, brightnessSetCmd, brightnessGetCmd)
-}
-
-func runBrightnessList(cmd *cobra.Command, args []string) {
- includeDDC, _ := cmd.Flags().GetBool("ddc")
-
- allDevices := []brightness.Device{}
-
- sysfs, err := brightness.NewSysfsBackend()
- if err != nil {
- log.Debugf("Failed to initialize sysfs backend: %v", err)
- } else {
- devices, err := sysfs.GetDevices()
- if err != nil {
- log.Debugf("Failed to get sysfs devices: %v", err)
- } else {
- allDevices = append(allDevices, devices...)
- }
- }
-
- if includeDDC {
- ddc, err := brightness.NewDDCBackend()
- if err != nil {
- fmt.Printf("Warning: Failed to initialize DDC backend: %v\n", err)
- } else {
- time.Sleep(100 * time.Millisecond)
- devices, err := ddc.GetDevices()
- if err != nil {
- fmt.Printf("Warning: Failed to get DDC devices: %v\n", err)
- } else {
- allDevices = append(allDevices, devices...)
- }
- ddc.Close()
- }
- }
-
- if len(allDevices) == 0 {
- fmt.Println("No brightness devices found")
- return
- }
-
- maxIDLen := len("Device")
- maxNameLen := len("Name")
- for _, dev := range allDevices {
- if len(dev.ID) > maxIDLen {
- maxIDLen = len(dev.ID)
- }
- if len(dev.Name) > maxNameLen {
- maxNameLen = len(dev.Name)
- }
- }
-
- idPad := maxIDLen + 2
- namePad := maxNameLen + 2
-
- fmt.Printf("%-*s %-12s %-*s %s\n", idPad, "Device", "Class", namePad, "Name", "Brightness")
-
- sepLen := idPad + 2 + 12 + 2 + namePad + 2 + 15
- for i := 0; i < sepLen; i++ {
- fmt.Print("─")
- }
- fmt.Println()
-
- for _, device := range allDevices {
- fmt.Printf("%-*s %-12s %-*s %3d%%\n",
- idPad,
- device.ID,
- device.Class,
- namePad,
- device.Name,
- device.CurrentPercent,
- )
- }
-}
-
-func runBrightnessSet(cmd *cobra.Command, args []string) {
- deviceID := args[0]
- var percent int
- if _, err := fmt.Sscanf(args[1], "%d", &percent); err != nil {
- log.Fatalf("Invalid percent value: %s", args[1])
- }
-
- if percent < 0 || percent > 100 {
- log.Fatalf("Percent must be between 0 and 100")
- }
-
- includeDDC, _ := cmd.Flags().GetBool("ddc")
- exponential, _ := cmd.Flags().GetBool("exponential")
- exponent, _ := cmd.Flags().GetFloat64("exponent")
-
- // For backlight/leds devices, try logind backend first (requires D-Bus connection)
- parts := strings.SplitN(deviceID, ":", 2)
- if len(parts) == 2 && (parts[0] == "backlight" || parts[0] == "leds") {
- subsystem := parts[0]
- name := parts[1]
-
- // Initialize backends needed for logind approach
- sysfs, err := brightness.NewSysfsBackend()
- if err != nil {
- log.Debugf("NewSysfsBackend failed: %v", err)
- } else {
- logind, err := brightness.NewLogindBackend()
- if err != nil {
- log.Debugf("NewLogindBackend failed: %v", err)
- } else {
- defer logind.Close()
-
- // Get device info to convert percent to value
- dev, err := sysfs.GetDevice(deviceID)
- if err == nil {
- // Calculate hardware value using the same logic as Manager.setViaSysfsWithLogind
- value := sysfs.PercentToValueWithExponent(percent, dev, exponential, exponent)
-
- // Call logind with hardware value
- if err := logind.SetBrightness(subsystem, name, uint32(value)); err == nil {
- log.Debugf("set %s to %d%% (%d) via logind", deviceID, percent, value)
- fmt.Printf("Set %s to %d%%\n", deviceID, percent)
- return
- } else {
- log.Debugf("logind.SetBrightness failed: %v", err)
- }
- } else {
- log.Debugf("sysfs.GetDeviceByID failed: %v", err)
- }
- }
- }
- }
-
- // Fallback to direct sysfs (requires write permissions)
- sysfs, err := brightness.NewSysfsBackend()
- if err == nil {
- if err := sysfs.SetBrightnessWithExponent(deviceID, percent, exponential, exponent); err == nil {
- fmt.Printf("Set %s to %d%%\n", deviceID, percent)
- return
- }
- log.Debugf("sysfs.SetBrightness failed: %v", err)
- } else {
- log.Debugf("NewSysfsBackend failed: %v", err)
- }
-
- // Try DDC if requested
- if includeDDC {
- ddc, err := brightness.NewDDCBackend()
- if err == nil {
- defer ddc.Close()
- time.Sleep(100 * time.Millisecond)
- if err := ddc.SetBrightnessWithExponent(deviceID, percent, exponential, exponent, nil); err == nil {
- fmt.Printf("Set %s to %d%%\n", deviceID, percent)
- return
- }
- log.Debugf("ddc.SetBrightness failed: %v", err)
- } else {
- log.Debugf("NewDDCBackend failed: %v", err)
- }
- }
-
- log.Fatalf("Failed to set brightness for device: %s", deviceID)
-}
-
-func runBrightnessGet(cmd *cobra.Command, args []string) {
- deviceID := args[0]
- includeDDC, _ := cmd.Flags().GetBool("ddc")
-
- allDevices := []brightness.Device{}
-
- sysfs, err := brightness.NewSysfsBackend()
- if err == nil {
- devices, err := sysfs.GetDevices()
- if err == nil {
- allDevices = append(allDevices, devices...)
- }
- }
-
- if includeDDC {
- ddc, err := brightness.NewDDCBackend()
- if err == nil {
- defer ddc.Close()
- time.Sleep(100 * time.Millisecond)
- devices, err := ddc.GetDevices()
- if err == nil {
- allDevices = append(allDevices, devices...)
- }
- }
- }
-
- for _, device := range allDevices {
- if device.ID == deviceID {
- fmt.Printf("%s: %d%% (%d/%d)\n",
- device.ID,
- device.CurrentPercent,
- device.Current,
- device.Max,
- )
- return
- }
- }
-
- log.Fatalf("Device not found: %s", deviceID)
-}
diff --git a/nix/inputs/dms-cli/cmd/dms/commands_common.go b/nix/inputs/dms-cli/cmd/dms/commands_common.go
deleted file mode 100644
index 1ecf2c4..0000000
--- a/nix/inputs/dms-cli/cmd/dms/commands_common.go
+++ /dev/null
@@ -1,370 +0,0 @@
-package main
-
-import (
- "fmt"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/AvengeMedia/danklinux/internal/plugins"
- "github.com/AvengeMedia/danklinux/internal/server"
- "github.com/spf13/cobra"
-)
-
-var versionCmd = &cobra.Command{
- Use: "version",
- Short: "Show version information",
- Run: runVersion,
-}
-
-var runCmd = &cobra.Command{
- Use: "run",
- Short: "Launch quickshell with DMS configuration",
- Long: "Launch quickshell with DMS configuration (qs -c dms)",
- Run: func(cmd *cobra.Command, args []string) {
- daemon, _ := cmd.Flags().GetBool("daemon")
- session, _ := cmd.Flags().GetBool("session")
- if daemon {
- runShellDaemon(session)
- } else {
- runShellInteractive(session)
- }
- },
-}
-
-var restartCmd = &cobra.Command{
- Use: "restart",
- Short: "Restart quickshell with DMS configuration",
- Long: "Kill existing DMS shell processes and restart quickshell with DMS configuration",
- Run: func(cmd *cobra.Command, args []string) {
- restartShell()
- },
-}
-
-var restartDetachedCmd = &cobra.Command{
- Use: "restart-detached ",
- Hidden: true,
- Args: cobra.ExactArgs(1),
- Run: func(cmd *cobra.Command, args []string) {
- runDetachedRestart(args[0])
- },
-}
-
-var killCmd = &cobra.Command{
- Use: "kill",
- Short: "Kill running DMS shell processes",
- Long: "Kill all running quickshell processes with DMS configuration",
- Run: func(cmd *cobra.Command, args []string) {
- killShell()
- },
-}
-
-var ipcCmd = &cobra.Command{
- Use: "ipc",
- Short: "Send IPC commands to running DMS shell",
- Long: "Send IPC commands to running DMS shell (qs -c dms ipc )",
- Run: func(cmd *cobra.Command, args []string) {
- runShellIPCCommand(args)
- },
-}
-
-var debugSrvCmd = &cobra.Command{
- Use: "debug-srv",
- Short: "Start the debug server",
- Long: "Start the Unix socket debug server for DMS",
- Run: func(cmd *cobra.Command, args []string) {
- if err := startDebugServer(); err != nil {
- log.Fatalf("Error starting debug server: %v", err)
- }
- },
-}
-
-var pluginsCmd = &cobra.Command{
- Use: "plugins",
- Short: "Manage DMS plugins",
- Long: "Browse and manage DMS plugins from the registry",
-}
-
-var pluginsBrowseCmd = &cobra.Command{
- Use: "browse",
- Short: "Browse available plugins",
- Long: "Browse available plugins from the DMS plugin registry",
- Run: func(cmd *cobra.Command, args []string) {
- if err := browsePlugins(); err != nil {
- log.Fatalf("Error browsing plugins: %v", err)
- }
- },
-}
-
-var pluginsListCmd = &cobra.Command{
- Use: "list",
- Short: "List installed plugins",
- Long: "List all installed DMS plugins",
- Run: func(cmd *cobra.Command, args []string) {
- if err := listInstalledPlugins(); err != nil {
- log.Fatalf("Error listing plugins: %v", err)
- }
- },
-}
-
-var pluginsInstallCmd = &cobra.Command{
- Use: "install ",
- Short: "Install a plugin by ID",
- Long: "Install a DMS plugin from the registry using its ID (e.g., 'myPlugin'). Plugin names with spaces are also supported for backward compatibility.",
- Args: cobra.ExactArgs(1),
- Run: func(cmd *cobra.Command, args []string) {
- if err := installPluginCLI(args[0]); err != nil {
- log.Fatalf("Error installing plugin: %v", err)
- }
- },
-}
-
-var pluginsUninstallCmd = &cobra.Command{
- Use: "uninstall ",
- Short: "Uninstall a plugin by ID",
- Long: "Uninstall a DMS plugin using its ID (e.g., 'myPlugin'). Plugin names with spaces are also supported for backward compatibility.",
- Args: cobra.ExactArgs(1),
- Run: func(cmd *cobra.Command, args []string) {
- if err := uninstallPluginCLI(args[0]); err != nil {
- log.Fatalf("Error uninstalling plugin: %v", err)
- }
- },
-}
-
-func runVersion(cmd *cobra.Command, args []string) {
- printASCII()
- fmt.Printf("%s\n", Version)
-}
-
-func startDebugServer() error {
- return server.Start(true)
-}
-
-func browsePlugins() error {
- registry, err := plugins.NewRegistry()
- if err != nil {
- return fmt.Errorf("failed to create registry: %w", err)
- }
-
- manager, err := plugins.NewManager()
- if err != nil {
- return fmt.Errorf("failed to create manager: %w", err)
- }
-
- fmt.Println("Fetching plugin registry...")
- pluginList, err := registry.List()
- if err != nil {
- return fmt.Errorf("failed to list plugins: %w", err)
- }
-
- if len(pluginList) == 0 {
- fmt.Println("No plugins found in registry.")
- return nil
- }
-
- fmt.Printf("\nAvailable Plugins (%d):\n\n", len(pluginList))
- for _, plugin := range pluginList {
- installed, _ := manager.IsInstalled(plugin)
- installedMarker := ""
- if installed {
- installedMarker = " [Installed]"
- }
-
- fmt.Printf(" %s%s\n", plugin.Name, installedMarker)
- fmt.Printf(" ID: %s\n", plugin.ID)
- fmt.Printf(" Category: %s\n", plugin.Category)
- fmt.Printf(" Author: %s\n", plugin.Author)
- fmt.Printf(" Description: %s\n", plugin.Description)
- fmt.Printf(" Repository: %s\n", plugin.Repo)
- if len(plugin.Capabilities) > 0 {
- fmt.Printf(" Capabilities: %s\n", strings.Join(plugin.Capabilities, ", "))
- }
- if len(plugin.Compositors) > 0 {
- fmt.Printf(" Compositors: %s\n", strings.Join(plugin.Compositors, ", "))
- }
- if len(plugin.Dependencies) > 0 {
- fmt.Printf(" Dependencies: %s\n", strings.Join(plugin.Dependencies, ", "))
- }
- fmt.Println()
- }
-
- return nil
-}
-
-func listInstalledPlugins() error {
- manager, err := plugins.NewManager()
- if err != nil {
- return fmt.Errorf("failed to create manager: %w", err)
- }
-
- registry, err := plugins.NewRegistry()
- if err != nil {
- return fmt.Errorf("failed to create registry: %w", err)
- }
-
- installedNames, err := manager.ListInstalled()
- if err != nil {
- return fmt.Errorf("failed to list installed plugins: %w", err)
- }
-
- if len(installedNames) == 0 {
- fmt.Println("No plugins installed.")
- return nil
- }
-
- allPlugins, err := registry.List()
- if err != nil {
- return fmt.Errorf("failed to list plugins: %w", err)
- }
-
- pluginMap := make(map[string]plugins.Plugin)
- for _, p := range allPlugins {
- pluginMap[p.ID] = p
- }
-
- fmt.Printf("\nInstalled Plugins (%d):\n\n", len(installedNames))
- for _, id := range installedNames {
- if plugin, ok := pluginMap[id]; ok {
- fmt.Printf(" %s\n", plugin.Name)
- fmt.Printf(" ID: %s\n", plugin.ID)
- fmt.Printf(" Category: %s\n", plugin.Category)
- fmt.Printf(" Author: %s\n", plugin.Author)
- fmt.Println()
- } else {
- fmt.Printf(" %s (not in registry)\n\n", id)
- }
- }
-
- return nil
-}
-
-func installPluginCLI(idOrName string) error {
- registry, err := plugins.NewRegistry()
- if err != nil {
- return fmt.Errorf("failed to create registry: %w", err)
- }
-
- manager, err := plugins.NewManager()
- if err != nil {
- return fmt.Errorf("failed to create manager: %w", err)
- }
-
- pluginList, err := registry.List()
- if err != nil {
- return fmt.Errorf("failed to list plugins: %w", err)
- }
-
- // First, try to find by ID (preferred method)
- var plugin *plugins.Plugin
- for _, p := range pluginList {
- if p.ID == idOrName {
- plugin = &p
- break
- }
- }
-
- // Fallback to name for backward compatibility
- if plugin == nil {
- for _, p := range pluginList {
- if p.Name == idOrName {
- plugin = &p
- break
- }
- }
- }
-
- if plugin == nil {
- return fmt.Errorf("plugin not found: %s", idOrName)
- }
-
- installed, err := manager.IsInstalled(*plugin)
- if err != nil {
- return fmt.Errorf("failed to check install status: %w", err)
- }
-
- if installed {
- return fmt.Errorf("plugin already installed: %s", plugin.Name)
- }
-
- fmt.Printf("Installing plugin: %s (ID: %s)\n", plugin.Name, plugin.ID)
- if err := manager.Install(*plugin); err != nil {
- return fmt.Errorf("failed to install plugin: %w", err)
- }
-
- fmt.Printf("Plugin installed successfully: %s\n", plugin.Name)
- return nil
-}
-
-func uninstallPluginCLI(idOrName string) error {
- manager, err := plugins.NewManager()
- if err != nil {
- return fmt.Errorf("failed to create manager: %w", err)
- }
-
- registry, err := plugins.NewRegistry()
- if err != nil {
- return fmt.Errorf("failed to create registry: %w", err)
- }
-
- pluginList, err := registry.List()
- if err != nil {
- return fmt.Errorf("failed to list plugins: %w", err)
- }
-
- // First, try to find by ID (preferred method)
- var plugin *plugins.Plugin
- for _, p := range pluginList {
- if p.ID == idOrName {
- plugin = &p
- break
- }
- }
-
- // Fallback to name for backward compatibility
- if plugin == nil {
- for _, p := range pluginList {
- if p.Name == idOrName {
- plugin = &p
- break
- }
- }
- }
-
- if plugin == nil {
- return fmt.Errorf("plugin not found: %s", idOrName)
- }
-
- installed, err := manager.IsInstalled(*plugin)
- if err != nil {
- return fmt.Errorf("failed to check install status: %w", err)
- }
-
- if !installed {
- return fmt.Errorf("plugin not installed: %s", plugin.Name)
- }
-
- fmt.Printf("Uninstalling plugin: %s (ID: %s)\n", plugin.Name, plugin.ID)
- if err := manager.Uninstall(*plugin); err != nil {
- return fmt.Errorf("failed to uninstall plugin: %w", err)
- }
-
- fmt.Printf("Plugin uninstalled successfully: %s\n", plugin.Name)
- return nil
-}
-
-// getCommonCommands returns the commands available in all builds
-func getCommonCommands() []*cobra.Command {
- return []*cobra.Command{
- versionCmd,
- runCmd,
- restartCmd,
- restartDetachedCmd,
- killCmd,
- ipcCmd,
- debugSrvCmd,
- pluginsCmd,
- dank16Cmd,
- brightnessCmd,
- hyprlandCmd,
- greeterCmd,
- }
-}
diff --git a/nix/inputs/dms-cli/cmd/dms/commands_dank16.go b/nix/inputs/dms-cli/cmd/dms/commands_dank16.go
deleted file mode 100644
index 20e3b55..0000000
--- a/nix/inputs/dms-cli/cmd/dms/commands_dank16.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/dank16"
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/spf13/cobra"
-)
-
-var dank16Cmd = &cobra.Command{
- Use: "dank16 ",
- Short: "Generate Base16 color palettes",
- Long: "Generate Base16 color palettes from a color with support for various output formats",
- Args: cobra.ExactArgs(1),
- Run: runDank16,
-}
-
-func init() {
- dank16Cmd.Flags().Bool("light", false, "Generate light theme variant")
- dank16Cmd.Flags().Bool("json", false, "Output in JSON format")
- dank16Cmd.Flags().Bool("kitty", false, "Output in Kitty terminal format")
- dank16Cmd.Flags().Bool("foot", false, "Output in Foot terminal format")
- dank16Cmd.Flags().Bool("alacritty", false, "Output in Alacritty terminal format")
- dank16Cmd.Flags().Bool("ghostty", false, "Output in Ghostty terminal format")
- dank16Cmd.Flags().String("vscode-enrich", "", "Enrich existing VSCode theme file with terminal colors")
- dank16Cmd.Flags().String("background", "", "Custom background color")
- dank16Cmd.Flags().String("contrast", "dps", "Contrast algorithm: dps (Delta Phi Star, default) or wcag")
-}
-
-func runDank16(cmd *cobra.Command, args []string) {
- primaryColor := args[0]
- if !strings.HasPrefix(primaryColor, "#") {
- primaryColor = "#" + primaryColor
- }
-
- isLight, _ := cmd.Flags().GetBool("light")
- isJson, _ := cmd.Flags().GetBool("json")
- isKitty, _ := cmd.Flags().GetBool("kitty")
- isFoot, _ := cmd.Flags().GetBool("foot")
- isAlacritty, _ := cmd.Flags().GetBool("alacritty")
- isGhostty, _ := cmd.Flags().GetBool("ghostty")
- vscodeEnrich, _ := cmd.Flags().GetString("vscode-enrich")
- background, _ := cmd.Flags().GetString("background")
- contrastAlgo, _ := cmd.Flags().GetString("contrast")
-
- if background != "" && !strings.HasPrefix(background, "#") {
- background = "#" + background
- }
-
- contrastAlgo = strings.ToLower(contrastAlgo)
- if contrastAlgo != "dps" && contrastAlgo != "wcag" {
- log.Fatalf("Invalid contrast algorithm: %s (must be 'dps' or 'wcag')", contrastAlgo)
- }
-
- opts := dank16.PaletteOptions{
- IsLight: isLight,
- Background: background,
- UseDPS: contrastAlgo == "dps",
- }
-
- colors := dank16.GeneratePalette(primaryColor, opts)
-
- if vscodeEnrich != "" {
- data, err := os.ReadFile(vscodeEnrich)
- if err != nil {
- log.Fatalf("Error reading file: %v", err)
- }
-
- enriched, err := dank16.EnrichVSCodeTheme(data, colors)
- if err != nil {
- log.Fatalf("Error enriching theme: %v", err)
- }
- fmt.Println(string(enriched))
- } else if isJson {
- fmt.Print(dank16.GenerateJSON(colors))
- } else if isKitty {
- fmt.Print(dank16.GenerateKittyTheme(colors))
- } else if isFoot {
- fmt.Print(dank16.GenerateFootTheme(colors))
- } else if isAlacritty {
- fmt.Print(dank16.GenerateAlacrittyTheme(colors))
- } else if isGhostty {
- fmt.Print(dank16.GenerateGhosttyTheme(colors))
- } else {
- fmt.Print(dank16.GenerateGhosttyTheme(colors))
- }
-}
diff --git a/nix/inputs/dms-cli/cmd/dms/commands_features.go b/nix/inputs/dms-cli/cmd/dms/commands_features.go
deleted file mode 100644
index cbd35eb..0000000
--- a/nix/inputs/dms-cli/cmd/dms/commands_features.go
+++ /dev/null
@@ -1,487 +0,0 @@
-//go:build !distro_binary
-
-package main
-
-import (
- "bufio"
- "errors"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/distros"
- "github.com/AvengeMedia/danklinux/internal/errdefs"
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/AvengeMedia/danklinux/internal/version"
- "github.com/spf13/cobra"
-)
-
-var updateCmd = &cobra.Command{
- Use: "update",
- Short: "Update DankMaterialShell to the latest version",
- Long: "Update DankMaterialShell to the latest version using the appropriate package manager for your distribution",
- Run: func(cmd *cobra.Command, args []string) {
- runUpdate()
- },
-}
-
-var updateCheckCmd = &cobra.Command{
- Use: "check",
- Short: "Check if updates are available for DankMaterialShell",
- Long: "Check for available updates without performing the actual update",
- Run: func(cmd *cobra.Command, args []string) {
- runUpdateCheck()
- },
-}
-
-func runUpdateCheck() {
- fmt.Println("Checking for DankMaterialShell updates...")
- fmt.Println()
-
- versionInfo, err := version.GetDMSVersionInfo()
- if err != nil {
- log.Fatalf("Error checking for updates: %v", err)
- }
-
- fmt.Printf("Current version: %s\n", versionInfo.Current)
- fmt.Printf("Latest version: %s\n", versionInfo.Latest)
- fmt.Println()
-
- if versionInfo.HasUpdate {
- fmt.Println("✓ Update available!")
- fmt.Println()
- fmt.Println("Run 'dms update' to install the latest version.")
- os.Exit(0)
- } else {
- fmt.Println("✓ You are running the latest version.")
- os.Exit(0)
- }
-}
-
-func runUpdate() {
- osInfo, err := distros.GetOSInfo()
- if err != nil {
- log.Fatalf("Error detecting OS: %v", err)
- }
-
- config, exists := distros.Registry[osInfo.Distribution.ID]
- if !exists {
- log.Fatalf("Unsupported distribution: %s", osInfo.Distribution.ID)
- }
-
- var updateErr error
- switch config.Family {
- case distros.FamilyArch:
- updateErr = updateArchLinux()
- case distros.FamilyNix:
- updateErr = updateNixOS()
- case distros.FamilySUSE:
- updateErr = updateOtherDistros()
- default:
- updateErr = updateOtherDistros()
- }
-
- if updateErr != nil {
- if errors.Is(updateErr, errdefs.ErrUpdateCancelled) {
- log.Info("Update cancelled.")
- return
- }
- if errors.Is(updateErr, errdefs.ErrNoUpdateNeeded) {
- return
- }
- log.Fatalf("Error updating DMS: %v", updateErr)
- }
-
- log.Info("Update complete! Restarting DMS...")
- restartShell()
-}
-
-func updateArchLinux() error {
- homeDir, err := os.UserHomeDir()
- if err == nil {
- dmsPath := filepath.Join(homeDir, ".config", "quickshell", "dms")
- if _, err := os.Stat(dmsPath); err == nil {
- return updateOtherDistros()
- }
- }
-
- var packageName string
- if isArchPackageInstalled("dms-shell-bin") {
- packageName = "dms-shell-bin"
- } else if isArchPackageInstalled("dms-shell-git") {
- packageName = "dms-shell-git"
- } else {
- fmt.Println("Info: Neither dms-shell-bin nor dms-shell-git package found.")
- fmt.Println("Info: Falling back to git-based update method...")
- return updateOtherDistros()
- }
-
- var helper string
- var updateCmd *exec.Cmd
-
- if commandExists("yay") {
- helper = "yay"
- updateCmd = exec.Command("yay", "-S", packageName)
- } else if commandExists("paru") {
- helper = "paru"
- updateCmd = exec.Command("paru", "-S", packageName)
- } else {
- fmt.Println("Error: Neither yay nor paru found - please install an AUR helper")
- fmt.Println("Info: Falling back to git-based update method...")
- return updateOtherDistros()
- }
-
- fmt.Printf("This will update DankMaterialShell using %s.\n", helper)
- if !confirmUpdate() {
- return errdefs.ErrUpdateCancelled
- }
-
- fmt.Printf("\nRunning: %s -S %s\n", helper, packageName)
- updateCmd.Stdout = os.Stdout
- updateCmd.Stderr = os.Stderr
- err = updateCmd.Run()
- if err != nil {
- fmt.Printf("Error: Failed to update using %s: %v\n", helper, err)
- }
-
- fmt.Println("dms successfully updated")
- return nil
-}
-
-func updateNixOS() error {
- fmt.Println("This will update DankMaterialShell using nix profile.")
- if !confirmUpdate() {
- return errdefs.ErrUpdateCancelled
- }
-
- fmt.Println("\nRunning: nix profile upgrade github:AvengeMedia/DankMaterialShell")
- updateCmd := exec.Command("nix", "profile", "upgrade", "github:AvengeMedia/DankMaterialShell")
- updateCmd.Stdout = os.Stdout
- updateCmd.Stderr = os.Stderr
- err := updateCmd.Run()
- if err != nil {
- fmt.Printf("Error: Failed to update using nix profile: %v\n", err)
- fmt.Println("Falling back to git-based update method...")
- return updateOtherDistros()
- }
-
- fmt.Println("dms successfully updated")
- return nil
-}
-
-func updateOtherDistros() error {
- homeDir, err := os.UserHomeDir()
- if err != nil {
- return fmt.Errorf("failed to get user home directory: %w", err)
- }
-
- dmsPath := filepath.Join(homeDir, ".config", "quickshell", "dms")
-
- if _, err := os.Stat(dmsPath); os.IsNotExist(err) {
- return fmt.Errorf("DMS configuration directory not found at %s", dmsPath)
- }
-
- fmt.Printf("Found DMS configuration at %s\n", dmsPath)
-
- versionInfo, err := version.GetDMSVersionInfo()
- if err == nil && !versionInfo.HasUpdate {
- fmt.Println()
- fmt.Printf("Current version: %s\n", versionInfo.Current)
- fmt.Printf("Latest version: %s\n", versionInfo.Latest)
- fmt.Println()
- fmt.Println("✓ You are already running the latest version.")
- return errdefs.ErrNoUpdateNeeded
- }
-
- fmt.Println("\nThis will update:")
- fmt.Println(" 1. The dms binary from GitHub releases")
- fmt.Println(" 2. DankMaterialShell configuration using git")
- if !confirmUpdate() {
- return errdefs.ErrUpdateCancelled
- }
-
- fmt.Println("\n=== Updating dms binary ===")
- if err := updateDMSBinary(); err != nil {
- fmt.Printf("Warning: Failed to update dms binary: %v\n", err)
- fmt.Println("Continuing with shell configuration update...")
- } else {
- fmt.Println("dms binary successfully updated")
- }
-
- fmt.Println("\n=== Updating DMS shell configuration ===")
-
- if err := os.Chdir(dmsPath); err != nil {
- return fmt.Errorf("failed to change to DMS directory: %w", err)
- }
-
- statusCmd := exec.Command("git", "status", "--porcelain")
- statusOutput, _ := statusCmd.Output()
- hasLocalChanges := len(strings.TrimSpace(string(statusOutput))) > 0
-
- currentRefCmd := exec.Command("git", "symbolic-ref", "-q", "HEAD")
- currentRefOutput, _ := currentRefCmd.Output()
- onBranch := len(currentRefOutput) > 0
-
- var currentTag string
- var currentBranch string
-
- if !onBranch {
- tagCmd := exec.Command("git", "describe", "--exact-match", "--tags", "HEAD")
- if tagOutput, err := tagCmd.Output(); err == nil {
- currentTag = strings.TrimSpace(string(tagOutput))
- }
- } else {
- branchCmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD")
- if branchOutput, err := branchCmd.Output(); err == nil {
- currentBranch = strings.TrimSpace(string(branchOutput))
- }
- }
-
- fmt.Println("Fetching latest changes...")
- fetchCmd := exec.Command("git", "fetch", "origin", "--tags", "--force")
- fetchCmd.Stdout = os.Stdout
- fetchCmd.Stderr = os.Stderr
- if err := fetchCmd.Run(); err != nil {
- return fmt.Errorf("failed to fetch changes: %w", err)
- }
-
- if currentTag != "" {
- latestTagCmd := exec.Command("git", "tag", "-l", "v0.1.*", "--sort=-version:refname")
- latestTagOutput, err := latestTagCmd.Output()
- if err != nil {
- return fmt.Errorf("failed to get latest tag: %w", err)
- }
-
- tags := strings.Split(strings.TrimSpace(string(latestTagOutput)), "\n")
- if len(tags) == 0 || tags[0] == "" {
- return fmt.Errorf("no v0.1.* tags found")
- }
- latestTag := tags[0]
-
- if latestTag == currentTag {
- fmt.Printf("Already on latest tag: %s\n", currentTag)
- return nil
- }
-
- fmt.Printf("Current tag: %s\n", currentTag)
- fmt.Printf("Latest tag: %s\n", latestTag)
-
- if hasLocalChanges {
- fmt.Println("\nWarning: You have local changes in your DMS configuration.")
- if offerReclone(dmsPath) {
- return nil
- }
- return errdefs.ErrUpdateCancelled
- }
-
- fmt.Printf("Updating to %s...\n", latestTag)
- checkoutCmd := exec.Command("git", "checkout", latestTag)
- checkoutCmd.Stdout = os.Stdout
- checkoutCmd.Stderr = os.Stderr
- if err := checkoutCmd.Run(); err != nil {
- fmt.Printf("Error: Failed to checkout %s: %v\n", latestTag, err)
- if offerReclone(dmsPath) {
- return nil
- }
- return fmt.Errorf("update cancelled")
- }
-
- fmt.Printf("\nUpdate complete! Updated from %s to %s\n", currentTag, latestTag)
- return nil
- }
-
- if currentBranch == "" {
- currentBranch = "master"
- }
-
- fmt.Printf("Current branch: %s\n", currentBranch)
-
- if hasLocalChanges {
- fmt.Println("\nWarning: You have local changes in your DMS configuration.")
- if offerReclone(dmsPath) {
- return nil
- }
- return errdefs.ErrUpdateCancelled
- }
-
- pullCmd := exec.Command("git", "pull", "origin", currentBranch)
- pullCmd.Stdout = os.Stdout
- pullCmd.Stderr = os.Stderr
- if err := pullCmd.Run(); err != nil {
- fmt.Printf("Error: Failed to pull latest changes: %v\n", err)
- if offerReclone(dmsPath) {
- return nil
- }
- return fmt.Errorf("update cancelled")
- }
-
- fmt.Println("\nUpdate complete!")
- return nil
-}
-
-func offerReclone(dmsPath string) bool {
- fmt.Println("\nWould you like to backup and re-clone the repository? (y/N): ")
- reader := bufio.NewReader(os.Stdin)
- response, err := reader.ReadString('\n')
- if err != nil || !strings.HasPrefix(strings.ToLower(strings.TrimSpace(response)), "y") {
- return false
- }
-
- timestamp := time.Now().Unix()
- backupPath := fmt.Sprintf("%s.backup-%d", dmsPath, timestamp)
-
- fmt.Printf("Backing up current directory to %s...\n", backupPath)
- if err := os.Rename(dmsPath, backupPath); err != nil {
- fmt.Printf("Error: Failed to backup directory: %v\n", err)
- return false
- }
-
- fmt.Println("Cloning fresh copy...")
- cloneCmd := exec.Command("git", "clone", "https://github.com/AvengeMedia/DankMaterialShell.git", dmsPath)
- cloneCmd.Stdout = os.Stdout
- cloneCmd.Stderr = os.Stderr
- if err := cloneCmd.Run(); err != nil {
- fmt.Printf("Error: Failed to clone repository: %v\n", err)
- fmt.Printf("Restoring backup...\n")
- os.Rename(backupPath, dmsPath)
- return false
- }
-
- fmt.Printf("Successfully re-cloned repository (backup at %s)\n", backupPath)
- return true
-}
-
-func confirmUpdate() bool {
- fmt.Print("Do you want to proceed with the update? (y/N): ")
- reader := bufio.NewReader(os.Stdin)
- response, err := reader.ReadString('\n')
- if err != nil {
- fmt.Printf("Error reading input: %v\n", err)
- return false
- }
- response = strings.TrimSpace(strings.ToLower(response))
- return response == "y" || response == "yes"
-}
-
-func updateDMSBinary() error {
- arch := ""
- switch strings.ToLower(os.Getenv("HOSTTYPE")) {
- case "x86_64", "amd64":
- arch = "amd64"
- case "aarch64", "arm64":
- arch = "arm64"
- default:
- cmd := exec.Command("uname", "-m")
- output, err := cmd.Output()
- if err != nil {
- return fmt.Errorf("failed to detect architecture: %w", err)
- }
- archStr := strings.TrimSpace(string(output))
- switch archStr {
- case "x86_64":
- arch = "amd64"
- case "aarch64":
- arch = "arm64"
- default:
- return fmt.Errorf("unsupported architecture: %s", archStr)
- }
- }
-
- fmt.Println("Fetching latest release version...")
- cmd := exec.Command("curl", "-s", "https://api.github.com/repos/AvengeMedia/danklinux/releases/latest")
- output, err := cmd.Output()
- if err != nil {
- return fmt.Errorf("failed to fetch latest release: %w", err)
- }
-
- version := ""
- for _, line := range strings.Split(string(output), "\n") {
- if strings.Contains(line, "\"tag_name\"") {
- parts := strings.Split(line, "\"")
- if len(parts) >= 4 {
- version = parts[3]
- break
- }
- }
- }
-
- if version == "" {
- return fmt.Errorf("could not determine latest version")
- }
-
- fmt.Printf("Latest version: %s\n", version)
-
- tempDir, err := os.MkdirTemp("", "dms-update-*")
- if err != nil {
- return fmt.Errorf("failed to create temp directory: %w", err)
- }
- defer os.RemoveAll(tempDir)
-
- binaryURL := fmt.Sprintf("https://github.com/AvengeMedia/danklinux/releases/download/%s/dms-%s.gz", version, arch)
- checksumURL := fmt.Sprintf("https://github.com/AvengeMedia/danklinux/releases/download/%s/dms-%s.gz.sha256", version, arch)
-
- binaryPath := filepath.Join(tempDir, "dms.gz")
- checksumPath := filepath.Join(tempDir, "dms.gz.sha256")
-
- fmt.Println("Downloading dms binary...")
- downloadCmd := exec.Command("curl", "-L", binaryURL, "-o", binaryPath)
- if err := downloadCmd.Run(); err != nil {
- return fmt.Errorf("failed to download binary: %w", err)
- }
-
- fmt.Println("Downloading checksum...")
- downloadCmd = exec.Command("curl", "-L", checksumURL, "-o", checksumPath)
- if err := downloadCmd.Run(); err != nil {
- return fmt.Errorf("failed to download checksum: %w", err)
- }
-
- fmt.Println("Verifying checksum...")
- checksumData, err := os.ReadFile(checksumPath)
- if err != nil {
- return fmt.Errorf("failed to read checksum file: %w", err)
- }
- expectedChecksum := strings.Fields(string(checksumData))[0]
-
- actualCmd := exec.Command("sha256sum", binaryPath)
- actualOutput, err := actualCmd.Output()
- if err != nil {
- return fmt.Errorf("failed to calculate checksum: %w", err)
- }
- actualChecksum := strings.Fields(string(actualOutput))[0]
-
- if expectedChecksum != actualChecksum {
- return fmt.Errorf("checksum verification failed\nExpected: %s\nGot: %s", expectedChecksum, actualChecksum)
- }
-
- fmt.Println("Decompressing binary...")
- decompressCmd := exec.Command("gunzip", binaryPath)
- if err := decompressCmd.Run(); err != nil {
- return fmt.Errorf("failed to decompress binary: %w", err)
- }
-
- decompressedPath := filepath.Join(tempDir, "dms")
-
- if err := os.Chmod(decompressedPath, 0755); err != nil {
- return fmt.Errorf("failed to make binary executable: %w", err)
- }
-
- currentPath, err := exec.LookPath("dms")
- if err != nil {
- return fmt.Errorf("could not find current dms binary: %w", err)
- }
-
- fmt.Printf("Installing to %s...\n", currentPath)
-
- replaceCmd := exec.Command("sudo", "install", "-m", "0755", decompressedPath, currentPath)
- replaceCmd.Stdin = os.Stdin
- replaceCmd.Stdout = os.Stdout
- replaceCmd.Stderr = os.Stderr
- if err := replaceCmd.Run(); err != nil {
- return fmt.Errorf("failed to replace binary: %w", err)
- }
-
- return nil
-}
diff --git a/nix/inputs/dms-cli/cmd/dms/commands_greeter.go b/nix/inputs/dms-cli/cmd/dms/commands_greeter.go
deleted file mode 100644
index d0bff4e..0000000
--- a/nix/inputs/dms-cli/cmd/dms/commands_greeter.go
+++ /dev/null
@@ -1,500 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
- "os/exec"
- "os/user"
- "path/filepath"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/greeter"
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/spf13/cobra"
-)
-
-var greeterCmd = &cobra.Command{
- Use: "greeter",
- Short: "Manage DMS greeter",
- Long: "Manage DMS greeter (greetd)",
-}
-
-var greeterInstallCmd = &cobra.Command{
- Use: "install",
- Short: "Install and configure DMS greeter",
- Long: "Install greetd and configure it to use DMS as the greeter interface",
- Run: func(cmd *cobra.Command, args []string) {
- if err := installGreeter(); err != nil {
- log.Fatalf("Error installing greeter: %v", err)
- }
- },
-}
-
-var greeterSyncCmd = &cobra.Command{
- Use: "sync",
- Short: "Sync DMS theme and settings with greeter",
- Long: "Synchronize your current user's DMS theme, settings, and wallpaper configuration with the login greeter screen",
- Run: func(cmd *cobra.Command, args []string) {
- if err := syncGreeter(); err != nil {
- log.Fatalf("Error syncing greeter: %v", err)
- }
- },
-}
-
-var greeterEnableCmd = &cobra.Command{
- Use: "enable",
- Short: "Enable DMS greeter in greetd config",
- Long: "Configure greetd to use DMS as the greeter",
- Run: func(cmd *cobra.Command, args []string) {
- if err := enableGreeter(); err != nil {
- log.Fatalf("Error enabling greeter: %v", err)
- }
- },
-}
-
-var greeterStatusCmd = &cobra.Command{
- Use: "status",
- Short: "Check greeter sync status",
- Long: "Check the status of greeter installation and configuration sync",
- Run: func(cmd *cobra.Command, args []string) {
- if err := checkGreeterStatus(); err != nil {
- log.Fatalf("Error checking greeter status: %v", err)
- }
- },
-}
-
-func installGreeter() error {
- fmt.Println("=== DMS Greeter Installation ===")
-
- logFunc := func(msg string) {
- fmt.Println(msg)
- }
-
- if err := greeter.EnsureGreetdInstalled(logFunc, ""); err != nil {
- return err
- }
-
- fmt.Println("\nDetecting DMS installation...")
- dmsPath, err := greeter.DetectDMSPath()
- if err != nil {
- return err
- }
- fmt.Printf("✓ Found DMS at: %s\n", dmsPath)
-
- fmt.Println("\nDetecting installed compositors...")
- compositors := greeter.DetectCompositors()
- if len(compositors) == 0 {
- return fmt.Errorf("no supported compositors found (niri or Hyprland required)")
- }
-
- var selectedCompositor string
- if len(compositors) == 1 {
- selectedCompositor = compositors[0]
- fmt.Printf("✓ Found compositor: %s\n", selectedCompositor)
- } else {
- var err error
- selectedCompositor, err = greeter.PromptCompositorChoice(compositors)
- if err != nil {
- return err
- }
- fmt.Printf("✓ Selected compositor: %s\n", selectedCompositor)
- }
-
- fmt.Println("\nSetting up dms-greeter group and permissions...")
- if err := greeter.SetupDMSGroup(logFunc, ""); err != nil {
- return err
- }
-
- fmt.Println("\nCopying greeter files...")
- if err := greeter.CopyGreeterFiles(dmsPath, selectedCompositor, logFunc, ""); err != nil {
- return err
- }
-
- fmt.Println("\nConfiguring greetd...")
- if err := greeter.ConfigureGreetd(dmsPath, selectedCompositor, logFunc, ""); err != nil {
- return err
- }
-
- fmt.Println("\nSynchronizing DMS configurations...")
- if err := greeter.SyncDMSConfigs(dmsPath, logFunc, ""); err != nil {
- return err
- }
-
- fmt.Println("\n=== Installation Complete ===")
- fmt.Println("\nTo test the greeter, run:")
- fmt.Println(" sudo systemctl start greetd")
- fmt.Println("\nTo enable on boot, run:")
- fmt.Println(" sudo systemctl enable --now greetd")
-
- return nil
-}
-
-func syncGreeter() error {
- fmt.Println("=== DMS Greeter Theme Sync ===")
- fmt.Println()
-
- logFunc := func(msg string) {
- fmt.Println(msg)
- }
-
- fmt.Println("Detecting DMS installation...")
- dmsPath, err := greeter.DetectDMSPath()
- if err != nil {
- return err
- }
- fmt.Printf("✓ Found DMS at: %s\n", dmsPath)
-
- cacheDir := "/var/cache/dms-greeter"
- if _, err := os.Stat(cacheDir); os.IsNotExist(err) {
- return fmt.Errorf("greeter cache directory not found at %s\nPlease install the greeter first", cacheDir)
- }
-
- greeterGroupExists := checkGroupExists("greeter")
- if greeterGroupExists {
- currentUser, err := user.Current()
- if err != nil {
- return fmt.Errorf("failed to get current user: %w", err)
- }
-
- groupsCmd := exec.Command("groups", currentUser.Username)
- groupsOutput, err := groupsCmd.Output()
- if err != nil {
- return fmt.Errorf("failed to check groups: %w", err)
- }
-
- inGreeterGroup := strings.Contains(string(groupsOutput), "greeter")
- if !inGreeterGroup {
- fmt.Println("\n⚠ Warning: You are not in the greeter group.")
- fmt.Print("Would you like to add your user to the greeter group? (y/N): ")
-
- var response string
- fmt.Scanln(&response)
- response = strings.ToLower(strings.TrimSpace(response))
-
- if response == "y" || response == "yes" {
- fmt.Println("\nAdding user to greeter group...")
- addUserCmd := exec.Command("sudo", "usermod", "-aG", "greeter", currentUser.Username)
- addUserCmd.Stdout = os.Stdout
- addUserCmd.Stderr = os.Stderr
- if err := addUserCmd.Run(); err != nil {
- return fmt.Errorf("failed to add user to greeter group: %w", err)
- }
- fmt.Println("✓ User added to greeter group")
- fmt.Println("⚠ You will need to log out and back in for the group change to take effect")
- }
- }
- }
-
- fmt.Println("\nSetting up permissions and ACLs...")
- if err := greeter.SetupDMSGroup(logFunc, ""); err != nil {
- return err
- }
-
- fmt.Println("\nSynchronizing DMS configurations...")
- if err := greeter.SyncDMSConfigs(dmsPath, logFunc, ""); err != nil {
- return err
- }
-
- fmt.Println("\n=== Sync Complete ===")
- fmt.Println("\nYour theme, settings, and wallpaper configuration have been synced with the greeter.")
- fmt.Println("The changes will be visible on the next login screen.")
-
- return nil
-}
-
-func checkGroupExists(groupName string) bool {
- data, err := os.ReadFile("/etc/group")
- if err != nil {
- return false
- }
-
- lines := strings.Split(string(data), "\n")
- for _, line := range lines {
- if strings.HasPrefix(line, groupName+":") {
- return true
- }
- }
- return false
-}
-
-func enableGreeter() error {
- fmt.Println("=== DMS Greeter Enable ===")
- fmt.Println()
-
- configPath := "/etc/greetd/config.toml"
- if _, err := os.Stat(configPath); os.IsNotExist(err) {
- return fmt.Errorf("greetd config not found at %s\nPlease install greetd first", configPath)
- }
-
- data, err := os.ReadFile(configPath)
- if err != nil {
- return fmt.Errorf("failed to read greetd config: %w", err)
- }
-
- configContent := string(data)
- if strings.Contains(configContent, "dms-greeter") {
- fmt.Println("✓ Greeter is already configured with dms-greeter")
- return nil
- }
-
- fmt.Println("Detecting installed compositors...")
- compositors := greeter.DetectCompositors()
-
- if commandExists("sway") {
- compositors = append(compositors, "sway")
- }
-
- if len(compositors) == 0 {
- return fmt.Errorf("no supported compositors found (niri, Hyprland, or sway required)")
- }
-
- var selectedCompositor string
- if len(compositors) == 1 {
- selectedCompositor = compositors[0]
- fmt.Printf("✓ Found compositor: %s\n", selectedCompositor)
- } else {
- var err error
- selectedCompositor, err = promptCompositorChoice(compositors)
- if err != nil {
- return err
- }
- fmt.Printf("✓ Selected compositor: %s\n", selectedCompositor)
- }
-
- backupPath := configPath + ".backup"
- backupCmd := exec.Command("sudo", "cp", configPath, backupPath)
- if err := backupCmd.Run(); err != nil {
- return fmt.Errorf("failed to backup config: %w", err)
- }
- fmt.Printf("✓ Backed up config to %s\n", backupPath)
-
- lines := strings.Split(configContent, "\n")
- var newLines []string
- for _, line := range lines {
- trimmed := strings.TrimSpace(line)
- if !strings.HasPrefix(trimmed, "command =") && !strings.HasPrefix(trimmed, "command=") {
- newLines = append(newLines, line)
- }
- }
-
- wrapperCmd := "dms-greeter"
- if !commandExists("dms-greeter") {
- wrapperCmd = "/usr/local/bin/dms-greeter"
- }
-
- compositorLower := strings.ToLower(selectedCompositor)
- commandLine := fmt.Sprintf(`command = "%s --command %s"`, wrapperCmd, compositorLower)
-
- var finalLines []string
- inDefaultSession := false
- commandAdded := false
-
- for _, line := range newLines {
- finalLines = append(finalLines, line)
- trimmed := strings.TrimSpace(line)
-
- if trimmed == "[default_session]" {
- inDefaultSession = true
- }
-
- if inDefaultSession && !commandAdded {
- if strings.HasPrefix(trimmed, "user =") || strings.HasPrefix(trimmed, "user=") {
- finalLines = append(finalLines, commandLine)
- commandAdded = true
- }
- }
- }
-
- if !commandAdded {
- finalLines = append(finalLines, commandLine)
- }
-
- newConfig := strings.Join(finalLines, "\n")
-
- tmpFile := "/tmp/greetd-config.toml"
- if err := os.WriteFile(tmpFile, []byte(newConfig), 0644); err != nil {
- return fmt.Errorf("failed to write temp config: %w", err)
- }
-
- moveCmd := exec.Command("sudo", "mv", tmpFile, configPath)
- if err := moveCmd.Run(); err != nil {
- return fmt.Errorf("failed to update config: %w", err)
- }
-
- fmt.Printf("✓ Updated greetd configuration to use %s\n", selectedCompositor)
- fmt.Println("\n=== Enable Complete ===")
- fmt.Println("\nTo start the greeter, run:")
- fmt.Println(" sudo systemctl start greetd")
- fmt.Println("\nTo enable on boot, run:")
- fmt.Println(" sudo systemctl enable --now greetd")
-
- return nil
-}
-
-func promptCompositorChoice(compositors []string) (string, error) {
- fmt.Println("\nMultiple compositors detected:")
- for i, comp := range compositors {
- fmt.Printf("%d) %s\n", i+1, comp)
- }
-
- var response string
- fmt.Print("Choose compositor for greeter: ")
- fmt.Scanln(&response)
- response = strings.TrimSpace(response)
-
- choice := 0
- fmt.Sscanf(response, "%d", &choice)
-
- if choice < 1 || choice > len(compositors) {
- return "", fmt.Errorf("invalid choice")
- }
-
- return compositors[choice-1], nil
-}
-
-func checkGreeterStatus() error {
- fmt.Println("=== DMS Greeter Status ===")
- fmt.Println()
-
- homeDir, err := os.UserHomeDir()
- if err != nil {
- return fmt.Errorf("failed to get user home directory: %w", err)
- }
-
- currentUser, err := user.Current()
- if err != nil {
- return fmt.Errorf("failed to get current user: %w", err)
- }
-
- configPath := "/etc/greetd/config.toml"
- fmt.Println("Greeter Configuration:")
- if data, err := os.ReadFile(configPath); err == nil {
- configContent := string(data)
- if strings.Contains(configContent, "dms-greeter") {
- lines := strings.Split(configContent, "\n")
- for _, line := range lines {
- trimmed := strings.TrimSpace(line)
- if strings.HasPrefix(trimmed, "command =") || strings.HasPrefix(trimmed, "command=") {
- parts := strings.SplitN(trimmed, "=", 2)
- if len(parts) == 2 {
- command := strings.Trim(strings.TrimSpace(parts[1]), `"`)
- fmt.Println(" ✓ Greeter is enabled")
-
- if strings.Contains(command, "--command niri") {
- fmt.Println(" Compositor: niri")
- } else if strings.Contains(command, "--command hyprland") {
- fmt.Println(" Compositor: Hyprland")
- } else if strings.Contains(command, "--command sway") {
- fmt.Println(" Compositor: sway")
- } else {
- fmt.Println(" Compositor: unknown")
- }
- }
- break
- }
- }
- } else {
- fmt.Println(" ✗ Greeter is NOT enabled")
- fmt.Println(" Run 'dms greeter enable' to enable it")
- }
- } else {
- fmt.Println(" ✗ Greeter config not found")
- fmt.Println(" Run 'dms greeter install' to install greeter")
- }
-
- fmt.Println("\nGroup Membership:")
- groupsCmd := exec.Command("groups", currentUser.Username)
- groupsOutput, err := groupsCmd.Output()
- if err != nil {
- return fmt.Errorf("failed to check groups: %w", err)
- }
-
- inGreeterGroup := strings.Contains(string(groupsOutput), "greeter")
- if inGreeterGroup {
- fmt.Println(" ✓ User is in greeter group")
- } else {
- fmt.Println(" ✗ User is NOT in greeter group")
- fmt.Println(" Run 'dms greeter install' to add user to greeter group")
- }
-
- cacheDir := "/var/cache/dms-greeter"
- fmt.Println("\nGreeter Cache Directory:")
- if stat, err := os.Stat(cacheDir); err == nil && stat.IsDir() {
- fmt.Printf(" ✓ %s exists\n", cacheDir)
- } else {
- fmt.Printf(" ✗ %s not found\n", cacheDir)
- fmt.Println(" Run 'dms greeter install' to create cache directory")
- return nil
- }
-
- fmt.Println("\nConfiguration Symlinks:")
- symlinks := []struct {
- source string
- target string
- desc string
- }{
- {
- source: filepath.Join(homeDir, ".config", "DankMaterialShell", "settings.json"),
- target: filepath.Join(cacheDir, "settings.json"),
- desc: "Settings",
- },
- {
- source: filepath.Join(homeDir, ".local", "state", "DankMaterialShell", "session.json"),
- target: filepath.Join(cacheDir, "session.json"),
- desc: "Session state",
- },
- {
- source: filepath.Join(homeDir, ".cache", "quickshell", "dankshell", "dms-colors.json"),
- target: filepath.Join(cacheDir, "colors.json"),
- desc: "Color theme",
- },
- }
-
- allGood := true
- for _, link := range symlinks {
- targetInfo, err := os.Lstat(link.target)
- if err != nil {
- fmt.Printf(" ✗ %s: symlink not found at %s\n", link.desc, link.target)
- allGood = false
- continue
- }
-
- if targetInfo.Mode()&os.ModeSymlink == 0 {
- fmt.Printf(" ✗ %s: %s is not a symlink\n", link.desc, link.target)
- allGood = false
- continue
- }
-
- linkDest, err := os.Readlink(link.target)
- if err != nil {
- fmt.Printf(" ✗ %s: failed to read symlink\n", link.desc)
- allGood = false
- continue
- }
-
- if linkDest != link.source {
- fmt.Printf(" ✗ %s: symlink points to wrong location\n", link.desc)
- fmt.Printf(" Expected: %s\n", link.source)
- fmt.Printf(" Got: %s\n", linkDest)
- allGood = false
- continue
- }
-
- if _, err := os.Stat(link.source); os.IsNotExist(err) {
- fmt.Printf(" ⚠ %s: symlink OK, but source file doesn't exist yet\n", link.desc)
- fmt.Printf(" Will be created when you run DMS\n")
- continue
- }
-
- fmt.Printf(" ✓ %s: synced correctly\n", link.desc)
- }
-
- fmt.Println()
- if allGood && inGreeterGroup {
- fmt.Println("✓ All checks passed! Greeter is properly configured.")
- } else if !allGood {
- fmt.Println("⚠ Some issues detected. Run 'dms greeter sync' to fix symlinks.")
- }
-
- return nil
-}
diff --git a/nix/inputs/dms-cli/cmd/dms/commands_hyprland.go b/nix/inputs/dms-cli/cmd/dms/commands_hyprland.go
deleted file mode 100644
index 46958ff..0000000
--- a/nix/inputs/dms-cli/cmd/dms/commands_hyprland.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "fmt"
- "os"
-
- "github.com/AvengeMedia/danklinux/internal/hyprland"
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/spf13/cobra"
-)
-
-var hyprlandCmd = &cobra.Command{
- Use: "hyprland",
- Short: "Hyprland utilities",
- Long: "Utilities for working with Hyprland configuration",
-}
-
-var hyprlandKeybindsCmd = &cobra.Command{
- Use: "keybinds",
- Short: "Parse Hyprland keybinds",
- Long: "Parse keybinds from Hyprland configuration files",
- Run: runHyprlandKeybinds,
-}
-
-func init() {
- hyprlandKeybindsCmd.Flags().String("path", "$HOME/.config/hypr", "Path to Hyprland config directory")
- hyprlandCmd.AddCommand(hyprlandKeybindsCmd)
-}
-
-func runHyprlandKeybinds(cmd *cobra.Command, args []string) {
- path, _ := cmd.Flags().GetString("path")
-
- section, err := hyprland.ParseKeys(path)
- if err != nil {
- log.Fatalf("Error parsing keybinds: %v", err)
- }
-
- output, err := json.Marshal(section)
- if err != nil {
- log.Fatalf("Error generating JSON: %v", err)
- }
-
- fmt.Fprintln(os.Stdout, string(output))
-}
diff --git a/nix/inputs/dms-cli/cmd/dms/commands_root.go b/nix/inputs/dms-cli/cmd/dms/commands_root.go
deleted file mode 100644
index 67002b5..0000000
--- a/nix/inputs/dms-cli/cmd/dms/commands_root.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package main
-
-import (
- "errors"
- "os"
-
- "github.com/AvengeMedia/danklinux/internal/distros"
- "github.com/AvengeMedia/danklinux/internal/dms"
- "github.com/AvengeMedia/danklinux/internal/log"
- tea "github.com/charmbracelet/bubbletea"
- "github.com/spf13/cobra"
-)
-
-var rootCmd = &cobra.Command{
- Use: "dms",
- Short: "dms CLI",
- Long: "dms is the DankMaterialShell management CLI and backend server.",
- Run: runInteractiveMode,
-}
-
-func runInteractiveMode(cmd *cobra.Command, args []string) {
- detector, err := dms.NewDetector()
- if err != nil && !errors.Is(err, &distros.UnsupportedDistributionError{}) {
- log.Fatalf("Error initializing DMS detector: %v", err)
- } else if errors.Is(err, &distros.UnsupportedDistributionError{}) {
- log.Error("Interactive mode is not supported on this distribution.")
- log.Info("Please run 'dms --help' for available commands.")
- os.Exit(1)
- }
-
- if !detector.IsDMSInstalled() {
- log.Error("DankMaterialShell (DMS) is not detected as installed on this system.")
- log.Info("Please install DMS using dankinstall before using this management interface.")
- os.Exit(1)
- }
-
- model := dms.NewModel(Version)
- p := tea.NewProgram(model, tea.WithAltScreen())
- if _, err := p.Run(); err != nil {
- log.Fatalf("Error running program: %v", err)
- }
-}
diff --git a/nix/inputs/dms-cli/cmd/dms/main.go b/nix/inputs/dms-cli/cmd/dms/main.go
deleted file mode 100644
index f1a8d47..0000000
--- a/nix/inputs/dms-cli/cmd/dms/main.go
+++ /dev/null
@@ -1,44 +0,0 @@
-//go:build !distro_binary
-
-package main
-
-import (
- "os"
-
- "github.com/AvengeMedia/danklinux/internal/log"
-)
-
-var Version = "dev"
-
-func init() {
- runCmd.Flags().BoolP("daemon", "d", false, "Run in daemon mode")
- runCmd.Flags().Bool("daemon-child", false, "Internal flag for daemon child process")
- runCmd.Flags().Bool("session", false, "Session managed (like as a systemd unit)")
- runCmd.Flags().MarkHidden("daemon-child")
-
- // Add subcommands to greeter
- greeterCmd.AddCommand(greeterInstallCmd, greeterSyncCmd, greeterEnableCmd, greeterStatusCmd)
-
- // Add subcommands to update
- updateCmd.AddCommand(updateCheckCmd)
-
- // Add subcommands to plugins
- pluginsCmd.AddCommand(pluginsBrowseCmd, pluginsListCmd, pluginsInstallCmd, pluginsUninstallCmd)
-
- // Add common commands to root
- rootCmd.AddCommand(getCommonCommands()...)
-
- rootCmd.AddCommand(updateCmd)
-
- rootCmd.SetHelpTemplate(getHelpTemplate())
-}
-
-func main() {
- if os.Geteuid() == 0 {
- log.Fatal("This program should not be run as root. Exiting.")
- }
-
- if err := rootCmd.Execute(); err != nil {
- log.Fatal(err)
- }
-}
diff --git a/nix/inputs/dms-cli/cmd/dms/main_distro.go b/nix/inputs/dms-cli/cmd/dms/main_distro.go
deleted file mode 100644
index ffb311e..0000000
--- a/nix/inputs/dms-cli/cmd/dms/main_distro.go
+++ /dev/null
@@ -1,41 +0,0 @@
-//go:build distro_binary
-
-package main
-
-import (
- "os"
-
- "github.com/AvengeMedia/danklinux/internal/log"
-)
-
-var Version = "dev"
-
-func init() {
- // Add flags
- runCmd.Flags().BoolP("daemon", "d", false, "Run in daemon mode")
- runCmd.Flags().Bool("daemon-child", false, "Internal flag for daemon child process")
- runCmd.Flags().Bool("session", false, "Session managed (like as a systemd unit)")
- runCmd.Flags().MarkHidden("daemon-child")
-
- // Add subcommands to greeter
- greeterCmd.AddCommand(greeterSyncCmd, greeterEnableCmd, greeterStatusCmd)
-
- // Add subcommands to plugins
- pluginsCmd.AddCommand(pluginsBrowseCmd, pluginsListCmd, pluginsInstallCmd, pluginsUninstallCmd)
-
- // Add common commands to root
- rootCmd.AddCommand(getCommonCommands()...)
-
- rootCmd.SetHelpTemplate(getHelpTemplate())
-}
-
-func main() {
- // Block root
- if os.Geteuid() == 0 {
- log.Fatal("This program should not be run as root. Exiting.")
- }
-
- if err := rootCmd.Execute(); err != nil {
- log.Fatal(err)
- }
-}
diff --git a/nix/inputs/dms-cli/cmd/dms/shell.go b/nix/inputs/dms-cli/cmd/dms/shell.go
deleted file mode 100644
index 44289e0..0000000
--- a/nix/inputs/dms-cli/cmd/dms/shell.go
+++ /dev/null
@@ -1,500 +0,0 @@
-package main
-
-import (
- "context"
- "fmt"
- "os"
- "os/exec"
- "os/signal"
- "path/filepath"
- "strconv"
- "strings"
- "syscall"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/AvengeMedia/danklinux/internal/server"
-)
-
-var isSessionManaged bool
-
-func execDetachedRestart(targetPID int) {
- selfPath, err := os.Executable()
- if err != nil {
- return
- }
-
- cmd := exec.Command(selfPath, "restart-detached", strconv.Itoa(targetPID))
- cmd.SysProcAttr = &syscall.SysProcAttr{
- Setsid: true,
- }
- cmd.Start()
-}
-
-func runDetachedRestart(targetPIDStr string) {
- targetPID, err := strconv.Atoi(targetPIDStr)
- if err != nil {
- return
- }
-
- time.Sleep(200 * time.Millisecond)
-
- proc, err := os.FindProcess(targetPID)
- if err == nil {
- proc.Signal(syscall.SIGTERM)
- }
-
- time.Sleep(500 * time.Millisecond)
-
- killShell()
- runShellDaemon(false)
-}
-
-func locateDMSConfig() (string, error) {
- var searchPaths []string
-
- configHome := os.Getenv("XDG_CONFIG_HOME")
- if configHome == "" {
- if homeDir, err := os.UserHomeDir(); err == nil {
- configHome = filepath.Join(homeDir, ".config")
- }
- }
-
- if configHome != "" {
- searchPaths = append(searchPaths, filepath.Join(configHome, "quickshell", "dms"))
- }
-
- searchPaths = append(searchPaths, "/usr/share/quickshell/dms")
-
- configDirs := os.Getenv("XDG_CONFIG_DIRS")
- if configDirs == "" {
- configDirs = "/etc/xdg"
- }
-
- for _, dir := range strings.Split(configDirs, ":") {
- if dir != "" {
- searchPaths = append(searchPaths, filepath.Join(dir, "quickshell", "dms"))
- }
- }
-
- for _, path := range searchPaths {
- shellPath := filepath.Join(path, "shell.qml")
- if info, err := os.Stat(shellPath); err == nil && !info.IsDir() {
- return path, nil
- }
- }
-
- return "", fmt.Errorf("could not find DMS config (shell.qml) in any valid config path")
-}
-
-func getRuntimeDir() string {
- if runtime := os.Getenv("XDG_RUNTIME_DIR"); runtime != "" {
- return runtime
- }
- return os.TempDir()
-}
-
-func getPIDFilePath() string {
- return filepath.Join(getRuntimeDir(), fmt.Sprintf("danklinux-%d.pid", os.Getpid()))
-}
-
-func writePIDFile(childPID int) error {
- pidFile := getPIDFilePath()
- return os.WriteFile(pidFile, []byte(strconv.Itoa(childPID)), 0644)
-}
-
-func removePIDFile() {
- pidFile := getPIDFilePath()
- os.Remove(pidFile)
-}
-
-func getAllDMSPIDs() []int {
- dir := getRuntimeDir()
- entries, err := os.ReadDir(dir)
- if err != nil {
- return nil
- }
-
- var pids []int
-
- for _, entry := range entries {
- if !strings.HasPrefix(entry.Name(), "danklinux-") || !strings.HasSuffix(entry.Name(), ".pid") {
- continue
- }
-
- pidFile := filepath.Join(dir, entry.Name())
- data, err := os.ReadFile(pidFile)
- if err != nil {
- continue
- }
-
- childPID, err := strconv.Atoi(strings.TrimSpace(string(data)))
- if err != nil {
- os.Remove(pidFile)
- continue
- }
-
- // Check if the child process is still alive
- proc, err := os.FindProcess(childPID)
- if err != nil {
- os.Remove(pidFile)
- continue
- }
-
- if err := proc.Signal(syscall.Signal(0)); err != nil {
- // Process is dead, remove stale PID file
- os.Remove(pidFile)
- continue
- }
-
- pids = append(pids, childPID)
-
- // Also get the parent PID from the filename
- parentPIDStr := strings.TrimPrefix(entry.Name(), "danklinux-")
- parentPIDStr = strings.TrimSuffix(parentPIDStr, ".pid")
- if parentPID, err := strconv.Atoi(parentPIDStr); err == nil {
- // Check if parent is still alive
- if parentProc, err := os.FindProcess(parentPID); err == nil {
- if err := parentProc.Signal(syscall.Signal(0)); err == nil {
- pids = append(pids, parentPID)
- }
- }
- }
- }
-
- return pids
-}
-
-func runShellInteractive(session bool) {
- isSessionManaged = session
- go printASCII()
- fmt.Fprintf(os.Stderr, "dms %s\n", Version)
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- socketPath := server.GetSocketPath()
-
- errChan := make(chan error, 2)
-
- go func() {
- if err := server.Start(false); err != nil {
- errChan <- fmt.Errorf("server error: %w", err)
- }
- }()
-
- configPath, err := locateDMSConfig()
- if err != nil {
- log.Fatalf("Error locating DMS config: %v", err)
- }
-
- log.Infof("Spawning quickshell with -p %s", configPath)
-
- cmd := exec.CommandContext(ctx, "qs", "-p", configPath)
- cmd.Env = append(os.Environ(), "DMS_SOCKET="+socketPath)
- if qtRules := log.GetQtLoggingRules(); qtRules != "" {
- cmd.Env = append(cmd.Env, "QT_LOGGING_RULES="+qtRules)
- }
-
- homeDir, err := os.UserHomeDir()
- if err == nil && os.Getenv("DMS_DISABLE_HOT_RELOAD") == "" {
- if !strings.HasPrefix(configPath, homeDir) {
- cmd.Env = append(cmd.Env, "DMS_DISABLE_HOT_RELOAD=1")
- }
- }
-
- cmd.Stdin = os.Stdin
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
-
- if err := cmd.Start(); err != nil {
- log.Fatalf("Error starting quickshell: %v", err)
- }
-
- // Write PID file for the quickshell child process
- if err := writePIDFile(cmd.Process.Pid); err != nil {
- log.Warnf("Failed to write PID file: %v", err)
- }
- defer removePIDFile()
-
- sigChan := make(chan os.Signal, 1)
- signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1)
-
- go func() {
- if err := cmd.Wait(); err != nil {
- errChan <- fmt.Errorf("quickshell exited: %w", err)
- } else {
- errChan <- fmt.Errorf("quickshell exited")
- }
- }()
-
- for {
- select {
- case sig := <-sigChan:
- // Handle SIGUSR1 restart for non-session managed processes
- if sig == syscall.SIGUSR1 && !isSessionManaged {
- log.Infof("Received SIGUSR1, spawning detached restart process...")
- execDetachedRestart(os.Getpid())
- // Exit immediately to avoid race conditions with detached restart
- return
- }
-
- // All other signals: clean shutdown
- log.Infof("\nReceived signal %v, shutting down...", sig)
- cancel()
- cmd.Process.Signal(syscall.SIGTERM)
- os.Remove(socketPath)
- return
-
- case err := <-errChan:
- log.Error(err)
- cancel()
- if cmd.Process != nil {
- cmd.Process.Signal(syscall.SIGTERM)
- }
- os.Remove(socketPath)
- os.Exit(1)
- }
- }
-}
-
-func restartShell() {
- pids := getAllDMSPIDs()
-
- if len(pids) == 0 {
- log.Info("No running DMS shell instances found. Starting daemon...")
- runShellDaemon(false)
- return
- }
-
- currentPid := os.Getpid()
- uniquePids := make(map[int]bool)
-
- for _, pid := range pids {
- if pid != currentPid {
- uniquePids[pid] = true
- }
- }
-
- for pid := range uniquePids {
- proc, err := os.FindProcess(pid)
- if err != nil {
- log.Errorf("Error finding process %d: %v", pid, err)
- continue
- }
-
- if err := proc.Signal(syscall.Signal(0)); err != nil {
- continue
- }
-
- if err := proc.Signal(syscall.SIGUSR1); err != nil {
- log.Errorf("Error sending SIGUSR1 to process %d: %v", pid, err)
- } else {
- log.Infof("Sent SIGUSR1 to DMS process with PID %d", pid)
- }
- }
-}
-
-func killShell() {
- // Get all tracked DMS PIDs from PID files
- pids := getAllDMSPIDs()
-
- if len(pids) == 0 {
- log.Info("No running DMS shell instances found.")
- return
- }
-
- currentPid := os.Getpid()
- uniquePids := make(map[int]bool)
-
- // Deduplicate and filter out current process
- for _, pid := range pids {
- if pid != currentPid {
- uniquePids[pid] = true
- }
- }
-
- // Kill all tracked processes
- for pid := range uniquePids {
- proc, err := os.FindProcess(pid)
- if err != nil {
- log.Errorf("Error finding process %d: %v", pid, err)
- continue
- }
-
- // Check if process is still alive before killing
- if err := proc.Signal(syscall.Signal(0)); err != nil {
- continue
- }
-
- if err := proc.Kill(); err != nil {
- log.Errorf("Error killing process %d: %v", pid, err)
- } else {
- log.Infof("Killed DMS process with PID %d", pid)
- }
- }
-
- // Clean up any remaining PID files
- dir := getRuntimeDir()
- entries, err := os.ReadDir(dir)
- if err != nil {
- return
- }
-
- for _, entry := range entries {
- if strings.HasPrefix(entry.Name(), "danklinux-") && strings.HasSuffix(entry.Name(), ".pid") {
- pidFile := filepath.Join(dir, entry.Name())
- os.Remove(pidFile)
- }
- }
-}
-
-func runShellDaemon(session bool) {
- isSessionManaged = session
- // Check if this is the daemon child process by looking for the hidden flag
- isDaemonChild := false
- for _, arg := range os.Args {
- if arg == "--daemon-child" {
- isDaemonChild = true
- break
- }
- }
-
- if !isDaemonChild {
- fmt.Fprintf(os.Stderr, "dms %s\n", Version)
-
- cmd := exec.Command(os.Args[0], "run", "-d", "--daemon-child")
- cmd.Env = os.Environ()
-
- cmd.SysProcAttr = &syscall.SysProcAttr{
- Setsid: true,
- }
-
- if err := cmd.Start(); err != nil {
- log.Fatalf("Error starting daemon: %v", err)
- }
-
- log.Infof("DMS shell daemon started (PID: %d)", cmd.Process.Pid)
- return
- }
-
- fmt.Fprintf(os.Stderr, "dms %s\n", Version)
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- socketPath := server.GetSocketPath()
-
- errChan := make(chan error, 2)
-
- go func() {
- if err := server.Start(false); err != nil {
- errChan <- fmt.Errorf("server error: %w", err)
- }
- }()
-
- configPath, err := locateDMSConfig()
- if err != nil {
- log.Fatalf("Error locating DMS config: %v", err)
- }
-
- log.Infof("Spawning quickshell with -p %s", configPath)
-
- cmd := exec.CommandContext(ctx, "qs", "-p", configPath)
- cmd.Env = append(os.Environ(), "DMS_SOCKET="+socketPath)
- if qtRules := log.GetQtLoggingRules(); qtRules != "" {
- cmd.Env = append(cmd.Env, "QT_LOGGING_RULES="+qtRules)
- }
-
- homeDir, err := os.UserHomeDir()
- if err == nil && os.Getenv("DMS_DISABLE_HOT_RELOAD") == "" {
- if !strings.HasPrefix(configPath, homeDir) {
- cmd.Env = append(cmd.Env, "DMS_DISABLE_HOT_RELOAD=1")
- }
- }
-
- devNull, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
- if err != nil {
- log.Fatalf("Error opening /dev/null: %v", err)
- }
- defer devNull.Close()
-
- cmd.Stdin = devNull
- cmd.Stdout = devNull
- cmd.Stderr = devNull
-
- if err := cmd.Start(); err != nil {
- log.Fatalf("Error starting daemon: %v", err)
- }
-
- // Write PID file for the quickshell child process
- if err := writePIDFile(cmd.Process.Pid); err != nil {
- log.Warnf("Failed to write PID file: %v", err)
- }
- defer removePIDFile()
-
- sigChan := make(chan os.Signal, 1)
- signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1)
-
- go func() {
- if err := cmd.Wait(); err != nil {
- errChan <- fmt.Errorf("quickshell exited: %w", err)
- } else {
- errChan <- fmt.Errorf("quickshell exited")
- }
- }()
-
- for {
- select {
- case sig := <-sigChan:
- // Handle SIGUSR1 restart for non-session managed processes
- if sig == syscall.SIGUSR1 && !isSessionManaged {
- log.Infof("Received SIGUSR1, spawning detached restart process...")
- execDetachedRestart(os.Getpid())
- // Exit immediately to avoid race conditions with detached restart
- return
- }
-
- // All other signals: clean shutdown
- cancel()
- cmd.Process.Signal(syscall.SIGTERM)
- os.Remove(socketPath)
- return
-
- case <-errChan:
- cancel()
- if cmd.Process != nil {
- cmd.Process.Signal(syscall.SIGTERM)
- }
- os.Remove(socketPath)
- os.Exit(1)
- }
- }
-}
-
-func runShellIPCCommand(args []string) {
- if len(args) == 0 {
- log.Error("IPC command requires arguments")
- log.Info("Usage: dms ipc [args...]")
- os.Exit(1)
- }
-
- if args[0] != "call" {
- args = append([]string{"call"}, args...)
- }
-
- configPath, err := locateDMSConfig()
- if err != nil {
- log.Fatalf("Error locating DMS config: %v", err)
- }
-
- cmdArgs := append([]string{"-p", configPath, "ipc"}, args...)
- cmd := exec.Command("qs", cmdArgs...)
- cmd.Stdin = os.Stdin
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
-
- if err := cmd.Run(); err != nil {
- log.Fatalf("Error running IPC command: %v", err)
- }
-}
diff --git a/nix/inputs/dms-cli/cmd/dms/ui.go b/nix/inputs/dms-cli/cmd/dms/ui.go
deleted file mode 100644
index 23d8795..0000000
--- a/nix/inputs/dms-cli/cmd/dms/ui.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package main
-
-import (
- "fmt"
-
- "github.com/AvengeMedia/danklinux/internal/tui"
- "github.com/charmbracelet/lipgloss"
-)
-
-func printASCII() {
- fmt.Print(getThemedASCII())
-}
-
-func getThemedASCII() string {
- theme := tui.TerminalTheme()
-
- logo := `
-██████╗ █████╗ ███╗ ██╗██╗ ██╗
-██╔══██╗██╔══██╗████╗ ██║██║ ██╔╝
-██║ ██║███████║██╔██╗ ██║█████╔╝
-██║ ██║██╔══██║██║╚██╗██║██╔═██╗
-██████╔╝██║ ██║██║ ╚████║██║ ██╗
-╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝`
-
- style := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)).
- Bold(true)
-
- return style.Render(logo) + "\n"
-}
-
-func getHelpTemplate() string {
- return getThemedASCII() + `
-{{.Long}}
-
-Usage:
- {{.UseLine}}{{if .HasAvailableSubCommands}}
-
-Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
- {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
-
-Flags:
-{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
-
-Global Flags:
-{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}
-
-Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
- {{rpad .Name .NamePadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
-
-Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
-`
-}
diff --git a/nix/inputs/dms-cli/cmd/dms/utils.go b/nix/inputs/dms-cli/cmd/dms/utils.go
deleted file mode 100644
index fe9dcee..0000000
--- a/nix/inputs/dms-cli/cmd/dms/utils.go
+++ /dev/null
@@ -1,14 +0,0 @@
-package main
-
-import "os/exec"
-
-func commandExists(cmd string) bool {
- _, err := exec.LookPath(cmd)
- return err == nil
-}
-
-func isArchPackageInstalled(packageName string) bool {
- cmd := exec.Command("pacman", "-Q", packageName)
- err := cmd.Run()
- return err == nil
-}
diff --git a/nix/inputs/dms-cli/flake.lock b/nix/inputs/dms-cli/flake.lock
deleted file mode 100644
index 17542b5..0000000
--- a/nix/inputs/dms-cli/flake.lock
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "nodes": {
- "nixpkgs": {
- "locked": {
- "lastModified": 1760878510,
- "narHash": "sha256-K5Osef2qexezUfs0alLvZ7nQFTGS9DL2oTVsIXsqLgs=",
- "owner": "NixOS",
- "repo": "nixpkgs",
- "rev": "5e2a59a5b1a82f89f2c7e598302a9cacebb72a67",
- "type": "github"
- },
- "original": {
- "owner": "NixOS",
- "ref": "nixos-unstable",
- "repo": "nixpkgs",
- "type": "github"
- }
- },
- "root": {
- "inputs": {
- "nixpkgs": "nixpkgs"
- }
- }
- },
- "root": "root",
- "version": 7
-}
diff --git a/nix/inputs/dms-cli/flake.nix b/nix/inputs/dms-cli/flake.nix
deleted file mode 100644
index f5efcf6..0000000
--- a/nix/inputs/dms-cli/flake.nix
+++ /dev/null
@@ -1,61 +0,0 @@
-{
- description = "DankMaterialShell Command Line Interface";
-
- inputs = {
- nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
- };
-
- outputs =
- { self, nixpkgs }:
- let
- supportedSystems = [
- "x86_64-linux"
- "aarch64-linux"
- ];
-
- forAllSystems =
- f:
- builtins.listToAttrs (
- map (system: {
- name = system;
- value = f system;
- }) supportedSystems
- );
-
- in
- {
- packages = forAllSystems (
- system:
- let
- pkgs = import nixpkgs { inherit system; };
- lib = pkgs.lib;
- in
- {
- dms-cli = pkgs.buildGoModule (finalAttrs: {
- pname = "dms-cli";
- version = "0.4.1";
- src = ./.;
- vendorHash = "sha256-XbCg6qQwD4g4R/hBReLGE4NOq9uv0LBqogmfpBs//Ic=";
-
- subPackages = [ "cmd/dms" ];
-
- ldflags = [
- "-s"
- "-w"
- "-X main.Version=${finalAttrs.version}"
- ];
-
- meta = {
- description = "DankMaterialShell Command Line Interface";
- homepage = "https://github.com/AvengeMedia/danklinux";
- mainProgram = "dms";
- license = lib.licenses.mit;
- platforms = lib.platforms.unix;
- };
- });
-
- default = self.packages.${system}.dms-cli;
- }
- );
- };
-}
diff --git a/nix/inputs/dms-cli/go.mod b/nix/inputs/dms-cli/go.mod
deleted file mode 100644
index 3477b80..0000000
--- a/nix/inputs/dms-cli/go.mod
+++ /dev/null
@@ -1,65 +0,0 @@
-module github.com/AvengeMedia/danklinux
-
-go 1.24.6
-
-require (
- github.com/Wifx/gonetworkmanager/v2 v2.2.0
- github.com/charmbracelet/bubbles v0.21.0
- github.com/charmbracelet/bubbletea v1.3.6
- github.com/charmbracelet/lipgloss v1.1.0
- github.com/charmbracelet/log v0.4.2
- github.com/godbus/dbus/v5 v5.1.0
- github.com/spf13/cobra v1.9.1
- github.com/stretchr/testify v1.11.1
- github.com/yaslama/go-wayland/wayland v0.0.0-20250907155644-2874f32d9c34
- golang.org/x/exp v0.0.0-20231006140011-7918f672742d
-)
-
-require (
- github.com/Microsoft/go-winio v0.6.2 // indirect
- github.com/ProtonMail/go-crypto v1.3.0 // indirect
- github.com/cloudflare/circl v1.6.1 // indirect
- github.com/cyphar/filepath-securejoin v0.4.1 // indirect
- github.com/emirpasic/gods v1.18.1 // indirect
- github.com/go-git/gcfg/v2 v2.0.2 // indirect
- github.com/go-git/go-billy/v6 v6.0.0-20250627091229-31e2a16eef30 // indirect
- github.com/go-logfmt/logfmt v0.6.0 // indirect
- github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
- github.com/kevinburke/ssh_config v1.4.0 // indirect
- github.com/klauspost/cpuid/v2 v2.3.0 // indirect
- github.com/pjbgf/sha1cd v0.5.0 // indirect
- github.com/sergi/go-diff v1.4.0 // indirect
- github.com/stretchr/objx v0.5.2 // indirect
- golang.org/x/crypto v0.42.0 // indirect
- golang.org/x/net v0.44.0 // indirect
-)
-
-require (
- github.com/atotto/clipboard v0.1.4 // indirect
- github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
- github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
- github.com/charmbracelet/harmonica v0.2.0 // indirect
- github.com/charmbracelet/x/ansi v0.9.3 // indirect
- github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
- github.com/charmbracelet/x/term v0.2.1 // indirect
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
- github.com/go-git/go-git/v6 v6.0.0-20250929195514-145daf2492dd
- github.com/inconshreveable/mousetrap v1.1.0 // indirect
- github.com/lucasb-eyer/go-colorful v1.3.0
- github.com/mattn/go-isatty v0.0.20 // indirect
- github.com/mattn/go-localereader v0.0.1 // indirect
- github.com/mattn/go-runewidth v0.0.16 // indirect
- github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
- github.com/muesli/cancelreader v0.2.2 // indirect
- github.com/muesli/termenv v0.16.0 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/rivo/uniseg v0.4.7 // indirect
- github.com/spf13/afero v1.15.0
- github.com/spf13/pflag v1.0.6 // indirect
- github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
- golang.org/x/sync v0.17.0 // indirect
- golang.org/x/sys v0.36.0
- golang.org/x/text v0.29.0 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
-)
diff --git a/nix/inputs/dms-cli/go.sum b/nix/inputs/dms-cli/go.sum
deleted file mode 100644
index cc84792..0000000
--- a/nix/inputs/dms-cli/go.sum
+++ /dev/null
@@ -1,141 +0,0 @@
-github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
-github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
-github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
-github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
-github.com/Wifx/gonetworkmanager/v2 v2.2.0 h1:kPstgsQtY8CmDOOFZd81ytM9Gi3f6ImzPCKF7nNhQ2U=
-github.com/Wifx/gonetworkmanager/v2 v2.2.0/go.mod h1:fMDb//SHsKWxyDUAwXvCqurV3npbIyyaQWenGpZ/uXg=
-github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
-github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
-github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
-github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
-github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
-github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
-github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
-github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
-github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
-github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
-github.com/charmbracelet/bubbletea v1.3.6 h1:VkHIxPJQeDt0aFJIsVxw8BQdh/F/L2KKZGsK6et5taU=
-github.com/charmbracelet/bubbletea v1.3.6/go.mod h1:oQD9VCRQFF8KplacJLo28/jofOI2ToOfGYeFgBBxHOc=
-github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
-github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
-github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
-github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
-github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
-github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
-github.com/charmbracelet/log v0.4.2 h1:hYt8Qj6a8yLnvR+h7MwsJv/XvmBJXiueUcI3cIxsyig=
-github.com/charmbracelet/log v0.4.2/go.mod h1:qifHGX/tc7eluv2R6pWIpyHDDrrb/AG71Pf2ysQu5nw=
-github.com/charmbracelet/x/ansi v0.9.3 h1:BXt5DHS/MKF+LjuK4huWrC6NCvHtexww7dMayh6GXd0=
-github.com/charmbracelet/x/ansi v0.9.3/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
-github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
-github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
-github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
-github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
-github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
-github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
-github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
-github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
-github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
-github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
-github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
-github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
-github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
-github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
-github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
-github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
-github.com/go-git/gcfg/v2 v2.0.2 h1:MY5SIIfTGGEMhdA7d7JePuVVxtKL7Hp+ApGDJAJ7dpo=
-github.com/go-git/gcfg/v2 v2.0.2/go.mod h1:/lv2NsxvhepuMrldsFilrgct6pxzpGdSRC13ydTLSLs=
-github.com/go-git/go-billy/v6 v6.0.0-20250627091229-31e2a16eef30 h1:4KqVJTL5eanN8Sgg3BV6f2/QzfZEFbCd+rTak1fGRRA=
-github.com/go-git/go-billy/v6 v6.0.0-20250627091229-31e2a16eef30/go.mod h1:snwvGrbywVFy2d6KJdQ132zapq4aLyzLMgpo79XdEfM=
-github.com/go-git/go-git-fixtures/v5 v5.1.1 h1:OH8i1ojV9bWfr0ZfasfpgtUXQHQyVS8HXik/V1C099w=
-github.com/go-git/go-git-fixtures/v5 v5.1.1/go.mod h1:Altk43lx3b1ks+dVoAG2300o5WWUnktvfY3VI6bcaXU=
-github.com/go-git/go-git/v6 v6.0.0-20250929195514-145daf2492dd h1:30HEd5KKVM7GgMJ1GSNuYxuZXEg8Pdlngp6T51faxoc=
-github.com/go-git/go-git/v6 v6.0.0-20250929195514-145daf2492dd/go.mod h1:lz8PQr/p79XpFq5ODVBwRJu5LnOF8Et7j95ehqmCMJU=
-github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
-github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
-github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
-github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
-github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
-github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
-github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ=
-github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
-github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
-github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
-github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
-github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
-github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
-github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
-github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
-github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
-github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
-github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
-github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
-github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
-github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
-github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
-github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0=
-github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
-github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
-github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
-github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
-github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
-github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
-github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
-github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
-github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
-github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
-github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
-github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
-github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
-github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
-github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
-github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
-github.com/yaslama/go-wayland/wayland v0.0.0-20250907155644-2874f32d9c34 h1:iTAt1me6SBYsuzrl/CmrxtATPlOG/pVviosM3DhUdKE=
-github.com/yaslama/go-wayland/wayland v0.0.0-20250907155644-2874f32d9c34/go.mod h1:jzmUN5lUAv2O8e63OvcauV4S30rIZ1BvF/PNYE37vDo=
-golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
-golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
-golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
-golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
-golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
-golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
-golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
-golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
-golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
-golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
-golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
-golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
-golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/nix/inputs/dms-cli/install.sh b/nix/inputs/dms-cli/install.sh
deleted file mode 100755
index 11b36d4..0000000
--- a/nix/inputs/dms-cli/install.sh
+++ /dev/null
@@ -1,86 +0,0 @@
-#!/bin/sh
-
-set -e
-
-# Colors for output
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-NC='\033[0m' # No Color
-
-# Check for root privileges
-if [ "$(id -u)" == "0" ]; then
- printf "%bError: This script must not be run as root%b\n" "$RED" "$NC"
- exit 1
-fi
-
-# Check if running on Linux
-if [ "$(uname)" != "Linux" ]; then
- printf "%bError: This installer only supports Linux systems%b\n" "$RED" "$NC"
- exit 1
-fi
-
-# Detect architecture
-ARCH=$(uname -m)
-case "$ARCH" in
- x86_64)
- ARCH="amd64"
- ;;
- aarch64)
- ARCH="arm64"
- ;;
- *)
- printf "%bError: Unsupported architecture: %s%b\n" "$RED" "$ARCH" "$NC"
- printf "This installer only supports x86_64 (amd64) and aarch64 (arm64) architectures\n"
- exit 1
- ;;
-esac
-
-# Get the latest release version
-LATEST_VERSION=$(curl -s https://api.github.com/repos/AvengeMedia/danklinux/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"
- exit 1
-fi
-
-printf "%bInstalling Dankinstall %s for %s...%b\n" "$GREEN" "$LATEST_VERSION" "$ARCH" "$NC"
-
-# Download and install
-TEMP_DIR=$(mktemp -d)
-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/danklinux/releases/download/$LATEST_VERSION/dankinstall-$ARCH.gz" -o "installer.gz"
-curl -L "https://github.com/AvengeMedia/danklinux/releases/download/$LATEST_VERSION/dankinstall-$ARCH.gz.sha256" -o "expected.sha256"
-
-# Get the expected checksum
-EXPECTED_CHECKSUM=$(cat expected.sha256 | awk '{print $1}')
-
-# Calculate actual checksum
-printf "%bVerifying checksum...%b\n" "$GREEN" "$NC"
-ACTUAL_CHECKSUM=$(sha256sum installer.gz | awk '{print $1}')
-
-# Compare checksums
-if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then
- printf "%bError: Checksum verification failed%b\n" "$RED" "$NC"
- printf "Expected: %s\n" "$EXPECTED_CHECKSUM"
- printf "Got: %s\n" "$ACTUAL_CHECKSUM"
- printf "The downloaded file may be corrupted or tampered with\n"
- cd - > /dev/null
- rm -rf "$TEMP_DIR"
- exit 1
-fi
-
-# Decompress the binary
-printf "%bDecompressing installer...%b\n" "$GREEN" "$NC"
-gunzip installer.gz
-chmod +x installer
-
-# Execute the installer
-printf "%bRunning installer...%b\n" "$GREEN" "$NC"
-./installer
-
-# Cleanup
-cd - > /dev/null
-rm -rf "$TEMP_DIR"
\ No newline at end of file
diff --git a/nix/inputs/dms-cli/internal/config/deployer.go b/nix/inputs/dms-cli/internal/config/deployer.go
deleted file mode 100644
index 1db3fe5..0000000
--- a/nix/inputs/dms-cli/internal/config/deployer.go
+++ /dev/null
@@ -1,574 +0,0 @@
-package config
-
-import (
- "context"
- "fmt"
- "os"
- "path/filepath"
- "regexp"
- "strings"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
-)
-
-type ConfigDeployer struct {
- logChan chan<- string
-}
-
-type DeploymentResult struct {
- ConfigType string
- Path string
- BackupPath string
- Deployed bool
- Error error
-}
-
-func NewConfigDeployer(logChan chan<- string) *ConfigDeployer {
- return &ConfigDeployer{
- logChan: logChan,
- }
-}
-
-func (cd *ConfigDeployer) log(message string) {
- if cd.logChan != nil {
- cd.logChan <- message
- }
-}
-
-// DeployConfigurations deploys all necessary configurations based on the chosen window manager
-func (cd *ConfigDeployer) DeployConfigurations(ctx context.Context, wm deps.WindowManager) ([]DeploymentResult, error) {
- return cd.DeployConfigurationsWithTerminal(ctx, wm, deps.TerminalGhostty)
-}
-
-// DeployConfigurationsWithTerminal deploys all necessary configurations based on chosen window manager and terminal
-func (cd *ConfigDeployer) DeployConfigurationsWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]DeploymentResult, error) {
- return cd.DeployConfigurationsSelective(ctx, wm, terminal, nil, nil)
-}
-
-func (cd *ConfigDeployer) DeployConfigurationsSelective(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal, installedDeps []deps.Dependency, replaceConfigs map[string]bool) ([]DeploymentResult, error) {
- return cd.DeployConfigurationsSelectiveWithReinstalls(ctx, wm, terminal, installedDeps, replaceConfigs, nil)
-}
-
-func (cd *ConfigDeployer) DeployConfigurationsSelectiveWithReinstalls(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal, installedDeps []deps.Dependency, replaceConfigs map[string]bool, reinstallItems map[string]bool) ([]DeploymentResult, error) {
- var results []DeploymentResult
-
- shouldReplaceConfig := func(configType string) bool {
- if replaceConfigs == nil {
- return true
- }
- replace, exists := replaceConfigs[configType]
- return !exists || replace
- }
-
- switch wm {
- case deps.WindowManagerNiri:
- if shouldReplaceConfig("Niri") {
- result, err := cd.deployNiriConfig(terminal)
- results = append(results, result)
- if err != nil {
- return results, fmt.Errorf("failed to deploy Niri config: %w", err)
- }
- }
- case deps.WindowManagerHyprland:
- if shouldReplaceConfig("Hyprland") {
- result, err := cd.deployHyprlandConfig(terminal)
- results = append(results, result)
- if err != nil {
- return results, fmt.Errorf("failed to deploy Hyprland config: %w", err)
- }
- }
- }
-
- switch terminal {
- case deps.TerminalGhostty:
- if shouldReplaceConfig("Ghostty") {
- ghosttyResults, err := cd.deployGhosttyConfig()
- results = append(results, ghosttyResults...)
- if err != nil {
- return results, fmt.Errorf("failed to deploy Ghostty config: %w", err)
- }
- }
- case deps.TerminalKitty:
- if shouldReplaceConfig("Kitty") {
- kittyResults, err := cd.deployKittyConfig()
- results = append(results, kittyResults...)
- if err != nil {
- return results, fmt.Errorf("failed to deploy Kitty config: %w", err)
- }
- }
- case deps.TerminalAlacritty:
- if shouldReplaceConfig("Alacritty") {
- alacrittyResults, err := cd.deployAlacrittyConfig()
- results = append(results, alacrittyResults...)
- if err != nil {
- return results, fmt.Errorf("failed to deploy Alacritty config: %w", err)
- }
- }
- }
-
- return results, nil
-}
-
-// deployNiriConfig handles Niri configuration deployment with backup and merging
-func (cd *ConfigDeployer) deployNiriConfig(terminal deps.Terminal) (DeploymentResult, error) {
- result := DeploymentResult{
- ConfigType: "Niri",
- Path: filepath.Join(os.Getenv("HOME"), ".config", "niri", "config.kdl"),
- }
-
- configDir := filepath.Dir(result.Path)
- if err := os.MkdirAll(configDir, 0755); err != nil {
- result.Error = fmt.Errorf("failed to create config directory: %w", err)
- return result, result.Error
- }
-
- var existingConfig string
- if _, err := os.Stat(result.Path); err == nil {
- cd.log("Found existing Niri configuration")
-
- existingData, err := os.ReadFile(result.Path)
- if err != nil {
- result.Error = fmt.Errorf("failed to read existing config: %w", err)
- return result, result.Error
- }
- existingConfig = string(existingData)
-
- timestamp := time.Now().Format("2006-01-02_15-04-05")
- result.BackupPath = result.Path + ".backup." + timestamp
- if err := os.WriteFile(result.BackupPath, existingData, 0644); err != nil {
- result.Error = fmt.Errorf("failed to create backup: %w", err)
- return result, result.Error
- }
- cd.log(fmt.Sprintf("Backed up existing config to %s", result.BackupPath))
- }
-
- // Detect polkit agent path
- polkitPath, err := cd.detectPolkitAgent()
- if err != nil {
- cd.log(fmt.Sprintf("Warning: Could not detect polkit agent: %v", err))
- polkitPath = "/usr/lib/mate-polkit/polkit-mate-authentication-agent-1" // fallback
- }
-
- // Determine terminal command based on choice
- var terminalCommand string
- switch terminal {
- case deps.TerminalGhostty:
- terminalCommand = "ghostty"
- case deps.TerminalKitty:
- terminalCommand = "kitty"
- case deps.TerminalAlacritty:
- terminalCommand = "alacritty"
- default:
- terminalCommand = "ghostty" // fallback to ghostty
- }
-
- newConfig := strings.ReplaceAll(NiriConfig, "{{POLKIT_AGENT_PATH}}", polkitPath)
- newConfig = strings.ReplaceAll(newConfig, "{{TERMINAL_COMMAND}}", terminalCommand)
-
- // If there was an existing config, merge the output sections
- if existingConfig != "" {
- mergedConfig, err := cd.mergeNiriOutputSections(newConfig, existingConfig)
- if err != nil {
- cd.log(fmt.Sprintf("Warning: Failed to merge output sections: %v", err))
- } else {
- newConfig = mergedConfig
- cd.log("Successfully merged existing output sections")
- }
- }
-
- if err := os.WriteFile(result.Path, []byte(newConfig), 0644); err != nil {
- result.Error = fmt.Errorf("failed to write config: %w", err)
- return result, result.Error
- }
-
- result.Deployed = true
- cd.log("Successfully deployed Niri configuration")
- return result, nil
-}
-
-func (cd *ConfigDeployer) deployGhosttyConfig() ([]DeploymentResult, error) {
- var results []DeploymentResult
-
- mainResult := DeploymentResult{
- ConfigType: "Ghostty",
- Path: filepath.Join(os.Getenv("HOME"), ".config", "ghostty", "config"),
- }
-
- configDir := filepath.Dir(mainResult.Path)
- if err := os.MkdirAll(configDir, 0755); err != nil {
- mainResult.Error = fmt.Errorf("failed to create config directory: %w", err)
- return []DeploymentResult{mainResult}, mainResult.Error
- }
-
- if _, err := os.Stat(mainResult.Path); err == nil {
- cd.log("Found existing Ghostty configuration")
-
- existingData, err := os.ReadFile(mainResult.Path)
- if err != nil {
- mainResult.Error = fmt.Errorf("failed to read existing config: %w", err)
- return []DeploymentResult{mainResult}, mainResult.Error
- }
-
- timestamp := time.Now().Format("2006-01-02_15-04-05")
- mainResult.BackupPath = mainResult.Path + ".backup." + timestamp
- if err := os.WriteFile(mainResult.BackupPath, existingData, 0644); err != nil {
- mainResult.Error = fmt.Errorf("failed to create backup: %w", err)
- return []DeploymentResult{mainResult}, mainResult.Error
- }
- cd.log(fmt.Sprintf("Backed up existing config to %s", mainResult.BackupPath))
- }
-
- if err := os.WriteFile(mainResult.Path, []byte(GhosttyConfig), 0644); err != nil {
- mainResult.Error = fmt.Errorf("failed to write config: %w", err)
- return []DeploymentResult{mainResult}, mainResult.Error
- }
-
- mainResult.Deployed = true
- cd.log("Successfully deployed Ghostty configuration")
- results = append(results, mainResult)
-
- colorResult := DeploymentResult{
- ConfigType: "Ghostty Colors",
- Path: filepath.Join(os.Getenv("HOME"), ".config", "ghostty", "config-dankcolors"),
- }
-
- if err := os.WriteFile(colorResult.Path, []byte(GhosttyColorConfig), 0644); err != nil {
- colorResult.Error = fmt.Errorf("failed to write color config: %w", err)
- return results, colorResult.Error
- }
-
- colorResult.Deployed = true
- cd.log("Successfully deployed Ghostty color configuration")
- results = append(results, colorResult)
-
- return results, nil
-}
-
-func (cd *ConfigDeployer) deployKittyConfig() ([]DeploymentResult, error) {
- var results []DeploymentResult
-
- mainResult := DeploymentResult{
- ConfigType: "Kitty",
- Path: filepath.Join(os.Getenv("HOME"), ".config", "kitty", "kitty.conf"),
- }
-
- configDir := filepath.Dir(mainResult.Path)
- if err := os.MkdirAll(configDir, 0755); err != nil {
- mainResult.Error = fmt.Errorf("failed to create config directory: %w", err)
- return []DeploymentResult{mainResult}, mainResult.Error
- }
-
- if _, err := os.Stat(mainResult.Path); err == nil {
- cd.log("Found existing Kitty configuration")
-
- existingData, err := os.ReadFile(mainResult.Path)
- if err != nil {
- mainResult.Error = fmt.Errorf("failed to read existing config: %w", err)
- return []DeploymentResult{mainResult}, mainResult.Error
- }
-
- timestamp := time.Now().Format("2006-01-02_15-04-05")
- mainResult.BackupPath = mainResult.Path + ".backup." + timestamp
- if err := os.WriteFile(mainResult.BackupPath, existingData, 0644); err != nil {
- mainResult.Error = fmt.Errorf("failed to create backup: %w", err)
- return []DeploymentResult{mainResult}, mainResult.Error
- }
- cd.log(fmt.Sprintf("Backed up existing config to %s", mainResult.BackupPath))
- }
-
- if err := os.WriteFile(mainResult.Path, []byte(KittyConfig), 0644); err != nil {
- mainResult.Error = fmt.Errorf("failed to write config: %w", err)
- return []DeploymentResult{mainResult}, mainResult.Error
- }
-
- mainResult.Deployed = true
- cd.log("Successfully deployed Kitty configuration")
- results = append(results, mainResult)
-
- themeResult := DeploymentResult{
- ConfigType: "Kitty Theme",
- Path: filepath.Join(os.Getenv("HOME"), ".config", "kitty", "dank-theme.conf"),
- }
-
- if err := os.WriteFile(themeResult.Path, []byte(KittyThemeConfig), 0644); err != nil {
- themeResult.Error = fmt.Errorf("failed to write theme config: %w", err)
- return results, themeResult.Error
- }
-
- themeResult.Deployed = true
- cd.log("Successfully deployed Kitty theme configuration")
- results = append(results, themeResult)
-
- tabsResult := DeploymentResult{
- ConfigType: "Kitty Tabs",
- Path: filepath.Join(os.Getenv("HOME"), ".config", "kitty", "dank-tabs.conf"),
- }
-
- if err := os.WriteFile(tabsResult.Path, []byte(KittyTabsConfig), 0644); err != nil {
- tabsResult.Error = fmt.Errorf("failed to write tabs config: %w", err)
- return results, tabsResult.Error
- }
-
- tabsResult.Deployed = true
- cd.log("Successfully deployed Kitty tabs configuration")
- results = append(results, tabsResult)
-
- return results, nil
-}
-
-func (cd *ConfigDeployer) deployAlacrittyConfig() ([]DeploymentResult, error) {
- var results []DeploymentResult
-
- mainResult := DeploymentResult{
- ConfigType: "Alacritty",
- Path: filepath.Join(os.Getenv("HOME"), ".config", "alacritty", "alacritty.toml"),
- }
-
- configDir := filepath.Dir(mainResult.Path)
- if err := os.MkdirAll(configDir, 0755); err != nil {
- mainResult.Error = fmt.Errorf("failed to create config directory: %w", err)
- return []DeploymentResult{mainResult}, mainResult.Error
- }
-
- if _, err := os.Stat(mainResult.Path); err == nil {
- cd.log("Found existing Alacritty configuration")
-
- existingData, err := os.ReadFile(mainResult.Path)
- if err != nil {
- mainResult.Error = fmt.Errorf("failed to read existing config: %w", err)
- return []DeploymentResult{mainResult}, mainResult.Error
- }
-
- timestamp := time.Now().Format("2006-01-02_15-04-05")
- mainResult.BackupPath = mainResult.Path + ".backup." + timestamp
- if err := os.WriteFile(mainResult.BackupPath, existingData, 0644); err != nil {
- mainResult.Error = fmt.Errorf("failed to create backup: %w", err)
- return []DeploymentResult{mainResult}, mainResult.Error
- }
- cd.log(fmt.Sprintf("Backed up existing config to %s", mainResult.BackupPath))
- }
-
- if err := os.WriteFile(mainResult.Path, []byte(AlacrittyConfig), 0644); err != nil {
- mainResult.Error = fmt.Errorf("failed to write config: %w", err)
- return []DeploymentResult{mainResult}, mainResult.Error
- }
-
- mainResult.Deployed = true
- cd.log("Successfully deployed Alacritty configuration")
- results = append(results, mainResult)
-
- themeResult := DeploymentResult{
- ConfigType: "Alacritty Theme",
- Path: filepath.Join(os.Getenv("HOME"), ".config", "alacritty", "dank-theme.toml"),
- }
-
- if err := os.WriteFile(themeResult.Path, []byte(AlacrittyThemeConfig), 0644); err != nil {
- themeResult.Error = fmt.Errorf("failed to write theme config: %w", err)
- return results, themeResult.Error
- }
-
- themeResult.Deployed = true
- cd.log("Successfully deployed Alacritty theme configuration")
- results = append(results, themeResult)
-
- return results, nil
-}
-
-// detectPolkitAgent tries to find the polkit authentication agent on the system
-// Prioritizes mate-polkit paths since that's what we install
-func (cd *ConfigDeployer) detectPolkitAgent() (string, error) {
- // Prioritize mate-polkit paths first
- matePaths := []string{
- "/usr/libexec/polkit-mate-authentication-agent-1", // Fedora path
- "/usr/lib/mate-polkit/polkit-mate-authentication-agent-1",
- "/usr/libexec/mate-polkit/polkit-mate-authentication-agent-1",
- "/usr/lib/polkit-mate/polkit-mate-authentication-agent-1",
- "/usr/lib/x86_64-linux-gnu/mate-polkit/polkit-mate-authentication-agent-1",
- }
-
- for _, path := range matePaths {
- if _, err := os.Stat(path); err == nil {
- cd.log(fmt.Sprintf("Found mate-polkit agent at: %s", path))
- return path, nil
- }
- }
-
- // Fallback to other polkit agents if mate-polkit is not found
- fallbackPaths := []string{
- "/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1",
- "/usr/libexec/polkit-gnome-authentication-agent-1",
- }
-
- for _, path := range fallbackPaths {
- if _, err := os.Stat(path); err == nil {
- cd.log(fmt.Sprintf("Found fallback polkit agent at: %s", path))
- return path, nil
- }
- }
-
- return "", fmt.Errorf("no polkit agent found in common locations")
-}
-
-// mergeNiriOutputSections extracts output sections from existing config and merges them into the new config
-func (cd *ConfigDeployer) mergeNiriOutputSections(newConfig, existingConfig string) (string, error) {
- // Regular expression to match output sections (including commented ones)
- outputRegex := regexp.MustCompile(`(?m)^(/-)?\s*output\s+"[^"]+"\s*\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}`)
-
- // Find all output sections in the existing config
- existingOutputs := outputRegex.FindAllString(existingConfig, -1)
-
- if len(existingOutputs) == 0 {
- // No output sections to merge
- return newConfig, nil
- }
-
- // Remove the example output section from the new config
- exampleOutputRegex := regexp.MustCompile(`(?m)^/-output "eDP-2" \{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}`)
- mergedConfig := exampleOutputRegex.ReplaceAllString(newConfig, "")
-
- // Find where to insert the output sections (after the input section)
- inputEndRegex := regexp.MustCompile(`(?m)^}$`)
- inputMatches := inputEndRegex.FindAllStringIndex(newConfig, -1)
-
- if len(inputMatches) < 1 {
- return "", fmt.Errorf("could not find insertion point for output sections")
- }
-
- // Insert after the first closing brace (end of input section)
- insertPos := inputMatches[0][1]
-
- var builder strings.Builder
- builder.WriteString(mergedConfig[:insertPos])
- builder.WriteString("\n// Outputs from existing configuration\n")
-
- for _, output := range existingOutputs {
- builder.WriteString(output)
- builder.WriteString("\n")
- }
-
- builder.WriteString(mergedConfig[insertPos:])
-
- return builder.String(), nil
-}
-
-// deployHyprlandConfig handles Hyprland configuration deployment with backup and merging
-func (cd *ConfigDeployer) deployHyprlandConfig(terminal deps.Terminal) (DeploymentResult, error) {
- result := DeploymentResult{
- ConfigType: "Hyprland",
- Path: filepath.Join(os.Getenv("HOME"), ".config", "hypr", "hyprland.conf"),
- }
-
- configDir := filepath.Dir(result.Path)
- if err := os.MkdirAll(configDir, 0755); err != nil {
- result.Error = fmt.Errorf("failed to create config directory: %w", err)
- return result, result.Error
- }
-
- var existingConfig string
- if _, err := os.Stat(result.Path); err == nil {
- cd.log("Found existing Hyprland configuration")
-
- existingData, err := os.ReadFile(result.Path)
- if err != nil {
- result.Error = fmt.Errorf("failed to read existing config: %w", err)
- return result, result.Error
- }
- existingConfig = string(existingData)
-
- timestamp := time.Now().Format("2006-01-02_15-04-05")
- result.BackupPath = result.Path + ".backup." + timestamp
- if err := os.WriteFile(result.BackupPath, existingData, 0644); err != nil {
- result.Error = fmt.Errorf("failed to create backup: %w", err)
- return result, result.Error
- }
- cd.log(fmt.Sprintf("Backed up existing config to %s", result.BackupPath))
- }
-
- // Detect polkit agent path
- polkitPath, err := cd.detectPolkitAgent()
- if err != nil {
- cd.log(fmt.Sprintf("Warning: Could not detect polkit agent: %v", err))
- polkitPath = "/usr/lib/mate-polkit/polkit-mate-authentication-agent-1" // fallback
- }
-
- // Determine terminal command based on choice
- var terminalCommand string
- switch terminal {
- case deps.TerminalGhostty:
- terminalCommand = "ghostty"
- case deps.TerminalKitty:
- terminalCommand = "kitty"
- case deps.TerminalAlacritty:
- terminalCommand = "alacritty"
- default:
- terminalCommand = "ghostty" // fallback to ghostty
- }
-
- newConfig := strings.ReplaceAll(HyprlandConfig, "{{POLKIT_AGENT_PATH}}", polkitPath)
- newConfig = strings.ReplaceAll(newConfig, "{{TERMINAL_COMMAND}}", terminalCommand)
-
- // If there was an existing config, merge the monitor sections
- if existingConfig != "" {
- mergedConfig, err := cd.mergeHyprlandMonitorSections(newConfig, existingConfig)
- if err != nil {
- cd.log(fmt.Sprintf("Warning: Failed to merge monitor sections: %v", err))
- } else {
- newConfig = mergedConfig
- cd.log("Successfully merged existing monitor sections")
- }
- }
-
- if err := os.WriteFile(result.Path, []byte(newConfig), 0644); err != nil {
- result.Error = fmt.Errorf("failed to write config: %w", err)
- return result, result.Error
- }
-
- result.Deployed = true
- cd.log("Successfully deployed Hyprland configuration")
- return result, nil
-}
-
-// mergeHyprlandMonitorSections extracts monitor sections from existing config and merges them into the new config
-func (cd *ConfigDeployer) mergeHyprlandMonitorSections(newConfig, existingConfig string) (string, error) {
- // Regular expression to match monitor lines (including commented ones)
- // Matches: monitor = NAME, RESOLUTION, POSITION, SCALE, etc.
- // Also matches commented versions: # monitor = ...
- monitorRegex := regexp.MustCompile(`(?m)^#?\s*monitor\s*=.*$`)
-
- // Find all monitor lines in the existing config
- existingMonitors := monitorRegex.FindAllString(existingConfig, -1)
-
- if len(existingMonitors) == 0 {
- // No monitor sections to merge
- return newConfig, nil
- }
-
- // Remove the example monitor line from the new config
- exampleMonitorRegex := regexp.MustCompile(`(?m)^# monitor = eDP-2.*$`)
- mergedConfig := exampleMonitorRegex.ReplaceAllString(newConfig, "")
-
- // Find where to insert the monitor sections (after the MONITOR CONFIG header)
- monitorHeaderRegex := regexp.MustCompile(`(?m)^# MONITOR CONFIG\n# ==================$`)
- headerMatch := monitorHeaderRegex.FindStringIndex(mergedConfig)
-
- if headerMatch == nil {
- return "", fmt.Errorf("could not find MONITOR CONFIG section")
- }
-
- // Insert after the header
- insertPos := headerMatch[1] + 1 // +1 for the newline
-
- var builder strings.Builder
- builder.WriteString(mergedConfig[:insertPos])
- builder.WriteString("# Monitors from existing configuration\n")
-
- for _, monitor := range existingMonitors {
- builder.WriteString(monitor)
- builder.WriteString("\n")
- }
-
- builder.WriteString(mergedConfig[insertPos:])
-
- return builder.String(), nil
-}
diff --git a/nix/inputs/dms-cli/internal/config/deployer_test.go b/nix/inputs/dms-cli/internal/config/deployer_test.go
deleted file mode 100644
index 7b96744..0000000
--- a/nix/inputs/dms-cli/internal/config/deployer_test.go
+++ /dev/null
@@ -1,673 +0,0 @@
-package config
-
-import (
- "os"
- "path/filepath"
- "strings"
- "testing"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestDetectPolkitAgent(t *testing.T) {
- cd := &ConfigDeployer{}
-
- // This test depends on the system having a polkit agent installed
- // We'll just test that the function doesn't crash and returns some path or error
- path, err := cd.detectPolkitAgent()
-
- if err != nil {
- // If no polkit agent is found, that's okay for testing
- assert.Contains(t, err.Error(), "no polkit agent found")
- } else {
- // If found, it should be a valid path
- assert.NotEmpty(t, path)
- assert.True(t, strings.Contains(path, "polkit"))
- }
-}
-
-func TestMergeNiriOutputSections(t *testing.T) {
- cd := &ConfigDeployer{}
-
- tests := []struct {
- name string
- newConfig string
- existingConfig string
- wantError bool
- wantContains []string
- }{
- {
- name: "no existing outputs",
- newConfig: `input {
- keyboard {
- xkb {
- }
- }
-}
-layout {
- gaps 5
-}`,
- existingConfig: `input {
- keyboard {
- xkb {
- }
- }
-}
-layout {
- gaps 10
-}`,
- wantError: false,
- wantContains: []string{"gaps 5"}, // Should keep new config
- },
- {
- name: "merge single output",
- newConfig: `input {
- keyboard {
- xkb {
- }
- }
-}
-/-output "eDP-2" {
- mode "2560x1600@239.998993"
- position x=2560 y=0
-}
-layout {
- gaps 5
-}`,
- existingConfig: `input {
- keyboard {
- xkb {
- }
- }
-}
-output "eDP-1" {
- mode "1920x1080@60.000000"
- position x=0 y=0
- scale 1.0
-}
-layout {
- gaps 10
-}`,
- wantError: false,
- wantContains: []string{
- "gaps 5", // New config preserved
- `output "eDP-1"`, // Existing output merged
- "1920x1080@60.000000", // Existing output details
- "Outputs from existing configuration", // Comment added
- },
- },
- {
- name: "merge multiple outputs",
- newConfig: `input {
- keyboard {
- xkb {
- }
- }
-}
-/-output "eDP-2" {
- mode "2560x1600@239.998993"
- position x=2560 y=0
-}
-layout {
- gaps 5
-}`,
- existingConfig: `input {
- keyboard {
- xkb {
- }
- }
-}
-output "eDP-1" {
- mode "1920x1080@60.000000"
- position x=0 y=0
- scale 1.0
-}
-/-output "HDMI-1" {
- mode "1920x1080@60.000000"
- position x=1920 y=0
-}
-layout {
- gaps 10
-}`,
- wantError: false,
- wantContains: []string{
- "gaps 5", // New config preserved
- `output "eDP-1"`, // First existing output
- `/-output "HDMI-1"`, // Second existing output (commented)
- "1920x1080@60.000000", // Output details
- },
- },
- {
- name: "merge commented outputs",
- newConfig: `input {
- keyboard {
- xkb {
- }
- }
-}
-/-output "eDP-2" {
- mode "2560x1600@239.998993"
- position x=2560 y=0
-}
-layout {
- gaps 5
-}`,
- existingConfig: `input {
- keyboard {
- xkb {
- }
- }
-}
-/-output "eDP-1" {
- mode "1920x1080@60.000000"
- position x=0 y=0
- scale 1.0
-}
-layout {
- gaps 10
-}`,
- wantError: false,
- wantContains: []string{
- "gaps 5", // New config preserved
- `/-output "eDP-1"`, // Commented output preserved
- "1920x1080@60.000000", // Output details
- },
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result, err := cd.mergeNiriOutputSections(tt.newConfig, tt.existingConfig)
-
- if tt.wantError {
- assert.Error(t, err)
- return
- }
-
- require.NoError(t, err)
-
- for _, want := range tt.wantContains {
- assert.Contains(t, result, want, "merged config should contain: %s", want)
- }
-
- // Verify the example output was removed
- assert.NotContains(t, result, `/-output "eDP-2"`, "example output should be removed")
- })
- }
-}
-
-func TestConfigDeploymentFlow(t *testing.T) {
- // Create a temporary directory for testing
- tempDir, err := os.MkdirTemp("", "dankinstall-test")
- require.NoError(t, err)
- defer os.RemoveAll(tempDir)
-
- // Set up test environment
- originalHome := os.Getenv("HOME")
- os.Setenv("HOME", tempDir)
- defer os.Setenv("HOME", originalHome)
-
- // Test data
- logChan := make(chan string, 100)
- cd := NewConfigDeployer(logChan)
-
- t.Run("deploy ghostty config to empty directory", func(t *testing.T) {
- results, err := cd.deployGhosttyConfig()
- require.NoError(t, err)
- require.Len(t, results, 2)
-
- mainResult := results[0]
- assert.Equal(t, "Ghostty", mainResult.ConfigType)
- assert.True(t, mainResult.Deployed)
- assert.Empty(t, mainResult.BackupPath)
- assert.FileExists(t, mainResult.Path)
-
- content, err := os.ReadFile(mainResult.Path)
- require.NoError(t, err)
- assert.Contains(t, string(content), "window-decoration = false")
-
- colorResult := results[1]
- assert.Equal(t, "Ghostty Colors", colorResult.ConfigType)
- assert.True(t, colorResult.Deployed)
- assert.FileExists(t, colorResult.Path)
-
- colorContent, err := os.ReadFile(colorResult.Path)
- require.NoError(t, err)
- assert.Contains(t, string(colorContent), "background = #101418")
- })
-
- t.Run("deploy ghostty config with existing file", func(t *testing.T) {
- existingContent := "# Old config\nfont-size = 14\n"
- ghosttyPath := getGhosttyPath()
- err := os.MkdirAll(filepath.Dir(ghosttyPath), 0755)
- require.NoError(t, err)
- err = os.WriteFile(ghosttyPath, []byte(existingContent), 0644)
- require.NoError(t, err)
-
- results, err := cd.deployGhosttyConfig()
- require.NoError(t, err)
- require.Len(t, results, 2)
-
- mainResult := results[0]
- assert.Equal(t, "Ghostty", mainResult.ConfigType)
- assert.True(t, mainResult.Deployed)
- assert.NotEmpty(t, mainResult.BackupPath)
- assert.FileExists(t, mainResult.Path)
- assert.FileExists(t, mainResult.BackupPath)
-
- backupContent, err := os.ReadFile(mainResult.BackupPath)
- require.NoError(t, err)
- assert.Equal(t, existingContent, string(backupContent))
-
- newContent, err := os.ReadFile(mainResult.Path)
- require.NoError(t, err)
- assert.NotContains(t, string(newContent), "# Old config")
-
- colorResult := results[1]
- assert.Equal(t, "Ghostty Colors", colorResult.ConfigType)
- assert.True(t, colorResult.Deployed)
- assert.FileExists(t, colorResult.Path)
- })
-}
-
-// Helper function to get Ghostty config path for testing
-func getGhosttyPath() string {
- return filepath.Join(os.Getenv("HOME"), ".config", "ghostty", "config")
-}
-
-func TestPolkitPathInjection(t *testing.T) {
-
- testConfig := `spawn-at-startup "{{POLKIT_AGENT_PATH}}"
-other content`
-
- result := strings.Replace(testConfig, "{{POLKIT_AGENT_PATH}}", "/test/polkit/path", 1)
-
- assert.Contains(t, result, `spawn-at-startup "/test/polkit/path"`)
- assert.NotContains(t, result, "{{POLKIT_AGENT_PATH}}")
-}
-
-func TestMergeHyprlandMonitorSections(t *testing.T) {
- cd := &ConfigDeployer{}
-
- tests := []struct {
- name string
- newConfig string
- existingConfig string
- wantError bool
- wantContains []string
- wantNotContains []string
- }{
- {
- name: "no existing monitors",
- newConfig: `# ==================
-# MONITOR CONFIG
-# ==================
-# monitor = eDP-2, 2560x1600@239.998993, 2560x0, 1, vrr, 1
-
-# ==================
-# ENVIRONMENT VARS
-# ==================
-env = XDG_CURRENT_DESKTOP,niri`,
- existingConfig: `# Some other config
-input {
- kb_layout = us
-}`,
- wantError: false,
- wantContains: []string{"MONITOR CONFIG", "ENVIRONMENT VARS"},
- },
- {
- name: "merge single monitor",
- newConfig: `# ==================
-# MONITOR CONFIG
-# ==================
-# monitor = eDP-2, 2560x1600@239.998993, 2560x0, 1, vrr, 1
-
-# ==================
-# ENVIRONMENT VARS
-# ==================`,
- existingConfig: `# My config
-monitor = DP-1, 1920x1080@144, 0x0, 1
-input {
- kb_layout = us
-}`,
- wantError: false,
- wantContains: []string{
- "MONITOR CONFIG",
- "monitor = DP-1, 1920x1080@144, 0x0, 1",
- "Monitors from existing configuration",
- },
- wantNotContains: []string{
- "monitor = eDP-2", // Example monitor should be removed
- },
- },
- {
- name: "merge multiple monitors",
- newConfig: `# ==================
-# MONITOR CONFIG
-# ==================
-# monitor = eDP-2, 2560x1600@239.998993, 2560x0, 1, vrr, 1
-
-# ==================
-# ENVIRONMENT VARS
-# ==================`,
- existingConfig: `monitor = DP-1, 1920x1080@144, 0x0, 1
-# monitor = HDMI-A-1, 1920x1080@60, 1920x0, 1
-monitor = eDP-1, 2560x1440@165, auto, 1.25`,
- wantError: false,
- wantContains: []string{
- "monitor = DP-1",
- "# monitor = HDMI-A-1", // Commented monitor preserved
- "monitor = eDP-1",
- "Monitors from existing configuration",
- },
- wantNotContains: []string{
- "monitor = eDP-2", // Example monitor should be removed
- },
- },
- {
- name: "preserve commented monitors",
- newConfig: `# ==================
-# MONITOR CONFIG
-# ==================
-# monitor = eDP-2, 2560x1600@239.998993, 2560x0, 1, vrr, 1
-
-# ==================`,
- existingConfig: `# monitor = DP-1, 1920x1080@144, 0x0, 1
-# monitor = HDMI-A-1, 1920x1080@60, 1920x0, 1`,
- wantError: false,
- wantContains: []string{
- "# monitor = DP-1",
- "# monitor = HDMI-A-1",
- "Monitors from existing configuration",
- },
- },
- {
- name: "no monitor config section",
- newConfig: `# Some config without monitor section
-input {
- kb_layout = us
-}`,
- existingConfig: `monitor = DP-1, 1920x1080@144, 0x0, 1`,
- wantError: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result, err := cd.mergeHyprlandMonitorSections(tt.newConfig, tt.existingConfig)
-
- if tt.wantError {
- assert.Error(t, err)
- return
- }
-
- require.NoError(t, err)
-
- for _, want := range tt.wantContains {
- assert.Contains(t, result, want, "merged config should contain: %s", want)
- }
-
- for _, notWant := range tt.wantNotContains {
- assert.NotContains(t, result, notWant, "merged config should NOT contain: %s", notWant)
- }
- })
- }
-}
-
-func TestHyprlandConfigDeployment(t *testing.T) {
- // Create a temporary directory for testing
- tempDir, err := os.MkdirTemp("", "dankinstall-hyprland-test")
- require.NoError(t, err)
- defer os.RemoveAll(tempDir)
-
- // Set up test environment
- originalHome := os.Getenv("HOME")
- os.Setenv("HOME", tempDir)
- defer os.Setenv("HOME", originalHome)
-
- logChan := make(chan string, 100)
- cd := NewConfigDeployer(logChan)
-
- t.Run("deploy hyprland config to empty directory", func(t *testing.T) {
- result, err := cd.deployHyprlandConfig(deps.TerminalGhostty)
- require.NoError(t, err)
-
- assert.Equal(t, "Hyprland", result.ConfigType)
- assert.True(t, result.Deployed)
- assert.Empty(t, result.BackupPath) // No existing config, so no backup
- assert.FileExists(t, result.Path)
-
- // Verify content
- content, err := os.ReadFile(result.Path)
- require.NoError(t, err)
- assert.Contains(t, string(content), "# MONITOR CONFIG")
- assert.Contains(t, string(content), "bind = $mod, T, exec, ghostty") // Terminal injection
- assert.Contains(t, string(content), "exec-once = ") // Polkit agent
- })
-
- t.Run("deploy hyprland config with existing monitors", func(t *testing.T) {
- // Create existing config with monitors
- existingContent := `# My existing Hyprland config
-monitor = DP-1, 1920x1080@144, 0x0, 1
-monitor = HDMI-A-1, 3840x2160@60, 1920x0, 1.5
-
-general {
- gaps_in = 10
-}
-`
- hyprPath := filepath.Join(tempDir, ".config", "hypr", "hyprland.conf")
- err := os.MkdirAll(filepath.Dir(hyprPath), 0755)
- require.NoError(t, err)
- err = os.WriteFile(hyprPath, []byte(existingContent), 0644)
- require.NoError(t, err)
-
- result, err := cd.deployHyprlandConfig(deps.TerminalKitty)
- require.NoError(t, err)
-
- assert.Equal(t, "Hyprland", result.ConfigType)
- assert.True(t, result.Deployed)
- assert.NotEmpty(t, result.BackupPath) // Should have backup
- assert.FileExists(t, result.Path)
- assert.FileExists(t, result.BackupPath)
-
- // Verify backup content
- backupContent, err := os.ReadFile(result.BackupPath)
- require.NoError(t, err)
- assert.Equal(t, existingContent, string(backupContent))
-
- // Verify new content preserves monitors
- newContent, err := os.ReadFile(result.Path)
- require.NoError(t, err)
- assert.Contains(t, string(newContent), "monitor = DP-1, 1920x1080@144")
- assert.Contains(t, string(newContent), "monitor = HDMI-A-1, 3840x2160@60")
- assert.Contains(t, string(newContent), "bind = $mod, T, exec, kitty") // Kitty terminal
- assert.NotContains(t, string(newContent), "monitor = eDP-2") // Example monitor removed
- })
-}
-
-func TestNiriConfigStructure(t *testing.T) {
- // Verify the embedded Niri config has expected sections
- assert.Contains(t, NiriConfig, "input {")
- assert.Contains(t, NiriConfig, "layout {")
- assert.Contains(t, NiriConfig, "binds {")
- assert.Contains(t, NiriConfig, "{{POLKIT_AGENT_PATH}}")
- assert.Contains(t, NiriConfig, `spawn "{{TERMINAL_COMMAND}}"`)
-}
-
-func TestHyprlandConfigStructure(t *testing.T) {
- // Verify the embedded Hyprland config has expected sections and placeholders
- assert.Contains(t, HyprlandConfig, "# MONITOR CONFIG")
- assert.Contains(t, HyprlandConfig, "# ENVIRONMENT VARS")
- assert.Contains(t, HyprlandConfig, "# STARTUP APPS")
- assert.Contains(t, HyprlandConfig, "# INPUT CONFIG")
- assert.Contains(t, HyprlandConfig, "# KEYBINDINGS")
- assert.Contains(t, HyprlandConfig, "{{POLKIT_AGENT_PATH}}")
- assert.Contains(t, HyprlandConfig, "{{TERMINAL_COMMAND}}")
- assert.Contains(t, HyprlandConfig, "exec-once = dms run")
- assert.Contains(t, HyprlandConfig, "bind = $mod, T, exec,")
- assert.Contains(t, HyprlandConfig, "bind = $mod, space, exec, dms ipc call spotlight toggle")
- assert.Contains(t, HyprlandConfig, "windowrulev2 = noborder, class:^(com\\.mitchellh\\.ghostty)$")
-}
-
-func TestGhosttyConfigStructure(t *testing.T) {
- assert.Contains(t, GhosttyConfig, "window-decoration = false")
- assert.Contains(t, GhosttyConfig, "background-opacity = 1.0")
- assert.Contains(t, GhosttyConfig, "config-file = ./config-dankcolors")
-}
-
-func TestGhosttyColorConfigStructure(t *testing.T) {
- assert.Contains(t, GhosttyColorConfig, "background = #101418")
- assert.Contains(t, GhosttyColorConfig, "foreground = #e0e2e8")
- assert.Contains(t, GhosttyColorConfig, "cursor-color = #9dcbfb")
- assert.Contains(t, GhosttyColorConfig, "palette = 0=#101418")
- assert.Contains(t, GhosttyColorConfig, "palette = 15=#ffffff")
-}
-
-func TestKittyConfigStructure(t *testing.T) {
- assert.Contains(t, KittyConfig, "font_size 12.0")
- assert.Contains(t, KittyConfig, "window_padding_width 12")
- assert.Contains(t, KittyConfig, "background_opacity 1.0")
- assert.Contains(t, KittyConfig, "include dank-tabs.conf")
- assert.Contains(t, KittyConfig, "include dank-theme.conf")
-}
-
-func TestKittyThemeConfigStructure(t *testing.T) {
- assert.Contains(t, KittyThemeConfig, "foreground #e0e2e8")
- assert.Contains(t, KittyThemeConfig, "background #101418")
- assert.Contains(t, KittyThemeConfig, "cursor #e0e2e8")
- assert.Contains(t, KittyThemeConfig, "color0 #101418")
- assert.Contains(t, KittyThemeConfig, "color15 #ffffff")
-}
-
-func TestKittyTabsConfigStructure(t *testing.T) {
- assert.Contains(t, KittyTabsConfig, "tab_bar_style powerline")
- assert.Contains(t, KittyTabsConfig, "tab_powerline_style slanted")
- assert.Contains(t, KittyTabsConfig, "active_tab_background #124a73")
- assert.Contains(t, KittyTabsConfig, "inactive_tab_background #101418")
-}
-
-func TestAlacrittyConfigStructure(t *testing.T) {
- assert.Contains(t, AlacrittyConfig, "[general]")
- assert.Contains(t, AlacrittyConfig, "~/.config/alacritty/dank-theme.toml")
- assert.Contains(t, AlacrittyConfig, "[window]")
- assert.Contains(t, AlacrittyConfig, "decorations = \"None\"")
- assert.Contains(t, AlacrittyConfig, "padding = { x = 12, y = 12 }")
- assert.Contains(t, AlacrittyConfig, "[cursor]")
- assert.Contains(t, AlacrittyConfig, "[keyboard]")
-}
-
-func TestAlacrittyThemeConfigStructure(t *testing.T) {
- assert.Contains(t, AlacrittyThemeConfig, "[colors.primary]")
- assert.Contains(t, AlacrittyThemeConfig, "background = '#101418'")
- assert.Contains(t, AlacrittyThemeConfig, "foreground = '#e0e2e8'")
- assert.Contains(t, AlacrittyThemeConfig, "[colors.cursor]")
- assert.Contains(t, AlacrittyThemeConfig, "cursor = '#9dcbfb'")
- assert.Contains(t, AlacrittyThemeConfig, "[colors.normal]")
- assert.Contains(t, AlacrittyThemeConfig, "[colors.bright]")
-}
-
-func TestKittyConfigDeployment(t *testing.T) {
- tempDir, err := os.MkdirTemp("", "dankinstall-kitty-test")
- require.NoError(t, err)
- defer os.RemoveAll(tempDir)
-
- originalHome := os.Getenv("HOME")
- os.Setenv("HOME", tempDir)
- defer os.Setenv("HOME", originalHome)
-
- logChan := make(chan string, 100)
- cd := NewConfigDeployer(logChan)
-
- t.Run("deploy kitty config to empty directory", func(t *testing.T) {
- results, err := cd.deployKittyConfig()
- require.NoError(t, err)
- require.Len(t, results, 3)
-
- mainResult := results[0]
- assert.Equal(t, "Kitty", mainResult.ConfigType)
- assert.True(t, mainResult.Deployed)
- assert.FileExists(t, mainResult.Path)
-
- content, err := os.ReadFile(mainResult.Path)
- require.NoError(t, err)
- assert.Contains(t, string(content), "include dank-theme.conf")
-
- themeResult := results[1]
- assert.Equal(t, "Kitty Theme", themeResult.ConfigType)
- assert.True(t, themeResult.Deployed)
- assert.FileExists(t, themeResult.Path)
-
- tabsResult := results[2]
- assert.Equal(t, "Kitty Tabs", tabsResult.ConfigType)
- assert.True(t, tabsResult.Deployed)
- assert.FileExists(t, tabsResult.Path)
- })
-}
-
-func TestAlacrittyConfigDeployment(t *testing.T) {
- tempDir, err := os.MkdirTemp("", "dankinstall-alacritty-test")
- require.NoError(t, err)
- defer os.RemoveAll(tempDir)
-
- originalHome := os.Getenv("HOME")
- os.Setenv("HOME", tempDir)
- defer os.Setenv("HOME", originalHome)
-
- logChan := make(chan string, 100)
- cd := NewConfigDeployer(logChan)
-
- t.Run("deploy alacritty config to empty directory", func(t *testing.T) {
- results, err := cd.deployAlacrittyConfig()
- require.NoError(t, err)
- require.Len(t, results, 2)
-
- mainResult := results[0]
- assert.Equal(t, "Alacritty", mainResult.ConfigType)
- assert.True(t, mainResult.Deployed)
- assert.FileExists(t, mainResult.Path)
-
- content, err := os.ReadFile(mainResult.Path)
- require.NoError(t, err)
- assert.Contains(t, string(content), "~/.config/alacritty/dank-theme.toml")
- assert.Contains(t, string(content), "[window]")
-
- themeResult := results[1]
- assert.Equal(t, "Alacritty Theme", themeResult.ConfigType)
- assert.True(t, themeResult.Deployed)
- assert.FileExists(t, themeResult.Path)
-
- themeContent, err := os.ReadFile(themeResult.Path)
- require.NoError(t, err)
- assert.Contains(t, string(themeContent), "[colors.primary]")
- assert.Contains(t, string(themeContent), "background = '#101418'")
- })
-
- t.Run("deploy alacritty config with existing file", func(t *testing.T) {
- existingContent := "# Old alacritty config\n[window]\nopacity = 0.9\n"
- alacrittyPath := filepath.Join(tempDir, ".config", "alacritty", "alacritty.toml")
- err := os.MkdirAll(filepath.Dir(alacrittyPath), 0755)
- require.NoError(t, err)
- err = os.WriteFile(alacrittyPath, []byte(existingContent), 0644)
- require.NoError(t, err)
-
- results, err := cd.deployAlacrittyConfig()
- require.NoError(t, err)
- require.Len(t, results, 2)
-
- mainResult := results[0]
- assert.True(t, mainResult.Deployed)
- assert.NotEmpty(t, mainResult.BackupPath)
- assert.FileExists(t, mainResult.BackupPath)
-
- backupContent, err := os.ReadFile(mainResult.BackupPath)
- require.NoError(t, err)
- assert.Equal(t, existingContent, string(backupContent))
-
- newContent, err := os.ReadFile(mainResult.Path)
- require.NoError(t, err)
- assert.NotContains(t, string(newContent), "# Old alacritty config")
- assert.Contains(t, string(newContent), "decorations = \"None\"")
- })
-}
diff --git a/nix/inputs/dms-cli/internal/config/dms.go b/nix/inputs/dms-cli/internal/config/dms.go
deleted file mode 100644
index 2ecc3ef..0000000
--- a/nix/inputs/dms-cli/internal/config/dms.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package config
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "strings"
-)
-
-// LocateDMSConfig searches for DMS installation following XDG Base Directory specification
-func LocateDMSConfig() (string, error) {
- var searchPaths []string
-
- configHome := os.Getenv("XDG_CONFIG_HOME")
- if configHome == "" {
- if homeDir, err := os.UserHomeDir(); err == nil {
- configHome = filepath.Join(homeDir, ".config")
- }
- }
-
- if configHome != "" {
- searchPaths = append(searchPaths, filepath.Join(configHome, "quickshell", "dms"))
- }
-
- searchPaths = append(searchPaths, "/usr/share/quickshell/dms")
-
- configDirs := os.Getenv("XDG_CONFIG_DIRS")
- if configDirs == "" {
- configDirs = "/etc/xdg"
- }
-
- for _, dir := range strings.Split(configDirs, ":") {
- if dir != "" {
- searchPaths = append(searchPaths, filepath.Join(dir, "quickshell", "dms"))
- }
- }
-
- for _, path := range searchPaths {
- shellPath := filepath.Join(path, "shell.qml")
- if info, err := os.Stat(shellPath); err == nil && !info.IsDir() {
- return path, nil
- }
- }
-
- return "", fmt.Errorf("could not find DMS config (shell.qml) in any valid config path")
-}
diff --git a/nix/inputs/dms-cli/internal/config/embedded/alacritty-theme.toml b/nix/inputs/dms-cli/internal/config/embedded/alacritty-theme.toml
deleted file mode 100644
index 4048457..0000000
--- a/nix/inputs/dms-cli/internal/config/embedded/alacritty-theme.toml
+++ /dev/null
@@ -1,31 +0,0 @@
-[colors.primary]
-background = '#101418'
-foreground = '#e0e2e8'
-
-[colors.selection]
-text = '#e0e2e8'
-background = '#124a73'
-
-[colors.cursor]
-text = '#101418'
-cursor = '#9dcbfb'
-
-[colors.normal]
-black = '#101418'
-red = '#d75a59'
-green = '#8ed88c'
-yellow = '#e0d99d'
-blue = '#4087bc'
-magenta = '#839fbc'
-cyan = '#9dcbfb'
-white = '#abb2bf'
-
-[colors.bright]
-black = '#5c6370'
-red = '#e57e7e'
-green = '#a2e5a0'
-yellow = '#efe9b3'
-blue = '#a7d9ff'
-magenta = '#3d8197'
-cyan = '#5c7ba3'
-white = '#ffffff'
diff --git a/nix/inputs/dms-cli/internal/config/embedded/alacritty.toml b/nix/inputs/dms-cli/internal/config/embedded/alacritty.toml
deleted file mode 100644
index b666177..0000000
--- a/nix/inputs/dms-cli/internal/config/embedded/alacritty.toml
+++ /dev/null
@@ -1,37 +0,0 @@
-[general]
-import = [
- "~/.config/alacritty/dank-theme.toml"
-]
-
-[window]
-decorations = "None"
-padding = { x = 12, y = 12 }
-opacity = 1.0
-
-[scrolling]
-history = 3023
-
-[cursor]
-style = { shape = "Block", blinking = "On" }
-blink_interval = 500
-unfocused_hollow = true
-
-[mouse]
-hide_when_typing = true
-
-[selection]
-save_to_clipboard = false
-
-[bell]
-duration = 0
-
-[keyboard]
-bindings = [
- { key = "C", mods = "Control|Shift", action = "Copy" },
- { key = "V", mods = "Control|Shift", action = "Paste" },
- { key = "N", mods = "Control|Shift", action = "SpawnNewInstance" },
- { key = "Equals", mods = "Control|Shift", action = "IncreaseFontSize" },
- { key = "Minus", mods = "Control", action = "DecreaseFontSize" },
- { key = "Key0", mods = "Control", action = "ResetFontSize" },
- { key = "Enter", mods = "Shift", chars = "\n" },
-]
diff --git a/nix/inputs/dms-cli/internal/config/embedded/ghostty-colors.conf b/nix/inputs/dms-cli/internal/config/embedded/ghostty-colors.conf
deleted file mode 100644
index 56dca5f..0000000
--- a/nix/inputs/dms-cli/internal/config/embedded/ghostty-colors.conf
+++ /dev/null
@@ -1,21 +0,0 @@
-background = #101418
-foreground = #e0e2e8
-cursor-color = #9dcbfb
-selection-background = #124a73
-selection-foreground = #e0e2e8
-palette = 0=#101418
-palette = 1=#d75a59
-palette = 2=#8ed88c
-palette = 3=#e0d99d
-palette = 4=#4087bc
-palette = 5=#839fbc
-palette = 6=#9dcbfb
-palette = 7=#abb2bf
-palette = 8=#5c6370
-palette = 9=#e57e7e
-palette = 10=#a2e5a0
-palette = 11=#efe9b3
-palette = 12=#a7d9ff
-palette = 13=#3d8197
-palette = 14=#5c7ba3
-palette = 15=#ffffff
diff --git a/nix/inputs/dms-cli/internal/config/embedded/ghostty.conf b/nix/inputs/dms-cli/internal/config/embedded/ghostty.conf
deleted file mode 100644
index f541237..0000000
--- a/nix/inputs/dms-cli/internal/config/embedded/ghostty.conf
+++ /dev/null
@@ -1,51 +0,0 @@
-# Font Configuration
-font-size = 12
-
-# Window Configuration
-window-decoration = false
-window-padding-x = 12
-window-padding-y = 12
-background-opacity = 1.0
-background-blur-radius = 32
-
-# Cursor Configuration
-cursor-style = block
-cursor-style-blink = true
-
-# Scrollback
-scrollback-limit = 3023
-
-# Terminal features
-mouse-hide-while-typing = true
-copy-on-select = false
-confirm-close-surface = false
-
-# Disable annoying copied to clipboard
-app-notifications = no-clipboard-copy,no-config-reload
-
-# Key bindings for common actions
-#keybind = ctrl+c=copy_to_clipboard
-#keybind = ctrl+v=paste_from_clipboard
-keybind = ctrl+shift+n=new_window
-keybind = ctrl+t=new_tab
-keybind = ctrl+plus=increase_font_size:1
-keybind = ctrl+minus=decrease_font_size:1
-keybind = ctrl+zero=reset_font_size
-
-# Material 3 UI elements
-unfocused-split-opacity = 0.7
-unfocused-split-fill = #44464f
-
-# Tab configuration
-gtk-titlebar = false
-
-# Shell integration
-shell-integration = detect
-shell-integration-features = cursor,sudo,title,no-cursor
-keybind = shift+enter=text:\n
-
-# Rando stuff
-gtk-single-instance = true
-
-# Dank color generation
-config-file = ./config-dankcolors
diff --git a/nix/inputs/dms-cli/internal/config/embedded/hyprland.conf b/nix/inputs/dms-cli/internal/config/embedded/hyprland.conf
deleted file mode 100644
index 6e812c9..0000000
--- a/nix/inputs/dms-cli/internal/config/embedded/hyprland.conf
+++ /dev/null
@@ -1,287 +0,0 @@
-# Hyprland Configuration
-# https://wiki.hypr.land/Configuring/
-
-# ==================
-# MONITOR CONFIG
-# ==================
-# monitor = eDP-2, 2560x1600@239.998993, 2560x0, 1, vrr, 1
-monitor = , preferred,auto,1
-
-# ==================
-# ENVIRONMENT VARS
-# ==================
-env = QT_QPA_PLATFORM,wayland
-env = ELECTRON_OZONE_PLATFORM_HINT,auto
-env = QT_QPA_PLATFORMTHEME,gtk3
-env = QT_QPA_PLATFORMTHEME_QT6,gtk3
-env = TERMINAL,{{TERMINAL_COMMAND}}
-
-# ==================
-# STARTUP APPS
-# ==================
-exec-once = bash -c "wl-paste --watch cliphist store &"
-exec-once = dms run
-exec-once = {{POLKIT_AGENT_PATH}}
-
-# ==================
-# INPUT CONFIG
-# ==================
-input {
- kb_layout = us
- numlock_by_default = true
-}
-
-# ==================
-# GENERAL LAYOUT
-# ==================
-general {
- gaps_in = 5
- gaps_out = 5
- border_size = 0 # off in niri
-
- col.active_border = rgba(707070ff)
- col.inactive_border = rgba(d0d0d0ff)
-
- layout = dwindle
-}
-
-# ==================
-# DECORATION
-# ==================
-decoration {
- rounding = 12
-
- active_opacity = 1.0
- inactive_opacity = 0.9
-
- shadow {
- enabled = true
- range = 30
- render_power = 5
- offset = 0 5
- color = rgba(00000070)
- }
-}
-
-# ==================
-# ANIMATIONS
-# ==================
-animations {
- enabled = true
-
- animation = windowsIn, 1, 3, default
- animation = windowsOut, 1, 3, default
- animation = workspaces, 1, 5, default
- animation = windowsMove, 1, 4, default
- animation = fade, 1, 3, default
- animation = border, 1, 3, default
-}
-
-# ==================
-# LAYOUTS
-# ==================
-dwindle {
- preserve_split = true
-}
-
-master {
- mfact = 0.5
-}
-
-# ==================
-# MISC
-# ==================
-misc {
- disable_hyprland_logo = true
- disable_splash_rendering = true
- vrr = 1
-}
-
-# ==================
-# WINDOW RULES
-# ==================
-windowrulev2 = tile, class:^(org\.wezfurlong\.wezterm)$
-
-windowrulev2 = rounding 12, class:^(org\.gnome\.)
-windowrulev2 = noborder, class:^(org\.gnome\.)
-
-windowrulev2 = tile, class:^(gnome-control-center)$
-windowrulev2 = tile, class:^(pavucontrol)$
-windowrulev2 = tile, class:^(nm-connection-editor)$
-
-windowrulev2 = float, class:^(gnome-calculator)$
-windowrulev2 = float, class:^(galculator)$
-windowrulev2 = float, class:^(blueman-manager)$
-windowrulev2 = float, class:^(org\.gnome\.Nautilus)$
-windowrulev2 = float, class:^(steam)$
-windowrulev2 = float, class:^(xdg-desktop-portal)$
-
-windowrulev2 = noborder, class:^(org\.wezfurlong\.wezterm)$
-windowrulev2 = noborder, class:^(Alacritty)$
-windowrulev2 = noborder, class:^(zen)$
-windowrulev2 = noborder, class:^(com\.mitchellh\.ghostty)$
-windowrulev2 = noborder, class:^(kitty)$
-
-windowrulev2 = float, class:^(firefox)$, title:^(Picture-in-Picture)$
-windowrulev2 = float, class:^(zoom)$
-
-windowrulev2 = opacity 0.9 0.9, floating:0, focus:0
-
-layerrule = noanim, ^(quickshell)$
-
-# ==================
-# KEYBINDINGS
-# ==================
-$mod = SUPER
-
-# === Application Launchers ===
-bind = $mod, T, exec, {{TERMINAL_COMMAND}}
-bind = $mod, space, exec, dms ipc call spotlight toggle
-bind = $mod, V, exec, dms ipc call clipboard toggle
-bind = $mod, M, exec, dms ipc call processlist toggle
-bind = $mod, comma, exec, dms ipc call settings toggle
-bind = $mod, N, exec, dms ipc call notifications toggle
-bind = $mod SHIFT, N, exec, dms ipc call notepad toggle
-bind = $mod, Y, exec, dms ipc call dankdash wallpaper
-bind = $mod, TAB, exec, dms ipc call hypr toggleOverview
-
-# === Security ===
-bind = $mod ALT, L, exec, dms ipc call lock lock
-bind = $mod SHIFT, E, exit
-bind = CTRL ALT, Delete, exec, dms ipc call processlist toggle
-
-# === Audio Controls ===
-bindel = , XF86AudioRaiseVolume, exec, dms ipc call audio increment 3
-bindel = , XF86AudioLowerVolume, exec, dms ipc call audio decrement 3
-bindl = , XF86AudioMute, exec, dms ipc call audio mute
-bindl = , XF86AudioMicMute, exec, dms ipc call audio micmute
-
-# === Brightness Controls ===
-bindel = , XF86MonBrightnessUp, exec, dms ipc call brightness increment 5 ""
-bindel = , XF86MonBrightnessDown, exec, dms ipc call brightness decrement 5 ""
-
-# === Window Management ===
-bind = $mod, Q, killactive
-bind = $mod, F, fullscreen, 1
-bind = $mod SHIFT, F, fullscreen, 0
-bind = $mod SHIFT, T, togglefloating
-bind = $mod, W, togglegroup
-
-# === Focus Navigation ===
-bind = $mod, left, movefocus, l
-bind = $mod, down, movefocus, d
-bind = $mod, up, movefocus, u
-bind = $mod, right, movefocus, r
-bind = $mod, H, movefocus, l
-bind = $mod, J, movefocus, d
-bind = $mod, K, movefocus, u
-bind = $mod, L, movefocus, r
-
-# === Window Movement ===
-bind = $mod SHIFT, left, movewindow, l
-bind = $mod SHIFT, down, movewindow, d
-bind = $mod SHIFT, up, movewindow, u
-bind = $mod SHIFT, right, movewindow, r
-bind = $mod SHIFT, H, movewindow, l
-bind = $mod SHIFT, J, movewindow, d
-bind = $mod SHIFT, K, movewindow, u
-bind = $mod SHIFT, L, movewindow, r
-
-# === Column Navigation ===
-bind = $mod, Home, focuswindow, first
-bind = $mod, End, focuswindow, last
-
-# === Monitor Navigation ===
-bind = $mod CTRL, left, focusmonitor, l
-bind = $mod CTRL, right, focusmonitor, r
-bind = $mod CTRL, H, focusmonitor, l
-bind = $mod CTRL, J, focusmonitor, d
-bind = $mod CTRL, K, focusmonitor, u
-bind = $mod CTRL, L, focusmonitor, r
-
-# === Move to Monitor ===
-bind = $mod SHIFT CTRL, left, movewindow, mon:l
-bind = $mod SHIFT CTRL, down, movewindow, mon:d
-bind = $mod SHIFT CTRL, up, movewindow, mon:u
-bind = $mod SHIFT CTRL, right, movewindow, mon:r
-bind = $mod SHIFT CTRL, H, movewindow, mon:l
-bind = $mod SHIFT CTRL, J, movewindow, mon:d
-bind = $mod SHIFT CTRL, K, movewindow, mon:u
-bind = $mod SHIFT CTRL, L, movewindow, mon:r
-
-# === Workspace Navigation ===
-bind = $mod, Page_Down, workspace, e+1
-bind = $mod, Page_Up, workspace, e-1
-bind = $mod, U, workspace, e+1
-bind = $mod, I, workspace, e-1
-bind = $mod CTRL, down, movetoworkspace, e+1
-bind = $mod CTRL, up, movetoworkspace, e-1
-bind = $mod CTRL, U, movetoworkspace, e+1
-bind = $mod CTRL, I, movetoworkspace, e-1
-
-# === Move Workspaces ===
-bind = $mod SHIFT, Page_Down, movetoworkspace, e+1
-bind = $mod SHIFT, Page_Up, movetoworkspace, e-1
-bind = $mod SHIFT, U, movetoworkspace, e+1
-bind = $mod SHIFT, I, movetoworkspace, e-1
-
-# === Mouse Wheel Navigation ===
-bind = $mod, mouse_down, workspace, e+1
-bind = $mod, mouse_up, workspace, e-1
-bind = $mod CTRL, mouse_down, movetoworkspace, e+1
-bind = $mod CTRL, mouse_up, movetoworkspace, e-1
-
-# === Numbered Workspaces ===
-bind = $mod, 1, workspace, 1
-bind = $mod, 2, workspace, 2
-bind = $mod, 3, workspace, 3
-bind = $mod, 4, workspace, 4
-bind = $mod, 5, workspace, 5
-bind = $mod, 6, workspace, 6
-bind = $mod, 7, workspace, 7
-bind = $mod, 8, workspace, 8
-bind = $mod, 9, workspace, 9
-
-# === Move to Numbered Workspaces ===
-bind = $mod SHIFT, 1, movetoworkspace, 1
-bind = $mod SHIFT, 2, movetoworkspace, 2
-bind = $mod SHIFT, 3, movetoworkspace, 3
-bind = $mod SHIFT, 4, movetoworkspace, 4
-bind = $mod SHIFT, 5, movetoworkspace, 5
-bind = $mod SHIFT, 6, movetoworkspace, 6
-bind = $mod SHIFT, 7, movetoworkspace, 7
-bind = $mod SHIFT, 8, movetoworkspace, 8
-bind = $mod SHIFT, 9, movetoworkspace, 9
-
-# === Column Management ===
-bind = $mod, bracketleft, layoutmsg, preselect l
-bind = $mod, bracketright, layoutmsg, preselect r
-
-# === Sizing & Layout ===
-bind = $mod, R, layoutmsg, togglesplit
-bind = $mod CTRL, F, resizeactive, exact 100%
-
-# === Move/resize windows with mainMod + LMB/RMB and dragging ===
-bindmd = $mod, mouse:272, Move window, movewindow
-bindmd = $mod, mouse:273, Resize window, resizewindow
-
-# === Move/resize windows with mainMod + LMB/RMB and dragging ===
-bindd = $mod, code:20, Expand window left, resizeactive, -100 0
-bindd = $mod, code:21, Shrink window left, resizeactive, 100 0
-
-# === Manual Sizing ===
-binde = $mod, minus, resizeactive, -10% 0
-binde = $mod, equal, resizeactive, 10% 0
-binde = $mod SHIFT, minus, resizeactive, 0 -10%
-binde = $mod SHIFT, equal, resizeactive, 0 10%
-
-# === Screenshots ===
-bind = , XF86Launch1, exec, grimblast copy area
-bind = CTRL, XF86Launch1, exec, grimblast copy screen
-bind = ALT, XF86Launch1, exec, grimblast copy active
-bind = , Print, exec, grimblast copy area
-bind = CTRL, Print, exec, grimblast copy screen
-bind = ALT, Print, exec, grimblast copy active
-
-# === System Controls ===
-bind = $mod SHIFT, P, dpms, off
diff --git a/nix/inputs/dms-cli/internal/config/embedded/kitty-tabs.conf b/nix/inputs/dms-cli/internal/config/embedded/kitty-tabs.conf
deleted file mode 100644
index b2305c8..0000000
--- a/nix/inputs/dms-cli/internal/config/embedded/kitty-tabs.conf
+++ /dev/null
@@ -1,24 +0,0 @@
-tab_bar_edge top
-tab_bar_style powerline
-tab_powerline_style slanted
-tab_bar_align left
-tab_bar_min_tabs 2
-tab_bar_margin_width 0.0
-tab_bar_margin_height 2.5 1.5
-tab_bar_margin_color #101418
-
-tab_bar_background #101418
-
-active_tab_foreground #cfe5ff
-active_tab_background #124a73
-active_tab_font_style bold
-
-inactive_tab_foreground #c2c7cf
-inactive_tab_background #101418
-inactive_tab_font_style normal
-
-tab_activity_symbol " ● "
-tab_numbers_style 1
-
-tab_title_template "{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.tab}{title[:30]}{title[30:] and '…'} [{index}]"
-active_tab_title_template "{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.tab}{title[:30]}{title[30:] and '…'} [{index}]"
diff --git a/nix/inputs/dms-cli/internal/config/embedded/kitty-theme.conf b/nix/inputs/dms-cli/internal/config/embedded/kitty-theme.conf
deleted file mode 100644
index 2587bcf..0000000
--- a/nix/inputs/dms-cli/internal/config/embedded/kitty-theme.conf
+++ /dev/null
@@ -1,24 +0,0 @@
-cursor #e0e2e8
-cursor_text_color #c2c7cf
-
-foreground #e0e2e8
-background #101418
-selection_foreground #243240
-selection_background #b9c8da
-url_color #9dcbfb
-color0 #101418
-color1 #d75a59
-color2 #8ed88c
-color3 #e0d99d
-color4 #4087bc
-color5 #839fbc
-color6 #9dcbfb
-color7 #abb2bf
-color8 #5c6370
-color9 #e57e7e
-color10 #a2e5a0
-color11 #efe9b3
-color12 #a7d9ff
-color13 #3d8197
-color14 #5c7ba3
-color15 #ffffff
diff --git a/nix/inputs/dms-cli/internal/config/embedded/kitty.conf b/nix/inputs/dms-cli/internal/config/embedded/kitty.conf
deleted file mode 100644
index 2ae96a0..0000000
--- a/nix/inputs/dms-cli/internal/config/embedded/kitty.conf
+++ /dev/null
@@ -1,37 +0,0 @@
-# Font Configuration
-font_size 12.0
-
-# Window Configuration
-window_padding_width 12
-background_opacity 1.0
-background_blur 32
-hide_window_decorations yes
-
-# Cursor Configuration
-cursor_shape block
-cursor_blink_interval 1
-
-# Scrollback
-scrollback_lines 3000
-
-# Terminal features
-copy_on_select yes
-strip_trailing_spaces smart
-
-# Key bindings for common actions
-map ctrl+shift+n new_window
-map ctrl+t new_tab
-map ctrl+plus change_font_size all +1.0
-map ctrl+minus change_font_size all -1.0
-map ctrl+0 change_font_size all 0
-
-# Tab configuration
-tab_bar_style powerline
-tab_bar_align left
-
-# Shell integration
-shell_integration enabled
-
-# Dank color generation
-include dank-tabs.conf
-include dank-theme.conf
diff --git a/nix/inputs/dms-cli/internal/config/embedded/niri.kdl b/nix/inputs/dms-cli/internal/config/embedded/niri.kdl
deleted file mode 100644
index 1faa139..0000000
--- a/nix/inputs/dms-cli/internal/config/embedded/niri.kdl
+++ /dev/null
@@ -1,418 +0,0 @@
-// This config is in the KDL format: https://kdl.dev
-// "/-" comments out the following node.
-// Check the wiki for a full description of the configuration:
-// https://github.com/YaLTeR/niri/wiki/Configuration:-Introduction
-config-notification {
- disable-failed
-}
-
-gestures {
- hot-corners {
- off
- }
-}
-
-// Input device configuration.
-// Find the full list of options on the wiki:
-// https://github.com/YaLTeR/niri/wiki/Configuration:-Input
-input {
- keyboard {
- xkb {
- }
- numlock
- }
- touchpad {
- }
- mouse {
- }
- trackpoint {
- }
-}
-// You can configure outputs by their name, which you can find
-// by running `niri msg outputs` while inside a niri instance.
-// The built-in laptop monitor is usually called "eDP-1".
-// Find more information on the wiki:
-// https://github.com/YaLTeR/niri/wiki/Configuration:-Outputs
-// Remember to uncomment the node by removing "/-"!
-/-output "eDP-2" {
- mode "2560x1600@239.998993"
- position x=2560 y=0
- variable-refresh-rate
-}
-// Settings that influence how windows are positioned and sized.
-// Find more information on the wiki:
-// https://github.com/YaLTeR/niri/wiki/Configuration:-Layout
-layout {
- // Set gaps around windows in logical pixels.
- gaps 5
- background-color "transparent"
- // When to center a column when changing focus, options are:
- // - "never", default behavior, focusing an off-screen column will keep at the left
- // or right edge of the screen.
- // - "always", the focused column will always be centered.
- // - "on-overflow", focusing a column will center it if it doesn't fit
- // together with the previously focused column.
- center-focused-column "never"
- // You can customize the widths that "switch-preset-column-width" (Mod+R) toggles between.
- preset-column-widths {
- // Proportion sets the width as a fraction of the output width, taking gaps into account.
- // For example, you can perfectly fit four windows sized "proportion 0.25" on an output.
- // The default preset widths are 1/3, 1/2 and 2/3 of the output.
- proportion 0.33333
- proportion 0.5
- proportion 0.66667
- // Fixed sets the width in logical pixels exactly.
- // fixed 1920
- }
- // You can also customize the heights that "switch-preset-window-height" (Mod+Shift+R) toggles between.
- // preset-window-heights { }
- // You can change the default width of the new windows.
- default-column-width { proportion 0.5; }
- // If you leave the brackets empty, the windows themselves will decide their initial width.
- // default-column-width {}
- // By default focus ring and border are rendered as a solid background rectangle
- // behind windows. That is, they will show up through semitransparent windows.
- // This is because windows using client-side decorations can have an arbitrary shape.
- //
- // If you don't like that, you should uncomment `prefer-no-csd` below.
- // Niri will draw focus ring and border *around* windows that agree to omit their
- // client-side decorations.
- //
- // Alternatively, you can override it with a window rule called
- // `draw-border-with-background`.
- border {
- off
- width 4
- active-color "#707070" // Neutral gray
- inactive-color "#d0d0d0" // Light gray
- urgent-color "#cc4444" // Softer red
- }
- focus-ring {
- width 2
- active-color "#808080" // Medium gray
- inactive-color "#505050" // Dark gray
- }
- shadow {
- softness 30
- spread 5
- offset x=0 y=5
- color "#0007"
- }
- struts {
- }
-}
-layer-rule {
- match namespace="^quickshell$"
- place-within-backdrop true
-}
-overview {
- workspace-shadow {
- off
- }
-}
-// Add lines like this to spawn processes at startup.
-// Note that running niri as a session supports xdg-desktop-autostart,
-// which may be more convenient to use.
-// See the binds section below for more spawn examples.
-// This line starts waybar, a commonly used bar for Wayland compositors.
-spawn-at-startup "bash" "-c" "wl-paste --watch cliphist store &"
-spawn-at-startup "dms" "run"
-spawn-at-startup "{{POLKIT_AGENT_PATH}}"
-environment {
- XDG_CURRENT_DESKTOP "niri"
- QT_QPA_PLATFORM "wayland"
- ELECTRON_OZONE_PLATFORM_HINT "auto"
- QT_QPA_PLATFORMTHEME "gtk3"
- QT_QPA_PLATFORMTHEME_QT6 "gtk3"
- TERMINAL "{{TERMINAL_COMMAND}}"
-}
-hotkey-overlay {
- skip-at-startup
-}
-prefer-no-csd
-screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png"
-animations {
- workspace-switch {
- spring damping-ratio=0.80 stiffness=523 epsilon=0.0001
- }
- window-open {
- duration-ms 150
- curve "ease-out-expo"
- }
- window-close {
- duration-ms 150
- curve "ease-out-quad"
- }
- horizontal-view-movement {
- spring damping-ratio=0.85 stiffness=423 epsilon=0.0001
- }
- window-movement {
- spring damping-ratio=0.75 stiffness=323 epsilon=0.0001
- }
- window-resize {
- spring damping-ratio=0.85 stiffness=423 epsilon=0.0001
- }
- config-notification-open-close {
- spring damping-ratio=0.65 stiffness=923 epsilon=0.001
- }
- screenshot-ui-open {
- duration-ms 200
- curve "ease-out-quad"
- }
- overview-open-close {
- spring damping-ratio=0.85 stiffness=800 epsilon=0.0001
- }
-}
-// Window rules let you adjust behavior for individual windows.
-// Find more information on the wiki:
-// https://github.com/YaLTeR/niri/wiki/Configuration:-Window-Rules
-// Work around WezTerm's initial configure bug
-// by setting an empty default-column-width.
-window-rule {
- // This regular expression is intentionally made as specific as possible,
- // since this is the default config, and we want no false positives.
- // You can get away with just app-id="wezterm" if you want.
- match app-id=r#"^org\.wezfurlong\.wezterm$"#
- default-column-width {}
-}
-window-rule {
- match app-id=r#"^org\.gnome\."#
- draw-border-with-background false
- geometry-corner-radius 12
- clip-to-geometry true
-}
-window-rule {
- match app-id=r#"^gnome-control-center$"#
- match app-id=r#"^pavucontrol$"#
- match app-id=r#"^nm-connection-editor$"#
- default-column-width { proportion 0.5; }
- open-floating false
-}
-window-rule {
- match app-id=r#"^gnome-calculator$"#
- match app-id=r#"^galculator$"#
- match app-id=r#"^blueman-manager$"#
- match app-id=r#"^org\.gnome\.Nautilus$"#
- match app-id=r#"^steam$"#
- match app-id=r#"^xdg-desktop-portal$"#
- open-floating true
-}
-window-rule {
- match app-id=r#"^org\.wezfurlong\.wezterm$"#
- match app-id="Alacritty"
- match app-id="zen"
- match app-id="com.mitchellh.ghostty"
- match app-id="kitty"
- draw-border-with-background false
-}
-window-rule {
- match is-active=false
- opacity 0.9
-}
-window-rule {
- match app-id=r#"firefox$"# title="^Picture-in-Picture$"
- match app-id="zoom"
- open-floating true
-}
-window-rule {
- geometry-corner-radius 12
- clip-to-geometry true
-}
-binds {
- // === System & Overview ===
- Mod+D { spawn "niri" "msg" "action" "toggle-overview"; }
- Mod+Tab repeat=false { toggle-overview; }
- Mod+Shift+Slash { show-hotkey-overlay; }
-
- // === Application Launchers ===
- Mod+T hotkey-overlay-title="Open Terminal" { spawn "{{TERMINAL_COMMAND}}"; }
- Mod+Space hotkey-overlay-title="Application Launcher" {
- spawn "dms" "ipc" "call" "spotlight" "toggle";
- }
- Mod+V hotkey-overlay-title="Clipboard Manager" {
- spawn "dms" "ipc" "call" "clipboard" "toggle";
- }
- Mod+M hotkey-overlay-title="Task Manager" {
- spawn "dms" "ipc" "call" "processlist" "toggle";
- }
- Mod+Comma hotkey-overlay-title="Settings" {
- spawn "dms" "ipc" "call" "settings" "toggle";
- }
- Mod+Y hotkey-overlay-title="Browse Wallpapers" {
- spawn "dms" "ipc" "call" "dankdash" "wallpaper";
- }
- Mod+N hotkey-overlay-title="Notification Center" { spawn "dms" "ipc" "call" "notifications" "toggle"; }
- Mod+Shift+N hotkey-overlay-title="Notepad" { spawn "dms" "ipc" "call" "notepad" "toggle"; }
-
- // === Security ===
- Mod+Alt+L hotkey-overlay-title="Lock Screen" {
- spawn "dms" "ipc" "call" "lock" "lock";
- }
- Mod+Shift+E { quit; }
- Ctrl+Alt+Delete hotkey-overlay-title="Task Manager" {
- spawn "dms" "ipc" "call" "processlist" "toggle";
- }
-
- // === Audio Controls ===
- XF86AudioRaiseVolume allow-when-locked=true {
- spawn "dms" "ipc" "call" "audio" "increment" "3";
- }
- XF86AudioLowerVolume allow-when-locked=true {
- spawn "dms" "ipc" "call" "audio" "decrement" "3";
- }
- XF86AudioMute allow-when-locked=true {
- spawn "dms" "ipc" "call" "audio" "mute";
- }
- XF86AudioMicMute allow-when-locked=true {
- spawn "dms" "ipc" "call" "audio" "micmute";
- }
-
- // === Brightness Controls ===
- XF86MonBrightnessUp allow-when-locked=true {
- spawn "dms" "ipc" "call" "brightness" "increment" "5" "";
- }
- XF86MonBrightnessDown allow-when-locked=true {
- spawn "dms" "ipc" "call" "brightness" "decrement" "5" "";
- }
-
- // === Window Management ===
- Mod+Q repeat=false { close-window; }
- Mod+F { maximize-column; }
- Mod+Shift+F { fullscreen-window; }
- Mod+Shift+T { toggle-window-floating; }
- Mod+Shift+V { switch-focus-between-floating-and-tiling; }
- Mod+W { toggle-column-tabbed-display; }
-
- // === Focus Navigation ===
- Mod+Left { focus-column-left; }
- Mod+Down { focus-window-down; }
- Mod+Up { focus-window-up; }
- Mod+Right { focus-column-right; }
- Mod+H { focus-column-left; }
- Mod+J { focus-window-down; }
- Mod+K { focus-window-up; }
- Mod+L { focus-column-right; }
-
- // === Window Movement ===
- Mod+Shift+Left { move-column-left; }
- Mod+Shift+Down { move-window-down; }
- Mod+Shift+Up { move-window-up; }
- Mod+Shift+Right { move-column-right; }
- Mod+Shift+H { move-column-left; }
- Mod+Shift+J { move-window-down; }
- Mod+Shift+K { move-window-up; }
- Mod+Shift+L { move-column-right; }
-
- // === Column Navigation ===
- Mod+Home { focus-column-first; }
- Mod+End { focus-column-last; }
- Mod+Ctrl+Home { move-column-to-first; }
- Mod+Ctrl+End { move-column-to-last; }
-
- // === Monitor Navigation ===
- Mod+Ctrl+Left { focus-monitor-left; }
- //Mod+Ctrl+Down { focus-monitor-down; }
- //Mod+Ctrl+Up { focus-monitor-up; }
- Mod+Ctrl+Right { focus-monitor-right; }
- Mod+Ctrl+H { focus-monitor-left; }
- Mod+Ctrl+J { focus-monitor-down; }
- Mod+Ctrl+K { focus-monitor-up; }
- Mod+Ctrl+L { focus-monitor-right; }
-
- // === Move to Monitor ===
- Mod+Shift+Ctrl+Left { move-column-to-monitor-left; }
- Mod+Shift+Ctrl+Down { move-column-to-monitor-down; }
- Mod+Shift+Ctrl+Up { move-column-to-monitor-up; }
- Mod+Shift+Ctrl+Right { move-column-to-monitor-right; }
- Mod+Shift+Ctrl+H { move-column-to-monitor-left; }
- Mod+Shift+Ctrl+J { move-column-to-monitor-down; }
- Mod+Shift+Ctrl+K { move-column-to-monitor-up; }
- Mod+Shift+Ctrl+L { move-column-to-monitor-right; }
-
- // === Workspace Navigation ===
- Mod+Page_Down { focus-workspace-down; }
- Mod+Page_Up { focus-workspace-up; }
- Mod+U { focus-workspace-down; }
- Mod+I { focus-workspace-up; }
- Mod+Ctrl+Down { move-column-to-workspace-down; }
- Mod+Ctrl+Up { move-column-to-workspace-up; }
- Mod+Ctrl+U { move-column-to-workspace-down; }
- Mod+Ctrl+I { move-column-to-workspace-up; }
-
- // === Move Workspaces ===
- Mod+Shift+Page_Down { move-workspace-down; }
- Mod+Shift+Page_Up { move-workspace-up; }
- Mod+Shift+U { move-workspace-down; }
- Mod+Shift+I { move-workspace-up; }
-
- // === Mouse Wheel Navigation ===
- Mod+WheelScrollDown cooldown-ms=150 { focus-workspace-down; }
- Mod+WheelScrollUp cooldown-ms=150 { focus-workspace-up; }
- Mod+Ctrl+WheelScrollDown cooldown-ms=150 { move-column-to-workspace-down; }
- Mod+Ctrl+WheelScrollUp cooldown-ms=150 { move-column-to-workspace-up; }
-
- Mod+WheelScrollRight { focus-column-right; }
- Mod+WheelScrollLeft { focus-column-left; }
- Mod+Ctrl+WheelScrollRight { move-column-right; }
- Mod+Ctrl+WheelScrollLeft { move-column-left; }
-
- Mod+Shift+WheelScrollDown { focus-column-right; }
- Mod+Shift+WheelScrollUp { focus-column-left; }
- Mod+Ctrl+Shift+WheelScrollDown { move-column-right; }
- Mod+Ctrl+Shift+WheelScrollUp { move-column-left; }
-
- // === Numbered Workspaces ===
- Mod+1 { focus-workspace 1; }
- Mod+2 { focus-workspace 2; }
- Mod+3 { focus-workspace 3; }
- Mod+4 { focus-workspace 4; }
- Mod+5 { focus-workspace 5; }
- Mod+6 { focus-workspace 6; }
- Mod+7 { focus-workspace 7; }
- Mod+8 { focus-workspace 8; }
- Mod+9 { focus-workspace 9; }
-
- // === Move to Numbered Workspaces ===
- Mod+Shift+1 { move-column-to-workspace 1; }
- Mod+Shift+2 { move-column-to-workspace 2; }
- Mod+Shift+3 { move-column-to-workspace 3; }
- Mod+Shift+4 { move-column-to-workspace 4; }
- Mod+Shift+5 { move-column-to-workspace 5; }
- Mod+Shift+6 { move-column-to-workspace 6; }
- Mod+Shift+7 { move-column-to-workspace 7; }
- Mod+Shift+8 { move-column-to-workspace 8; }
- Mod+Shift+9 { move-column-to-workspace 9; }
-
- // === Column Management ===
- Mod+BracketLeft { consume-or-expel-window-left; }
- Mod+BracketRight { consume-or-expel-window-right; }
- Mod+Period { expel-window-from-column; }
-
- // === Sizing & Layout ===
- Mod+R { switch-preset-column-width; }
- Mod+Shift+R { switch-preset-window-height; }
- Mod+Ctrl+R { reset-window-height; }
- Mod+Ctrl+F { expand-column-to-available-width; }
- Mod+C { center-column; }
- Mod+Ctrl+C { center-visible-columns; }
-
- // === Manual Sizing ===
- Mod+Minus { set-column-width "-10%"; }
- Mod+Equal { set-column-width "+10%"; }
- Mod+Shift+Minus { set-window-height "-10%"; }
- Mod+Shift+Equal { set-window-height "+10%"; }
-
- // === Screenshots ===
- XF86Launch1 { screenshot; }
- Ctrl+XF86Launch1 { screenshot-screen; }
- Alt+XF86Launch1 { screenshot-window; }
- Print { screenshot; }
- Ctrl+Print { screenshot-screen; }
- Alt+Print { screenshot-window; }
- // === System Controls ===
- Mod+Escape allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; }
- Mod+Shift+P { power-off-monitors; }
-}
-debug {
- honor-xdg-activation-with-invalid-serial
-}
diff --git a/nix/inputs/dms-cli/internal/config/hyprland.go b/nix/inputs/dms-cli/internal/config/hyprland.go
deleted file mode 100644
index e572955..0000000
--- a/nix/inputs/dms-cli/internal/config/hyprland.go
+++ /dev/null
@@ -1,6 +0,0 @@
-package config
-
-import _ "embed"
-
-//go:embed embedded/hyprland.conf
-var HyprlandConfig string
diff --git a/nix/inputs/dms-cli/internal/config/niri.go b/nix/inputs/dms-cli/internal/config/niri.go
deleted file mode 100644
index 78fb03a..0000000
--- a/nix/inputs/dms-cli/internal/config/niri.go
+++ /dev/null
@@ -1,6 +0,0 @@
-package config
-
-import _ "embed"
-
-//go:embed embedded/niri.kdl
-var NiriConfig string
diff --git a/nix/inputs/dms-cli/internal/config/terminals.go b/nix/inputs/dms-cli/internal/config/terminals.go
deleted file mode 100644
index a5bba04..0000000
--- a/nix/inputs/dms-cli/internal/config/terminals.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package config
-
-import _ "embed"
-
-//go:embed embedded/ghostty.conf
-var GhosttyConfig string
-
-//go:embed embedded/ghostty-colors.conf
-var GhosttyColorConfig string
-
-//go:embed embedded/kitty.conf
-var KittyConfig string
-
-//go:embed embedded/kitty-theme.conf
-var KittyThemeConfig string
-
-//go:embed embedded/kitty-tabs.conf
-var KittyTabsConfig string
-
-//go:embed embedded/alacritty.toml
-var AlacrittyConfig string
-
-//go:embed embedded/alacritty-theme.toml
-var AlacrittyThemeConfig string
diff --git a/nix/inputs/dms-cli/internal/dank16/dank16.go b/nix/inputs/dms-cli/internal/dank16/dank16.go
deleted file mode 100644
index 4140eb0..0000000
--- a/nix/inputs/dms-cli/internal/dank16/dank16.go
+++ /dev/null
@@ -1,453 +0,0 @@
-package dank16
-
-import (
- "fmt"
- "math"
-
- "github.com/lucasb-eyer/go-colorful"
-)
-
-type RGB struct {
- R, G, B float64
-}
-
-type HSV struct {
- H, S, V float64
-}
-
-func HexToRGB(hex string) RGB {
- if hex[0] == '#' {
- hex = hex[1:]
- }
- var r, g, b uint8
- fmt.Sscanf(hex, "%02x%02x%02x", &r, &g, &b)
- return RGB{
- R: float64(r) / 255.0,
- G: float64(g) / 255.0,
- B: float64(b) / 255.0,
- }
-}
-
-func RGBToHex(rgb RGB) string {
- r := math.Max(0, math.Min(1, rgb.R))
- g := math.Max(0, math.Min(1, rgb.G))
- b := math.Max(0, math.Min(1, rgb.B))
- return fmt.Sprintf("#%02x%02x%02x", int(r*255), int(g*255), int(b*255))
-}
-
-func RGBToHSV(rgb RGB) HSV {
- max := math.Max(math.Max(rgb.R, rgb.G), rgb.B)
- min := math.Min(math.Min(rgb.R, rgb.G), rgb.B)
- delta := max - min
-
- var h float64
- if delta == 0 {
- h = 0
- } else if max == rgb.R {
- h = math.Mod((rgb.G-rgb.B)/delta, 6.0) / 6.0
- } else if max == rgb.G {
- h = ((rgb.B-rgb.R)/delta + 2.0) / 6.0
- } else {
- h = ((rgb.R-rgb.G)/delta + 4.0) / 6.0
- }
-
- if h < 0 {
- h += 1.0
- }
-
- var s float64
- if max == 0 {
- s = 0
- } else {
- s = delta / max
- }
-
- return HSV{H: h, S: s, V: max}
-}
-
-func HSVToRGB(hsv HSV) RGB {
- h := hsv.H * 6.0
- c := hsv.V * hsv.S
- x := c * (1.0 - math.Abs(math.Mod(h, 2.0)-1.0))
- m := hsv.V - c
-
- var r, g, b float64
- switch int(h) {
- case 0:
- r, g, b = c, x, 0
- case 1:
- r, g, b = x, c, 0
- case 2:
- r, g, b = 0, c, x
- case 3:
- r, g, b = 0, x, c
- case 4:
- r, g, b = x, 0, c
- case 5:
- r, g, b = c, 0, x
- default:
- r, g, b = c, 0, x
- }
-
- return RGB{R: r + m, G: g + m, B: b + m}
-}
-
-func sRGBToLinear(c float64) float64 {
- if c <= 0.04045 {
- return c / 12.92
- }
- return math.Pow((c+0.055)/1.055, 2.4)
-}
-
-func Luminance(hex string) float64 {
- rgb := HexToRGB(hex)
- return 0.2126*sRGBToLinear(rgb.R) + 0.7152*sRGBToLinear(rgb.G) + 0.0722*sRGBToLinear(rgb.B)
-}
-
-func ContrastRatio(hexFg, hexBg string) float64 {
- lumFg := Luminance(hexFg)
- lumBg := Luminance(hexBg)
- lighter := math.Max(lumFg, lumBg)
- darker := math.Min(lumFg, lumBg)
- return (lighter + 0.05) / (darker + 0.05)
-}
-
-func getLstar(hex string) float64 {
- rgb := HexToRGB(hex)
- col := colorful.Color{R: rgb.R, G: rgb.G, B: rgb.B}
- L, _, _ := col.Lab()
- return L * 100.0 // go-colorful uses 0-1, we need 0-100 for DPS
-}
-
-// Lab to hex, clamping if needed
-func labToHex(L, a, b float64) string {
- c := colorful.Lab(L/100.0, a, b) // back to 0-1 for go-colorful
- r, g, b2 := c.Clamped().RGB255()
- return fmt.Sprintf("#%02x%02x%02x", r, g, b2)
-}
-
-// Adjust brightness while keeping the same hue
-func retoneToL(hex string, Ltarget float64) string {
- rgb := HexToRGB(hex)
- col := colorful.Color{R: rgb.R, G: rgb.G, B: rgb.B}
- L, a, b := col.Lab()
- L100 := L * 100.0
-
- scale := 1.0
- if L100 != 0 {
- scale = Ltarget / L100
- }
-
- a2, b2 := a*scale, b*scale
-
- // Don't let it get too saturated
- maxChroma := 0.4
- if math.Hypot(a2, b2) > maxChroma {
- k := maxChroma / math.Hypot(a2, b2)
- a2 *= k
- b2 *= k
- }
-
- return labToHex(Ltarget, a2, b2)
-}
-
-func DeltaPhiStar(hexFg, hexBg string, negativePolarity bool) float64 {
- Lf := getLstar(hexFg)
- Lb := getLstar(hexBg)
-
- phi := 1.618
- inv := 0.618
- lc := math.Pow(math.Abs(math.Pow(Lb, phi)-math.Pow(Lf, phi)), inv)*1.414 - 40
-
- if negativePolarity {
- lc += 5
- }
-
- return lc
-}
-
-func DeltaPhiStarContrast(hexFg, hexBg string, isLightMode bool) float64 {
- negativePolarity := !isLightMode
- return DeltaPhiStar(hexFg, hexBg, negativePolarity)
-}
-
-func EnsureContrast(hexColor, hexBg string, minRatio float64, isLightMode bool) string {
- currentRatio := ContrastRatio(hexColor, hexBg)
- if currentRatio >= minRatio {
- return hexColor
- }
-
- rgb := HexToRGB(hexColor)
- hsv := RGBToHSV(rgb)
-
- for step := 1; step < 30; step++ {
- delta := float64(step) * 0.02
-
- if isLightMode {
- newV := math.Max(0, hsv.V-delta)
- candidate := RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV}))
- if ContrastRatio(candidate, hexBg) >= minRatio {
- return candidate
- }
-
- newV = math.Min(1, hsv.V+delta)
- candidate = RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV}))
- if ContrastRatio(candidate, hexBg) >= minRatio {
- return candidate
- }
- } else {
- newV := math.Min(1, hsv.V+delta)
- candidate := RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV}))
- if ContrastRatio(candidate, hexBg) >= minRatio {
- return candidate
- }
-
- newV = math.Max(0, hsv.V-delta)
- candidate = RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV}))
- if ContrastRatio(candidate, hexBg) >= minRatio {
- return candidate
- }
- }
- }
-
- return hexColor
-}
-
-func EnsureContrastDPS(hexColor, hexBg string, minLc float64, isLightMode bool) string {
- currentLc := DeltaPhiStarContrast(hexColor, hexBg, isLightMode)
- if currentLc >= minLc {
- return hexColor
- }
-
- rgb := HexToRGB(hexColor)
- hsv := RGBToHSV(rgb)
-
- for step := 1; step < 50; step++ {
- delta := float64(step) * 0.015
-
- if isLightMode {
- newV := math.Max(0, hsv.V-delta)
- candidate := RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV}))
- if DeltaPhiStarContrast(candidate, hexBg, isLightMode) >= minLc {
- return candidate
- }
-
- newV = math.Min(1, hsv.V+delta)
- candidate = RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV}))
- if DeltaPhiStarContrast(candidate, hexBg, isLightMode) >= minLc {
- return candidate
- }
- } else {
- newV := math.Min(1, hsv.V+delta)
- candidate := RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV}))
- if DeltaPhiStarContrast(candidate, hexBg, isLightMode) >= minLc {
- return candidate
- }
-
- newV = math.Max(0, hsv.V-delta)
- candidate = RGBToHex(HSVToRGB(HSV{H: hsv.H, S: hsv.S, V: newV}))
- if DeltaPhiStarContrast(candidate, hexBg, isLightMode) >= minLc {
- return candidate
- }
- }
- }
-
- return hexColor
-}
-
-// Nudge L* until contrast is good enough. Keeps hue intact unlike HSV fiddling.
-func EnsureContrastDPSLstar(hexColor, hexBg string, minLc float64, isLightMode bool) string {
- current := DeltaPhiStarContrast(hexColor, hexBg, isLightMode)
- if current >= minLc {
- return hexColor
- }
-
- fg := HexToRGB(hexColor)
- cf := colorful.Color{R: fg.R, G: fg.G, B: fg.B}
- Lf, af, bf := cf.Lab()
-
- dir := 1.0
- if isLightMode {
- dir = -1.0 // light mode = darker text
- }
-
- step := 0.5
- for i := 0; i < 120; i++ {
- Lf = math.Max(0, math.Min(100, Lf+dir*step))
- cand := labToHex(Lf, af, bf)
- if DeltaPhiStarContrast(cand, hexBg, isLightMode) >= minLc {
- return cand
- }
- }
-
- return hexColor
-}
-
-type PaletteOptions struct {
- IsLight bool
- Background string
- UseDPS bool
-}
-
-func ensureContrastAuto(hexColor, hexBg string, target float64, opts PaletteOptions) string {
- if opts.UseDPS {
- return EnsureContrastDPSLstar(hexColor, hexBg, target, opts.IsLight)
- }
- return EnsureContrast(hexColor, hexBg, target, opts.IsLight)
-}
-
-func DeriveContainer(primary string, isLight bool) string {
- rgb := HexToRGB(primary)
- hsv := RGBToHSV(rgb)
-
- if isLight {
- containerV := math.Min(hsv.V*1.77, 1.0)
- containerS := hsv.S * 0.32
- return RGBToHex(HSVToRGB(HSV{H: hsv.H, S: containerS, V: containerV}))
- }
- containerV := hsv.V * 0.463
- containerS := math.Min(hsv.S*1.834, 1.0)
- return RGBToHex(HSVToRGB(HSV{H: hsv.H, S: containerS, V: containerV}))
-}
-
-func GeneratePalette(primaryColor string, opts PaletteOptions) []string {
- baseColor := DeriveContainer(primaryColor, opts.IsLight)
-
- rgb := HexToRGB(baseColor)
- hsv := RGBToHSV(rgb)
-
- palette := make([]string, 0, 16)
-
- var normalTextTarget, secondaryTarget float64
- if opts.UseDPS {
- normalTextTarget = 40.0
- secondaryTarget = 35.0
- } else {
- normalTextTarget = 4.5
- secondaryTarget = 3.0
- }
-
- var bgColor string
- if opts.Background != "" {
- bgColor = opts.Background
- } else if opts.IsLight {
- bgColor = "#f8f8f8"
- } else {
- bgColor = "#1a1a1a"
- }
- palette = append(palette, bgColor)
-
- hueShift := (hsv.H - 0.6) * 0.12
- satBoost := 1.15
-
- redH := math.Mod(0.0+hueShift+1.0, 1.0)
- var redColor string
- if opts.IsLight {
- redColor = RGBToHex(HSVToRGB(HSV{H: redH, S: math.Min(0.80*satBoost, 1.0), V: 0.55}))
- palette = append(palette, ensureContrastAuto(redColor, bgColor, normalTextTarget, opts))
- } else {
- redColor = RGBToHex(HSVToRGB(HSV{H: redH, S: math.Min(0.65*satBoost, 1.0), V: 0.80}))
- palette = append(palette, ensureContrastAuto(redColor, bgColor, normalTextTarget, opts))
- }
-
- greenH := math.Mod(0.33+hueShift+1.0, 1.0)
- var greenColor string
- if opts.IsLight {
- greenColor = RGBToHex(HSVToRGB(HSV{H: greenH, S: math.Min(math.Max(hsv.S*0.9, 0.80)*satBoost, 1.0), V: 0.45}))
- palette = append(palette, ensureContrastAuto(greenColor, bgColor, normalTextTarget, opts))
- } else {
- greenColor = RGBToHex(HSVToRGB(HSV{H: greenH, S: math.Min(0.42*satBoost, 1.0), V: 0.84}))
- palette = append(palette, ensureContrastAuto(greenColor, bgColor, normalTextTarget, opts))
- }
-
- yellowH := math.Mod(0.15+hueShift+1.0, 1.0)
- var yellowColor string
- if opts.IsLight {
- yellowColor = RGBToHex(HSVToRGB(HSV{H: yellowH, S: math.Min(0.75*satBoost, 1.0), V: 0.50}))
- palette = append(palette, ensureContrastAuto(yellowColor, bgColor, normalTextTarget, opts))
- } else {
- yellowColor = RGBToHex(HSVToRGB(HSV{H: yellowH, S: math.Min(0.38*satBoost, 1.0), V: 0.86}))
- palette = append(palette, ensureContrastAuto(yellowColor, bgColor, normalTextTarget, opts))
- }
-
- var blueColor string
- if opts.IsLight {
- blueColor = RGBToHex(HSVToRGB(HSV{H: hsv.H, S: math.Max(hsv.S*0.9, 0.7), V: hsv.V * 1.1}))
- palette = append(palette, ensureContrastAuto(blueColor, bgColor, normalTextTarget, opts))
- } else {
- blueColor = RGBToHex(HSVToRGB(HSV{H: hsv.H, S: math.Max(hsv.S*0.8, 0.6), V: math.Min(hsv.V*1.6, 1.0)}))
- palette = append(palette, ensureContrastAuto(blueColor, bgColor, normalTextTarget, opts))
- }
-
- magH := hsv.H - 0.03
- if magH < 0 {
- magH += 1.0
- }
- var magColor string
- hr := HexToRGB(primaryColor)
- hh := RGBToHSV(hr)
- if opts.IsLight {
- magColor = RGBToHex(HSVToRGB(HSV{H: hh.H, S: math.Max(hh.S*0.9, 0.7), V: hh.V * 0.85}))
- palette = append(palette, ensureContrastAuto(magColor, bgColor, normalTextTarget, opts))
- } else {
- magColor = RGBToHex(HSVToRGB(HSV{H: hh.H, S: hh.S * 0.8, V: hh.V * 0.75}))
- palette = append(palette, ensureContrastAuto(magColor, bgColor, normalTextTarget, opts))
- }
-
- cyanH := hsv.H + 0.08
- if cyanH > 1.0 {
- cyanH -= 1.0
- }
- palette = append(palette, ensureContrastAuto(primaryColor, bgColor, normalTextTarget, opts))
-
- if opts.IsLight {
- palette = append(palette, "#1a1a1a")
- palette = append(palette, "#2e2e2e")
- } else {
- palette = append(palette, "#abb2bf")
- palette = append(palette, "#5c6370")
- }
-
- if opts.IsLight {
- brightRed := RGBToHex(HSVToRGB(HSV{H: redH, S: math.Min(0.70*satBoost, 1.0), V: 0.65}))
- palette = append(palette, ensureContrastAuto(brightRed, bgColor, secondaryTarget, opts))
- brightGreen := RGBToHex(HSVToRGB(HSV{H: greenH, S: math.Min(math.Max(hsv.S*0.85, 0.75)*satBoost, 1.0), V: 0.55}))
- palette = append(palette, ensureContrastAuto(brightGreen, bgColor, secondaryTarget, opts))
- brightYellow := RGBToHex(HSVToRGB(HSV{H: yellowH, S: math.Min(0.68*satBoost, 1.0), V: 0.60}))
- palette = append(palette, ensureContrastAuto(brightYellow, bgColor, secondaryTarget, opts))
- hr := HexToRGB(primaryColor)
- hh := RGBToHSV(hr)
- brightBlue := RGBToHex(HSVToRGB(HSV{H: hh.H, S: math.Min(hh.S*1.1, 1.0), V: math.Min(hh.V*1.2, 1.0)}))
- palette = append(palette, ensureContrastAuto(brightBlue, bgColor, secondaryTarget, opts))
- brightMag := RGBToHex(HSVToRGB(HSV{H: magH, S: math.Max(hsv.S*0.9, 0.75), V: math.Min(hsv.V*1.25, 1.0)}))
- palette = append(palette, ensureContrastAuto(brightMag, bgColor, secondaryTarget, opts))
- brightCyan := RGBToHex(HSVToRGB(HSV{H: cyanH, S: math.Max(hsv.S*0.75, 0.65), V: math.Min(hsv.V*1.25, 1.0)}))
- palette = append(palette, ensureContrastAuto(brightCyan, bgColor, secondaryTarget, opts))
- } else {
- brightRed := RGBToHex(HSVToRGB(HSV{H: redH, S: math.Min(0.50*satBoost, 1.0), V: 0.88}))
- palette = append(palette, ensureContrastAuto(brightRed, bgColor, secondaryTarget, opts))
- brightGreen := RGBToHex(HSVToRGB(HSV{H: greenH, S: math.Min(0.35*satBoost, 1.0), V: 0.88}))
- palette = append(palette, ensureContrastAuto(brightGreen, bgColor, secondaryTarget, opts))
- brightYellow := RGBToHex(HSVToRGB(HSV{H: yellowH, S: math.Min(0.30*satBoost, 1.0), V: 0.91}))
- palette = append(palette, ensureContrastAuto(brightYellow, bgColor, secondaryTarget, opts))
- // Make it way brighter for type names in dark mode
- brightBlue := retoneToL(primaryColor, 85.0)
- palette = append(palette, brightBlue)
- brightMag := RGBToHex(HSVToRGB(HSV{H: magH, S: math.Max(hsv.S*0.7, 0.6), V: math.Min(hsv.V*1.3, 0.9)}))
- palette = append(palette, ensureContrastAuto(brightMag, bgColor, secondaryTarget, opts))
- brightCyanH := hsv.H + 0.02
- if brightCyanH > 1.0 {
- brightCyanH -= 1.0
- }
- brightCyan := RGBToHex(HSVToRGB(HSV{H: brightCyanH, S: math.Max(hsv.S*0.6, 0.5), V: math.Min(hsv.V*1.2, 0.85)}))
- palette = append(palette, ensureContrastAuto(brightCyan, bgColor, secondaryTarget, opts))
- }
-
- if opts.IsLight {
- palette = append(palette, "#1a1a1a")
- } else {
- palette = append(palette, "#ffffff")
- }
-
- return palette
-}
diff --git a/nix/inputs/dms-cli/internal/dank16/dank16_test.go b/nix/inputs/dms-cli/internal/dank16/dank16_test.go
deleted file mode 100644
index 4b6f167..0000000
--- a/nix/inputs/dms-cli/internal/dank16/dank16_test.go
+++ /dev/null
@@ -1,727 +0,0 @@
-package dank16
-
-import (
- "encoding/json"
- "math"
- "testing"
-)
-
-func TestHexToRGB(t *testing.T) {
- tests := []struct {
- name string
- input string
- expected RGB
- }{
- {
- name: "black with hash",
- input: "#000000",
- expected: RGB{R: 0.0, G: 0.0, B: 0.0},
- },
- {
- name: "white with hash",
- input: "#ffffff",
- expected: RGB{R: 1.0, G: 1.0, B: 1.0},
- },
- {
- name: "red without hash",
- input: "ff0000",
- expected: RGB{R: 1.0, G: 0.0, B: 0.0},
- },
- {
- name: "purple",
- input: "#625690",
- expected: RGB{R: 0.3843137254901961, G: 0.33725490196078434, B: 0.5647058823529412},
- },
- {
- name: "mid gray",
- input: "#808080",
- expected: RGB{R: 0.5019607843137255, G: 0.5019607843137255, B: 0.5019607843137255},
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := HexToRGB(tt.input)
- if !floatEqual(result.R, tt.expected.R) || !floatEqual(result.G, tt.expected.G) || !floatEqual(result.B, tt.expected.B) {
- t.Errorf("HexToRGB(%s) = %v, expected %v", tt.input, result, tt.expected)
- }
- })
- }
-}
-
-func TestRGBToHex(t *testing.T) {
- tests := []struct {
- name string
- input RGB
- expected string
- }{
- {
- name: "black",
- input: RGB{R: 0.0, G: 0.0, B: 0.0},
- expected: "#000000",
- },
- {
- name: "white",
- input: RGB{R: 1.0, G: 1.0, B: 1.0},
- expected: "#ffffff",
- },
- {
- name: "red",
- input: RGB{R: 1.0, G: 0.0, B: 0.0},
- expected: "#ff0000",
- },
- {
- name: "clamping above 1.0",
- input: RGB{R: 1.5, G: 0.5, B: 0.5},
- expected: "#ff7f7f",
- },
- {
- name: "clamping below 0.0",
- input: RGB{R: -0.5, G: 0.5, B: 0.5},
- expected: "#007f7f",
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := RGBToHex(tt.input)
- if result != tt.expected {
- t.Errorf("RGBToHex(%v) = %s, expected %s", tt.input, result, tt.expected)
- }
- })
- }
-}
-
-func TestRGBToHSV(t *testing.T) {
- tests := []struct {
- name string
- input RGB
- expected HSV
- }{
- {
- name: "black",
- input: RGB{R: 0.0, G: 0.0, B: 0.0},
- expected: HSV{H: 0.0, S: 0.0, V: 0.0},
- },
- {
- name: "white",
- input: RGB{R: 1.0, G: 1.0, B: 1.0},
- expected: HSV{H: 0.0, S: 0.0, V: 1.0},
- },
- {
- name: "red",
- input: RGB{R: 1.0, G: 0.0, B: 0.0},
- expected: HSV{H: 0.0, S: 1.0, V: 1.0},
- },
- {
- name: "green",
- input: RGB{R: 0.0, G: 1.0, B: 0.0},
- expected: HSV{H: 0.3333333333333333, S: 1.0, V: 1.0},
- },
- {
- name: "blue",
- input: RGB{R: 0.0, G: 0.0, B: 1.0},
- expected: HSV{H: 0.6666666666666666, S: 1.0, V: 1.0},
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := RGBToHSV(tt.input)
- if !floatEqual(result.H, tt.expected.H) || !floatEqual(result.S, tt.expected.S) || !floatEqual(result.V, tt.expected.V) {
- t.Errorf("RGBToHSV(%v) = %v, expected %v", tt.input, result, tt.expected)
- }
- })
- }
-}
-
-func TestHSVToRGB(t *testing.T) {
- tests := []struct {
- name string
- input HSV
- expected RGB
- }{
- {
- name: "black",
- input: HSV{H: 0.0, S: 0.0, V: 0.0},
- expected: RGB{R: 0.0, G: 0.0, B: 0.0},
- },
- {
- name: "white",
- input: HSV{H: 0.0, S: 0.0, V: 1.0},
- expected: RGB{R: 1.0, G: 1.0, B: 1.0},
- },
- {
- name: "red",
- input: HSV{H: 0.0, S: 1.0, V: 1.0},
- expected: RGB{R: 1.0, G: 0.0, B: 0.0},
- },
- {
- name: "green",
- input: HSV{H: 0.3333333333333333, S: 1.0, V: 1.0},
- expected: RGB{R: 0.0, G: 1.0, B: 0.0},
- },
- {
- name: "blue",
- input: HSV{H: 0.6666666666666666, S: 1.0, V: 1.0},
- expected: RGB{R: 0.0, G: 0.0, B: 1.0},
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := HSVToRGB(tt.input)
- if !floatEqual(result.R, tt.expected.R) || !floatEqual(result.G, tt.expected.G) || !floatEqual(result.B, tt.expected.B) {
- t.Errorf("HSVToRGB(%v) = %v, expected %v", tt.input, result, tt.expected)
- }
- })
- }
-}
-
-func TestLuminance(t *testing.T) {
- tests := []struct {
- name string
- input string
- expected float64
- }{
- {
- name: "black",
- input: "#000000",
- expected: 0.0,
- },
- {
- name: "white",
- input: "#ffffff",
- expected: 1.0,
- },
- {
- name: "red",
- input: "#ff0000",
- expected: 0.2126,
- },
- {
- name: "green",
- input: "#00ff00",
- expected: 0.7152,
- },
- {
- name: "blue",
- input: "#0000ff",
- expected: 0.0722,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := Luminance(tt.input)
- if !floatEqual(result, tt.expected) {
- t.Errorf("Luminance(%s) = %f, expected %f", tt.input, result, tt.expected)
- }
- })
- }
-}
-
-func TestContrastRatio(t *testing.T) {
- tests := []struct {
- name string
- fg string
- bg string
- expected float64
- }{
- {
- name: "black on white",
- fg: "#000000",
- bg: "#ffffff",
- expected: 21.0,
- },
- {
- name: "white on black",
- fg: "#ffffff",
- bg: "#000000",
- expected: 21.0,
- },
- {
- name: "same color",
- fg: "#808080",
- bg: "#808080",
- expected: 1.0,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := ContrastRatio(tt.fg, tt.bg)
- if !floatEqual(result, tt.expected) {
- t.Errorf("ContrastRatio(%s, %s) = %f, expected %f", tt.fg, tt.bg, result, tt.expected)
- }
- })
- }
-}
-
-func TestEnsureContrast(t *testing.T) {
- tests := []struct {
- name string
- color string
- bg string
- minRatio float64
- isLightMode bool
- }{
- {
- name: "already sufficient contrast dark mode",
- color: "#ffffff",
- bg: "#000000",
- minRatio: 4.5,
- isLightMode: false,
- },
- {
- name: "already sufficient contrast light mode",
- color: "#000000",
- bg: "#ffffff",
- minRatio: 4.5,
- isLightMode: true,
- },
- {
- name: "needs adjustment dark mode",
- color: "#404040",
- bg: "#1a1a1a",
- minRatio: 4.5,
- isLightMode: false,
- },
- {
- name: "needs adjustment light mode",
- color: "#c0c0c0",
- bg: "#f8f8f8",
- minRatio: 4.5,
- isLightMode: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := EnsureContrast(tt.color, tt.bg, tt.minRatio, tt.isLightMode)
- actualRatio := ContrastRatio(result, tt.bg)
- if actualRatio < tt.minRatio {
- t.Errorf("EnsureContrast(%s, %s, %f, %t) = %s with ratio %f, expected ratio >= %f",
- tt.color, tt.bg, tt.minRatio, tt.isLightMode, result, actualRatio, tt.minRatio)
- }
- })
- }
-}
-
-func TestGeneratePalette(t *testing.T) {
- tests := []struct {
- name string
- base string
- opts PaletteOptions
- }{
- {
- name: "dark theme default",
- base: "#625690",
- opts: PaletteOptions{IsLight: false},
- },
- {
- name: "light theme default",
- base: "#625690",
- opts: PaletteOptions{IsLight: true},
- },
- {
- name: "light theme with custom background",
- base: "#625690",
- opts: PaletteOptions{
- IsLight: true,
- Background: "#fafafa",
- },
- },
- {
- name: "dark theme with custom background",
- base: "#625690",
- opts: PaletteOptions{
- IsLight: false,
- Background: "#0a0a0a",
- },
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := GeneratePalette(tt.base, tt.opts)
-
- if len(result) != 16 {
- t.Errorf("GeneratePalette returned %d colors, expected 16", len(result))
- }
-
- for i, color := range result {
- if len(color) != 7 || color[0] != '#' {
- t.Errorf("Color at index %d (%s) is not a valid hex color", i, color)
- }
- }
-
- if tt.opts.Background != "" && result[0] != tt.opts.Background {
- t.Errorf("Background color = %s, expected %s", result[0], tt.opts.Background)
- } else if !tt.opts.IsLight && tt.opts.Background == "" && result[0] != "#1a1a1a" {
- t.Errorf("Dark mode background = %s, expected #1a1a1a", result[0])
- } else if tt.opts.IsLight && tt.opts.Background == "" && result[0] != "#f8f8f8" {
- t.Errorf("Light mode background = %s, expected #f8f8f8", result[0])
- }
-
- if tt.opts.IsLight && result[15] != "#1a1a1a" {
- t.Errorf("Light mode foreground = %s, expected #1a1a1a", result[15])
- } else if !tt.opts.IsLight && result[15] != "#ffffff" {
- t.Errorf("Dark mode foreground = %s, expected #ffffff", result[15])
- }
- })
- }
-}
-
-func TestEnrichVSCodeTheme(t *testing.T) {
- colors := GeneratePalette("#625690", PaletteOptions{IsLight: false})
-
- baseTheme := map[string]interface{}{
- "name": "Test Theme",
- "type": "dark",
- "colors": map[string]interface{}{
- "editor.background": "#000000",
- },
- }
-
- themeJSON, err := json.Marshal(baseTheme)
- if err != nil {
- t.Fatalf("Failed to marshal base theme: %v", err)
- }
-
- result, err := EnrichVSCodeTheme(themeJSON, colors)
- if err != nil {
- t.Fatalf("EnrichVSCodeTheme failed: %v", err)
- }
-
- var enriched map[string]interface{}
- if err := json.Unmarshal(result, &enriched); err != nil {
- t.Fatalf("Failed to unmarshal result: %v", err)
- }
-
- colorsMap, ok := enriched["colors"].(map[string]interface{})
- if !ok {
- t.Fatal("colors is not a map")
- }
-
- terminalColors := []string{
- "terminal.ansiBlack",
- "terminal.ansiRed",
- "terminal.ansiGreen",
- "terminal.ansiYellow",
- "terminal.ansiBlue",
- "terminal.ansiMagenta",
- "terminal.ansiCyan",
- "terminal.ansiWhite",
- "terminal.ansiBrightBlack",
- "terminal.ansiBrightRed",
- "terminal.ansiBrightGreen",
- "terminal.ansiBrightYellow",
- "terminal.ansiBrightBlue",
- "terminal.ansiBrightMagenta",
- "terminal.ansiBrightCyan",
- "terminal.ansiBrightWhite",
- }
-
- for i, key := range terminalColors {
- if val, ok := colorsMap[key]; !ok {
- t.Errorf("Missing terminal color: %s", key)
- } else if val != colors[i] {
- t.Errorf("%s = %s, expected %s", key, val, colors[i])
- }
- }
-
- if colorsMap["editor.background"] != "#000000" {
- t.Error("Original theme colors should be preserved")
- }
-}
-
-func TestEnrichVSCodeThemeInvalidJSON(t *testing.T) {
- colors := GeneratePalette("#625690", PaletteOptions{IsLight: false})
- invalidJSON := []byte("{invalid json")
-
- _, err := EnrichVSCodeTheme(invalidJSON, colors)
- if err == nil {
- t.Error("Expected error for invalid JSON, got nil")
- }
-}
-
-func TestRoundTripConversion(t *testing.T) {
- testColors := []string{"#000000", "#ffffff", "#ff0000", "#00ff00", "#0000ff", "#625690", "#808080"}
-
- for _, hex := range testColors {
- t.Run(hex, func(t *testing.T) {
- rgb := HexToRGB(hex)
- result := RGBToHex(rgb)
- if result != hex {
- t.Errorf("Round trip %s -> RGB -> %s failed", hex, result)
- }
- })
- }
-}
-
-func TestRGBHSVRoundTrip(t *testing.T) {
- testCases := []RGB{
- {R: 0.0, G: 0.0, B: 0.0},
- {R: 1.0, G: 1.0, B: 1.0},
- {R: 1.0, G: 0.0, B: 0.0},
- {R: 0.0, G: 1.0, B: 0.0},
- {R: 0.0, G: 0.0, B: 1.0},
- {R: 0.5, G: 0.5, B: 0.5},
- {R: 0.3843137254901961, G: 0.33725490196078434, B: 0.5647058823529412},
- }
-
- for _, rgb := range testCases {
- t.Run("", func(t *testing.T) {
- hsv := RGBToHSV(rgb)
- result := HSVToRGB(hsv)
- if !floatEqual(result.R, rgb.R) || !floatEqual(result.G, rgb.G) || !floatEqual(result.B, rgb.B) {
- t.Errorf("Round trip RGB->HSV->RGB failed: %v -> %v -> %v", rgb, hsv, result)
- }
- })
- }
-}
-
-func floatEqual(a, b float64) bool {
- return math.Abs(a-b) < 1e-9
-}
-
-func TestDeltaPhiStar(t *testing.T) {
- tests := []struct {
- name string
- fg string
- bg string
- negativePolarity bool
- minExpected float64
- }{
- {
- name: "white on black (negative polarity)",
- fg: "#ffffff",
- bg: "#000000",
- negativePolarity: true,
- minExpected: 100.0,
- },
- {
- name: "black on white (positive polarity)",
- fg: "#000000",
- bg: "#ffffff",
- negativePolarity: false,
- minExpected: 100.0,
- },
- {
- name: "low contrast same color",
- fg: "#808080",
- bg: "#808080",
- negativePolarity: false,
- minExpected: -40.0,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := DeltaPhiStar(tt.fg, tt.bg, tt.negativePolarity)
- if result < tt.minExpected {
- t.Errorf("DeltaPhiStar(%s, %s, %v) = %f, expected >= %f",
- tt.fg, tt.bg, tt.negativePolarity, result, tt.minExpected)
- }
- })
- }
-}
-
-func TestDeltaPhiStarContrast(t *testing.T) {
- tests := []struct {
- name string
- fg string
- bg string
- isLightMode bool
- minExpected float64
- }{
- {
- name: "white on black (dark mode)",
- fg: "#ffffff",
- bg: "#000000",
- isLightMode: false,
- minExpected: 100.0,
- },
- {
- name: "black on white (light mode)",
- fg: "#000000",
- bg: "#ffffff",
- isLightMode: true,
- minExpected: 100.0,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := DeltaPhiStarContrast(tt.fg, tt.bg, tt.isLightMode)
- if result < tt.minExpected {
- t.Errorf("DeltaPhiStarContrast(%s, %s, %v) = %f, expected >= %f",
- tt.fg, tt.bg, tt.isLightMode, result, tt.minExpected)
- }
- })
- }
-}
-
-func TestEnsureContrastDPS(t *testing.T) {
- tests := []struct {
- name string
- color string
- bg string
- minLc float64
- isLightMode bool
- }{
- {
- name: "already sufficient contrast dark mode",
- color: "#ffffff",
- bg: "#000000",
- minLc: 60.0,
- isLightMode: false,
- },
- {
- name: "already sufficient contrast light mode",
- color: "#000000",
- bg: "#ffffff",
- minLc: 60.0,
- isLightMode: true,
- },
- {
- name: "needs adjustment dark mode",
- color: "#404040",
- bg: "#1a1a1a",
- minLc: 60.0,
- isLightMode: false,
- },
- {
- name: "needs adjustment light mode",
- color: "#c0c0c0",
- bg: "#f8f8f8",
- minLc: 60.0,
- isLightMode: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := EnsureContrastDPS(tt.color, tt.bg, tt.minLc, tt.isLightMode)
- actualLc := DeltaPhiStarContrast(result, tt.bg, tt.isLightMode)
- if actualLc < tt.minLc {
- t.Errorf("EnsureContrastDPS(%s, %s, %f, %t) = %s with Lc %f, expected Lc >= %f",
- tt.color, tt.bg, tt.minLc, tt.isLightMode, result, actualLc, tt.minLc)
- }
- })
- }
-}
-
-func TestGeneratePaletteWithDPS(t *testing.T) {
- tests := []struct {
- name string
- base string
- opts PaletteOptions
- }{
- {
- name: "dark theme with DPS",
- base: "#625690",
- opts: PaletteOptions{IsLight: false, UseDPS: true},
- },
- {
- name: "light theme with DPS",
- base: "#625690",
- opts: PaletteOptions{IsLight: true, UseDPS: true},
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := GeneratePalette(tt.base, tt.opts)
-
- if len(result) != 16 {
- t.Errorf("GeneratePalette returned %d colors, expected 16", len(result))
- }
-
- for i, color := range result {
- if len(color) != 7 || color[0] != '#' {
- t.Errorf("Color at index %d (%s) is not a valid hex color", i, color)
- }
- }
-
- bgColor := result[0]
- for i := 1; i < 8; i++ {
- lc := DeltaPhiStarContrast(result[i], bgColor, tt.opts.IsLight)
- minLc := 30.0
- if lc < minLc && lc > 0 {
- t.Errorf("Color %d (%s) has insufficient DPS contrast %f with background %s (expected >= %f)",
- i, result[i], lc, bgColor, minLc)
- }
- }
- })
- }
-}
-
-func TestDeriveContainer(t *testing.T) {
- tests := []struct {
- name string
- primary string
- isLight bool
- expected string
- }{
- {
- name: "dark mode",
- primary: "#ccbdff",
- isLight: false,
- expected: "#4a3e76",
- },
- {
- name: "light mode",
- primary: "#625690",
- isLight: true,
- expected: "#e7deff",
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := DeriveContainer(tt.primary, tt.isLight)
-
- resultRGB := HexToRGB(result)
- expectedRGB := HexToRGB(tt.expected)
-
- rDiff := math.Abs(resultRGB.R - expectedRGB.R)
- gDiff := math.Abs(resultRGB.G - expectedRGB.G)
- bDiff := math.Abs(resultRGB.B - expectedRGB.B)
-
- tolerance := 0.02
- if rDiff > tolerance || gDiff > tolerance || bDiff > tolerance {
- t.Errorf("DeriveContainer(%s, %v) = %s, expected %s (RGB diff: R:%.4f G:%.4f B:%.4f)",
- tt.primary, tt.isLight, result, tt.expected, rDiff, gDiff, bDiff)
- }
- })
- }
-}
-
-func TestContrastAlgorithmComparison(t *testing.T) {
- base := "#625690"
-
- optsWCAG := PaletteOptions{IsLight: false, UseDPS: false}
- optsDPS := PaletteOptions{IsLight: false, UseDPS: true}
-
- paletteWCAG := GeneratePalette(base, optsWCAG)
- paletteDPS := GeneratePalette(base, optsDPS)
-
- if len(paletteWCAG) != 16 || len(paletteDPS) != 16 {
- t.Fatal("Both palettes should have 16 colors")
- }
-
- if paletteWCAG[0] != paletteDPS[0] {
- t.Errorf("Background colors differ: WCAG=%s, DPS=%s", paletteWCAG[0], paletteDPS[0])
- }
-
- differentCount := 0
- for i := 0; i < 16; i++ {
- if paletteWCAG[i] != paletteDPS[i] {
- differentCount++
- }
- }
-
- t.Logf("WCAG and DPS palettes differ in %d/16 colors", differentCount)
-}
diff --git a/nix/inputs/dms-cli/internal/dank16/terminals.go b/nix/inputs/dms-cli/internal/dank16/terminals.go
deleted file mode 100644
index d2290b6..0000000
--- a/nix/inputs/dms-cli/internal/dank16/terminals.go
+++ /dev/null
@@ -1,126 +0,0 @@
-package dank16
-
-import (
- "encoding/json"
- "fmt"
- "strings"
-)
-
-func GenerateJSON(colors []string) string {
- colorMap := make(map[string]string)
-
- for i, color := range colors {
- colorMap[fmt.Sprintf("color%d", i)] = color
- }
-
- marshalled, _ := json.Marshal(colorMap)
-
- return string(marshalled)
-}
-
-func GenerateKittyTheme(colors []string) string {
- kittyColors := []struct {
- name string
- index int
- }{
- {"color0", 0},
- {"color1", 1},
- {"color2", 2},
- {"color3", 3},
- {"color4", 4},
- {"color5", 5},
- {"color6", 6},
- {"color7", 7},
- {"color8", 8},
- {"color9", 9},
- {"color10", 10},
- {"color11", 11},
- {"color12", 12},
- {"color13", 13},
- {"color14", 14},
- {"color15", 15},
- }
-
- var result strings.Builder
- for _, kc := range kittyColors {
- fmt.Fprintf(&result, "%s %s\n", kc.name, colors[kc.index])
- }
- return result.String()
-}
-
-func GenerateFootTheme(colors []string) string {
- footColors := []struct {
- name string
- index int
- }{
- {"regular0", 0},
- {"regular1", 1},
- {"regular2", 2},
- {"regular3", 3},
- {"regular4", 4},
- {"regular5", 5},
- {"regular6", 6},
- {"regular7", 7},
- {"bright0", 8},
- {"bright1", 9},
- {"bright2", 10},
- {"bright3", 11},
- {"bright4", 12},
- {"bright5", 13},
- {"bright6", 14},
- {"bright7", 15},
- }
-
- var result strings.Builder
- for _, fc := range footColors {
- fmt.Fprintf(&result, "%s=%s\n", fc.name, strings.TrimPrefix(colors[fc.index], "#"))
- }
- return result.String()
-}
-
-func GenerateAlacrittyTheme(colors []string) string {
- alacrittyColors := []struct {
- section string
- name string
- index int
- }{
- {"normal", "black", 0},
- {"normal", "red", 1},
- {"normal", "green", 2},
- {"normal", "yellow", 3},
- {"normal", "blue", 4},
- {"normal", "magenta", 5},
- {"normal", "cyan", 6},
- {"normal", "white", 7},
- {"bright", "black", 8},
- {"bright", "red", 9},
- {"bright", "green", 10},
- {"bright", "yellow", 11},
- {"bright", "blue", 12},
- {"bright", "magenta", 13},
- {"bright", "cyan", 14},
- {"bright", "white", 15},
- }
-
- var result strings.Builder
- currentSection := ""
- for _, ac := range alacrittyColors {
- if ac.section != currentSection {
- if currentSection != "" {
- result.WriteString("\n")
- }
- fmt.Fprintf(&result, "[colors.%s]\n", ac.section)
- currentSection = ac.section
- }
- fmt.Fprintf(&result, "%-7s = '%s'\n", ac.name, colors[ac.index])
- }
- return result.String()
-}
-
-func GenerateGhosttyTheme(colors []string) string {
- var result strings.Builder
- for i, color := range colors {
- fmt.Fprintf(&result, "palette = %d=%s\n", i, color)
- }
- return result.String()
-}
diff --git a/nix/inputs/dms-cli/internal/dank16/vscode.go b/nix/inputs/dms-cli/internal/dank16/vscode.go
deleted file mode 100644
index cd4d4d7..0000000
--- a/nix/inputs/dms-cli/internal/dank16/vscode.go
+++ /dev/null
@@ -1,250 +0,0 @@
-package dank16
-
-import (
- "encoding/json"
- "fmt"
-)
-
-type VSCodeTheme struct {
- Schema string `json:"$schema"`
- Name string `json:"name"`
- Type string `json:"type"`
- Colors map[string]string `json:"colors"`
- TokenColors []VSCodeTokenColor `json:"tokenColors"`
- SemanticHighlighting bool `json:"semanticHighlighting"`
- SemanticTokenColors map[string]VSCodeTokenSetting `json:"semanticTokenColors"`
-}
-
-type VSCodeTokenColor struct {
- Scope interface{} `json:"scope"`
- Settings VSCodeTokenSetting `json:"settings"`
-}
-
-type VSCodeTokenSetting struct {
- Foreground string `json:"foreground,omitempty"`
- FontStyle string `json:"fontStyle,omitempty"`
-}
-
-func updateTokenColor(tc interface{}, scopeToColor map[string]string) {
- tcMap, ok := tc.(map[string]interface{})
- if !ok {
- return
- }
-
- scopes, ok := tcMap["scope"].([]interface{})
- if !ok {
- return
- }
-
- settings, ok := tcMap["settings"].(map[string]interface{})
- if !ok {
- return
- }
-
- isYaml := hasScopeContaining(scopes, "yaml")
-
- for _, scope := range scopes {
- scopeStr, ok := scope.(string)
- if !ok {
- continue
- }
-
- if scopeStr == "string" && isYaml {
- continue
- }
-
- if applyColorToScope(settings, scope, scopeToColor) {
- break
- }
- }
-}
-
-func applyColorToScope(settings map[string]interface{}, scope interface{}, scopeToColor map[string]string) bool {
- scopeStr, ok := scope.(string)
- if !ok {
- return false
- }
-
- newColor, exists := scopeToColor[scopeStr]
- if !exists {
- return false
- }
-
- settings["foreground"] = newColor
- return true
-}
-
-func hasScopeContaining(scopes []interface{}, substring string) bool {
- for _, scope := range scopes {
- scopeStr, ok := scope.(string)
- if !ok {
- continue
- }
-
- for i := 0; i <= len(scopeStr)-len(substring); i++ {
- if scopeStr[i:i+len(substring)] == substring {
- return true
- }
- }
- }
- return false
-}
-
-func EnrichVSCodeTheme(themeData []byte, colors []string) ([]byte, error) {
- var theme map[string]interface{}
- if err := json.Unmarshal(themeData, &theme); err != nil {
- return nil, err
- }
-
- colorsMap, ok := theme["colors"].(map[string]interface{})
- if !ok {
- colorsMap = make(map[string]interface{})
- theme["colors"] = colorsMap
- }
-
- bg := colors[0]
- isLight := false
- if len(bg) == 7 && bg[0] == '#' {
- r, g, b := 0, 0, 0
- fmt.Sscanf(bg[1:], "%02x%02x%02x", &r, &g, &b)
- luminance := (0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b)) / 255.0
- isLight = luminance > 0.5
- }
-
- if isLight {
- theme["type"] = "light"
- } else {
- theme["type"] = "dark"
- }
-
- colorsMap["terminal.ansiBlack"] = colors[0]
- colorsMap["terminal.ansiRed"] = colors[1]
- colorsMap["terminal.ansiGreen"] = colors[2]
- colorsMap["terminal.ansiYellow"] = colors[3]
- colorsMap["terminal.ansiBlue"] = colors[4]
- colorsMap["terminal.ansiMagenta"] = colors[5]
- colorsMap["terminal.ansiCyan"] = colors[6]
- colorsMap["terminal.ansiWhite"] = colors[7]
- colorsMap["terminal.ansiBrightBlack"] = colors[8]
- colorsMap["terminal.ansiBrightRed"] = colors[9]
- colorsMap["terminal.ansiBrightGreen"] = colors[10]
- colorsMap["terminal.ansiBrightYellow"] = colors[11]
- colorsMap["terminal.ansiBrightBlue"] = colors[12]
- colorsMap["terminal.ansiBrightMagenta"] = colors[13]
- colorsMap["terminal.ansiBrightCyan"] = colors[14]
- colorsMap["terminal.ansiBrightWhite"] = colors[15]
-
- tokenColors, ok := theme["tokenColors"].([]interface{})
- if ok {
- scopeToColor := map[string]string{
- "comment": colors[8],
- "punctuation.definition.comment": colors[8],
- "keyword": colors[5],
- "storage.type": colors[13],
- "storage.modifier": colors[5],
- "variable": colors[15],
- "variable.parameter": colors[7],
- "meta.object-literal.key": colors[4],
- "meta.property.object": colors[4],
- "variable.other.property": colors[4],
- "constant.other.symbol": colors[12],
- "constant.numeric": colors[12],
- "constant.language": colors[12],
- "constant.character": colors[3],
- "entity.name.type": colors[12],
- "support.type": colors[13],
- "entity.name.class": colors[12],
- "entity.name.function": colors[2],
- "support.function": colors[2],
- "support.class": colors[15],
- "support.variable": colors[15],
- "variable.language": colors[12],
- "entity.name.tag.yaml": colors[12],
- "string.unquoted.plain.out.yaml": colors[15],
- "string.unquoted.yaml": colors[15],
- "string": colors[3],
- }
-
- for i, tc := range tokenColors {
- updateTokenColor(tc, scopeToColor)
- tokenColors[i] = tc
- }
-
- yamlRules := []VSCodeTokenColor{
- {
- Scope: "entity.name.tag.yaml",
- Settings: VSCodeTokenSetting{Foreground: colors[12]},
- },
- {
- Scope: []string{"string.unquoted.plain.out.yaml", "string.unquoted.yaml"},
- Settings: VSCodeTokenSetting{Foreground: colors[15]},
- },
- }
-
- for _, rule := range yamlRules {
- tokenColors = append(tokenColors, rule)
- }
-
- theme["tokenColors"] = tokenColors
- }
-
- if semanticTokenColors, ok := theme["semanticTokenColors"].(map[string]interface{}); ok {
- updates := map[string]string{
- "variable": colors[15],
- "variable.readonly": colors[12],
- "property": colors[4],
- "function": colors[2],
- "method": colors[2],
- "type": colors[12],
- "class": colors[12],
- "typeParameter": colors[13],
- "enumMember": colors[12],
- "string": colors[3],
- "number": colors[12],
- "comment": colors[8],
- "keyword": colors[5],
- "operator": colors[15],
- "parameter": colors[7],
- "namespace": colors[15],
- }
-
- for key, color := range updates {
- if existing, ok := semanticTokenColors[key].(map[string]interface{}); ok {
- existing["foreground"] = color
- } else {
- semanticTokenColors[key] = map[string]interface{}{
- "foreground": color,
- }
- }
- }
- } else {
- semanticTokenColors := make(map[string]interface{})
- updates := map[string]string{
- "variable": colors[7],
- "variable.readonly": colors[12],
- "property": colors[4],
- "function": colors[2],
- "method": colors[2],
- "type": colors[12],
- "class": colors[12],
- "typeParameter": colors[13],
- "enumMember": colors[12],
- "string": colors[3],
- "number": colors[12],
- "comment": colors[8],
- "keyword": colors[5],
- "operator": colors[15],
- "parameter": colors[7],
- "namespace": colors[15],
- }
-
- for key, color := range updates {
- semanticTokenColors[key] = map[string]interface{}{
- "foreground": color,
- }
- }
- theme["semanticTokenColors"] = semanticTokenColors
- }
-
- return json.MarshalIndent(theme, "", " ")
-}
diff --git a/nix/inputs/dms-cli/internal/deps/detector.go b/nix/inputs/dms-cli/internal/deps/detector.go
deleted file mode 100644
index e4f54a7..0000000
--- a/nix/inputs/dms-cli/internal/deps/detector.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package deps
-
-import (
- "context"
-)
-
-type DependencyStatus int
-
-const (
- StatusMissing DependencyStatus = iota
- StatusInstalled
- StatusNeedsUpdate
- StatusNeedsReinstall
-)
-
-type PackageVariant int
-
-const (
- VariantStable PackageVariant = iota
- VariantGit
-)
-
-type Dependency struct {
- Name string
- Status DependencyStatus
- Version string
- Description string
- Required bool
- Variant PackageVariant
- CanToggle bool
-}
-
-type WindowManager int
-
-const (
- WindowManagerHyprland WindowManager = iota
- WindowManagerNiri
-)
-
-type Terminal int
-
-const (
- TerminalGhostty Terminal = iota
- TerminalKitty
- TerminalAlacritty
-)
-
-type DependencyDetector interface {
- DetectDependencies(ctx context.Context, wm WindowManager) ([]Dependency, error)
- DetectDependenciesWithTerminal(ctx context.Context, wm WindowManager, terminal Terminal) ([]Dependency, error)
-}
diff --git a/nix/inputs/dms-cli/internal/distros/arch.go b/nix/inputs/dms-cli/internal/distros/arch.go
deleted file mode 100644
index 141f966..0000000
--- a/nix/inputs/dms-cli/internal/distros/arch.go
+++ /dev/null
@@ -1,785 +0,0 @@
-package distros
-
-import (
- "context"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
-)
-
-func init() {
- Register("arch", "#1793D1", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewArchDistribution(config, logChan)
- })
- Register("archarm", "#1793D1", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewArchDistribution(config, logChan)
- })
- Register("archcraft", "#1793D1", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewArchDistribution(config, logChan)
- })
- Register("cachyos", "#08A283", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewArchDistribution(config, logChan)
- })
- Register("endeavouros", "#7F3FBF", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewArchDistribution(config, logChan)
- })
- Register("manjaro", "#35BF5C", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewArchDistribution(config, logChan)
- })
- Register("obarun", "#2494be", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewArchDistribution(config, logChan)
- })
- Register("garuda", "#cba6f7", FamilyArch, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewArchDistribution(config, logChan)
- })
-}
-
-type ArchDistribution struct {
- *BaseDistribution
- *ManualPackageInstaller
- config DistroConfig
-}
-
-func NewArchDistribution(config DistroConfig, logChan chan<- string) *ArchDistribution {
- base := NewBaseDistribution(logChan)
- return &ArchDistribution{
- BaseDistribution: base,
- ManualPackageInstaller: &ManualPackageInstaller{BaseDistribution: base},
- config: config,
- }
-}
-
-func (a *ArchDistribution) GetID() string {
- return a.config.ID
-}
-
-func (a *ArchDistribution) GetColorHex() string {
- return a.config.ColorHex
-}
-
-func (a *ArchDistribution) GetFamily() DistroFamily {
- return a.config.Family
-}
-
-func (a *ArchDistribution) GetPackageManager() PackageManagerType {
- return PackageManagerPacman
-}
-
-func (a *ArchDistribution) DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error) {
- return a.DetectDependenciesWithTerminal(ctx, wm, deps.TerminalGhostty)
-}
-
-func (a *ArchDistribution) DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error) {
- var dependencies []deps.Dependency
-
- // DMS at the top (shell is prominent)
- dependencies = append(dependencies, a.detectDMS())
-
- // Terminal with choice support
- dependencies = append(dependencies, a.detectSpecificTerminal(terminal))
-
- // Common detections using base methods
- dependencies = append(dependencies, a.detectGit())
- dependencies = append(dependencies, a.detectWindowManager(wm))
- dependencies = append(dependencies, a.detectQuickshell())
- dependencies = append(dependencies, a.detectXDGPortal())
- dependencies = append(dependencies, a.detectPolkitAgent())
- dependencies = append(dependencies, a.detectAccountsService())
-
- // Hyprland-specific tools
- if wm == deps.WindowManagerHyprland {
- dependencies = append(dependencies, a.detectHyprlandTools()...)
- }
-
- // Niri-specific tools
- if wm == deps.WindowManagerNiri {
- dependencies = append(dependencies, a.detectXwaylandSatellite())
- }
-
- // Base detections (common across distros)
- dependencies = append(dependencies, a.detectMatugen())
- dependencies = append(dependencies, a.detectDgop())
- dependencies = append(dependencies, a.detectHyprpicker())
- dependencies = append(dependencies, a.detectClipboardTools()...)
-
- return dependencies, nil
-}
-
-func (a *ArchDistribution) detectXDGPortal() deps.Dependency {
- status := deps.StatusMissing
- if a.packageInstalled("xdg-desktop-portal-gtk") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "xdg-desktop-portal-gtk",
- Status: status,
- Description: "Desktop integration portal for GTK",
- Required: true,
- }
-}
-
-func (a *ArchDistribution) detectPolkitAgent() deps.Dependency {
- status := deps.StatusMissing
- if a.packageInstalled("mate-polkit") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "mate-polkit",
- Status: status,
- Description: "PolicyKit authentication agent",
- Required: true,
- }
-}
-
-func (a *ArchDistribution) detectAccountsService() deps.Dependency {
- status := deps.StatusMissing
- if a.packageInstalled("accountsservice") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "accountsservice",
- Status: status,
- Description: "D-Bus interface for user account query and manipulation",
- Required: true,
- }
-}
-
-func (a *ArchDistribution) packageInstalled(pkg string) bool {
- cmd := exec.Command("pacman", "-Q", pkg)
- err := cmd.Run()
- return err == nil
-}
-
-func (a *ArchDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping {
- return a.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant))
-}
-
-func (a *ArchDistribution) GetPackageMappingWithVariants(wm deps.WindowManager, variants map[string]deps.PackageVariant) map[string]PackageMapping {
- packages := map[string]PackageMapping{
- "dms (DankMaterialShell)": a.getDMSMapping(variants["dms (DankMaterialShell)"]),
- "git": {Name: "git", Repository: RepoTypeSystem},
- "quickshell": a.getQuickshellMapping(variants["quickshell"]),
- "matugen": a.getMatugenMapping(variants["matugen"]),
- "dgop": {Name: "dgop", Repository: RepoTypeSystem},
- "ghostty": {Name: "ghostty", Repository: RepoTypeSystem},
- "kitty": {Name: "kitty", Repository: RepoTypeSystem},
- "alacritty": {Name: "alacritty", Repository: RepoTypeSystem},
- "cliphist": {Name: "cliphist", Repository: RepoTypeSystem},
- "wl-clipboard": {Name: "wl-clipboard", Repository: RepoTypeSystem},
- "xdg-desktop-portal-gtk": {Name: "xdg-desktop-portal-gtk", Repository: RepoTypeSystem},
- "mate-polkit": {Name: "mate-polkit", Repository: RepoTypeSystem},
- "accountsservice": {Name: "accountsservice", Repository: RepoTypeSystem},
- "hyprpicker": {Name: "hyprpicker", Repository: RepoTypeSystem},
- }
-
- switch wm {
- case deps.WindowManagerHyprland:
- packages["hyprland"] = a.getHyprlandMapping(variants["hyprland"])
- packages["grim"] = PackageMapping{Name: "grim", Repository: RepoTypeSystem}
- packages["slurp"] = PackageMapping{Name: "slurp", Repository: RepoTypeSystem}
- packages["hyprctl"] = a.getHyprlandMapping(variants["hyprland"])
- packages["grimblast"] = PackageMapping{Name: "grimblast", Repository: RepoTypeManual, BuildFunc: "installGrimblast"}
- packages["jq"] = PackageMapping{Name: "jq", Repository: RepoTypeSystem}
- case deps.WindowManagerNiri:
- packages["niri"] = a.getNiriMapping(variants["niri"])
- packages["xwayland-satellite"] = PackageMapping{Name: "xwayland-satellite", Repository: RepoTypeSystem}
- }
-
- return packages
-}
-
-func (a *ArchDistribution) getQuickshellMapping(variant deps.PackageVariant) PackageMapping {
- if forceQuickshellGit || variant == deps.VariantGit {
- return PackageMapping{Name: "quickshell-git", Repository: RepoTypeAUR}
- }
- return PackageMapping{Name: "quickshell", Repository: RepoTypeSystem}
-}
-
-func (a *ArchDistribution) getHyprlandMapping(variant deps.PackageVariant) PackageMapping {
- if variant == deps.VariantGit {
- return PackageMapping{Name: "hyprland-git", Repository: RepoTypeAUR}
- }
- return PackageMapping{Name: "hyprland", Repository: RepoTypeSystem}
-}
-
-func (a *ArchDistribution) getNiriMapping(variant deps.PackageVariant) PackageMapping {
- if variant == deps.VariantGit {
- return PackageMapping{Name: "niri-git", Repository: RepoTypeAUR}
- }
- return PackageMapping{Name: "niri", Repository: RepoTypeSystem}
-}
-
-func (a *ArchDistribution) getMatugenMapping(variant deps.PackageVariant) PackageMapping {
- if runtime.GOARCH == "arm64" {
- return PackageMapping{Name: "matugen-git", Repository: RepoTypeAUR}
- }
-
- if variant == deps.VariantGit {
- return PackageMapping{Name: "matugen-git", Repository: RepoTypeAUR}
- }
- return PackageMapping{Name: "matugen", Repository: RepoTypeSystem}
-}
-
-func (a *ArchDistribution) getDMSMapping(variant deps.PackageVariant) PackageMapping {
- if forceDMSGit || variant == deps.VariantGit {
- return PackageMapping{Name: "dms-shell-git", Repository: RepoTypeAUR}
- }
-
- if a.packageInstalled("dms-shell-git") {
- return PackageMapping{Name: "dms-shell-git", Repository: RepoTypeAUR}
- }
-
- if a.packageInstalled("dms-shell-bin") {
- return PackageMapping{Name: "dms-shell-bin", Repository: RepoTypeAUR}
- }
-
- return PackageMapping{Name: "dms-shell-bin", Repository: RepoTypeAUR}
-}
-
-func (a *ArchDistribution) detectXwaylandSatellite() deps.Dependency {
- status := deps.StatusMissing
- if a.commandExists("xwayland-satellite") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "xwayland-satellite",
- Status: status,
- Description: "Xwayland support",
- Required: true,
- }
-}
-
-func (a *ArchDistribution) InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.06,
- Step: "Checking base-devel...",
- IsComplete: false,
- LogOutput: "Checking if base-devel is installed",
- }
-
- checkCmd := exec.CommandContext(ctx, "pacman", "-Qq", "base-devel")
- if err := checkCmd.Run(); err == nil {
- a.log("base-devel already installed")
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.10,
- Step: "base-devel already installed",
- IsComplete: false,
- LogOutput: "base-devel is already installed on the system",
- }
- return nil
- }
-
- a.log("Installing base-devel...")
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.08,
- Step: "Installing base-devel...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo pacman -S --needed --noconfirm base-devel",
- LogOutput: "Installing base-devel development tools",
- }
-
- cmd := exec.CommandContext(ctx, "bash", "-c", fmt.Sprintf("echo '%s' | sudo -S pacman -S --needed --noconfirm base-devel", sudoPassword))
- if err := a.runWithProgress(cmd, progressChan, PhasePrerequisites, 0.08, 0.10); err != nil {
- return fmt.Errorf("failed to install base-devel: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.12,
- Step: "base-devel installation complete",
- IsComplete: false,
- LogOutput: "base-devel successfully installed",
- }
-
- return nil
-}
-
-func (a *ArchDistribution) InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, progressChan chan<- InstallProgressMsg) error {
- // Phase 1: Check Prerequisites
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.05,
- Step: "Checking system prerequisites...",
- IsComplete: false,
- LogOutput: "Starting prerequisite check...",
- }
-
- if err := a.InstallPrerequisites(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install prerequisites: %w", err)
- }
-
- systemPkgs, aurPkgs, manualPkgs := a.categorizePackages(dependencies, wm, reinstallFlags)
-
- // Phase 3: System Packages
- if len(systemPkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.35,
- Step: fmt.Sprintf("Installing %d system packages...", len(systemPkgs)),
- IsComplete: false,
- NeedsSudo: true,
- LogOutput: fmt.Sprintf("Installing system packages: %s", strings.Join(systemPkgs, ", ")),
- }
- if err := a.installSystemPackages(ctx, systemPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install system packages: %w", err)
- }
- }
-
- // Phase 4: AUR Packages
- if len(aurPkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: 0.65,
- Step: fmt.Sprintf("Installing %d AUR packages...", len(aurPkgs)),
- IsComplete: false,
- LogOutput: fmt.Sprintf("Installing AUR packages: %s", strings.Join(aurPkgs, ", ")),
- }
- if err := a.installAURPackages(ctx, aurPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install AUR packages: %w", err)
- }
- }
-
- // Phase 5: Manual Builds
- if len(manualPkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.85,
- Step: fmt.Sprintf("Building %d packages from source...", len(manualPkgs)),
- IsComplete: false,
- LogOutput: fmt.Sprintf("Building from source: %s", strings.Join(manualPkgs, ", ")),
- }
- if err := a.InstallManualPackages(ctx, manualPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install manual packages: %w", err)
- }
- }
-
- // Phase 6: Configuration
- progressChan <- InstallProgressMsg{
- Phase: PhaseConfiguration,
- Progress: 0.90,
- Step: "Configuring system...",
- IsComplete: false,
- LogOutput: "Starting post-installation configuration...",
- }
-
- // Phase 7: Complete
- progressChan <- InstallProgressMsg{
- Phase: PhaseComplete,
- Progress: 1.0,
- Step: "Installation complete!",
- IsComplete: true,
- LogOutput: "All packages installed and configured successfully",
- }
-
- return nil
-}
-
-func (a *ArchDistribution) categorizePackages(dependencies []deps.Dependency, wm deps.WindowManager, reinstallFlags map[string]bool) ([]string, []string, []string) {
- systemPkgs := []string{}
- aurPkgs := []string{}
- manualPkgs := []string{}
-
- variantMap := make(map[string]deps.PackageVariant)
- for _, dep := range dependencies {
- variantMap[dep.Name] = dep.Variant
- }
-
- packageMap := a.GetPackageMappingWithVariants(wm, variantMap)
-
- for _, dep := range dependencies {
- // Skip installed packages unless marked for reinstall
- if dep.Status == deps.StatusInstalled && !reinstallFlags[dep.Name] {
- continue
- }
-
- pkgInfo, exists := packageMap[dep.Name]
- if !exists {
- // If no mapping exists, treat as manual build
- manualPkgs = append(manualPkgs, dep.Name)
- continue
- }
-
- switch pkgInfo.Repository {
- case RepoTypeAUR:
- aurPkgs = append(aurPkgs, pkgInfo.Name)
- case RepoTypeSystem:
- systemPkgs = append(systemPkgs, pkgInfo.Name)
- case RepoTypeManual:
- manualPkgs = append(manualPkgs, dep.Name)
- }
- }
-
- return systemPkgs, aurPkgs, manualPkgs
-}
-
-func (a *ArchDistribution) installSystemPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- a.log(fmt.Sprintf("Installing system packages: %s", strings.Join(packages, ", ")))
-
- args := []string{"pacman", "-S", "--needed", "--noconfirm"}
- args = append(args, packages...)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.40,
- Step: "Installing system packages...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")),
- }
-
- cmdStr := fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, strings.Join(args, " "))
- cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
- return a.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.40, 0.60)
-}
-
-func (a *ArchDistribution) installAURPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- a.log(fmt.Sprintf("Installing AUR packages manually: %s", strings.Join(packages, ", ")))
-
- hasNiri := false
- hasQuickshell := false
- for _, pkg := range packages {
- if pkg == "niri-git" {
- hasNiri = true
- }
- if pkg == "quickshell" || pkg == "quickshell-git" {
- hasQuickshell = true
- }
- }
-
- // If quickshell is in the list, always reinstall google-breakpad first
- if hasQuickshell {
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: 0.63,
- Step: "Reinstalling google-breakpad for quickshell...",
- IsComplete: false,
- CommandInfo: "Reinstalling prerequisite AUR package for quickshell",
- }
-
- if err := a.installSingleAURPackage(ctx, "google-breakpad", sudoPassword, progressChan, 0.63, 0.65); err != nil {
- return fmt.Errorf("failed to reinstall google-breakpad prerequisite for quickshell: %w", err)
- }
- }
-
- // If niri is in the list, install makepkg-git-lfs-proto first if not already installed
- if hasNiri {
- if !a.packageInstalled("makepkg-git-lfs-proto") {
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: 0.65,
- Step: "Installing makepkg-git-lfs-proto for niri...",
- IsComplete: false,
- CommandInfo: "Installing prerequisite for niri-git",
- }
-
- if err := a.installSingleAURPackage(ctx, "makepkg-git-lfs-proto", sudoPassword, progressChan, 0.65, 0.67); err != nil {
- return fmt.Errorf("failed to install makepkg-git-lfs-proto prerequisite for niri: %w", err)
- }
- }
- }
-
- // Reorder packages to ensure dms-shell-git dependencies are installed first
- orderedPackages := a.reorderAURPackages(packages)
-
- baseProgress := 0.67
- progressStep := 0.13 / float64(len(orderedPackages))
-
- for i, pkg := range orderedPackages {
- currentProgress := baseProgress + (float64(i) * progressStep)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: currentProgress,
- Step: fmt.Sprintf("Installing AUR package %s (%d/%d)...", pkg, i+1, len(packages)),
- IsComplete: false,
- CommandInfo: fmt.Sprintf("Building and installing %s", pkg),
- }
-
- if err := a.installSingleAURPackage(ctx, pkg, sudoPassword, progressChan, currentProgress, currentProgress+progressStep); err != nil {
- return fmt.Errorf("failed to install AUR package %s: %w", pkg, err)
- }
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: 0.80,
- Step: "All AUR packages installed successfully",
- IsComplete: false,
- LogOutput: fmt.Sprintf("Successfully installed AUR packages: %s", strings.Join(packages, ", ")),
- }
-
- return nil
-}
-
-func (a *ArchDistribution) reorderAURPackages(packages []string) []string {
- dmsDepencies := []string{"quickshell", "quickshell-git", "dgop"}
-
- var deps []string
- var others []string
- var dmsShell []string
-
- for _, pkg := range packages {
- if pkg == "dms-shell-git" || pkg == "dms-shell-bin" {
- dmsShell = append(dmsShell, pkg)
- } else {
- isDep := false
- for _, dep := range dmsDepencies {
- if pkg == dep {
- deps = append(deps, pkg)
- isDep = true
- break
- }
- }
- if !isDep {
- others = append(others, pkg)
- }
- }
- }
-
- result := append(deps, others...)
- result = append(result, dmsShell...)
- return result
-}
-
-func (a *ArchDistribution) installSingleAURPackage(ctx context.Context, pkg, sudoPassword string, progressChan chan<- InstallProgressMsg, startProgress, endProgress float64) error {
- homeDir, err := os.UserHomeDir()
- if err != nil {
- return fmt.Errorf("failed to get user home directory: %w", err)
- }
-
- buildDir := filepath.Join(homeDir, ".cache", "dankinstall", "aur-builds", pkg)
-
- // Clean up any existing cache first
- if err := os.RemoveAll(buildDir); err != nil {
- a.log(fmt.Sprintf("Warning: failed to clean existing cache for %s: %v", pkg, err))
- }
-
- if err := os.MkdirAll(buildDir, 0755); err != nil {
- return fmt.Errorf("failed to create build directory: %w", err)
- }
- defer func() {
- if removeErr := os.RemoveAll(buildDir); removeErr != nil {
- a.log(fmt.Sprintf("Warning: failed to cleanup build directory %s: %v", buildDir, removeErr))
- }
- }()
-
- // Clone the AUR package
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: startProgress + 0.1*(endProgress-startProgress),
- Step: fmt.Sprintf("Cloning %s from AUR...", pkg),
- IsComplete: false,
- CommandInfo: fmt.Sprintf("git clone https://aur.archlinux.org/%s.git", pkg),
- }
-
- cloneCmd := exec.CommandContext(ctx, "git", "clone", fmt.Sprintf("https://aur.archlinux.org/%s.git", pkg), filepath.Join(buildDir, pkg))
- if err := a.runWithProgress(cloneCmd, progressChan, PhaseAURPackages, startProgress+0.1*(endProgress-startProgress), startProgress+0.2*(endProgress-startProgress)); err != nil {
- return fmt.Errorf("failed to clone %s: %w", pkg, err)
- }
-
- packageDir := filepath.Join(buildDir, pkg)
-
- if pkg == "niri-git" {
- pkgbuildPath := filepath.Join(packageDir, "PKGBUILD")
- sedCmd := exec.CommandContext(ctx, "sed", "-i", "s/makepkg-git-lfs-proto//g", pkgbuildPath)
- if err := sedCmd.Run(); err != nil {
- return fmt.Errorf("failed to patch PKGBUILD for niri-git: %w", err)
- }
-
- srcinfoPath := filepath.Join(packageDir, ".SRCINFO")
- sedCmd2 := exec.CommandContext(ctx, "sed", "-i", "/makedepends = makepkg-git-lfs-proto/d", srcinfoPath)
- if err := sedCmd2.Run(); err != nil {
- return fmt.Errorf("failed to patch .SRCINFO for niri-git: %w", err)
- }
- }
-
- if pkg == "dms-shell-git" || pkg == "dms-shell-bin" {
- srcinfoPath := filepath.Join(packageDir, ".SRCINFO")
- depsToRemove := []string{
- "depends = quickshell",
- "depends = dgop",
- }
-
- for _, dep := range depsToRemove {
- sedCmd := exec.CommandContext(ctx, "sed", "-i", fmt.Sprintf("/%s/d", dep), srcinfoPath)
- if err := sedCmd.Run(); err != nil {
- return fmt.Errorf("failed to remove dependency %s from .SRCINFO for %s: %w", dep, pkg, err)
- }
- }
- }
-
- // Remove all optdepends from .SRCINFO for all packages
- srcinfoPath := filepath.Join(packageDir, ".SRCINFO")
- optdepsCmd := exec.CommandContext(ctx, "sed", "-i", "/^[[:space:]]*optdepends = /d", srcinfoPath)
- if err := optdepsCmd.Run(); err != nil {
- return fmt.Errorf("failed to remove optdepends from .SRCINFO for %s: %w", pkg, err)
- }
-
- // Skip dependency installation for dms-shell-git and dms-shell-bin
- // since we manually manage those dependencies
- if pkg != "dms-shell-git" && pkg != "dms-shell-bin" {
- // Pre-install dependencies from .SRCINFO
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: startProgress + 0.3*(endProgress-startProgress),
- Step: fmt.Sprintf("Installing dependencies for %s...", pkg),
- IsComplete: false,
- CommandInfo: "Installing package dependencies and makedepends",
- }
-
- // Install dependencies and makedepends explicitly
- srcinfoPath = filepath.Join(packageDir, ".SRCINFO")
-
- depsCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf(`
- deps=$(grep "depends = " "%s" | grep -v "makedepends" | sed 's/.*depends = //' | tr '\n' ' ' | sed 's/[[:space:]]*$//')
- if [[ "%s" == *"quickshell"* ]]; then
- deps=$(echo "$deps" | sed 's/google-breakpad//g' | sed 's/ / /g' | sed 's/^ *//g' | sed 's/ *$//g')
- fi
- if [ ! -z "$deps" ] && [ "$deps" != " " ]; then
- echo '%s' | sudo -S pacman -S --needed --noconfirm $deps
- fi
- `, srcinfoPath, pkg, sudoPassword))
-
- if err := a.runWithProgress(depsCmd, progressChan, PhaseAURPackages, startProgress+0.3*(endProgress-startProgress), startProgress+0.35*(endProgress-startProgress)); err != nil {
- return fmt.Errorf("FAILED to install runtime dependencies for %s: %w", pkg, err)
- }
-
- makedepsCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf(`
- makedeps=$(grep -E "^[[:space:]]*makedepends = " "%s" | sed 's/^[[:space:]]*makedepends = //' | tr '\n' ' ')
- if [ ! -z "$makedeps" ]; then
- echo '%s' | sudo -S pacman -S --needed --noconfirm $makedeps
- fi
- `, srcinfoPath, sudoPassword))
-
- if err := a.runWithProgress(makedepsCmd, progressChan, PhaseAURPackages, startProgress+0.35*(endProgress-startProgress), startProgress+0.4*(endProgress-startProgress)); err != nil {
- return fmt.Errorf("FAILED to install make dependencies for %s: %w", pkg, err)
- }
- } else {
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: startProgress + 0.35*(endProgress-startProgress),
- Step: fmt.Sprintf("Skipping dependency installation for %s (manually managed)...", pkg),
- IsComplete: false,
- LogOutput: fmt.Sprintf("Dependencies for %s are installed separately", pkg),
- }
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: startProgress + 0.4*(endProgress-startProgress),
- Step: fmt.Sprintf("Building %s...", pkg),
- IsComplete: false,
- CommandInfo: "makepkg --noconfirm",
- }
-
- buildCmd := exec.CommandContext(ctx, "makepkg", "--noconfirm")
- buildCmd.Dir = packageDir
- buildCmd.Env = append(os.Environ(), "PKGEXT=.pkg.tar") // Disable compression for speed
-
- if err := a.runWithProgress(buildCmd, progressChan, PhaseAURPackages, startProgress+0.4*(endProgress-startProgress), startProgress+0.7*(endProgress-startProgress)); err != nil {
- return fmt.Errorf("failed to build %s: %w", pkg, err)
- }
-
- // Find built package file
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: startProgress + 0.7*(endProgress-startProgress),
- Step: fmt.Sprintf("Installing %s...", pkg),
- IsComplete: false,
- CommandInfo: "sudo pacman -U built-package",
- }
-
- // Find .pkg.tar* files - for split packages, install the base and any installed compositor variants
- var files []string
- if pkg == "dms-shell-git" || pkg == "dms-shell-bin" {
- // For DMS split packages, install base package
- pattern := filepath.Join(packageDir, fmt.Sprintf("%s-%s*.pkg.tar*", pkg, "*"))
- matches, err := filepath.Glob(pattern)
- if err == nil {
- for _, match := range matches {
- basename := filepath.Base(match)
- // Always include base package
- if !strings.Contains(basename, "hyprland") && !strings.Contains(basename, "niri") {
- files = append(files, match)
- }
- }
- }
-
- // Also update compositor-specific packages if they're installed
- if strings.HasSuffix(pkg, "-git") {
- if a.packageInstalled("dms-shell-hyprland-git") {
- hyprlandPattern := filepath.Join(packageDir, "dms-shell-hyprland-git-*.pkg.tar*")
- if hyprlandMatches, err := filepath.Glob(hyprlandPattern); err == nil && len(hyprlandMatches) > 0 {
- files = append(files, hyprlandMatches[0])
- }
- }
- if a.packageInstalled("dms-shell-niri-git") {
- niriPattern := filepath.Join(packageDir, "dms-shell-niri-git-*.pkg.tar*")
- if niriMatches, err := filepath.Glob(niriPattern); err == nil && len(niriMatches) > 0 {
- files = append(files, niriMatches[0])
- }
- }
- }
- } else {
- // For other packages, install all built packages
- matches, _ := filepath.Glob(filepath.Join(packageDir, "*.pkg.tar*"))
- files = matches
- }
-
- if len(files) == 0 {
- return fmt.Errorf("no package files found after building %s", pkg)
- }
-
- installArgs := []string{"pacman", "-U", "--noconfirm"}
- installArgs = append(installArgs, files...)
-
- cmdStr := fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, strings.Join(installArgs, " "))
- installCmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
-
- fileNames := make([]string, len(files))
- for i, f := range files {
- fileNames[i] = filepath.Base(f)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: startProgress + 0.7*(endProgress-startProgress),
- LogOutput: fmt.Sprintf("Installing packages: %s", strings.Join(fileNames, ", ")),
- }
-
- if err := a.runWithProgress(installCmd, progressChan, PhaseAURPackages, startProgress+0.7*(endProgress-startProgress), endProgress); err != nil {
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: startProgress,
- LogOutput: fmt.Sprintf("ERROR: pacman -U failed for %s with error: %v", pkg, err),
- Error: err,
- }
- return fmt.Errorf("failed to install built package %s: %w", pkg, err)
- }
-
- a.log(fmt.Sprintf("Successfully installed AUR package: %s", pkg))
- return nil
-}
diff --git a/nix/inputs/dms-cli/internal/distros/base.go b/nix/inputs/dms-cli/internal/distros/base.go
deleted file mode 100644
index d74f1f8..0000000
--- a/nix/inputs/dms-cli/internal/distros/base.go
+++ /dev/null
@@ -1,622 +0,0 @@
-package distros
-
-import (
- "bufio"
- "context"
- _ "embed"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "regexp"
- "runtime"
- "strings"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
- "github.com/AvengeMedia/danklinux/internal/version"
-)
-
-const forceQuickshellGit = false
-const forceDMSGit = false
-
-// BaseDistribution provides common functionality for all distributions
-type BaseDistribution struct {
- logChan chan<- string
-}
-
-// NewBaseDistribution creates a new base distribution
-func NewBaseDistribution(logChan chan<- string) *BaseDistribution {
- return &BaseDistribution{
- logChan: logChan,
- }
-}
-
-// Common helper methods
-func (b *BaseDistribution) commandExists(cmd string) bool {
- _, err := exec.LookPath(cmd)
- return err == nil
-}
-
-func (b *BaseDistribution) CommandExists(cmd string) bool {
- return b.commandExists(cmd)
-}
-
-func (b *BaseDistribution) log(message string) {
- if b.logChan != nil {
- b.logChan <- message
- }
-}
-
-func (b *BaseDistribution) logError(message string, err error) {
- errorMsg := fmt.Sprintf("ERROR: %s: %v", message, err)
- b.log(errorMsg)
-}
-
-// Common dependency detection methods
-func (b *BaseDistribution) detectGit() deps.Dependency {
- status := deps.StatusMissing
- if b.commandExists("git") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "git",
- Status: status,
- Description: "Version control system",
- Required: true,
- }
-}
-
-func (b *BaseDistribution) detectMatugen() deps.Dependency {
- status := deps.StatusMissing
- if b.commandExists("matugen") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "matugen",
- Status: status,
- Description: "Material Design color generation tool",
- Required: true,
- }
-}
-
-func (b *BaseDistribution) detectDgop() deps.Dependency {
- status := deps.StatusMissing
- if b.commandExists("dgop") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "dgop",
- Status: status,
- Description: "Desktop portal management tool",
- Required: true,
- }
-}
-
-func (b *BaseDistribution) detectDMS() deps.Dependency {
- dmsPath := filepath.Join(os.Getenv("HOME"), ".config/quickshell/dms")
-
- status := deps.StatusMissing
- currentVersion := ""
-
- if _, err := os.Stat(dmsPath); err == nil {
- status = deps.StatusInstalled
-
- // Only get current version, don't check for updates (lazy loading)
- current, err := version.GetCurrentDMSVersion()
- if err == nil {
- currentVersion = current
- }
- }
-
- dep := deps.Dependency{
- Name: "dms (DankMaterialShell)",
- Status: status,
- Description: "Desktop Management System configuration",
- Required: true,
- CanToggle: true,
- }
-
- if currentVersion != "" {
- dep.Version = currentVersion
- }
-
- return dep
-}
-
-func (b *BaseDistribution) detectSpecificTerminal(terminal deps.Terminal) deps.Dependency {
- switch terminal {
- case deps.TerminalGhostty:
- status := deps.StatusMissing
- if b.commandExists("ghostty") {
- status = deps.StatusInstalled
- }
- return deps.Dependency{
- Name: "ghostty",
- Status: status,
- Description: "A fast, native terminal emulator built in Zig.",
- Required: true,
- }
- case deps.TerminalKitty:
- status := deps.StatusMissing
- if b.commandExists("kitty") {
- status = deps.StatusInstalled
- }
- return deps.Dependency{
- Name: "kitty",
- Status: status,
- Description: "A feature-rich, customizable terminal emulator.",
- Required: true,
- }
- case deps.TerminalAlacritty:
- status := deps.StatusMissing
- if b.commandExists("alacritty") {
- status = deps.StatusInstalled
- }
- return deps.Dependency{
- Name: "alacritty",
- Status: status,
- Description: "A simple terminal emulator. (No dynamic theming)",
- Required: true,
- }
- default:
- return b.detectSpecificTerminal(deps.TerminalGhostty)
- }
-}
-
-func (b *BaseDistribution) detectClipboardTools() []deps.Dependency {
- var dependencies []deps.Dependency
-
- cliphist := deps.StatusMissing
- if b.commandExists("cliphist") {
- cliphist = deps.StatusInstalled
- }
-
- wlClipboard := deps.StatusMissing
- if b.commandExists("wl-copy") && b.commandExists("wl-paste") {
- wlClipboard = deps.StatusInstalled
- }
-
- dependencies = append(dependencies,
- deps.Dependency{
- Name: "cliphist",
- Status: cliphist,
- Description: "Wayland clipboard manager",
- Required: true,
- },
- deps.Dependency{
- Name: "wl-clipboard",
- Status: wlClipboard,
- Description: "Wayland clipboard utilities",
- Required: true,
- },
- )
-
- return dependencies
-}
-
-func (b *BaseDistribution) detectHyprpicker() deps.Dependency {
- status := deps.StatusMissing
- if b.commandExists("hyprpicker") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "hyprpicker",
- Status: status,
- Description: "Color picker for Wayland",
- Required: true,
- }
-}
-
-func (b *BaseDistribution) detectHyprlandTools() []deps.Dependency {
- var dependencies []deps.Dependency
-
- tools := []struct {
- name string
- description string
- }{
- {"grim", "Screenshot utility for Wayland"},
- {"slurp", "Region selection utility for Wayland"},
- {"hyprctl", "Hyprland control utility"},
- {"grimblast", "Screenshot script for Hyprland"},
- {"jq", "JSON processor"},
- }
-
- for _, tool := range tools {
- status := deps.StatusMissing
- if b.commandExists(tool.name) {
- status = deps.StatusInstalled
- }
-
- dependencies = append(dependencies, deps.Dependency{
- Name: tool.name,
- Status: status,
- Description: tool.description,
- Required: true,
- })
- }
-
- return dependencies
-}
-
-func (b *BaseDistribution) detectQuickshell() deps.Dependency {
- if !b.commandExists("qs") {
- return deps.Dependency{
- Name: "quickshell",
- Status: deps.StatusMissing,
- Description: "QtQuick based desktop shell toolkit",
- Required: true,
- Variant: deps.VariantStable,
- CanToggle: true,
- }
- }
-
- cmd := exec.Command("qs", "--version")
- output, err := cmd.Output()
- if err != nil {
- return deps.Dependency{
- Name: "quickshell",
- Status: deps.StatusNeedsReinstall,
- Description: "QtQuick based desktop shell toolkit (version check failed)",
- Required: true,
- Variant: deps.VariantStable,
- CanToggle: true,
- }
- }
-
- versionStr := string(output)
- versionRegex := regexp.MustCompile(`quickshell (\d+\.\d+\.\d+)`)
- matches := versionRegex.FindStringSubmatch(versionStr)
-
- if len(matches) < 2 {
- return deps.Dependency{
- Name: "quickshell",
- Status: deps.StatusNeedsReinstall,
- Description: "QtQuick based desktop shell toolkit (unknown version)",
- Required: true,
- Variant: deps.VariantStable,
- CanToggle: true,
- }
- }
-
- version := matches[1]
- variant := deps.VariantStable
- if strings.Contains(versionStr, "git") || strings.Contains(versionStr, "+") {
- variant = deps.VariantGit
- }
-
- if b.versionCompare(version, "0.2.0") >= 0 {
- return deps.Dependency{
- Name: "quickshell",
- Status: deps.StatusInstalled,
- Version: version,
- Description: "QtQuick based desktop shell toolkit",
- Required: true,
- Variant: variant,
- CanToggle: true,
- }
- }
-
- return deps.Dependency{
- Name: "quickshell",
- Status: deps.StatusNeedsUpdate,
- Variant: variant,
- CanToggle: true,
- Version: version,
- Description: "QtQuick based desktop shell toolkit (needs 0.2.0+)",
- Required: true,
- }
-}
-
-func (b *BaseDistribution) detectWindowManager(wm deps.WindowManager) deps.Dependency {
- switch wm {
- case deps.WindowManagerHyprland:
- status := deps.StatusMissing
- variant := deps.VariantStable
- version := ""
-
- if b.commandExists("hyprland") || b.commandExists("Hyprland") {
- status = deps.StatusInstalled
- cmd := exec.Command("hyprctl", "version")
- if output, err := cmd.Output(); err == nil {
- outStr := string(output)
- if strings.Contains(outStr, "git") || strings.Contains(outStr, "dirty") {
- variant = deps.VariantGit
- }
- if versionRegex := regexp.MustCompile(`v(\d+\.\d+\.\d+)`); versionRegex.MatchString(outStr) {
- matches := versionRegex.FindStringSubmatch(outStr)
- if len(matches) > 1 {
- version = matches[1]
- }
- }
- }
- }
- return deps.Dependency{
- Name: "hyprland",
- Status: status,
- Version: version,
- Description: "Dynamic tiling Wayland compositor",
- Required: true,
- Variant: variant,
- CanToggle: true,
- }
- case deps.WindowManagerNiri:
- status := deps.StatusMissing
- variant := deps.VariantStable
- version := ""
-
- if b.commandExists("niri") {
- status = deps.StatusInstalled
- cmd := exec.Command("niri", "--version")
- if output, err := cmd.Output(); err == nil {
- outStr := string(output)
- if strings.Contains(outStr, "git") || strings.Contains(outStr, "+") {
- variant = deps.VariantGit
- }
- if versionRegex := regexp.MustCompile(`niri (\d+\.\d+)`); versionRegex.MatchString(outStr) {
- matches := versionRegex.FindStringSubmatch(outStr)
- if len(matches) > 1 {
- version = matches[1]
- }
- }
- }
- }
- return deps.Dependency{
- Name: "niri",
- Status: status,
- Version: version,
- Description: "Scrollable-tiling Wayland compositor",
- Required: true,
- Variant: variant,
- CanToggle: true,
- }
- default:
- return deps.Dependency{
- Name: "unknown-wm",
- Status: deps.StatusMissing,
- Description: "Unknown window manager",
- Required: true,
- }
- }
-}
-
-// Version comparison helper
-func (b *BaseDistribution) versionCompare(v1, v2 string) int {
- parts1 := strings.Split(v1, ".")
- parts2 := strings.Split(v2, ".")
-
- for i := 0; i < len(parts1) && i < len(parts2); i++ {
- if parts1[i] < parts2[i] {
- return -1
- }
- if parts1[i] > parts2[i] {
- return 1
- }
- }
-
- if len(parts1) < len(parts2) {
- return -1
- }
- if len(parts1) > len(parts2) {
- return 1
- }
-
- return 0
-}
-
-// Common installation helper
-func (b *BaseDistribution) runWithProgress(cmd *exec.Cmd, progressChan chan<- InstallProgressMsg, phase InstallPhase, startProgress, endProgress float64) error {
- return b.runWithProgressStep(cmd, progressChan, phase, startProgress, endProgress, "Installing...")
-}
-
-func (b *BaseDistribution) runWithProgressStep(cmd *exec.Cmd, progressChan chan<- InstallProgressMsg, phase InstallPhase, startProgress, endProgress float64, stepMessage string) error {
- stdout, err := cmd.StdoutPipe()
- if err != nil {
- return fmt.Errorf("failed to create stdout pipe: %w", err)
- }
- stderr, err := cmd.StderrPipe()
- if err != nil {
- return fmt.Errorf("failed to create stderr pipe: %w", err)
- }
-
- if err := cmd.Start(); err != nil {
- return err
- }
-
- outputChan := make(chan string, 100)
- done := make(chan error, 1)
-
- go func() {
- scanner := bufio.NewScanner(stdout)
- for scanner.Scan() {
- line := scanner.Text()
- b.log(line)
- outputChan <- line
- }
- }()
-
- go func() {
- scanner := bufio.NewScanner(stderr)
- for scanner.Scan() {
- line := scanner.Text()
- b.log(line)
- outputChan <- line
- }
- }()
-
- go func() {
- done <- cmd.Wait()
- close(outputChan)
- }()
-
- ticker := time.NewTicker(200 * time.Millisecond)
- defer ticker.Stop()
-
- progress := startProgress
- progressStep := (endProgress - startProgress) / 50
- lastOutput := ""
- timeout := time.NewTimer(10 * time.Minute)
- defer timeout.Stop()
-
- for {
- select {
- case err := <-done:
- if err != nil {
- b.logError("Command execution failed", err)
- b.log(fmt.Sprintf("Last output before failure: %s", lastOutput))
- progressChan <- InstallProgressMsg{
- Phase: phase,
- Progress: startProgress,
- Step: "Command failed",
- IsComplete: false,
- LogOutput: lastOutput,
- Error: err,
- }
- return err
- }
- progressChan <- InstallProgressMsg{
- Phase: phase,
- Progress: endProgress,
- Step: "Installation step complete",
- IsComplete: false,
- LogOutput: lastOutput,
- }
- return nil
- case output, ok := <-outputChan:
- if ok {
- lastOutput = output
- progressChan <- InstallProgressMsg{
- Phase: phase,
- Progress: progress,
- Step: stepMessage,
- IsComplete: false,
- LogOutput: output,
- }
- timeout.Reset(10 * time.Minute)
- }
- case <-timeout.C:
- if cmd.Process != nil {
- cmd.Process.Kill()
- }
- err := fmt.Errorf("installation timed out after 10 minutes")
- progressChan <- InstallProgressMsg{
- Phase: phase,
- Progress: startProgress,
- Step: "Installation timed out",
- IsComplete: false,
- LogOutput: lastOutput,
- Error: err,
- }
- return err
- case <-ticker.C:
- if progress < endProgress-0.01 {
- progress += progressStep
- progressChan <- InstallProgressMsg{
- Phase: phase,
- Progress: progress,
- Step: "Installing...",
- IsComplete: false,
- LogOutput: lastOutput,
- }
- }
- }
- }
-}
-
-// installDMSBinary installs the DMS binary from GitHub releases
-func (b *BaseDistribution) installDMSBinary(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- b.log("Installing/updating DMS binary...")
-
- // Detect architecture
- arch := runtime.GOARCH
- switch arch {
- case "amd64":
- case "arm64":
- default:
- return fmt.Errorf("unsupported architecture for DMS: %s", arch)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseConfiguration,
- Progress: 0.80,
- Step: "Downloading DMS binary...",
- IsComplete: false,
- CommandInfo: fmt.Sprintf("Downloading dms-%s.gz", arch),
- }
-
- // Get latest release version
- latestVersionCmd := exec.CommandContext(ctx, "bash", "-c",
- `curl -s https://api.github.com/repos/AvengeMedia/danklinux/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/'`)
- versionOutput, err := latestVersionCmd.Output()
- if err != nil {
- return fmt.Errorf("failed to get latest DMS version: %w", err)
- }
- version := strings.TrimSpace(string(versionOutput))
- if version == "" {
- return fmt.Errorf("could not determine latest DMS version")
- }
-
- homeDir, err := os.UserHomeDir()
- if err != nil {
- return fmt.Errorf("failed to get user home directory: %w", err)
- }
- tmpDir := filepath.Join(homeDir, ".cache", "dankinstall", "manual-builds")
- if err := os.MkdirAll(tmpDir, 0755); err != nil {
- return fmt.Errorf("failed to create temp directory: %w", err)
- }
- defer os.RemoveAll(tmpDir)
-
- // Download the gzipped binary
- downloadURL := fmt.Sprintf("https://github.com/AvengeMedia/danklinux/releases/download/%s/dms-%s.gz", version, arch)
- gzPath := filepath.Join(tmpDir, "dms.gz")
-
- downloadCmd := exec.CommandContext(ctx, "curl", "-L", downloadURL, "-o", gzPath)
- if err := downloadCmd.Run(); err != nil {
- return fmt.Errorf("failed to download DMS binary: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseConfiguration,
- Progress: 0.85,
- Step: "Extracting DMS binary...",
- IsComplete: false,
- CommandInfo: "gunzip dms.gz",
- }
-
- // Extract the binary
- extractCmd := exec.CommandContext(ctx, "gunzip", gzPath)
- if err := extractCmd.Run(); err != nil {
- return fmt.Errorf("failed to extract DMS binary: %w", err)
- }
-
- binaryPath := filepath.Join(tmpDir, "dms")
-
- // Make it executable
- chmodCmd := exec.CommandContext(ctx, "chmod", "+x", binaryPath)
- if err := chmodCmd.Run(); err != nil {
- return fmt.Errorf("failed to make DMS binary executable: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseConfiguration,
- Progress: 0.88,
- Step: "Installing DMS to /usr/local/bin...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo cp dms /usr/local/bin/",
- }
-
- // Install to /usr/local/bin
- installCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S cp %s /usr/local/bin/dms", sudoPassword, binaryPath))
- if err := installCmd.Run(); err != nil {
- return fmt.Errorf("failed to install DMS binary: %w", err)
- }
-
- b.log("DMS binary installed successfully")
- return nil
-}
diff --git a/nix/inputs/dms-cli/internal/distros/base_test.go b/nix/inputs/dms-cli/internal/distros/base_test.go
deleted file mode 100644
index 3d226b7..0000000
--- a/nix/inputs/dms-cli/internal/distros/base_test.go
+++ /dev/null
@@ -1,220 +0,0 @@
-package distros
-
-import (
- "os"
- "os/exec"
- "path/filepath"
- "testing"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
-)
-
-func TestBaseDistribution_detectDMS_NotInstalled(t *testing.T) {
- originalHome := os.Getenv("HOME")
- defer os.Setenv("HOME", originalHome)
-
- tempDir := t.TempDir()
- os.Setenv("HOME", tempDir)
-
- logChan := make(chan string, 10)
- defer close(logChan)
-
- base := NewBaseDistribution(logChan)
- dep := base.detectDMS()
-
- if dep.Status != deps.StatusMissing {
- t.Errorf("Expected StatusMissing, got %d", dep.Status)
- }
-
- if dep.Name != "dms (DankMaterialShell)" {
- t.Errorf("Expected name 'dms (DankMaterialShell)', got %s", dep.Name)
- }
-
- if !dep.Required {
- t.Error("Expected Required to be true")
- }
-}
-
-func TestBaseDistribution_detectDMS_Installed(t *testing.T) {
- if !commandExists("git") {
- t.Skip("git not available")
- }
-
- tempDir := t.TempDir()
- dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms")
- os.MkdirAll(dmsPath, 0755)
-
- originalHome := os.Getenv("HOME")
- defer os.Setenv("HOME", originalHome)
- os.Setenv("HOME", tempDir)
-
- exec.Command("git", "init", dmsPath).Run()
- exec.Command("git", "-C", dmsPath, "config", "user.email", "test@test.com").Run()
- exec.Command("git", "-C", dmsPath, "config", "user.name", "Test User").Run()
- exec.Command("git", "-C", dmsPath, "checkout", "-b", "master").Run()
-
- testFile := filepath.Join(dmsPath, "test.txt")
- os.WriteFile(testFile, []byte("test"), 0644)
- exec.Command("git", "-C", dmsPath, "add", ".").Run()
- exec.Command("git", "-C", dmsPath, "commit", "-m", "initial").Run()
-
- logChan := make(chan string, 10)
- defer close(logChan)
-
- base := NewBaseDistribution(logChan)
- dep := base.detectDMS()
-
- if dep.Status == deps.StatusMissing {
- t.Error("Expected DMS to be detected as installed")
- }
-
- if dep.Name != "dms (DankMaterialShell)" {
- t.Errorf("Expected name 'dms (DankMaterialShell)', got %s", dep.Name)
- }
-
- if !dep.Required {
- t.Error("Expected Required to be true")
- }
-
- t.Logf("Status: %d, Version: %s", dep.Status, dep.Version)
-}
-
-func TestBaseDistribution_detectDMS_NeedsUpdate(t *testing.T) {
- if !commandExists("git") {
- t.Skip("git not available")
- }
-
- tempDir := t.TempDir()
- dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms")
- os.MkdirAll(dmsPath, 0755)
-
- originalHome := os.Getenv("HOME")
- defer os.Setenv("HOME", originalHome)
- os.Setenv("HOME", tempDir)
-
- exec.Command("git", "init", dmsPath).Run()
- exec.Command("git", "-C", dmsPath, "config", "user.email", "test@test.com").Run()
- exec.Command("git", "-C", dmsPath, "config", "user.name", "Test User").Run()
- exec.Command("git", "-C", dmsPath, "remote", "add", "origin", "https://github.com/AvengeMedia/DankMaterialShell.git").Run()
-
- testFile := filepath.Join(dmsPath, "test.txt")
- os.WriteFile(testFile, []byte("test"), 0644)
- exec.Command("git", "-C", dmsPath, "add", ".").Run()
- exec.Command("git", "-C", dmsPath, "commit", "-m", "initial").Run()
- exec.Command("git", "-C", dmsPath, "tag", "v0.0.1").Run()
- exec.Command("git", "-C", dmsPath, "checkout", "v0.0.1").Run()
-
- logChan := make(chan string, 10)
- defer close(logChan)
-
- base := NewBaseDistribution(logChan)
- dep := base.detectDMS()
-
- if dep.Name != "dms (DankMaterialShell)" {
- t.Errorf("Expected name 'dms (DankMaterialShell)', got %s", dep.Name)
- }
-
- if !dep.Required {
- t.Error("Expected Required to be true")
- }
-
- t.Logf("Status: %d, Version: %s", dep.Status, dep.Version)
-}
-
-func TestBaseDistribution_detectDMS_DirectoryWithoutGit(t *testing.T) {
- tempDir := t.TempDir()
- dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms")
- os.MkdirAll(dmsPath, 0755)
-
- originalHome := os.Getenv("HOME")
- defer os.Setenv("HOME", originalHome)
- os.Setenv("HOME", tempDir)
-
- logChan := make(chan string, 10)
- defer close(logChan)
-
- base := NewBaseDistribution(logChan)
- dep := base.detectDMS()
-
- if dep.Status == deps.StatusMissing {
- t.Error("Expected DMS to be detected as present")
- }
-
- if dep.Name != "dms (DankMaterialShell)" {
- t.Errorf("Expected name 'dms (DankMaterialShell)', got %s", dep.Name)
- }
-
- if !dep.Required {
- t.Error("Expected Required to be true")
- }
-}
-
-func TestBaseDistribution_NewBaseDistribution(t *testing.T) {
- logChan := make(chan string, 10)
- defer close(logChan)
-
- base := NewBaseDistribution(logChan)
-
- if base == nil {
- t.Fatal("NewBaseDistribution returned nil")
- }
-
- if base.logChan == nil {
- t.Error("logChan was not set")
- }
-}
-
-func commandExists(cmd string) bool {
- _, err := exec.LookPath(cmd)
- return err == nil
-}
-
-func TestBaseDistribution_versionCompare(t *testing.T) {
- logChan := make(chan string, 10)
- defer close(logChan)
-
- base := NewBaseDistribution(logChan)
-
- tests := []struct {
- v1 string
- v2 string
- expected int
- }{
- {"0.1.0", "0.1.0", 0},
- {"0.1.0", "0.1.1", -1},
- {"0.1.1", "0.1.0", 1},
- {"0.2.0", "0.1.9", 1},
- {"1.0.0", "0.9.9", 1},
- }
-
- for _, tt := range tests {
- result := base.versionCompare(tt.v1, tt.v2)
- if result != tt.expected {
- t.Errorf("versionCompare(%q, %q) = %d; want %d", tt.v1, tt.v2, result, tt.expected)
- }
- }
-}
-
-func TestBaseDistribution_versionCompare_WithPrefix(t *testing.T) {
- logChan := make(chan string, 10)
- defer close(logChan)
-
- base := NewBaseDistribution(logChan)
-
- tests := []struct {
- v1 string
- v2 string
- expected int
- }{
- {"v0.1.0", "v0.1.0", 0},
- {"v0.1.0", "v0.1.1", -1},
- {"v0.1.1", "v0.1.0", 1},
- }
-
- for _, tt := range tests {
- result := base.versionCompare(tt.v1, tt.v2)
- if result != tt.expected {
- t.Errorf("versionCompare(%q, %q) = %d; want %d", tt.v1, tt.v2, result, tt.expected)
- }
- }
-}
diff --git a/nix/inputs/dms-cli/internal/distros/debian.go b/nix/inputs/dms-cli/internal/distros/debian.go
deleted file mode 100644
index 16975f0..0000000
--- a/nix/inputs/dms-cli/internal/distros/debian.go
+++ /dev/null
@@ -1,537 +0,0 @@
-package distros
-
-import (
- "context"
- "fmt"
- "os/exec"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
-)
-
-func init() {
- Register("debian", "#A80030", FamilyDebian, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewDebianDistribution(config, logChan)
- })
-}
-
-type DebianDistribution struct {
- *BaseDistribution
- *ManualPackageInstaller
- config DistroConfig
-}
-
-func NewDebianDistribution(config DistroConfig, logChan chan<- string) *DebianDistribution {
- base := NewBaseDistribution(logChan)
- return &DebianDistribution{
- BaseDistribution: base,
- ManualPackageInstaller: &ManualPackageInstaller{BaseDistribution: base},
- config: config,
- }
-}
-
-func (d *DebianDistribution) GetID() string {
- return d.config.ID
-}
-
-func (d *DebianDistribution) GetColorHex() string {
- return d.config.ColorHex
-}
-
-func (d *DebianDistribution) GetFamily() DistroFamily {
- return d.config.Family
-}
-
-func (d *DebianDistribution) GetPackageManager() PackageManagerType {
- return PackageManagerAPT
-}
-
-func (d *DebianDistribution) DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error) {
- return d.DetectDependenciesWithTerminal(ctx, wm, deps.TerminalGhostty)
-}
-
-func (d *DebianDistribution) DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error) {
- var dependencies []deps.Dependency
-
- dependencies = append(dependencies, d.detectDMS())
-
- dependencies = append(dependencies, d.detectSpecificTerminal(terminal))
-
- dependencies = append(dependencies, d.detectGit())
- dependencies = append(dependencies, d.detectWindowManager(wm))
- dependencies = append(dependencies, d.detectQuickshell())
- dependencies = append(dependencies, d.detectXDGPortal())
- dependencies = append(dependencies, d.detectPolkitAgent())
- dependencies = append(dependencies, d.detectAccountsService())
-
- if wm == deps.WindowManagerNiri {
- dependencies = append(dependencies, d.detectXwaylandSatellite())
- }
-
- dependencies = append(dependencies, d.detectMatugen())
- dependencies = append(dependencies, d.detectDgop())
- dependencies = append(dependencies, d.detectHyprpicker())
- dependencies = append(dependencies, d.detectClipboardTools()...)
-
- return dependencies, nil
-}
-
-func (d *DebianDistribution) detectXDGPortal() deps.Dependency {
- status := deps.StatusMissing
- if d.packageInstalled("xdg-desktop-portal-gtk") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "xdg-desktop-portal-gtk",
- Status: status,
- Description: "Desktop integration portal for GTK",
- Required: true,
- }
-}
-
-func (d *DebianDistribution) detectPolkitAgent() deps.Dependency {
- status := deps.StatusMissing
- if d.packageInstalled("mate-polkit") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "mate-polkit",
- Status: status,
- Description: "PolicyKit authentication agent",
- Required: true,
- }
-}
-
-func (d *DebianDistribution) detectXwaylandSatellite() deps.Dependency {
- status := deps.StatusMissing
- if d.commandExists("xwayland-satellite") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "xwayland-satellite",
- Status: status,
- Description: "Xwayland support",
- Required: true,
- }
-}
-
-func (d *DebianDistribution) detectAccountsService() deps.Dependency {
- status := deps.StatusMissing
- if d.packageInstalled("accountsservice") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "accountsservice",
- Status: status,
- Description: "D-Bus interface for user account query and manipulation",
- Required: true,
- }
-}
-
-func (d *DebianDistribution) packageInstalled(pkg string) bool {
- cmd := exec.Command("dpkg", "-l", pkg)
- err := cmd.Run()
- return err == nil
-}
-
-func (d *DebianDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping {
- packages := map[string]PackageMapping{
- "git": {Name: "git", Repository: RepoTypeSystem},
- "kitty": {Name: "kitty", Repository: RepoTypeSystem},
- "alacritty": {Name: "alacritty", Repository: RepoTypeSystem},
- "wl-clipboard": {Name: "wl-clipboard", Repository: RepoTypeSystem},
- "xdg-desktop-portal-gtk": {Name: "xdg-desktop-portal-gtk", Repository: RepoTypeSystem},
- "mate-polkit": {Name: "mate-polkit", Repository: RepoTypeSystem},
- "accountsservice": {Name: "accountsservice", Repository: RepoTypeSystem},
-
- "dms (DankMaterialShell)": {Name: "dms", Repository: RepoTypeManual, BuildFunc: "installDankMaterialShell"},
- "niri": {Name: "niri", Repository: RepoTypeManual, BuildFunc: "installNiri"},
- "quickshell": {Name: "quickshell", Repository: RepoTypeManual, BuildFunc: "installQuickshell"},
- "ghostty": {Name: "ghostty", Repository: RepoTypeManual, BuildFunc: "installGhostty"},
- "matugen": {Name: "matugen", Repository: RepoTypeManual, BuildFunc: "installMatugen"},
- "dgop": {Name: "dgop", Repository: RepoTypeManual, BuildFunc: "installDgop"},
- "cliphist": {Name: "cliphist", Repository: RepoTypeManual, BuildFunc: "installCliphist"},
- "hyprpicker": {Name: "hyprpicker", Repository: RepoTypeManual, BuildFunc: "installHyprpicker"},
- }
-
- if wm == deps.WindowManagerNiri {
- packages["niri"] = PackageMapping{Name: "niri", Repository: RepoTypeManual, BuildFunc: "installNiri"}
- packages["xwayland-satellite"] = PackageMapping{Name: "xwayland-satellite", Repository: RepoTypeManual, BuildFunc: "installXwaylandSatellite"}
- }
-
- return packages
-}
-
-func (d *DebianDistribution) InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.06,
- Step: "Updating package lists...",
- IsComplete: false,
- LogOutput: "Updating APT package lists",
- }
-
- updateCmd := exec.CommandContext(ctx, "bash", "-c", fmt.Sprintf("echo '%s' | sudo -S apt-get update", sudoPassword))
- if err := d.runWithProgress(updateCmd, progressChan, PhasePrerequisites, 0.06, 0.07); err != nil {
- return fmt.Errorf("failed to update package lists: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.08,
- Step: "Installing build-essential...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo apt-get install -y build-essential",
- LogOutput: "Installing build tools",
- }
-
- checkCmd := exec.CommandContext(ctx, "dpkg", "-l", "build-essential")
- if err := checkCmd.Run(); err != nil {
- cmd := exec.CommandContext(ctx, "bash", "-c", fmt.Sprintf("echo '%s' | sudo -S apt-get install -y build-essential", sudoPassword))
- if err := d.runWithProgress(cmd, progressChan, PhasePrerequisites, 0.08, 0.09); err != nil {
- return fmt.Errorf("failed to install build-essential: %w", err)
- }
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.10,
- Step: "Installing development dependencies...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo apt-get install -y curl wget git cmake ninja-build pkg-config libxcb-cursor-dev libglib2.0-dev libpolkit-agent-1-dev",
- LogOutput: "Installing additional development tools",
- }
-
- devToolsCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S apt-get install -y curl wget git cmake ninja-build pkg-config libxcb-cursor-dev libglib2.0-dev libpolkit-agent-1-dev", sudoPassword))
- if err := d.runWithProgress(devToolsCmd, progressChan, PhasePrerequisites, 0.10, 0.12); err != nil {
- return fmt.Errorf("failed to install development tools: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.12,
- Step: "Prerequisites installation complete",
- IsComplete: false,
- LogOutput: "Prerequisites successfully installed",
- }
-
- return nil
-}
-
-func (d *DebianDistribution) InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, progressChan chan<- InstallProgressMsg) error {
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.05,
- Step: "Checking system prerequisites...",
- IsComplete: false,
- LogOutput: "Starting prerequisite check...",
- }
-
- if err := d.InstallPrerequisites(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install prerequisites: %w", err)
- }
-
- systemPkgs, manualPkgs := d.categorizePackages(dependencies, wm, reinstallFlags)
-
- if len(systemPkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.35,
- Step: fmt.Sprintf("Installing %d system packages...", len(systemPkgs)),
- IsComplete: false,
- NeedsSudo: true,
- LogOutput: fmt.Sprintf("Installing system packages: %s", strings.Join(systemPkgs, ", ")),
- }
- if err := d.installAPTPackages(ctx, systemPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install APT packages: %w", err)
- }
- }
-
- if len(manualPkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.80,
- Step: "Installing build dependencies...",
- IsComplete: false,
- LogOutput: "Installing build tools for manual compilation",
- }
- if err := d.installBuildDependencies(ctx, manualPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install build dependencies: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.85,
- Step: fmt.Sprintf("Building %d packages from source...", len(manualPkgs)),
- IsComplete: false,
- LogOutput: fmt.Sprintf("Building from source: %s", strings.Join(manualPkgs, ", ")),
- }
- if err := d.InstallManualPackages(ctx, manualPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install manual packages: %w", err)
- }
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseConfiguration,
- Progress: 0.90,
- Step: "Configuring system...",
- IsComplete: false,
- LogOutput: "Starting post-installation configuration...",
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseComplete,
- Progress: 1.0,
- Step: "Installation complete!",
- IsComplete: true,
- LogOutput: "All packages installed and configured successfully",
- }
-
- return nil
-}
-
-func (d *DebianDistribution) categorizePackages(dependencies []deps.Dependency, wm deps.WindowManager, reinstallFlags map[string]bool) ([]string, []string) {
- systemPkgs := []string{}
- manualPkgs := []string{}
-
- packageMap := d.GetPackageMapping(wm)
-
- for _, dep := range dependencies {
- if dep.Status == deps.StatusInstalled && !reinstallFlags[dep.Name] {
- continue
- }
-
- pkgInfo, exists := packageMap[dep.Name]
- if !exists {
- d.log(fmt.Sprintf("Warning: No package mapping for %s", dep.Name))
- continue
- }
-
- switch pkgInfo.Repository {
- case RepoTypeSystem:
- systemPkgs = append(systemPkgs, pkgInfo.Name)
- case RepoTypeManual:
- manualPkgs = append(manualPkgs, dep.Name)
- }
- }
-
- return systemPkgs, manualPkgs
-}
-
-func (d *DebianDistribution) installAPTPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- d.log(fmt.Sprintf("Installing APT packages: %s", strings.Join(packages, ", ")))
-
- args := []string{"apt-get", "install", "-y"}
- args = append(args, packages...)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.40,
- Step: "Installing system packages...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")),
- }
-
- cmdStr := fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, strings.Join(args, " "))
- cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
- return d.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.40, 0.60)
-}
-
-func (d *DebianDistribution) installBuildDependencies(ctx context.Context, manualPkgs []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- buildDeps := make(map[string]bool)
-
- for _, pkg := range manualPkgs {
- switch pkg {
- case "niri":
- buildDeps["curl"] = true
- buildDeps["libxkbcommon-dev"] = true
- buildDeps["libwayland-dev"] = true
- buildDeps["libudev-dev"] = true
- buildDeps["libinput-dev"] = true
- buildDeps["libdisplay-info-dev"] = true
- buildDeps["libpango1.0-dev"] = true
- buildDeps["libcairo-dev"] = true
- buildDeps["libpipewire-0.3-dev"] = true
- buildDeps["libc6-dev"] = true
- buildDeps["clang"] = true
- buildDeps["libseat-dev"] = true
- buildDeps["libgbm-dev"] = true
- buildDeps["alacritty"] = true
- buildDeps["fuzzel"] = true
- case "quickshell":
- buildDeps["qt6-base-dev"] = true
- buildDeps["qt6-base-private-dev"] = true
- buildDeps["qt6-declarative-dev"] = true
- buildDeps["qt6-declarative-private-dev"] = true
- buildDeps["qt6-wayland-dev"] = true
- buildDeps["qt6-wayland-private-dev"] = true
- buildDeps["qt6-tools-dev"] = true
- buildDeps["libqt6svg6-dev"] = true
- buildDeps["qt6-shadertools-dev"] = true
- buildDeps["spirv-tools"] = true
- buildDeps["libcli11-dev"] = true
- buildDeps["libjemalloc-dev"] = true
- buildDeps["libwayland-dev"] = true
- buildDeps["wayland-protocols"] = true
- buildDeps["libdrm-dev"] = true
- buildDeps["libgbm-dev"] = true
- buildDeps["libegl-dev"] = true
- buildDeps["libgles2-mesa-dev"] = true
- buildDeps["libgl1-mesa-dev"] = true
- buildDeps["libxcb1-dev"] = true
- buildDeps["libpipewire-0.3-dev"] = true
- buildDeps["libpam0g-dev"] = true
- case "ghostty":
- buildDeps["curl"] = true
- case "matugen":
- buildDeps["curl"] = true
- }
- }
-
- for _, pkg := range manualPkgs {
- switch pkg {
- case "niri", "matugen":
- if err := d.installRust(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install Rust: %w", err)
- }
- case "cliphist", "dgop":
- if err := d.installGo(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install Go: %w", err)
- }
- }
- }
-
- if len(buildDeps) == 0 {
- return nil
- }
-
- depList := make([]string, 0, len(buildDeps))
- for dep := range buildDeps {
- depList = append(depList, dep)
- }
-
- args := []string{"apt-get", "install", "-y"}
- args = append(args, depList...)
-
- cmdStr := fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, strings.Join(args, " "))
- cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
- return d.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.80, 0.82)
-}
-
-func (d *DebianDistribution) installRust(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if d.commandExists("cargo") {
- return nil
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.82,
- Step: "Installing rustup...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo apt-get install rustup",
- }
-
- rustupInstallCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S apt-get install -y rustup", sudoPassword))
- if err := d.runWithProgress(rustupInstallCmd, progressChan, PhaseSystemPackages, 0.82, 0.83); err != nil {
- return fmt.Errorf("failed to install rustup: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.83,
- Step: "Installing stable Rust toolchain...",
- IsComplete: false,
- CommandInfo: "rustup install stable",
- }
-
- rustInstallCmd := exec.CommandContext(ctx, "bash", "-c", "rustup install stable && rustup default stable")
- if err := d.runWithProgress(rustInstallCmd, progressChan, PhaseSystemPackages, 0.83, 0.84); err != nil {
- return fmt.Errorf("failed to install Rust toolchain: %w", err)
- }
-
- if !d.commandExists("cargo") {
- d.log("Warning: cargo not found in PATH after Rust installation, trying to source environment")
- }
-
- return nil
-}
-
-func (d *DebianDistribution) installGo(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if d.commandExists("go") {
- return nil
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.87,
- Step: "Installing Go...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo apt-get install golang-go",
- }
-
- installCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S apt-get install -y golang-go", sudoPassword))
- return d.runWithProgress(installCmd, progressChan, PhaseSystemPackages, 0.87, 0.90)
-}
-
-func (d *DebianDistribution) installGhosttyDebian(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- d.log("Installing Ghostty using Debian installer script...")
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.1,
- Step: "Running Ghostty Debian installer...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "curl -fsSL https://raw.githubusercontent.com/mkasberg/ghostty-ubuntu/HEAD/install.sh | sudo bash",
- LogOutput: "Installing Ghostty using pre-built Debian package",
- }
-
- installCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/mkasberg/ghostty-ubuntu/HEAD/install.sh)\"", sudoPassword))
-
- if err := d.runWithProgress(installCmd, progressChan, PhaseSystemPackages, 0.1, 0.9); err != nil {
- return fmt.Errorf("failed to install Ghostty: %w", err)
- }
-
- d.log("Ghostty installed successfully using Debian installer")
- return nil
-}
-
-func (d *DebianDistribution) InstallManualPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- d.log(fmt.Sprintf("Installing manual packages: %s", strings.Join(packages, ", ")))
-
- for _, pkg := range packages {
- switch pkg {
- case "ghostty":
- if err := d.installGhosttyDebian(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install ghostty: %w", err)
- }
- default:
- if err := d.ManualPackageInstaller.InstallManualPackages(ctx, []string{pkg}, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install %s: %w", pkg, err)
- }
- }
- }
-
- return nil
-}
diff --git a/nix/inputs/dms-cli/internal/distros/factory.go b/nix/inputs/dms-cli/internal/distros/factory.go
deleted file mode 100644
index 70518d3..0000000
--- a/nix/inputs/dms-cli/internal/distros/factory.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package distros
-
-import (
- "github.com/AvengeMedia/danklinux/internal/deps"
-)
-
-// NewDependencyDetector creates a DependencyDetector for the specified distribution
-func NewDependencyDetector(distribution string, logChan chan<- string) (deps.DependencyDetector, error) {
- distro, err := NewDistribution(distribution, logChan)
- if err != nil {
- return nil, err
- }
- return distro, nil
-}
-
-// NewPackageInstaller creates a Distribution for package installation
-func NewPackageInstaller(distribution string, logChan chan<- string) (Distribution, error) {
- return NewDistribution(distribution, logChan)
-}
diff --git a/nix/inputs/dms-cli/internal/distros/fedora.go b/nix/inputs/dms-cli/internal/distros/fedora.go
deleted file mode 100644
index 72204ae..0000000
--- a/nix/inputs/dms-cli/internal/distros/fedora.go
+++ /dev/null
@@ -1,553 +0,0 @@
-package distros
-
-import (
- "context"
- "fmt"
- "os/exec"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
-)
-
-func init() {
- Register("fedora", "#0B57A4", FamilyFedora, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewFedoraDistribution(config, logChan)
- })
- Register("nobara", "#0B57A4", FamilyFedora, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewFedoraDistribution(config, logChan)
- })
- Register("fedora-asahi-remix", "#0B57A4", FamilyFedora, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewFedoraDistribution(config, logChan)
- })
-
- Register("bluefin", "#0B57A4", FamilyFedora, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewFedoraDistribution(config, logChan)
- })
-}
-
-type FedoraDistribution struct {
- *BaseDistribution
- *ManualPackageInstaller
- config DistroConfig
-}
-
-func NewFedoraDistribution(config DistroConfig, logChan chan<- string) *FedoraDistribution {
- base := NewBaseDistribution(logChan)
- return &FedoraDistribution{
- BaseDistribution: base,
- ManualPackageInstaller: &ManualPackageInstaller{BaseDistribution: base},
- config: config,
- }
-}
-
-func (f *FedoraDistribution) GetID() string {
- return f.config.ID
-}
-
-func (f *FedoraDistribution) GetColorHex() string {
- return f.config.ColorHex
-}
-
-func (f *FedoraDistribution) GetFamily() DistroFamily {
- return f.config.Family
-}
-
-func (f *FedoraDistribution) GetPackageManager() PackageManagerType {
- return PackageManagerDNF
-}
-
-func (f *FedoraDistribution) DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error) {
- return f.DetectDependenciesWithTerminal(ctx, wm, deps.TerminalGhostty)
-}
-
-func (f *FedoraDistribution) DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error) {
- var dependencies []deps.Dependency
-
- // DMS at the top (shell is prominent)
- dependencies = append(dependencies, f.detectDMS())
-
- // Terminal with choice support
- dependencies = append(dependencies, f.detectSpecificTerminal(terminal))
-
- // Common detections using base methods
- dependencies = append(dependencies, f.detectGit())
- dependencies = append(dependencies, f.detectWindowManager(wm))
- dependencies = append(dependencies, f.detectQuickshell())
- dependencies = append(dependencies, f.detectXDGPortal())
- dependencies = append(dependencies, f.detectPolkitAgent())
- dependencies = append(dependencies, f.detectAccountsService())
-
- // Hyprland-specific tools
- if wm == deps.WindowManagerHyprland {
- dependencies = append(dependencies, f.detectHyprlandTools()...)
- }
-
- // Niri-specific tools
- if wm == deps.WindowManagerNiri {
- dependencies = append(dependencies, f.detectXwaylandSatellite())
- }
-
- // Base detections (common across distros)
- dependencies = append(dependencies, f.detectMatugen())
- dependencies = append(dependencies, f.detectDgop())
- dependencies = append(dependencies, f.detectHyprpicker())
- dependencies = append(dependencies, f.detectClipboardTools()...)
-
- return dependencies, nil
-}
-
-func (f *FedoraDistribution) detectXDGPortal() deps.Dependency {
- status := deps.StatusMissing
- if f.packageInstalled("xdg-desktop-portal-gtk") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "xdg-desktop-portal-gtk",
- Status: status,
- Description: "Desktop integration portal for GTK",
- Required: true,
- }
-}
-
-func (f *FedoraDistribution) detectPolkitAgent() deps.Dependency {
- status := deps.StatusMissing
- if f.packageInstalled("mate-polkit") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "mate-polkit",
- Status: status,
- Description: "PolicyKit authentication agent",
- Required: true,
- }
-}
-
-func (f *FedoraDistribution) packageInstalled(pkg string) bool {
- cmd := exec.Command("rpm", "-q", pkg)
- err := cmd.Run()
- return err == nil
-}
-
-func (f *FedoraDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping {
- return f.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant))
-}
-
-func (f *FedoraDistribution) GetPackageMappingWithVariants(wm deps.WindowManager, variants map[string]deps.PackageVariant) map[string]PackageMapping {
- packages := map[string]PackageMapping{
- // Standard DNF packages
- "git": {Name: "git", Repository: RepoTypeSystem},
- "ghostty": {Name: "ghostty", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"},
- "kitty": {Name: "kitty", Repository: RepoTypeSystem},
- "alacritty": {Name: "alacritty", Repository: RepoTypeSystem},
- "wl-clipboard": {Name: "wl-clipboard", Repository: RepoTypeSystem},
- "xdg-desktop-portal-gtk": {Name: "xdg-desktop-portal-gtk", Repository: RepoTypeSystem},
- "mate-polkit": {Name: "mate-polkit", Repository: RepoTypeSystem},
- "accountsservice": {Name: "accountsservice", Repository: RepoTypeSystem},
- "hyprpicker": f.getHyprpickerMapping(variants["hyprland"]),
-
- // COPR packages
- "quickshell": f.getQuickshellMapping(variants["quickshell"]),
- "matugen": {Name: "matugen", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"},
- "cliphist": {Name: "cliphist", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"},
- "dms (DankMaterialShell)": f.getDmsMapping(variants["dms (DankMaterialShell)"]),
- "dgop": {Name: "dgop", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"},
- }
-
- switch wm {
- case deps.WindowManagerHyprland:
- packages["hyprland"] = f.getHyprlandMapping(variants["hyprland"])
- packages["grim"] = PackageMapping{Name: "grim", Repository: RepoTypeSystem}
- packages["slurp"] = PackageMapping{Name: "slurp", Repository: RepoTypeSystem}
- packages["hyprctl"] = f.getHyprlandMapping(variants["hyprland"])
- packages["grimblast"] = PackageMapping{Name: "grimblast", Repository: RepoTypeManual, BuildFunc: "installGrimblast"}
- packages["jq"] = PackageMapping{Name: "jq", Repository: RepoTypeSystem}
- case deps.WindowManagerNiri:
- packages["niri"] = f.getNiriMapping(variants["niri"])
- packages["xwayland-satellite"] = PackageMapping{Name: "xwayland-satellite", Repository: RepoTypeCOPR, RepoURL: "yalter/niri"}
- }
-
- return packages
-}
-
-func (f *FedoraDistribution) getQuickshellMapping(variant deps.PackageVariant) PackageMapping {
- if forceQuickshellGit || variant == deps.VariantGit {
- return PackageMapping{Name: "quickshell-git", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"}
- }
- return PackageMapping{Name: "quickshell", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"}
-}
-
-func (f *FedoraDistribution) getDmsMapping(variant deps.PackageVariant) PackageMapping {
- if variant == deps.VariantGit {
- return PackageMapping{Name: "dms", Repository: RepoTypeCOPR, RepoURL: "avengemedia/dms-git"}
- }
- return PackageMapping{Name: "dms", Repository: RepoTypeCOPR, RepoURL: "avengemedia/dms"}
-}
-
-func (f *FedoraDistribution) getHyprlandMapping(variant deps.PackageVariant) PackageMapping {
- if variant == deps.VariantGit {
- return PackageMapping{Name: "hyprland-git", Repository: RepoTypeCOPR, RepoURL: "solopasha/hyprland"}
- }
- return PackageMapping{Name: "hyprland", Repository: RepoTypeCOPR, RepoURL: "solopasha/hyprland"}
-}
-
-func (f *FedoraDistribution) getHyprpickerMapping(variant deps.PackageVariant) PackageMapping {
- if variant == deps.VariantGit {
- return PackageMapping{Name: "hyprpicker-git", Repository: RepoTypeCOPR, RepoURL: "solopasha/hyprland"}
- }
- return PackageMapping{Name: "hyprpicker", Repository: RepoTypeCOPR, RepoURL: "avengemedia/danklinux"}
-}
-
-func (f *FedoraDistribution) getNiriMapping(variant deps.PackageVariant) PackageMapping {
- if variant == deps.VariantGit {
- return PackageMapping{Name: "niri", Repository: RepoTypeCOPR, RepoURL: "yalter/niri-git"}
- }
- return PackageMapping{Name: "niri", Repository: RepoTypeCOPR, RepoURL: "yalter/niri"}
-}
-
-func (f *FedoraDistribution) detectXwaylandSatellite() deps.Dependency {
- status := deps.StatusMissing
- if f.commandExists("xwayland-satellite") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "xwayland-satellite",
- Status: status,
- Description: "Xwayland support",
- Required: true,
- }
-}
-
-func (f *FedoraDistribution) detectAccountsService() deps.Dependency {
- status := deps.StatusMissing
- if f.packageInstalled("accountsservice") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "accountsservice",
- Status: status,
- Description: "D-Bus interface for user account query and manipulation",
- Required: true,
- }
-}
-
-func (f *FedoraDistribution) getPrerequisites() []string {
- return []string{
- "dnf-plugins-core",
- "make",
- "unzip",
- "libwayland-server",
- }
-}
-
-func (f *FedoraDistribution) InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- prerequisites := f.getPrerequisites()
- var missingPkgs []string
-
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.06,
- Step: "Checking prerequisites...",
- IsComplete: false,
- LogOutput: "Checking prerequisite packages",
- }
-
- for _, pkg := range prerequisites {
- checkCmd := exec.CommandContext(ctx, "rpm", "-q", pkg)
- if err := checkCmd.Run(); err != nil {
- missingPkgs = append(missingPkgs, pkg)
- }
- }
-
- _, err := exec.LookPath("go")
- if err != nil {
- f.log("go not found in PATH, will install golang-bin")
- missingPkgs = append(missingPkgs, "golang-bin")
- } else {
- f.log("go already available in PATH")
- }
-
- if len(missingPkgs) == 0 {
- f.log("All prerequisites already installed")
- return nil
- }
-
- f.log(fmt.Sprintf("Installing prerequisites: %s", strings.Join(missingPkgs, ", ")))
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.08,
- Step: fmt.Sprintf("Installing %d prerequisites...", len(missingPkgs)),
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo dnf install -y %s", strings.Join(missingPkgs, " ")),
- LogOutput: fmt.Sprintf("Installing prerequisites: %s", strings.Join(missingPkgs, ", ")),
- }
-
- args := []string{"dnf", "install", "-y"}
- args = append(args, missingPkgs...)
- cmdStr := fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, strings.Join(args, " "))
- cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
- output, err := cmd.CombinedOutput()
- if err != nil {
- f.logError("failed to install prerequisites", err)
- f.log(fmt.Sprintf("Prerequisites command output: %s", string(output)))
- return fmt.Errorf("failed to install prerequisites: %w", err)
- }
- f.log(fmt.Sprintf("Prerequisites install output: %s", string(output)))
-
- return nil
-}
-
-func (f *FedoraDistribution) InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, progressChan chan<- InstallProgressMsg) error {
- // Phase 1: Check Prerequisites
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.05,
- Step: "Checking system prerequisites...",
- IsComplete: false,
- LogOutput: "Starting prerequisite check...",
- }
-
- if err := f.InstallPrerequisites(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install prerequisites: %w", err)
- }
-
- dnfPkgs, coprPkgs, manualPkgs := f.categorizePackages(dependencies, wm, reinstallFlags)
-
- // Phase 2: Enable COPR repositories
- if len(coprPkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.15,
- Step: "Enabling COPR repositories...",
- IsComplete: false,
- LogOutput: "Setting up COPR repositories for additional packages",
- }
- if err := f.enableCOPRRepos(ctx, coprPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to enable COPR repositories: %w", err)
- }
- }
-
- // Phase 3: System Packages (DNF)
- if len(dnfPkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.35,
- Step: fmt.Sprintf("Installing %d system packages...", len(dnfPkgs)),
- IsComplete: false,
- NeedsSudo: true,
- LogOutput: fmt.Sprintf("Installing system packages: %s", strings.Join(dnfPkgs, ", ")),
- }
- if err := f.installDNFPackages(ctx, dnfPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install DNF packages: %w", err)
- }
- }
-
- // Phase 4: COPR Packages
- coprPkgNames := f.extractPackageNames(coprPkgs)
- if len(coprPkgNames) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages, // Reusing AUR phase for COPR
- Progress: 0.65,
- Step: fmt.Sprintf("Installing %d COPR packages...", len(coprPkgNames)),
- IsComplete: false,
- LogOutput: fmt.Sprintf("Installing COPR packages: %s", strings.Join(coprPkgNames, ", ")),
- }
- if err := f.installCOPRPackages(ctx, coprPkgNames, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install COPR packages: %w", err)
- }
- }
-
- // Phase 5: Manual Builds
- if len(manualPkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.85,
- Step: fmt.Sprintf("Building %d packages from source...", len(manualPkgs)),
- IsComplete: false,
- LogOutput: fmt.Sprintf("Building from source: %s", strings.Join(manualPkgs, ", ")),
- }
- if err := f.InstallManualPackages(ctx, manualPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install manual packages: %w", err)
- }
- }
-
- // Phase 6: Configuration
- progressChan <- InstallProgressMsg{
- Phase: PhaseConfiguration,
- Progress: 0.90,
- Step: "Configuring system...",
- IsComplete: false,
- LogOutput: "Starting post-installation configuration...",
- }
-
- // Phase 7: Complete
- progressChan <- InstallProgressMsg{
- Phase: PhaseComplete,
- Progress: 1.0,
- Step: "Installation complete!",
- IsComplete: true,
- LogOutput: "All packages installed and configured successfully",
- }
-
- return nil
-}
-
-func (f *FedoraDistribution) categorizePackages(dependencies []deps.Dependency, wm deps.WindowManager, reinstallFlags map[string]bool) ([]string, []PackageMapping, []string) {
- dnfPkgs := []string{}
- coprPkgs := []PackageMapping{}
- manualPkgs := []string{}
-
- variantMap := make(map[string]deps.PackageVariant)
- for _, dep := range dependencies {
- variantMap[dep.Name] = dep.Variant
- }
-
- packageMap := f.GetPackageMappingWithVariants(wm, variantMap)
-
- for _, dep := range dependencies {
- // Skip installed packages unless marked for reinstall
- if dep.Status == deps.StatusInstalled && !reinstallFlags[dep.Name] {
- continue
- }
-
- pkgInfo, exists := packageMap[dep.Name]
- if !exists {
- f.log(fmt.Sprintf("Warning: No package mapping for %s", dep.Name))
- continue
- }
-
- switch pkgInfo.Repository {
- case RepoTypeSystem:
- dnfPkgs = append(dnfPkgs, pkgInfo.Name)
- case RepoTypeCOPR:
- coprPkgs = append(coprPkgs, pkgInfo)
- case RepoTypeManual:
- manualPkgs = append(manualPkgs, dep.Name)
- }
- }
-
- return dnfPkgs, coprPkgs, manualPkgs
-}
-
-func (f *FedoraDistribution) extractPackageNames(packages []PackageMapping) []string {
- names := make([]string, len(packages))
- for i, pkg := range packages {
- names[i] = pkg.Name
- }
- return names
-}
-
-func (f *FedoraDistribution) enableCOPRRepos(ctx context.Context, coprPkgs []PackageMapping, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- enabledRepos := make(map[string]bool)
-
- for _, pkg := range coprPkgs {
- if pkg.RepoURL != "" && !enabledRepos[pkg.RepoURL] {
- f.log(fmt.Sprintf("Enabling COPR repository: %s", pkg.RepoURL))
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.20,
- Step: fmt.Sprintf("Enabling COPR repo %s...", pkg.RepoURL),
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo dnf copr enable -y %s", pkg.RepoURL),
- }
-
- cmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S dnf copr enable -y %s 2>&1", sudoPassword, pkg.RepoURL))
- output, err := cmd.CombinedOutput()
- if err != nil {
- f.logError(fmt.Sprintf("failed to enable COPR repo %s", pkg.RepoURL), err)
- f.log(fmt.Sprintf("COPR enable command output: %s", string(output)))
- return fmt.Errorf("failed to enable COPR repo %s: %w", pkg.RepoURL, err)
- }
- f.log(fmt.Sprintf("COPR repo %s enabled successfully: %s", pkg.RepoURL, string(output)))
- enabledRepos[pkg.RepoURL] = true
-
- // Special handling for niri COPR repo - set priority=1
- if pkg.RepoURL == "yalter/niri-git" {
- f.log("Setting priority=1 for niri-git COPR repo...")
- repoFile := "/etc/yum.repos.d/_copr:copr.fedorainfracloud.org:yalter:niri-git.repo"
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.22,
- Step: "Setting niri COPR repo priority...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("echo \"priority=1\" | sudo tee -a %s", repoFile),
- }
-
- priorityCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S bash -c 'echo \"priority=1\" | tee -a %s' 2>&1", sudoPassword, repoFile))
- priorityOutput, err := priorityCmd.CombinedOutput()
- if err != nil {
- f.logError("failed to set niri COPR repo priority", err)
- f.log(fmt.Sprintf("Priority command output: %s", string(priorityOutput)))
- return fmt.Errorf("failed to set niri COPR repo priority: %w", err)
- }
- f.log(fmt.Sprintf("niri COPR repo priority set successfully: %s", string(priorityOutput)))
- }
- }
- }
-
- return nil
-}
-
-func (f *FedoraDistribution) installDNFPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- f.log(fmt.Sprintf("Installing DNF packages: %s", strings.Join(packages, ", ")))
-
- args := []string{"dnf", "install", "-y"}
- args = append(args, packages...)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.40,
- Step: "Installing system packages...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")),
- }
-
- cmdStr := fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, strings.Join(args, " "))
- cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
- return f.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.40, 0.60)
-}
-
-func (f *FedoraDistribution) installCOPRPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- f.log(fmt.Sprintf("Installing COPR packages: %s", strings.Join(packages, ", ")))
-
- args := []string{"dnf", "install", "-y"}
-
- for _, pkg := range packages {
- if pkg == "niri" || pkg == "niri-git" {
- args = append(args, "--setopt=install_weak_deps=False")
- break
- }
- }
-
- args = append(args, packages...)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: 0.70,
- Step: "Installing COPR packages...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")),
- }
-
- cmdStr := fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, strings.Join(args, " "))
- cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
- return f.runWithProgress(cmd, progressChan, PhaseAURPackages, 0.70, 0.85)
-}
diff --git a/nix/inputs/dms-cli/internal/distros/gentoo.go b/nix/inputs/dms-cli/internal/distros/gentoo.go
deleted file mode 100644
index e2e5fd8..0000000
--- a/nix/inputs/dms-cli/internal/distros/gentoo.go
+++ /dev/null
@@ -1,607 +0,0 @@
-package distros
-
-import (
- "context"
- "fmt"
- "os/exec"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
-)
-
-func init() {
- Register("gentoo", "#54487A", FamilyGentoo, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewGentooDistribution(config, logChan)
- })
-}
-
-type GentooDistribution struct {
- *BaseDistribution
- *ManualPackageInstaller
- config DistroConfig
-}
-
-func NewGentooDistribution(config DistroConfig, logChan chan<- string) *GentooDistribution {
- base := NewBaseDistribution(logChan)
- return &GentooDistribution{
- BaseDistribution: base,
- ManualPackageInstaller: &ManualPackageInstaller{BaseDistribution: base},
- config: config,
- }
-}
-
-func (g *GentooDistribution) GetID() string {
- return g.config.ID
-}
-
-func (g *GentooDistribution) GetColorHex() string {
- return g.config.ColorHex
-}
-
-func (g *GentooDistribution) GetFamily() DistroFamily {
- return g.config.Family
-}
-
-func (g *GentooDistribution) GetPackageManager() PackageManagerType {
- return PackageManagerPortage
-}
-
-func (g *GentooDistribution) DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error) {
- return g.DetectDependenciesWithTerminal(ctx, wm, deps.TerminalGhostty)
-}
-
-func (g *GentooDistribution) DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error) {
- var dependencies []deps.Dependency
-
- dependencies = append(dependencies, g.detectDMS())
-
- dependencies = append(dependencies, g.detectSpecificTerminal(terminal))
-
- dependencies = append(dependencies, g.detectGit())
- dependencies = append(dependencies, g.detectWindowManager(wm))
- dependencies = append(dependencies, g.detectQuickshell())
- dependencies = append(dependencies, g.detectXDGPortal())
- dependencies = append(dependencies, g.detectPolkitAgent())
- dependencies = append(dependencies, g.detectAccountsService())
-
- if wm == deps.WindowManagerHyprland {
- dependencies = append(dependencies, g.detectHyprlandTools()...)
- }
-
- if wm == deps.WindowManagerNiri {
- dependencies = append(dependencies, g.detectXwaylandSatellite())
- }
-
- dependencies = append(dependencies, g.detectMatugen())
- dependencies = append(dependencies, g.detectDgop())
- dependencies = append(dependencies, g.detectHyprpicker())
- dependencies = append(dependencies, g.detectClipboardTools()...)
-
- return dependencies, nil
-}
-
-func (g *GentooDistribution) detectXDGPortal() deps.Dependency {
- status := deps.StatusMissing
- if g.packageInstalled("sys-apps/xdg-desktop-portal-gtk") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "xdg-desktop-portal-gtk",
- Status: status,
- Description: "Desktop integration portal for GTK",
- Required: true,
- }
-}
-
-func (g *GentooDistribution) detectPolkitAgent() deps.Dependency {
- status := deps.StatusMissing
- if g.packageInstalled("mate-extra/mate-polkit") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "mate-polkit",
- Status: status,
- Description: "PolicyKit authentication agent",
- Required: true,
- }
-}
-
-func (g *GentooDistribution) detectXwaylandSatellite() deps.Dependency {
- status := deps.StatusMissing
- if g.commandExists("xwayland-satellite") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "xwayland-satellite",
- Status: status,
- Description: "Xwayland support",
- Required: true,
- }
-}
-
-func (g *GentooDistribution) detectAccountsService() deps.Dependency {
- status := deps.StatusMissing
- if g.packageInstalled("sys-apps/accountsservice") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "accountsservice",
- Status: status,
- Description: "D-Bus interface for user account query and manipulation",
- Required: true,
- }
-}
-
-func (g *GentooDistribution) packageInstalled(pkg string) bool {
- cmd := exec.Command("qlist", "-I", pkg)
- err := cmd.Run()
- return err == nil
-}
-
-func (g *GentooDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping {
- return g.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant))
-}
-
-func (g *GentooDistribution) GetPackageMappingWithVariants(wm deps.WindowManager, variants map[string]deps.PackageVariant) map[string]PackageMapping {
- packages := map[string]PackageMapping{
- "git": {Name: "dev-vcs/git", Repository: RepoTypeSystem},
- "ghostty": {Name: "x11-terms/ghostty", Repository: RepoTypeSystem, UseFlags: "X wayland", AcceptKeywords: "~amd64"},
- "kitty": {Name: "x11-terms/kitty", Repository: RepoTypeSystem, UseFlags: "X wayland"},
- "alacritty": {Name: "x11-terms/alacritty", Repository: RepoTypeSystem, UseFlags: "X wayland"},
- "wl-clipboard": {Name: "gui-apps/wl-clipboard", Repository: RepoTypeSystem},
- "xdg-desktop-portal-gtk": {Name: "sys-apps/xdg-desktop-portal-gtk", Repository: RepoTypeSystem, UseFlags: "wayland X"},
- "mate-polkit": {Name: "mate-extra/mate-polkit", Repository: RepoTypeSystem},
- "accountsservice": {Name: "sys-apps/accountsservice", Repository: RepoTypeSystem},
- "hyprpicker": g.getHyprpickerMapping(variants["hyprland"]),
-
- "quickshell": g.getQuickshellMapping(variants["quickshell"]),
- "matugen": {Name: "x11-misc/matugen", Repository: RepoTypeGURU, AcceptKeywords: "~amd64"},
- "cliphist": {Name: "app-misc/cliphist", Repository: RepoTypeGURU, AcceptKeywords: "~amd64"},
- "dms (DankMaterialShell)": g.getDmsMapping(variants["dms (DankMaterialShell)"]),
- "dgop": {Name: "dgop", Repository: RepoTypeManual, BuildFunc: "installDgop"},
- }
-
- switch wm {
- case deps.WindowManagerHyprland:
- packages["hyprland"] = g.getHyprlandMapping(variants["hyprland"])
- packages["grim"] = PackageMapping{Name: "gui-apps/grim", Repository: RepoTypeSystem}
- packages["slurp"] = PackageMapping{Name: "gui-apps/slurp", Repository: RepoTypeSystem}
- packages["hyprctl"] = g.getHyprlandMapping(variants["hyprland"])
- packages["grimblast"] = PackageMapping{Name: "grimblast", Repository: RepoTypeManual, BuildFunc: "installGrimblast"}
- packages["jq"] = PackageMapping{Name: "app-misc/jq", Repository: RepoTypeSystem}
- case deps.WindowManagerNiri:
- packages["niri"] = g.getNiriMapping(variants["niri"])
- packages["xwayland-satellite"] = PackageMapping{Name: "xwayland-satellite", Repository: RepoTypeManual, BuildFunc: "installXwaylandSatellite"}
- }
-
- return packages
-}
-
-func (g *GentooDistribution) getQuickshellMapping(variant deps.PackageVariant) PackageMapping {
- if forceQuickshellGit || variant == deps.VariantGit {
- return PackageMapping{Name: "gui-apps/quickshell", Repository: RepoTypeGURU, UseFlags: "-breakpad jemalloc sockets wayland layer-shell session-lock toplevel-management screencopy X pipewire tray mpris pam hyprland hyprland-global-shortcuts hyprland-focus-grab i3 i3-ipc bluetooth", AcceptKeywords: "~amd64"}
- }
- return PackageMapping{Name: "gui-apps/quickshell", Repository: RepoTypeGURU, UseFlags: "-breakpad jemalloc sockets wayland layer-shell session-lock toplevel-management screencopy X pipewire tray mpris pam hyprland hyprland-global-shortcuts hyprland-focus-grab i3 i3-ipc bluetooth", AcceptKeywords: "~amd64"}
-}
-
-func (g *GentooDistribution) getDmsMapping(_ deps.PackageVariant) PackageMapping {
- return PackageMapping{Name: "dms", Repository: RepoTypeManual, BuildFunc: "installDankMaterialShell"}
-}
-
-func (g *GentooDistribution) getHyprlandMapping(variant deps.PackageVariant) PackageMapping {
- if variant == deps.VariantGit {
- return PackageMapping{Name: "gui-wm/hyprland", Repository: RepoTypeGURU, UseFlags: "X", AcceptKeywords: "~amd64"}
- }
- return PackageMapping{Name: "gui-wm/hyprland", Repository: RepoTypeSystem, UseFlags: "X", AcceptKeywords: "~amd64"}
-}
-
-func (g *GentooDistribution) getHyprpickerMapping(_ deps.PackageVariant) PackageMapping {
- return PackageMapping{Name: "gui-apps/hyprpicker", Repository: RepoTypeGURU, AcceptKeywords: "~amd64"}
-}
-
-func (g *GentooDistribution) getNiriMapping(variant deps.PackageVariant) PackageMapping {
- if variant == deps.VariantGit {
- return PackageMapping{Name: "gui-wm/niri", Repository: RepoTypeGURU, UseFlags: "dbus screencast", AcceptKeywords: "~amd64"}
- }
- return PackageMapping{Name: "gui-wm/niri", Repository: RepoTypeSystem, UseFlags: "dbus screencast", AcceptKeywords: "~amd64"}
-}
-
-func (g *GentooDistribution) getPrerequisites() []string {
- return []string{
- "app-eselect/eselect-repository",
- "dev-vcs/git",
- "dev-build/make",
- "app-arch/unzip",
- "dev-util/pkgconf",
- }
-}
-
-func (g *GentooDistribution) InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- prerequisites := g.getPrerequisites()
- var missingPkgs []string
-
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.06,
- Step: "Checking prerequisites...",
- IsComplete: false,
- LogOutput: "Checking prerequisite packages",
- }
-
- for _, pkg := range prerequisites {
- checkCmd := exec.CommandContext(ctx, "qlist", "-I", pkg)
- if err := checkCmd.Run(); err != nil {
- missingPkgs = append(missingPkgs, pkg)
- }
- }
-
- _, err := exec.LookPath("go")
- if err != nil {
- g.log("go not found in PATH, will install dev-lang/go")
- missingPkgs = append(missingPkgs, "dev-lang/go")
- } else {
- g.log("go already available in PATH")
- }
-
- if len(missingPkgs) == 0 {
- g.log("All prerequisites already installed")
- return nil
- }
-
- g.log(fmt.Sprintf("Installing prerequisites: %s", strings.Join(missingPkgs, ", ")))
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.08,
- Step: fmt.Sprintf("Installing %d prerequisites...", len(missingPkgs)),
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo emerge --ask=n %s", strings.Join(missingPkgs, " ")),
- LogOutput: fmt.Sprintf("Installing prerequisites: %s", strings.Join(missingPkgs, ", ")),
- }
-
- args := []string{"emerge", "--ask=n", "--quiet"}
- args = append(args, missingPkgs...)
- cmdStr := fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, strings.Join(args, " "))
- cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
- output, err := cmd.CombinedOutput()
- if err != nil {
- g.logError("failed to install prerequisites", err)
- g.log(fmt.Sprintf("Prerequisites command output: %s", string(output)))
- return fmt.Errorf("failed to install prerequisites: %w", err)
- }
- g.log(fmt.Sprintf("Prerequisites install output: %s", string(output)))
-
- return nil
-}
-
-func (g *GentooDistribution) InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, progressChan chan<- InstallProgressMsg) error {
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.05,
- Step: "Checking system prerequisites...",
- IsComplete: false,
- LogOutput: "Starting prerequisite check...",
- }
-
- if err := g.InstallPrerequisites(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install prerequisites: %w", err)
- }
-
- systemPkgs, guruPkgs, manualPkgs := g.categorizePackages(dependencies, wm, reinstallFlags)
-
- g.log(fmt.Sprintf("CATEGORIZED PACKAGES: system=%d, guru=%d, manual=%d", len(systemPkgs), len(guruPkgs), len(manualPkgs)))
-
- if len(systemPkgs) > 0 {
- systemPkgNames := g.extractPackageNames(systemPkgs)
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.35,
- Step: fmt.Sprintf("Installing %d system packages...", len(systemPkgs)),
- IsComplete: false,
- NeedsSudo: true,
- LogOutput: fmt.Sprintf("Installing system packages: %s", strings.Join(systemPkgNames, ", ")),
- }
- if err := g.installPortagePackages(ctx, systemPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install Portage packages: %w", err)
- }
- }
-
- if len(guruPkgs) > 0 {
- g.log(fmt.Sprintf("FOUND %d GURU PACKAGES - WILL SYNC GURU REPO", len(guruPkgs)))
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: 0.60,
- Step: "Syncing GURU repository...",
- IsComplete: false,
- LogOutput: "Syncing GURU repository to fetch latest ebuilds",
- }
- g.log("ABOUT TO CALL syncGURURepo")
- if err := g.syncGURURepo(ctx, sudoPassword, progressChan); err != nil {
- g.log(fmt.Sprintf("syncGURURepo RETURNED ERROR: %v", err))
- return fmt.Errorf("failed to sync GURU repository: %w", err)
- }
- g.log("syncGURURepo COMPLETED SUCCESSFULLY")
-
- guruPkgNames := g.extractPackageNames(guruPkgs)
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: 0.65,
- Step: fmt.Sprintf("Installing %d GURU packages...", len(guruPkgs)),
- IsComplete: false,
- LogOutput: fmt.Sprintf("Installing GURU packages: %s", strings.Join(guruPkgNames, ", ")),
- }
- if err := g.installGURUPackages(ctx, guruPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install GURU packages: %w", err)
- }
- }
-
- if len(manualPkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.85,
- Step: fmt.Sprintf("Building %d packages from source...", len(manualPkgs)),
- IsComplete: false,
- LogOutput: fmt.Sprintf("Building from source: %s", strings.Join(manualPkgs, ", ")),
- }
- if err := g.InstallManualPackages(ctx, manualPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install manual packages: %w", err)
- }
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseConfiguration,
- Progress: 0.90,
- Step: "Configuring system...",
- IsComplete: false,
- LogOutput: "Starting post-installation configuration...",
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseComplete,
- Progress: 1.0,
- Step: "Installation complete!",
- IsComplete: true,
- LogOutput: "All packages installed and configured successfully",
- }
-
- return nil
-}
-
-func (g *GentooDistribution) categorizePackages(dependencies []deps.Dependency, wm deps.WindowManager, reinstallFlags map[string]bool) ([]PackageMapping, []PackageMapping, []string) {
- systemPkgs := []PackageMapping{}
- guruPkgs := []PackageMapping{}
- manualPkgs := []string{}
-
- variantMap := make(map[string]deps.PackageVariant)
- for _, dep := range dependencies {
- variantMap[dep.Name] = dep.Variant
- }
-
- packageMap := g.GetPackageMappingWithVariants(wm, variantMap)
-
- for _, dep := range dependencies {
- if dep.Status == deps.StatusInstalled && !reinstallFlags[dep.Name] {
- continue
- }
-
- pkgInfo, exists := packageMap[dep.Name]
- if !exists {
- g.log(fmt.Sprintf("Warning: No package mapping for %s", dep.Name))
- continue
- }
-
- switch pkgInfo.Repository {
- case RepoTypeSystem:
- systemPkgs = append(systemPkgs, pkgInfo)
- case RepoTypeGURU:
- guruPkgs = append(guruPkgs, pkgInfo)
- case RepoTypeManual:
- manualPkgs = append(manualPkgs, dep.Name)
- }
- }
-
- return systemPkgs, guruPkgs, manualPkgs
-}
-
-func (g *GentooDistribution) extractPackageNames(packages []PackageMapping) []string {
- names := make([]string, len(packages))
- for i, pkg := range packages {
- names[i] = pkg.Name
- }
- return names
-}
-
-func (g *GentooDistribution) installPortagePackages(ctx context.Context, packages []PackageMapping, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- packageNames := g.extractPackageNames(packages)
- g.log(fmt.Sprintf("Installing Portage packages: %s", strings.Join(packageNames, ", ")))
-
- for _, pkg := range packages {
- if pkg.AcceptKeywords != "" {
- if err := g.setPackageAcceptKeywords(ctx, pkg.Name, pkg.AcceptKeywords, sudoPassword); err != nil {
- return fmt.Errorf("failed to set accept keywords for %s: %w", pkg.Name, err)
- }
- }
- if pkg.UseFlags != "" {
- if err := g.setPackageUseFlags(ctx, pkg.Name, pkg.UseFlags, sudoPassword); err != nil {
- return fmt.Errorf("failed to set USE flags for %s: %w", pkg.Name, err)
- }
- }
- }
-
- args := []string{"emerge", "--ask=n", "--quiet"}
- args = append(args, packageNames...)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.40,
- Step: "Installing system packages...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")),
- }
-
- cmdStr := fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, strings.Join(args, " "))
- cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
- return g.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.40, 0.60)
-}
-
-func (g *GentooDistribution) setPackageUseFlags(ctx context.Context, packageName, useFlags, sudoPassword string) error {
- packageUseDir := "/etc/portage/package.use"
-
- mkdirCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S mkdir -p %s", sudoPassword, packageUseDir))
- if output, err := mkdirCmd.CombinedOutput(); err != nil {
- g.log(fmt.Sprintf("mkdir output: %s", string(output)))
- return fmt.Errorf("failed to create package.use directory: %w", err)
- }
-
- useFlagLine := fmt.Sprintf("%s %s", packageName, useFlags)
-
- appendCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S bash -c \"echo '%s' >> %s/danklinux\"", sudoPassword, useFlagLine, packageUseDir))
-
- output, err := appendCmd.CombinedOutput()
- if err != nil {
- g.log(fmt.Sprintf("append output: %s", string(output)))
- return fmt.Errorf("failed to write USE flags to package.use: %w", err)
- }
-
- g.log(fmt.Sprintf("Set USE flags for %s: %s", packageName, useFlags))
- return nil
-}
-
-func (g *GentooDistribution) syncGURURepo(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- g.log("Enabling GURU repository...")
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.55,
- Step: "Enabling GURU repository...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo eselect repository enable guru",
- }
-
- // Enable GURU repository
- enableCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S eselect repository enable guru", sudoPassword))
- output, err := enableCmd.CombinedOutput()
- if err != nil {
- g.logError("failed to enable GURU repository", err)
- g.log(fmt.Sprintf("eselect repository enable output: %s", string(output)))
- return fmt.Errorf("failed to enable GURU repository: %w", err)
- }
- g.log(fmt.Sprintf("GURU repository enabled: %s", string(output)))
-
- // Sync GURU repository
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.57,
- Step: "Syncing GURU repository...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo emaint sync --repo guru",
- }
-
- g.log("Syncing GURU repository...")
- syncCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S emaint sync --repo guru", sudoPassword))
- syncOutput, syncErr := syncCmd.CombinedOutput()
- if syncErr != nil {
- g.logError("failed to sync GURU repository", syncErr)
- g.log(fmt.Sprintf("emaint sync output: %s", string(syncOutput)))
- return fmt.Errorf("failed to sync GURU repository: %w", syncErr)
- }
- g.log(fmt.Sprintf("GURU repository synced: %s", string(syncOutput)))
-
- return nil
-}
-
-func (g *GentooDistribution) setPackageAcceptKeywords(ctx context.Context, packageName, keywords, sudoPassword string) error {
- checkCmd := exec.CommandContext(ctx, "portageq", "match", "/", packageName)
- if output, err := checkCmd.CombinedOutput(); err == nil && len(output) > 0 {
- g.log(fmt.Sprintf("Package %s is already available (may already be unmasked)", packageName))
- return nil
- }
-
- acceptKeywordsDir := "/etc/portage/package.accept_keywords"
-
- mkdirCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S mkdir -p %s", sudoPassword, acceptKeywordsDir))
- if output, err := mkdirCmd.CombinedOutput(); err != nil {
- g.log(fmt.Sprintf("mkdir output: %s", string(output)))
- return fmt.Errorf("failed to create package.accept_keywords directory: %w", err)
- }
-
- keywordLine := fmt.Sprintf("%s %s", packageName, keywords)
-
- checkExistingCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("grep -q '^%s ' %s/danklinux 2>/dev/null", packageName, acceptKeywordsDir))
- if checkExistingCmd.Run() == nil {
- g.log(fmt.Sprintf("Accept keywords already set for %s", packageName))
- return nil
- }
-
- appendCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S bash -c \"echo '%s' >> %s/danklinux\"", sudoPassword, keywordLine, acceptKeywordsDir))
-
- output, err := appendCmd.CombinedOutput()
- if err != nil {
- g.log(fmt.Sprintf("append output: %s", string(output)))
- return fmt.Errorf("failed to write accept keywords: %w", err)
- }
-
- g.log(fmt.Sprintf("Set accept keywords for %s: %s", packageName, keywords))
- return nil
-}
-
-func (g *GentooDistribution) installGURUPackages(ctx context.Context, packages []PackageMapping, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- packageNames := g.extractPackageNames(packages)
- g.log(fmt.Sprintf("Installing GURU packages: %s", strings.Join(packageNames, ", ")))
-
- for _, pkg := range packages {
- if pkg.AcceptKeywords != "" {
- if err := g.setPackageAcceptKeywords(ctx, pkg.Name, pkg.AcceptKeywords, sudoPassword); err != nil {
- return fmt.Errorf("failed to set accept keywords for %s: %w", pkg.Name, err)
- }
- }
- if pkg.UseFlags != "" {
- if err := g.setPackageUseFlags(ctx, pkg.Name, pkg.UseFlags, sudoPassword); err != nil {
- return fmt.Errorf("failed to set USE flags for %s: %w", pkg.Name, err)
- }
- }
- }
-
- guruPackages := make([]string, len(packageNames))
- for i, pkg := range packageNames {
- guruPackages[i] = pkg + "::guru"
- }
-
- args := []string{"emerge", "--ask=n", "--quiet"}
- args = append(args, guruPackages...)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: 0.70,
- Step: "Installing GURU packages...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")),
- }
-
- cmdStr := fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, strings.Join(args, " "))
- cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
- return g.runWithProgress(cmd, progressChan, PhaseAURPackages, 0.70, 0.85)
-}
diff --git a/nix/inputs/dms-cli/internal/distros/interface.go b/nix/inputs/dms-cli/internal/distros/interface.go
deleted file mode 100644
index 133ece1..0000000
--- a/nix/inputs/dms-cli/internal/distros/interface.go
+++ /dev/null
@@ -1,156 +0,0 @@
-package distros
-
-import (
- "context"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
-)
-
-// DistroFamily represents a family of related distributions
-type DistroFamily string
-
-const (
- FamilyArch DistroFamily = "arch"
- FamilyFedora DistroFamily = "fedora"
- FamilySUSE DistroFamily = "suse"
- FamilyUbuntu DistroFamily = "ubuntu"
- FamilyDebian DistroFamily = "debian"
- FamilyNix DistroFamily = "nix"
- FamilyGentoo DistroFamily = "gentoo"
-)
-
-// PackageManagerType defines the package manager a distro uses
-type PackageManagerType string
-
-const (
- PackageManagerPacman PackageManagerType = "pacman"
- PackageManagerDNF PackageManagerType = "dnf"
- PackageManagerAPT PackageManagerType = "apt"
- PackageManagerZypper PackageManagerType = "zypper"
- PackageManagerNix PackageManagerType = "nix"
- PackageManagerPortage PackageManagerType = "portage"
-)
-
-// RepositoryType defines the type of repository for a package
-type RepositoryType string
-
-const (
- RepoTypeSystem RepositoryType = "system" // Standard system repo (pacman, dnf, apt)
- RepoTypeAUR RepositoryType = "aur" // Arch User Repository
- RepoTypeCOPR RepositoryType = "copr" // Fedora COPR
- RepoTypePPA RepositoryType = "ppa" // Ubuntu PPA
- RepoTypeFlake RepositoryType = "flake" // Nix flake
- RepoTypeGURU RepositoryType = "guru" // Gentoo GURU
- RepoTypeManual RepositoryType = "manual" // Manual build from source
-)
-
-// InstallPhase represents the current phase of installation
-type InstallPhase int
-
-const (
- PhasePrerequisites InstallPhase = iota
- PhaseAURHelper
- PhaseSystemPackages
- PhaseAURPackages
- PhaseCursorTheme
- PhaseConfiguration
- PhaseComplete
-)
-
-// InstallProgressMsg represents progress during package installation
-type InstallProgressMsg struct {
- Phase InstallPhase
- Progress float64
- Step string
- IsComplete bool
- NeedsSudo bool
- CommandInfo string
- LogOutput string
- Error error
-}
-
-// PackageMapping defines how to install a package on a specific distro
-type PackageMapping struct {
- Name string // Package name to install
- Repository RepositoryType // Repository type
- RepoURL string // Repository URL if needed (e.g., COPR repo, PPA)
- BuildFunc string // Name of manual build function if RepoTypeManual
- UseFlags string // USE flags for Gentoo packages
- AcceptKeywords string // Accept keywords for Gentoo packages (e.g., "~amd64")
-}
-
-// Distribution defines a Linux distribution with all its specific configurations
-type Distribution interface {
- // Metadata
- GetID() string
- GetColorHex() string
- GetFamily() DistroFamily
- GetPackageManager() PackageManagerType
-
- // Dependency Detection
- DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error)
- DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error)
-
- // Package Installation
- InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, progressChan chan<- InstallProgressMsg) error
-
- // Package Mapping
- GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping
-
- // Prerequisites
- InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error
-}
-
-// DistroConfig holds configuration for a distribution
-type DistroConfig struct {
- ID string
- ColorHex string
- Family DistroFamily
- Constructor func(config DistroConfig, logChan chan<- string) Distribution
-}
-
-// Registry holds all supported distributions
-var Registry = make(map[string]DistroConfig)
-
-// Register adds a distribution to the registry
-func Register(id, colorHex string, family DistroFamily, constructor func(config DistroConfig, logChan chan<- string) Distribution) {
- Registry[id] = DistroConfig{
- ID: id,
- ColorHex: colorHex,
- Family: family,
- Constructor: constructor,
- }
-}
-
-// GetSupportedDistros returns a list of all supported distribution IDs
-func GetSupportedDistros() []string {
- ids := make([]string, 0, len(Registry))
- for id := range Registry {
- ids = append(ids, id)
- }
- return ids
-}
-
-// IsDistroSupported checks if a distribution ID is supported
-func IsDistroSupported(id string) bool {
- _, exists := Registry[id]
- return exists
-}
-
-// NewDistribution creates a distribution instance by ID
-func NewDistribution(id string, logChan chan<- string) (Distribution, error) {
- config, exists := Registry[id]
- if !exists {
- return nil, &UnsupportedDistributionError{ID: id}
- }
- return config.Constructor(config, logChan), nil
-}
-
-// UnsupportedDistributionError is returned when a distribution is not supported
-type UnsupportedDistributionError struct {
- ID string
-}
-
-func (e *UnsupportedDistributionError) Error() string {
- return "unsupported distribution: " + e.ID
-}
diff --git a/nix/inputs/dms-cli/internal/distros/manual_packages.go b/nix/inputs/dms-cli/internal/distros/manual_packages.go
deleted file mode 100644
index 04c2ab4..0000000
--- a/nix/inputs/dms-cli/internal/distros/manual_packages.go
+++ /dev/null
@@ -1,802 +0,0 @@
-package distros
-
-import (
- "context"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
-)
-
-// ManualPackageInstaller provides methods for installing packages from source
-type ManualPackageInstaller struct {
- *BaseDistribution
-}
-
-// parseLatestTagFromGitOutput parses git ls-remote output and returns the latest tag
-func (m *ManualPackageInstaller) parseLatestTagFromGitOutput(output string) string {
- lines := strings.Split(output, "\n")
- for _, line := range lines {
- if strings.Contains(line, "refs/tags/") && !strings.Contains(line, "^{}") {
- parts := strings.Split(line, "refs/tags/")
- if len(parts) > 1 {
- latestTag := strings.TrimSpace(parts[1])
- return latestTag
- }
- }
- }
- return ""
-}
-
-// getLatestQuickshellTag fetches the latest tag from the quickshell repository
-func (m *ManualPackageInstaller) getLatestQuickshellTag(ctx context.Context) string {
- tagCmd := exec.CommandContext(ctx, "git", "ls-remote", "--tags", "--sort=-v:refname",
- "https://github.com/quickshell-mirror/quickshell.git")
- tagOutput, err := tagCmd.Output()
- if err != nil {
- m.log(fmt.Sprintf("Warning: failed to fetch quickshell tags: %v", err))
- return ""
- }
-
- return m.parseLatestTagFromGitOutput(string(tagOutput))
-}
-
-// InstallManualPackages handles packages that need manual building
-func (m *ManualPackageInstaller) InstallManualPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- m.log(fmt.Sprintf("Installing manual packages: %s", strings.Join(packages, ", ")))
-
- for _, pkg := range packages {
- switch pkg {
- case "dms (DankMaterialShell)", "dms":
- if err := m.installDankMaterialShell(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install DankMaterialShell: %w", err)
- }
- case "dgop":
- if err := m.installDgop(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install dgop: %w", err)
- }
- case "grimblast":
- if err := m.installGrimblast(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install grimblast: %w", err)
- }
- case "niri":
- if err := m.installNiri(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install niri: %w", err)
- }
- case "quickshell":
- if err := m.installQuickshell(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install quickshell: %w", err)
- }
- case "hyprland":
- if err := m.installHyprland(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install hyprland: %w", err)
- }
- case "hyprpicker":
- if err := m.installHyprpicker(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install hyprpicker: %w", err)
- }
- case "ghostty":
- if err := m.installGhostty(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install ghostty: %w", err)
- }
- case "matugen":
- if err := m.installMatugen(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install matugen: %w", err)
- }
- case "cliphist":
- if err := m.installCliphist(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install cliphist: %w", err)
- }
- case "xwayland-satellite":
- if err := m.installXwaylandSatellite(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install xwayland-satellite: %w", err)
- }
- default:
- m.log(fmt.Sprintf("Warning: No manual build method for %s", pkg))
- }
- }
-
- return nil
-}
-
-func (m *ManualPackageInstaller) installDgop(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- m.log("Installing dgop from source...")
-
- homeDir := os.Getenv("HOME")
- if homeDir == "" {
- return fmt.Errorf("HOME environment variable not set")
- }
-
- cacheDir := filepath.Join(homeDir, ".cache", "dankinstall")
- if err := os.MkdirAll(cacheDir, 0755); err != nil {
- return fmt.Errorf("failed to create cache directory: %w", err)
- }
-
- tmpDir := filepath.Join(cacheDir, "dgop-build")
- if err := os.MkdirAll(tmpDir, 0755); err != nil {
- return fmt.Errorf("failed to create temp directory: %w", err)
- }
- defer os.RemoveAll(tmpDir)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.1,
- Step: "Cloning dgop repository...",
- IsComplete: false,
- CommandInfo: "git clone https://github.com/AvengeMedia/dgop.git",
- }
-
- cloneCmd := exec.CommandContext(ctx, "git", "clone", "https://github.com/AvengeMedia/dgop.git", tmpDir)
- if err := cloneCmd.Run(); err != nil {
- m.logError("failed to clone dgop repository", err)
- return fmt.Errorf("failed to clone dgop repository: %w", err)
- }
-
- buildCmd := exec.CommandContext(ctx, "make")
- buildCmd.Dir = tmpDir
- buildCmd.Env = append(os.Environ(), "TMPDIR="+cacheDir)
- if err := m.runWithProgressStep(buildCmd, progressChan, PhaseSystemPackages, 0.4, 0.7, "Building dgop..."); err != nil {
- return fmt.Errorf("failed to build dgop: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.7,
- Step: "Installing dgop...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo make install",
- }
-
- installCmd := exec.CommandContext(ctx, "bash", "-c", fmt.Sprintf("echo '%s' | sudo -S make install", sudoPassword))
- installCmd.Dir = tmpDir
- if err := installCmd.Run(); err != nil {
- m.logError("failed to install dgop", err)
- return fmt.Errorf("failed to install dgop: %w", err)
- }
-
- m.log("dgop installed successfully from source")
- return nil
-}
-
-func (m *ManualPackageInstaller) installGrimblast(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- m.log("Installing grimblast script for Hyprland...")
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.1,
- Step: "Downloading grimblast script...",
- IsComplete: false,
- CommandInfo: "curl grimblast script",
- }
-
- grimblastURL := "https://raw.githubusercontent.com/hyprwm/contrib/refs/heads/main/grimblast/grimblast"
- tmpPath := filepath.Join(os.TempDir(), "grimblast")
-
- downloadCmd := exec.CommandContext(ctx, "curl", "-L", "-o", tmpPath, grimblastURL)
- if err := downloadCmd.Run(); err != nil {
- m.logError("failed to download grimblast", err)
- return fmt.Errorf("failed to download grimblast: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.5,
- Step: "Making grimblast executable...",
- IsComplete: false,
- CommandInfo: "chmod +x grimblast",
- }
-
- chmodCmd := exec.CommandContext(ctx, "chmod", "+x", tmpPath)
- if err := chmodCmd.Run(); err != nil {
- m.logError("failed to make grimblast executable", err)
- return fmt.Errorf("failed to make grimblast executable: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.8,
- Step: "Installing grimblast to /usr/local/bin...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo cp grimblast /usr/local/bin/",
- }
-
- installCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S cp %s /usr/local/bin/grimblast", sudoPassword, tmpPath))
- if err := installCmd.Run(); err != nil {
- m.logError("failed to install grimblast", err)
- return fmt.Errorf("failed to install grimblast: %w", err)
- }
-
- os.Remove(tmpPath)
-
- m.log("grimblast installed successfully to /usr/local/bin")
- return nil
-}
-
-func (m *ManualPackageInstaller) installNiri(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- m.log("Installing niri from source...")
-
- homeDir, _ := os.UserHomeDir()
- buildDir := filepath.Join(homeDir, ".cache", "dankinstall", "niri-build")
- tmpDir := filepath.Join(homeDir, ".cache", "dankinstall", "tmp")
- if err := os.MkdirAll(buildDir, 0755); err != nil {
- return fmt.Errorf("failed to create build directory: %w", err)
- }
- if err := os.MkdirAll(tmpDir, 0755); err != nil {
- return fmt.Errorf("failed to create temp directory: %w", err)
- }
- defer func() {
- os.RemoveAll(buildDir)
- os.RemoveAll(tmpDir)
- }()
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.2,
- Step: "Cloning niri repository...",
- IsComplete: false,
- CommandInfo: "git clone https://github.com/YaLTeR/niri.git",
- }
-
- cloneCmd := exec.CommandContext(ctx, "git", "clone", "https://github.com/YaLTeR/niri.git", buildDir)
- if err := cloneCmd.Run(); err != nil {
- return fmt.Errorf("failed to clone niri: %w", err)
- }
-
- checkoutCmd := exec.CommandContext(ctx, "git", "-C", buildDir, "checkout", "v25.08")
- if err := checkoutCmd.Run(); err != nil {
- m.log(fmt.Sprintf("Warning: failed to checkout v25.08, using main: %v", err))
- }
-
- if !m.commandExists("cargo-deb") {
- cargoDebInstallCmd := exec.CommandContext(ctx, "cargo", "install", "cargo-deb")
- cargoDebInstallCmd.Env = append(os.Environ(), "TMPDIR="+tmpDir)
- if err := m.runWithProgressStep(cargoDebInstallCmd, progressChan, PhaseSystemPackages, 0.3, 0.35, "Installing cargo-deb..."); err != nil {
- return fmt.Errorf("failed to install cargo-deb: %w", err)
- }
- }
-
- buildDebCmd := exec.CommandContext(ctx, "cargo", "deb")
- buildDebCmd.Dir = buildDir
- buildDebCmd.Env = append(os.Environ(), "TMPDIR="+tmpDir)
- if err := m.runWithProgressStep(buildDebCmd, progressChan, PhaseSystemPackages, 0.35, 0.95, "Building niri deb package..."); err != nil {
- return fmt.Errorf("failed to build niri deb: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.95,
- Step: "Installing niri deb package...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "dpkg -i niri.deb",
- }
-
- installDebCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S dpkg -i %s/target/debian/niri_*.deb", sudoPassword, buildDir))
-
- output, err := installDebCmd.CombinedOutput()
- if err != nil {
- m.log(fmt.Sprintf("dpkg install failed. Output:\n%s", string(output)))
- return fmt.Errorf("failed to install niri deb package: %w\nOutput:\n%s", err, string(output))
- }
-
- m.log(fmt.Sprintf("dpkg install successful. Output:\n%s", string(output)))
-
- m.log("niri installed successfully from source")
- return nil
-}
-
-func (m *ManualPackageInstaller) installQuickshell(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- m.log("Installing quickshell from source...")
-
- homeDir := os.Getenv("HOME")
- if homeDir == "" {
- return fmt.Errorf("HOME environment variable not set")
- }
-
- cacheDir := filepath.Join(homeDir, ".cache", "dankinstall")
- if err := os.MkdirAll(cacheDir, 0755); err != nil {
- return fmt.Errorf("failed to create cache directory: %w", err)
- }
-
- tmpDir := filepath.Join(cacheDir, "quickshell-build")
- if err := os.MkdirAll(tmpDir, 0755); err != nil {
- return fmt.Errorf("failed to create temp directory: %w", err)
- }
- defer os.RemoveAll(tmpDir)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.1,
- Step: "Cloning quickshell repository...",
- IsComplete: false,
- CommandInfo: "git clone https://github.com/quickshell-mirror/quickshell.git",
- }
-
- var cloneCmd *exec.Cmd
- if forceQuickshellGit {
- cloneCmd = exec.CommandContext(ctx, "git", "clone", "https://github.com/quickshell-mirror/quickshell.git", tmpDir)
- } else {
- // Get latest tag from repository
- latestTag := m.getLatestQuickshellTag(ctx)
- if latestTag != "" {
- m.log(fmt.Sprintf("Using latest quickshell tag: %s", latestTag))
- cloneCmd = exec.CommandContext(ctx, "git", "clone", "--branch", latestTag, "https://github.com/quickshell-mirror/quickshell.git", tmpDir)
- } else {
- m.log("Warning: failed to fetch latest tag, using default branch")
- cloneCmd = exec.CommandContext(ctx, "git", "clone", "https://github.com/quickshell-mirror/quickshell.git", tmpDir)
- }
- }
- if err := cloneCmd.Run(); err != nil {
- return fmt.Errorf("failed to clone quickshell: %w", err)
- }
-
- buildDir := tmpDir + "/build"
- if err := os.MkdirAll(buildDir, 0755); err != nil {
- return fmt.Errorf("failed to create build directory: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.3,
- Step: "Configuring quickshell build...",
- IsComplete: false,
- CommandInfo: "cmake -B build -S . -G Ninja",
- }
-
- configureCmd := exec.CommandContext(ctx, "cmake", "-GNinja", "-B", "build",
- "-DCMAKE_BUILD_TYPE=RelWithDebInfo",
- "-DCRASH_REPORTER=off",
- "-DCMAKE_CXX_STANDARD=20")
- configureCmd.Dir = tmpDir
- configureCmd.Env = append(os.Environ(), "TMPDIR="+cacheDir)
-
- output, err := configureCmd.CombinedOutput()
- if err != nil {
- m.log(fmt.Sprintf("cmake configure failed. Output:\n%s", string(output)))
- return fmt.Errorf("failed to configure quickshell: %w\nCMake output:\n%s", err, string(output))
- }
-
- m.log(fmt.Sprintf("cmake configure successful. Output:\n%s", string(output)))
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.4,
- Step: "Building quickshell (this may take a while)...",
- IsComplete: false,
- CommandInfo: "cmake --build build",
- }
-
- buildCmd := exec.CommandContext(ctx, "cmake", "--build", "build")
- buildCmd.Dir = tmpDir
- buildCmd.Env = append(os.Environ(), "TMPDIR="+cacheDir)
- if err := m.runWithProgressStep(buildCmd, progressChan, PhaseSystemPackages, 0.4, 0.8, "Building quickshell..."); err != nil {
- return fmt.Errorf("failed to build quickshell: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.8,
- Step: "Installing quickshell...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo cmake --install build",
- }
-
- installCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("cd %s && echo '%s' | sudo -S cmake --install build", tmpDir, sudoPassword))
- if err := installCmd.Run(); err != nil {
- return fmt.Errorf("failed to install quickshell: %w", err)
- }
-
- m.log("quickshell installed successfully from source")
- return nil
-}
-
-func (m *ManualPackageInstaller) installHyprland(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- m.log("Installing Hyprland from source...")
-
- homeDir := os.Getenv("HOME")
- if homeDir == "" {
- return fmt.Errorf("HOME environment variable not set")
- }
-
- cacheDir := filepath.Join(homeDir, ".cache", "dankinstall")
- if err := os.MkdirAll(cacheDir, 0755); err != nil {
- return fmt.Errorf("failed to create cache directory: %w", err)
- }
-
- tmpDir := filepath.Join(cacheDir, "hyprland-build")
- if err := os.MkdirAll(tmpDir, 0755); err != nil {
- return fmt.Errorf("failed to create temp directory: %w", err)
- }
- defer os.RemoveAll(tmpDir)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.1,
- Step: "Cloning Hyprland repository...",
- IsComplete: false,
- CommandInfo: "git clone --recursive https://github.com/hyprwm/Hyprland.git",
- }
-
- cloneCmd := exec.CommandContext(ctx, "git", "clone", "--recursive", "https://github.com/hyprwm/Hyprland.git", tmpDir)
- if err := cloneCmd.Run(); err != nil {
- return fmt.Errorf("failed to clone Hyprland: %w", err)
- }
-
- checkoutCmd := exec.CommandContext(ctx, "git", "-C", tmpDir, "checkout", "v0.50.1")
- if err := checkoutCmd.Run(); err != nil {
- m.log(fmt.Sprintf("Warning: failed to checkout v0.50.1, using main: %v", err))
- }
-
- buildCmd := exec.CommandContext(ctx, "make", "all")
- buildCmd.Dir = tmpDir
- buildCmd.Env = append(os.Environ(), "TMPDIR="+cacheDir)
- if err := m.runWithProgressStep(buildCmd, progressChan, PhaseSystemPackages, 0.2, 0.8, "Building Hyprland..."); err != nil {
- return fmt.Errorf("failed to build Hyprland: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.8,
- Step: "Installing Hyprland...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo make install",
- }
-
- installCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("cd %s && echo '%s' | sudo -S make install", tmpDir, sudoPassword))
- if err := installCmd.Run(); err != nil {
- return fmt.Errorf("failed to install Hyprland: %w", err)
- }
-
- m.log("Hyprland installed successfully from source")
- return nil
-}
-
-func (m *ManualPackageInstaller) installHyprpicker(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- m.log("Installing hyprpicker from source...")
-
- homeDir := os.Getenv("HOME")
- if homeDir == "" {
- return fmt.Errorf("HOME environment variable not set")
- }
-
- cacheDir := filepath.Join(homeDir, ".cache", "dankinstall")
- if err := os.MkdirAll(cacheDir, 0755); err != nil {
- return fmt.Errorf("failed to create cache directory: %w", err)
- }
-
- tmpDir := filepath.Join(cacheDir, "hyprpicker-build")
- if err := os.MkdirAll(tmpDir, 0755); err != nil {
- return fmt.Errorf("failed to create temp directory: %w", err)
- }
- defer os.RemoveAll(tmpDir)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.2,
- Step: "Cloning hyprpicker repository...",
- IsComplete: false,
- CommandInfo: "git clone https://github.com/hyprwm/hyprpicker.git",
- }
-
- cloneCmd := exec.CommandContext(ctx, "git", "clone", "https://github.com/hyprwm/hyprpicker.git", tmpDir)
- if err := cloneCmd.Run(); err != nil {
- return fmt.Errorf("failed to clone hyprpicker: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.4,
- Step: "Building hyprpicker...",
- IsComplete: false,
- CommandInfo: "make all",
- }
-
- buildCmd := exec.CommandContext(ctx, "make", "all")
- buildCmd.Dir = tmpDir
- buildCmd.Env = append(os.Environ(), "TMPDIR="+cacheDir)
- if err := buildCmd.Run(); err != nil {
- return fmt.Errorf("failed to build hyprpicker: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.8,
- Step: "Installing hyprpicker...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo make install",
- }
-
- installCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("cd %s && echo '%s' | sudo -S make install", tmpDir, sudoPassword))
- if err := installCmd.Run(); err != nil {
- return fmt.Errorf("failed to install hyprpicker: %w", err)
- }
-
- m.log("hyprpicker installed successfully from source")
- return nil
-}
-
-func (m *ManualPackageInstaller) installGhostty(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- m.log("Installing Ghostty from source...")
-
- homeDir := os.Getenv("HOME")
- if homeDir == "" {
- return fmt.Errorf("HOME environment variable not set")
- }
-
- cacheDir := filepath.Join(homeDir, ".cache", "dankinstall")
- if err := os.MkdirAll(cacheDir, 0755); err != nil {
- return fmt.Errorf("failed to create cache directory: %w", err)
- }
-
- tmpDir := filepath.Join(cacheDir, "ghostty-build")
- if err := os.MkdirAll(tmpDir, 0755); err != nil {
- return fmt.Errorf("failed to create temp directory: %w", err)
- }
- defer os.RemoveAll(tmpDir)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.1,
- Step: "Cloning Ghostty repository...",
- IsComplete: false,
- CommandInfo: "git clone https://github.com/ghostty-org/ghostty.git",
- }
-
- cloneCmd := exec.CommandContext(ctx, "git", "clone", "https://github.com/ghostty-org/ghostty.git", tmpDir)
- if err := cloneCmd.Run(); err != nil {
- return fmt.Errorf("failed to clone Ghostty: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.2,
- Step: "Building Ghostty (this may take a while)...",
- IsComplete: false,
- CommandInfo: "zig build -Doptimize=ReleaseFast",
- }
-
- buildCmd := exec.CommandContext(ctx, "zig", "build", "-Doptimize=ReleaseFast")
- buildCmd.Dir = tmpDir
- buildCmd.Env = append(os.Environ(), "TMPDIR="+cacheDir)
- if err := buildCmd.Run(); err != nil {
- return fmt.Errorf("failed to build Ghostty: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.8,
- Step: "Installing Ghostty...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo cp zig-out/bin/ghostty /usr/local/bin/",
- }
-
- installCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S cp %s/zig-out/bin/ghostty /usr/local/bin/", sudoPassword, tmpDir))
- if err := installCmd.Run(); err != nil {
- return fmt.Errorf("failed to install Ghostty: %w", err)
- }
-
- m.log("Ghostty installed successfully from source")
- return nil
-}
-
-func (m *ManualPackageInstaller) installMatugen(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- m.log("Installing matugen from source...")
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.1,
- Step: "Installing matugen via cargo...",
- IsComplete: false,
- CommandInfo: "cargo install matugen",
- }
-
- installCmd := exec.CommandContext(ctx, "cargo", "install", "matugen")
- if err := m.runWithProgressStep(installCmd, progressChan, PhaseSystemPackages, 0.1, 0.7, "Building matugen..."); err != nil {
- return fmt.Errorf("failed to install matugen: %w", err)
- }
-
- homeDir := os.Getenv("HOME")
- sourcePath := filepath.Join(homeDir, ".cargo", "bin", "matugen")
- targetPath := "/usr/local/bin/matugen"
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.7,
- Step: "Installing matugen binary to system...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo cp %s %s", sourcePath, targetPath),
- }
-
- copyCmd := exec.CommandContext(ctx, "sudo", "-S", "cp", sourcePath, targetPath)
- copyCmd.Stdin = strings.NewReader(sudoPassword + "\n")
- if err := copyCmd.Run(); err != nil {
- return fmt.Errorf("failed to copy matugen to /usr/local/bin: %w", err)
- }
-
- // Make it executable
- chmodCmd := exec.CommandContext(ctx, "sudo", "-S", "chmod", "+x", targetPath)
- chmodCmd.Stdin = strings.NewReader(sudoPassword + "\n")
- if err := chmodCmd.Run(); err != nil {
- return fmt.Errorf("failed to make matugen executable: %w", err)
- }
-
- m.log("matugen installed successfully from source")
- return nil
-}
-
-func (m *ManualPackageInstaller) installDankMaterialShell(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- m.log("Installing DankMaterialShell (DMS)...")
-
- // Always install/update the DMS binary
- if err := m.installDMSBinary(ctx, sudoPassword, progressChan); err != nil {
- m.logError("Failed to install DMS binary", err)
- }
-
- // Handle DMS config - clone if missing, pull if exists
- dmsPath := filepath.Join(os.Getenv("HOME"), ".config/quickshell/dms")
- if _, err := os.Stat(dmsPath); os.IsNotExist(err) {
- // Config doesn't exist, clone it
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.90,
- Step: "Cloning DankMaterialShell config...",
- IsComplete: false,
- CommandInfo: "git clone https://github.com/AvengeMedia/DankMaterialShell.git ~/.config/quickshell/dms",
- }
-
- configDir := filepath.Dir(dmsPath)
- if err := os.MkdirAll(configDir, 0755); err != nil {
- return fmt.Errorf("failed to create quickshell config directory: %w", err)
- }
-
- cloneCmd := exec.CommandContext(ctx, "git", "clone",
- "https://github.com/AvengeMedia/DankMaterialShell.git", dmsPath)
- if err := cloneCmd.Run(); err != nil {
- return fmt.Errorf("failed to clone DankMaterialShell: %w", err)
- }
-
- if !forceDMSGit {
- fetchCmd := exec.CommandContext(ctx, "git", "-C", dmsPath, "fetch", "--tags")
- if err := fetchCmd.Run(); err == nil {
- tagCmd := exec.CommandContext(ctx, "git", "-C", dmsPath, "describe", "--tags", "--abbrev=0", "origin/master")
- if tagOutput, err := tagCmd.Output(); err == nil {
- latestTag := strings.TrimSpace(string(tagOutput))
- checkoutCmd := exec.CommandContext(ctx, "git", "-C", dmsPath, "checkout", latestTag)
- if err := checkoutCmd.Run(); err == nil {
- m.log(fmt.Sprintf("Checked out latest tag: %s", latestTag))
- }
- }
- }
- }
-
- m.log("DankMaterialShell config cloned successfully")
- } else {
- // Config exists, update it
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.90,
- Step: "Updating DankMaterialShell config...",
- IsComplete: false,
- CommandInfo: "git pull in ~/.config/quickshell/dms",
- }
-
- pullCmd := exec.CommandContext(ctx, "git", "pull")
- pullCmd.Dir = dmsPath
- if err := pullCmd.Run(); err != nil {
- m.logError("Failed to update DankMaterialShell config", err)
- } else {
- m.log("DankMaterialShell config updated successfully")
- }
- }
-
- return nil
-}
-
-func (m *ManualPackageInstaller) installCliphist(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- m.log("Installing cliphist from source...")
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.1,
- Step: "Installing cliphist via go install...",
- IsComplete: false,
- CommandInfo: "go install go.senan.xyz/cliphist@latest",
- }
-
- installCmd := exec.CommandContext(ctx, "go", "install", "go.senan.xyz/cliphist@latest")
- if err := m.runWithProgressStep(installCmd, progressChan, PhaseSystemPackages, 0.1, 0.7, "Building cliphist..."); err != nil {
- return fmt.Errorf("failed to install cliphist: %w", err)
- }
-
- homeDir := os.Getenv("HOME")
- sourcePath := filepath.Join(homeDir, "go", "bin", "cliphist")
- targetPath := "/usr/local/bin/cliphist"
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.7,
- Step: "Installing cliphist binary to system...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo cp %s %s", sourcePath, targetPath),
- }
-
- copyCmd := exec.CommandContext(ctx, "sudo", "-S", "cp", sourcePath, targetPath)
- copyCmd.Stdin = strings.NewReader(sudoPassword + "\n")
- if err := copyCmd.Run(); err != nil {
- return fmt.Errorf("failed to copy cliphist to /usr/local/bin: %w", err)
- }
-
- // Make it executable
- chmodCmd := exec.CommandContext(ctx, "sudo", "-S", "chmod", "+x", targetPath)
- chmodCmd.Stdin = strings.NewReader(sudoPassword + "\n")
- if err := chmodCmd.Run(); err != nil {
- return fmt.Errorf("failed to make cliphist executable: %w", err)
- }
-
- m.log("cliphist installed successfully from source")
- return nil
-}
-
-func (m *ManualPackageInstaller) installXwaylandSatellite(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- m.log("Installing xwayland-satellite from source...")
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.1,
- Step: "Installing xwayland-satellite via cargo...",
- IsComplete: false,
- CommandInfo: "cargo install --git https://github.com/Supreeeme/xwayland-satellite --tag v0.7",
- }
-
- installCmd := exec.CommandContext(ctx, "cargo", "install", "--git", "https://github.com/Supreeeme/xwayland-satellite", "--tag", "v0.7")
- if err := m.runWithProgressStep(installCmd, progressChan, PhaseSystemPackages, 0.1, 0.7, "Building xwayland-satellite..."); err != nil {
- return fmt.Errorf("failed to install xwayland-satellite: %w", err)
- }
-
- homeDir := os.Getenv("HOME")
- sourcePath := filepath.Join(homeDir, ".cargo", "bin", "xwayland-satellite")
- targetPath := "/usr/local/bin/xwayland-satellite"
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.7,
- Step: "Installing xwayland-satellite binary to system...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo cp %s %s", sourcePath, targetPath),
- }
-
- copyCmd := exec.CommandContext(ctx, "sudo", "-S", "cp", sourcePath, targetPath)
- copyCmd.Stdin = strings.NewReader(sudoPassword + "\n")
- if err := copyCmd.Run(); err != nil {
- return fmt.Errorf("failed to copy xwayland-satellite to /usr/local/bin: %w", err)
- }
-
- chmodCmd := exec.CommandContext(ctx, "sudo", "-S", "chmod", "+x", targetPath)
- chmodCmd.Stdin = strings.NewReader(sudoPassword + "\n")
- if err := chmodCmd.Run(); err != nil {
- return fmt.Errorf("failed to make xwayland-satellite executable: %w", err)
- }
-
- m.log("xwayland-satellite installed successfully from source")
- return nil
-}
diff --git a/nix/inputs/dms-cli/internal/distros/manual_packages_test.go b/nix/inputs/dms-cli/internal/distros/manual_packages_test.go
deleted file mode 100644
index 4d9fc62..0000000
--- a/nix/inputs/dms-cli/internal/distros/manual_packages_test.go
+++ /dev/null
@@ -1,122 +0,0 @@
-package distros
-
-import (
- "testing"
-)
-
-func TestManualPackageInstaller_parseLatestTagFromGitOutput(t *testing.T) {
- tests := []struct {
- name string
- input string
- expected string
- }{
- {
- name: "normal tag output",
- input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v0.2.1
-a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/v0.2.0
-703a3789083d2f990c4e99cd25c97c2a4cccbd81 refs/tags/v0.1.0`,
- expected: "v0.2.1",
- },
- {
- name: "annotated tags with ^{}",
- input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v0.2.1
-b1b150fab00a93ea983aaca5df55304bc837f51c refs/tags/v0.2.1^{}
-a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/v0.2.0`,
- expected: "v0.2.1",
- },
- {
- name: "mixed tags",
- input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v0.3.0
-b1b150fab00a93ea983aaca5df55304bc837f51c refs/tags/v0.3.0^{}
-a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/v0.2.0
-c1c150fab00a93ea983aaca5df55304bc837f51d refs/tags/beta-1`,
- expected: "v0.3.0",
- },
- {
- name: "empty output",
- input: "",
- expected: "",
- },
- {
- name: "no tags",
- input: "some other output\nwithout tags",
- expected: "",
- },
- {
- name: "only annotated tags",
- input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v0.2.1^{}
-a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/v0.2.0^{}`,
- expected: "",
- },
- {
- name: "single tag",
- input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v1.0.0`,
- expected: "v1.0.0",
- },
- {
- name: "tag with extra whitespace",
- input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v0.2.1
-a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/v0.2.0`,
- expected: "v0.2.1",
- },
- {
- name: "beta and rc tags",
- input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v0.3.0-beta.1
-a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/v0.2.0`,
- expected: "v0.3.0-beta.1",
- },
- {
- name: "tags without v prefix",
- input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/0.2.1
-a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/0.2.0`,
- expected: "0.2.1",
- },
- {
- name: "multiple lines with spaces",
- input: `
-a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v1.2.3
-a5431dd02dc23d9ef1680e67777fed00fe5f7cda refs/tags/v1.2.2
-`,
- expected: "v1.2.3",
- },
- {
- name: "tag at end of line",
- input: `a1a150fab00a93ea983aaca5df55304bc837f51b refs/tags/v0.2.1`,
- expected: "v0.2.1",
- },
- }
-
- logChan := make(chan string, 100)
- defer close(logChan)
-
- base := NewBaseDistribution(logChan)
- installer := &ManualPackageInstaller{BaseDistribution: base}
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := installer.parseLatestTagFromGitOutput(tt.input)
-
- if result != tt.expected {
- t.Errorf("parseLatestTagFromGitOutput() = %q, expected %q", result, tt.expected)
- }
- })
- }
-}
-
-func TestManualPackageInstaller_parseLatestTagFromGitOutput_EmptyInstaller(t *testing.T) {
- // Test that parsing works even with a minimal installer setup
- logChan := make(chan string, 10)
- defer close(logChan)
-
- base := NewBaseDistribution(logChan)
- installer := &ManualPackageInstaller{BaseDistribution: base}
-
- input := `abc123 refs/tags/v1.0.0
-def456 refs/tags/v0.9.0`
-
- result := installer.parseLatestTagFromGitOutput(input)
-
- if result != "v1.0.0" {
- t.Errorf("Expected v1.0.0, got %s", result)
- }
-}
diff --git a/nix/inputs/dms-cli/internal/distros/nixos.go b/nix/inputs/dms-cli/internal/distros/nixos.go
deleted file mode 100644
index 68561a9..0000000
--- a/nix/inputs/dms-cli/internal/distros/nixos.go
+++ /dev/null
@@ -1,458 +0,0 @@
-package distros
-
-import (
- "context"
- "fmt"
- "os/exec"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
-)
-
-func init() {
- Register("nixos", "#7EBAE4", FamilyNix, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewNixOSDistribution(config, logChan)
- })
-}
-
-type NixOSDistribution struct {
- *BaseDistribution
- config DistroConfig
-}
-
-func NewNixOSDistribution(config DistroConfig, logChan chan<- string) *NixOSDistribution {
- base := NewBaseDistribution(logChan)
- return &NixOSDistribution{
- BaseDistribution: base,
- config: config,
- }
-}
-
-func (n *NixOSDistribution) GetID() string {
- return n.config.ID
-}
-
-func (n *NixOSDistribution) GetColorHex() string {
- return n.config.ColorHex
-}
-
-func (n *NixOSDistribution) GetFamily() DistroFamily {
- return n.config.Family
-}
-
-func (n *NixOSDistribution) GetPackageManager() PackageManagerType {
- return PackageManagerNix
-}
-
-func (n *NixOSDistribution) DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error) {
- return n.DetectDependenciesWithTerminal(ctx, wm, deps.TerminalGhostty)
-}
-
-func (n *NixOSDistribution) DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error) {
- var dependencies []deps.Dependency
-
- // DMS at the top (shell is prominent)
- dependencies = append(dependencies, n.detectDMS())
-
- // Terminal with choice support
- dependencies = append(dependencies, n.detectSpecificTerminal(terminal))
-
- // Common detections using base methods
- dependencies = append(dependencies, n.detectGit())
- dependencies = append(dependencies, n.detectWindowManager(wm))
- dependencies = append(dependencies, n.detectQuickshell())
- dependencies = append(dependencies, n.detectXDGPortal())
- dependencies = append(dependencies, n.detectPolkitAgent())
- dependencies = append(dependencies, n.detectAccountsService())
-
- // Hyprland-specific tools
- if wm == deps.WindowManagerHyprland {
- dependencies = append(dependencies, n.detectHyprlandTools()...)
- }
-
- // Niri-specific tools
- if wm == deps.WindowManagerNiri {
- dependencies = append(dependencies, n.detectXwaylandSatellite())
- }
-
- // Base detections (common across distros)
- dependencies = append(dependencies, n.detectMatugen())
- dependencies = append(dependencies, n.detectDgop())
- dependencies = append(dependencies, n.detectHyprpicker())
- dependencies = append(dependencies, n.detectClipboardTools()...)
-
- return dependencies, nil
-}
-
-func (n *NixOSDistribution) detectDMS() deps.Dependency {
- status := deps.StatusMissing
-
- // For NixOS, check if quickshell can find the dms config
- cmd := exec.Command("qs", "-c", "dms", "--list")
- if err := cmd.Run(); err == nil {
- status = deps.StatusInstalled
- } else if n.packageInstalled("DankMaterialShell") {
- // Fallback: check if flake is in profile
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "dms (DankMaterialShell)",
- Status: status,
- Description: "Desktop Management System configuration (installed as flake)",
- Required: true,
- }
-}
-
-func (n *NixOSDistribution) detectXDGPortal() deps.Dependency {
- status := deps.StatusMissing
- if n.packageInstalled("xdg-desktop-portal-gtk") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "xdg-desktop-portal-gtk",
- Status: status,
- Description: "Desktop integration portal for GTK",
- Required: true,
- }
-}
-
-func (n *NixOSDistribution) detectWindowManager(wm deps.WindowManager) deps.Dependency {
- switch wm {
- case deps.WindowManagerHyprland:
- status := deps.StatusMissing
- description := "Dynamic tiling Wayland compositor"
- if n.commandExists("hyprland") || n.commandExists("Hyprland") {
- status = deps.StatusInstalled
- } else {
- description = "Install system-wide: programs.hyprland.enable = true; in configuration.nix"
- }
- return deps.Dependency{
- Name: "hyprland",
- Status: status,
- Description: description,
- Required: true,
- }
- case deps.WindowManagerNiri:
- status := deps.StatusMissing
- description := "Scrollable-tiling Wayland compositor"
- if n.commandExists("niri") {
- status = deps.StatusInstalled
- } else {
- description = "Install system-wide: environment.systemPackages = [ pkgs.niri ]; in configuration.nix"
- }
- return deps.Dependency{
- Name: "niri",
- Status: status,
- Description: description,
- Required: true,
- }
- default:
- return deps.Dependency{
- Name: "unknown-wm",
- Status: deps.StatusMissing,
- Description: "Unknown window manager",
- Required: true,
- }
- }
-}
-
-func (n *NixOSDistribution) detectHyprlandTools() []deps.Dependency {
- var dependencies []deps.Dependency
-
- tools := []struct {
- name string
- description string
- }{
- {"grim", "Screenshot utility for Wayland"},
- {"slurp", "Region selection utility for Wayland"},
- {"hyprctl", "Hyprland control utility (comes with system Hyprland)"},
- {"hyprpicker", "Color picker for Hyprland"},
- {"grimblast", "Screenshot script for Hyprland"},
- {"jq", "JSON processor"},
- }
-
- for _, tool := range tools {
- status := deps.StatusMissing
-
- // Special handling for hyprctl - it comes with system hyprland
- if tool.name == "hyprctl" {
- if n.commandExists("hyprctl") {
- status = deps.StatusInstalled
- }
- } else {
- if n.commandExists(tool.name) {
- status = deps.StatusInstalled
- }
- }
-
- dependencies = append(dependencies, deps.Dependency{
- Name: tool.name,
- Status: status,
- Description: tool.description,
- Required: true,
- })
- }
-
- return dependencies
-}
-
-func (n *NixOSDistribution) detectXwaylandSatellite() deps.Dependency {
- status := deps.StatusMissing
- if n.commandExists("xwayland-satellite") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "xwayland-satellite",
- Status: status,
- Description: "Xwayland support",
- Required: true,
- }
-}
-
-func (n *NixOSDistribution) detectPolkitAgent() deps.Dependency {
- status := deps.StatusMissing
- if n.packageInstalled("mate-polkit") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "mate-polkit",
- Status: status,
- Description: "PolicyKit authentication agent",
- Required: true,
- }
-}
-
-func (n *NixOSDistribution) detectAccountsService() deps.Dependency {
- status := deps.StatusMissing
- if n.packageInstalled("accountsservice") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "accountsservice",
- Status: status,
- Description: "D-Bus interface for user account query and manipulation",
- Required: true,
- }
-}
-
-func (n *NixOSDistribution) packageInstalled(pkg string) bool {
- cmd := exec.Command("nix", "profile", "list")
- output, err := cmd.Output()
- if err != nil {
- return false
- }
- return strings.Contains(string(output), pkg)
-}
-
-func (n *NixOSDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping {
- packages := map[string]PackageMapping{
- "git": {Name: "nixpkgs#git", Repository: RepoTypeSystem},
- "quickshell": {Name: "github:quickshell-mirror/quickshell", Repository: RepoTypeFlake},
- "matugen": {Name: "github:InioX/matugen", Repository: RepoTypeFlake},
- "dgop": {Name: "github:AvengeMedia/dgop", Repository: RepoTypeFlake},
- "dms (DankMaterialShell)": {Name: "github:AvengeMedia/DankMaterialShell", Repository: RepoTypeFlake},
- "ghostty": {Name: "nixpkgs#ghostty", Repository: RepoTypeSystem},
- "alacritty": {Name: "nixpkgs#alacritty", Repository: RepoTypeSystem},
- "cliphist": {Name: "nixpkgs#cliphist", Repository: RepoTypeSystem},
- "wl-clipboard": {Name: "nixpkgs#wl-clipboard", Repository: RepoTypeSystem},
- "xdg-desktop-portal-gtk": {Name: "nixpkgs#xdg-desktop-portal-gtk", Repository: RepoTypeSystem},
- "mate-polkit": {Name: "nixpkgs#mate.mate-polkit", Repository: RepoTypeSystem},
- "accountsservice": {Name: "nixpkgs#accountsservice", Repository: RepoTypeSystem},
- "hyprpicker": {Name: "nixpkgs#hyprpicker", Repository: RepoTypeSystem},
- }
-
- // Note: Window managers (hyprland/niri) should be installed system-wide on NixOS
- // We only install the tools here
- switch wm {
- case deps.WindowManagerHyprland:
- // Skip hyprland itself - should be installed system-wide
- packages["grim"] = PackageMapping{Name: "nixpkgs#grim", Repository: RepoTypeSystem}
- packages["slurp"] = PackageMapping{Name: "nixpkgs#slurp", Repository: RepoTypeSystem}
- packages["grimblast"] = PackageMapping{Name: "github:hyprwm/contrib#grimblast", Repository: RepoTypeFlake}
- packages["jq"] = PackageMapping{Name: "nixpkgs#jq", Repository: RepoTypeSystem}
- case deps.WindowManagerNiri:
- // Skip niri itself - should be installed system-wide
- packages["xwayland-satellite"] = PackageMapping{Name: "nixpkgs#xwayland-satellite", Repository: RepoTypeFlake}
- }
-
- return packages
-}
-
-func (n *NixOSDistribution) InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.10,
- Step: "NixOS prerequisites ready",
- IsComplete: false,
- LogOutput: "NixOS package manager is ready to use",
- }
- return nil
-}
-
-func (n *NixOSDistribution) InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, progressChan chan<- InstallProgressMsg) error {
- // Phase 1: Check Prerequisites
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.05,
- Step: "Checking system prerequisites...",
- IsComplete: false,
- LogOutput: "Starting prerequisite check...",
- }
-
- if err := n.InstallPrerequisites(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install prerequisites: %w", err)
- }
-
- nixpkgsPkgs, flakePkgs := n.categorizePackages(dependencies, wm, reinstallFlags)
-
- // Phase 2: Nixpkgs Packages
- if len(nixpkgsPkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.35,
- Step: fmt.Sprintf("Installing %d packages from nixpkgs...", len(nixpkgsPkgs)),
- IsComplete: false,
- LogOutput: fmt.Sprintf("Installing nixpkgs packages: %s", strings.Join(nixpkgsPkgs, ", ")),
- }
- if err := n.installNixpkgsPackages(ctx, nixpkgsPkgs, progressChan); err != nil {
- return fmt.Errorf("failed to install nixpkgs packages: %w", err)
- }
- }
-
- // Phase 3: Flake Packages
- if len(flakePkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: 0.65,
- Step: fmt.Sprintf("Installing %d packages from flakes...", len(flakePkgs)),
- IsComplete: false,
- LogOutput: fmt.Sprintf("Installing flake packages: %s", strings.Join(flakePkgs, ", ")),
- }
- if err := n.installFlakePackages(ctx, flakePkgs, progressChan); err != nil {
- return fmt.Errorf("failed to install flake packages: %w", err)
- }
- }
-
- // Phase 4: Configuration
- progressChan <- InstallProgressMsg{
- Phase: PhaseConfiguration,
- Progress: 0.90,
- Step: "Configuring system...",
- IsComplete: false,
- LogOutput: "Starting post-installation configuration...",
- }
- if err := n.postInstallConfig(progressChan); err != nil {
- return fmt.Errorf("failed to configure system: %w", err)
- }
-
- // Phase 5: Complete
- progressChan <- InstallProgressMsg{
- Phase: PhaseComplete,
- Progress: 1.0,
- Step: "Installation complete!",
- IsComplete: true,
- LogOutput: "All packages installed and configured successfully",
- }
-
- return nil
-}
-
-func (n *NixOSDistribution) categorizePackages(dependencies []deps.Dependency, wm deps.WindowManager, reinstallFlags map[string]bool) ([]string, []string) {
- nixpkgsPkgs := []string{}
- flakePkgs := []string{}
-
- packageMap := n.GetPackageMapping(wm)
-
- for _, dep := range dependencies {
- // Skip installed packages unless marked for reinstall
- if dep.Status == deps.StatusInstalled && !reinstallFlags[dep.Name] {
- continue
- }
-
- pkgInfo, exists := packageMap[dep.Name]
- if !exists {
- n.log(fmt.Sprintf("Warning: No package mapping found for %s", dep.Name))
- continue
- }
-
- switch pkgInfo.Repository {
- case RepoTypeSystem:
- nixpkgsPkgs = append(nixpkgsPkgs, pkgInfo.Name)
- case RepoTypeFlake:
- flakePkgs = append(flakePkgs, pkgInfo.Name)
- }
- }
-
- return nixpkgsPkgs, flakePkgs
-}
-
-func (n *NixOSDistribution) installNixpkgsPackages(ctx context.Context, packages []string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- n.log(fmt.Sprintf("Installing nixpkgs packages: %s", strings.Join(packages, ", ")))
-
- args := []string{"profile", "install"}
- args = append(args, packages...)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.40,
- Step: "Installing nixpkgs packages...",
- IsComplete: false,
- CommandInfo: fmt.Sprintf("nix %s", strings.Join(args, " ")),
- }
-
- cmd := exec.CommandContext(ctx, "nix", args...)
- return n.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.40, 0.60)
-}
-
-func (n *NixOSDistribution) installFlakePackages(ctx context.Context, packages []string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- n.log(fmt.Sprintf("Installing flake packages: %s", strings.Join(packages, ", ")))
-
- baseProgress := 0.65
- progressStep := 0.20 / float64(len(packages))
-
- for i, pkg := range packages {
- currentProgress := baseProgress + (float64(i) * progressStep)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: currentProgress,
- Step: fmt.Sprintf("Installing flake package %s (%d/%d)...", pkg, i+1, len(packages)),
- IsComplete: false,
- CommandInfo: fmt.Sprintf("nix profile install %s", pkg),
- }
-
- cmd := exec.CommandContext(ctx, "nix", "profile", "install", pkg)
- if err := n.runWithProgress(cmd, progressChan, PhaseAURPackages, currentProgress, currentProgress+progressStep); err != nil {
- return fmt.Errorf("failed to install flake package %s: %w", pkg, err)
- }
- }
-
- return nil
-}
-
-func (n *NixOSDistribution) postInstallConfig(progressChan chan<- InstallProgressMsg) error {
- // For NixOS, DMS is installed as a flake package, so we skip both the binary installation and git clone
- // The flake installation handles both the binary and config files correctly
- progressChan <- InstallProgressMsg{
- Phase: PhaseConfiguration,
- Progress: 0.95,
- Step: "NixOS configuration complete",
- IsComplete: false,
- LogOutput: "DMS installed via flake - binary and config handled by Nix",
- }
-
- return nil
-}
diff --git a/nix/inputs/dms-cli/internal/distros/opensuse.go b/nix/inputs/dms-cli/internal/distros/opensuse.go
deleted file mode 100644
index 70c91a5..0000000
--- a/nix/inputs/dms-cli/internal/distros/opensuse.go
+++ /dev/null
@@ -1,608 +0,0 @@
-package distros
-
-import (
- "context"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
-)
-
-func init() {
- Register("opensuse-tumbleweed", "#73BA25", FamilySUSE, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewOpenSUSEDistribution(config, logChan)
- })
-}
-
-type OpenSUSEDistribution struct {
- *BaseDistribution
- *ManualPackageInstaller
- config DistroConfig
-}
-
-func NewOpenSUSEDistribution(config DistroConfig, logChan chan<- string) *OpenSUSEDistribution {
- base := NewBaseDistribution(logChan)
- return &OpenSUSEDistribution{
- BaseDistribution: base,
- ManualPackageInstaller: &ManualPackageInstaller{BaseDistribution: base},
- config: config,
- }
-}
-
-func (o *OpenSUSEDistribution) GetID() string {
- return o.config.ID
-}
-
-func (o *OpenSUSEDistribution) GetColorHex() string {
- return o.config.ColorHex
-}
-
-func (o *OpenSUSEDistribution) GetFamily() DistroFamily {
- return o.config.Family
-}
-
-func (o *OpenSUSEDistribution) GetPackageManager() PackageManagerType {
- return PackageManagerZypper
-}
-
-func (o *OpenSUSEDistribution) DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error) {
- return o.DetectDependenciesWithTerminal(ctx, wm, deps.TerminalGhostty)
-}
-
-func (o *OpenSUSEDistribution) DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error) {
- var dependencies []deps.Dependency
-
- // DMS at the top (shell is prominent)
- dependencies = append(dependencies, o.detectDMS())
-
- // Terminal with choice support
- dependencies = append(dependencies, o.detectSpecificTerminal(terminal))
-
- // Common detections using base methods
- dependencies = append(dependencies, o.detectGit())
- dependencies = append(dependencies, o.detectWindowManager(wm))
- dependencies = append(dependencies, o.detectQuickshell())
- dependencies = append(dependencies, o.detectXDGPortal())
- dependencies = append(dependencies, o.detectPolkitAgent())
- dependencies = append(dependencies, o.detectAccountsService())
-
- // Hyprland-specific tools
- if wm == deps.WindowManagerHyprland {
- dependencies = append(dependencies, o.detectHyprlandTools()...)
- }
-
- // Niri-specific tools
- if wm == deps.WindowManagerNiri {
- dependencies = append(dependencies, o.detectXwaylandSatellite())
- }
-
- // Base detections (common across distros)
- dependencies = append(dependencies, o.detectMatugen())
- dependencies = append(dependencies, o.detectDgop())
- dependencies = append(dependencies, o.detectHyprpicker())
- dependencies = append(dependencies, o.detectClipboardTools()...)
-
- return dependencies, nil
-}
-
-func (o *OpenSUSEDistribution) detectXDGPortal() deps.Dependency {
- status := deps.StatusMissing
- if o.packageInstalled("xdg-desktop-portal-gtk") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "xdg-desktop-portal-gtk",
- Status: status,
- Description: "Desktop integration portal for GTK",
- Required: true,
- }
-}
-
-func (o *OpenSUSEDistribution) detectPolkitAgent() deps.Dependency {
- status := deps.StatusMissing
- if o.packageInstalled("mate-polkit") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "mate-polkit",
- Status: status,
- Description: "PolicyKit authentication agent",
- Required: true,
- }
-}
-
-func (o *OpenSUSEDistribution) packageInstalled(pkg string) bool {
- cmd := exec.Command("rpm", "-q", pkg)
- err := cmd.Run()
- return err == nil
-}
-
-func (o *OpenSUSEDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping {
- return o.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant))
-}
-
-func (o *OpenSUSEDistribution) GetPackageMappingWithVariants(wm deps.WindowManager, variants map[string]deps.PackageVariant) map[string]PackageMapping {
- packages := map[string]PackageMapping{
- // Standard zypper packages
- "git": {Name: "git", Repository: RepoTypeSystem},
- "ghostty": {Name: "ghostty", Repository: RepoTypeSystem},
- "kitty": {Name: "kitty", Repository: RepoTypeSystem},
- "alacritty": {Name: "alacritty", Repository: RepoTypeSystem},
- "wl-clipboard": {Name: "wl-clipboard", Repository: RepoTypeSystem},
- "xdg-desktop-portal-gtk": {Name: "xdg-desktop-portal-gtk", Repository: RepoTypeSystem},
- "mate-polkit": {Name: "mate-polkit", Repository: RepoTypeSystem},
- "accountsservice": {Name: "accountsservice", Repository: RepoTypeSystem},
- "cliphist": {Name: "cliphist", Repository: RepoTypeSystem},
- "hyprpicker": {Name: "hyprpicker", Repository: RepoTypeSystem},
-
- // Manual builds
- "dms (DankMaterialShell)": {Name: "dms", Repository: RepoTypeManual, BuildFunc: "installDankMaterialShell"},
- "dgop": {Name: "dgop", Repository: RepoTypeManual, BuildFunc: "installDgop"},
- "quickshell": {Name: "quickshell", Repository: RepoTypeManual, BuildFunc: "installQuickshell"},
- "matugen": {Name: "matugen", Repository: RepoTypeManual, BuildFunc: "installMatugen"},
- }
-
- switch wm {
- case deps.WindowManagerHyprland:
- packages["hyprland"] = PackageMapping{Name: "hyprland", Repository: RepoTypeSystem}
- packages["grim"] = PackageMapping{Name: "grim", Repository: RepoTypeSystem}
- packages["slurp"] = PackageMapping{Name: "slurp", Repository: RepoTypeSystem}
- packages["hyprctl"] = PackageMapping{Name: "hyprland", Repository: RepoTypeSystem}
- packages["grimblast"] = PackageMapping{Name: "grimblast", Repository: RepoTypeManual, BuildFunc: "installGrimblast"}
- packages["jq"] = PackageMapping{Name: "jq", Repository: RepoTypeSystem}
- case deps.WindowManagerNiri:
- packages["niri"] = PackageMapping{Name: "niri", Repository: RepoTypeSystem}
- packages["xwayland-satellite"] = PackageMapping{Name: "xwayland-satellite", Repository: RepoTypeSystem}
- }
-
- return packages
-}
-
-func (o *OpenSUSEDistribution) detectXwaylandSatellite() deps.Dependency {
- status := deps.StatusMissing
- if o.commandExists("xwayland-satellite") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "xwayland-satellite",
- Status: status,
- Description: "Xwayland support",
- Required: true,
- }
-}
-
-func (o *OpenSUSEDistribution) detectAccountsService() deps.Dependency {
- status := deps.StatusMissing
- if o.packageInstalled("accountsservice") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "accountsservice",
- Status: status,
- Description: "D-Bus interface for user account query and manipulation",
- Required: true,
- }
-}
-
-func (o *OpenSUSEDistribution) getPrerequisites() []string {
- return []string{
- "make",
- "unzip",
- "gcc",
- "gcc-c++",
- "cmake",
- "ninja",
- "pkgconf-pkg-config",
- "git",
- "qt6-base-devel",
- "qt6-declarative-devel",
- "qt6-declarative-private-devel",
- "qt6-shadertools",
- "qt6-shadertools-devel",
- "qt6-wayland-devel",
- "qt6-waylandclient-private-devel",
- "spirv-tools-devel",
- "cli11-devel",
- "wayland-protocols-devel",
- "libgbm-devel",
- "libdrm-devel",
- "pipewire-devel",
- "jemalloc-devel",
- "wayland-utils",
- "Mesa-libGLESv3-devel",
- "pam-devel",
- "glib2-devel",
- "polkit-devel",
- }
-}
-
-func (o *OpenSUSEDistribution) InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- prerequisites := o.getPrerequisites()
- var missingPkgs []string
-
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.06,
- Step: "Checking prerequisites...",
- IsComplete: false,
- LogOutput: "Checking prerequisite packages",
- }
-
- for _, pkg := range prerequisites {
- checkCmd := exec.CommandContext(ctx, "rpm", "-q", pkg)
- if err := checkCmd.Run(); err != nil {
- missingPkgs = append(missingPkgs, pkg)
- }
- }
-
- _, err := exec.LookPath("go")
- if err != nil {
- o.log("go not found in PATH, will install go")
- missingPkgs = append(missingPkgs, "go")
- } else {
- o.log("go already available in PATH")
- }
-
- if len(missingPkgs) == 0 {
- o.log("All prerequisites already installed")
- return nil
- }
-
- o.log(fmt.Sprintf("Installing prerequisites: %s", strings.Join(missingPkgs, ", ")))
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.08,
- Step: fmt.Sprintf("Installing %d prerequisites...", len(missingPkgs)),
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo zypper install -y %s", strings.Join(missingPkgs, " ")),
- LogOutput: fmt.Sprintf("Installing prerequisites: %s", strings.Join(missingPkgs, ", ")),
- }
-
- args := []string{"zypper", "install", "-y"}
- args = append(args, missingPkgs...)
- cmdStr := fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, strings.Join(args, " "))
- cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
- output, err := cmd.CombinedOutput()
- if err != nil {
- o.logError("failed to install prerequisites", err)
- o.log(fmt.Sprintf("Prerequisites command output: %s", string(output)))
- return fmt.Errorf("failed to install prerequisites: %w", err)
- }
- o.log(fmt.Sprintf("Prerequisites install output: %s", string(output)))
-
- return nil
-}
-
-func (o *OpenSUSEDistribution) InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, progressChan chan<- InstallProgressMsg) error {
- // Phase 1: Check Prerequisites
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.05,
- Step: "Checking system prerequisites...",
- IsComplete: false,
- LogOutput: "Starting prerequisite check...",
- }
-
- if err := o.InstallPrerequisites(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install prerequisites: %w", err)
- }
-
- systemPkgs, manualPkgs := o.categorizePackages(dependencies, wm, reinstallFlags)
-
- // Phase 2: System Packages (Zypper)
- if len(systemPkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.35,
- Step: fmt.Sprintf("Installing %d system packages...", len(systemPkgs)),
- IsComplete: false,
- NeedsSudo: true,
- LogOutput: fmt.Sprintf("Installing system packages: %s", strings.Join(systemPkgs, ", ")),
- }
- if err := o.installZypperPackages(ctx, systemPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install zypper packages: %w", err)
- }
- }
-
- // Phase 3: Manual Builds
- if len(manualPkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.85,
- Step: fmt.Sprintf("Building %d packages from source...", len(manualPkgs)),
- IsComplete: false,
- LogOutput: fmt.Sprintf("Building from source: %s", strings.Join(manualPkgs, ", ")),
- }
- if err := o.InstallManualPackages(ctx, manualPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install manual packages: %w", err)
- }
- }
-
- // Phase 4: Configuration
- progressChan <- InstallProgressMsg{
- Phase: PhaseConfiguration,
- Progress: 0.90,
- Step: "Configuring system...",
- IsComplete: false,
- LogOutput: "Starting post-installation configuration...",
- }
-
- // Phase 5: Complete
- progressChan <- InstallProgressMsg{
- Phase: PhaseComplete,
- Progress: 1.0,
- Step: "Installation complete!",
- IsComplete: true,
- LogOutput: "All packages installed and configured successfully",
- }
-
- return nil
-}
-
-func (o *OpenSUSEDistribution) categorizePackages(dependencies []deps.Dependency, wm deps.WindowManager, reinstallFlags map[string]bool) ([]string, []string) {
- systemPkgs := []string{}
- manualPkgs := []string{}
-
- variantMap := make(map[string]deps.PackageVariant)
- for _, dep := range dependencies {
- variantMap[dep.Name] = dep.Variant
- }
-
- packageMap := o.GetPackageMappingWithVariants(wm, variantMap)
-
- for _, dep := range dependencies {
- // Skip installed packages unless marked for reinstall
- if dep.Status == deps.StatusInstalled && !reinstallFlags[dep.Name] {
- continue
- }
-
- pkgInfo, exists := packageMap[dep.Name]
- if !exists {
- o.log(fmt.Sprintf("Warning: No package mapping for %s", dep.Name))
- continue
- }
-
- switch pkgInfo.Repository {
- case RepoTypeSystem:
- systemPkgs = append(systemPkgs, pkgInfo.Name)
- case RepoTypeManual:
- manualPkgs = append(manualPkgs, dep.Name)
- }
- }
-
- return systemPkgs, manualPkgs
-}
-
-func (o *OpenSUSEDistribution) installZypperPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- o.log(fmt.Sprintf("Installing zypper packages: %s", strings.Join(packages, ", ")))
-
- args := []string{"zypper", "install", "-y"}
- args = append(args, packages...)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.40,
- Step: "Installing system packages...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")),
- }
-
- cmdStr := fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, strings.Join(args, " "))
- cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
- return o.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.40, 0.60)
-}
-
-// installQuickshell overrides the base implementation to set openSUSE-specific CFLAGS
-func (o *OpenSUSEDistribution) installQuickshell(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- o.log("Installing quickshell from source (with openSUSE-specific build flags)...")
-
- homeDir := os.Getenv("HOME")
- if homeDir == "" {
- return fmt.Errorf("HOME environment variable not set")
- }
-
- cacheDir := filepath.Join(homeDir, ".cache", "dankinstall")
- if err := os.MkdirAll(cacheDir, 0755); err != nil {
- return fmt.Errorf("failed to create cache directory: %w", err)
- }
-
- tmpDir := filepath.Join(cacheDir, "quickshell-build")
- if err := os.MkdirAll(tmpDir, 0755); err != nil {
- return fmt.Errorf("failed to create temp directory: %w", err)
- }
- defer os.RemoveAll(tmpDir)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.1,
- Step: "Cloning quickshell repository...",
- IsComplete: false,
- CommandInfo: "git clone https://github.com/quickshell-mirror/quickshell.git",
- }
-
- var cloneCmd *exec.Cmd
- if forceQuickshellGit {
- cloneCmd = exec.CommandContext(ctx, "git", "clone", "https://github.com/quickshell-mirror/quickshell.git", tmpDir)
- } else {
- // Get latest tag from repository
- latestTag := o.getLatestQuickshellTag(ctx)
- if latestTag != "" {
- o.log(fmt.Sprintf("Using latest quickshell tag: %s", latestTag))
- cloneCmd = exec.CommandContext(ctx, "git", "clone", "--branch", latestTag, "https://github.com/quickshell-mirror/quickshell.git", tmpDir)
- } else {
- o.log("Warning: failed to fetch latest tag, using default branch")
- cloneCmd = exec.CommandContext(ctx, "git", "clone", "https://github.com/quickshell-mirror/quickshell.git", tmpDir)
- }
- }
- if err := cloneCmd.Run(); err != nil {
- return fmt.Errorf("failed to clone quickshell: %w", err)
- }
-
- buildDir := tmpDir + "/build"
- if err := os.MkdirAll(buildDir, 0755); err != nil {
- return fmt.Errorf("failed to create build directory: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.3,
- Step: "Configuring quickshell build (with openSUSE flags)...",
- IsComplete: false,
- CommandInfo: "cmake -B build -S . -G Ninja",
- }
-
- // Get optflags from rpm
- optflagsCmd := exec.CommandContext(ctx, "rpm", "--eval", "%{optflags}")
- optflagsOutput, err := optflagsCmd.Output()
- optflags := strings.TrimSpace(string(optflagsOutput))
- if err != nil || optflags == "" {
- o.log("Warning: Could not get optflags from rpm, using default -O2 -g")
- optflags = "-O2 -g"
- }
-
- // Set openSUSE-specific CFLAGS
- customCFLAGS := fmt.Sprintf("%s -I/usr/include/wayland", optflags)
-
- configureCmd := exec.CommandContext(ctx, "cmake", "-GNinja", "-B", "build",
- "-DCMAKE_BUILD_TYPE=RelWithDebInfo",
- "-DCRASH_REPORTER=off",
- "-DCMAKE_CXX_STANDARD=20")
- configureCmd.Dir = tmpDir
- configureCmd.Env = append(os.Environ(),
- "TMPDIR="+cacheDir,
- "CFLAGS="+customCFLAGS,
- "CXXFLAGS="+customCFLAGS)
-
- o.log(fmt.Sprintf("Using CFLAGS: %s", customCFLAGS))
-
- output, err := configureCmd.CombinedOutput()
- if err != nil {
- o.log(fmt.Sprintf("cmake configure failed. Output:\n%s", string(output)))
- return fmt.Errorf("failed to configure quickshell: %w\nCMake output:\n%s", err, string(output))
- }
-
- o.log(fmt.Sprintf("cmake configure successful. Output:\n%s", string(output)))
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.4,
- Step: "Building quickshell (this may take a while)...",
- IsComplete: false,
- CommandInfo: "cmake --build build",
- }
-
- buildCmd := exec.CommandContext(ctx, "cmake", "--build", "build")
- buildCmd.Dir = tmpDir
- buildCmd.Env = append(os.Environ(),
- "TMPDIR="+cacheDir,
- "CFLAGS="+customCFLAGS,
- "CXXFLAGS="+customCFLAGS)
- if err := o.runWithProgressStep(buildCmd, progressChan, PhaseSystemPackages, 0.4, 0.8, "Building quickshell..."); err != nil {
- return fmt.Errorf("failed to build quickshell: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.8,
- Step: "Installing quickshell...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo cmake --install build",
- }
-
- installCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("cd %s && echo '%s' | sudo -S cmake --install build", tmpDir, sudoPassword))
- if err := installCmd.Run(); err != nil {
- return fmt.Errorf("failed to install quickshell: %w", err)
- }
-
- o.log("quickshell installed successfully from source")
- return nil
-}
-
-func (o *OpenSUSEDistribution) installRust(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if o.commandExists("cargo") {
- return nil
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.82,
- Step: "Installing rustup...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo zypper install rustup",
- }
-
- rustupInstallCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S zypper install -y rustup", sudoPassword))
- if err := o.runWithProgress(rustupInstallCmd, progressChan, PhaseSystemPackages, 0.82, 0.83); err != nil {
- return fmt.Errorf("failed to install rustup: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.83,
- Step: "Installing stable Rust toolchain...",
- IsComplete: false,
- CommandInfo: "rustup install stable",
- }
-
- rustInstallCmd := exec.CommandContext(ctx, "bash", "-c", "rustup install stable && rustup default stable")
- if err := o.runWithProgress(rustInstallCmd, progressChan, PhaseSystemPackages, 0.83, 0.84); err != nil {
- return fmt.Errorf("failed to install Rust toolchain: %w", err)
- }
-
- if !o.commandExists("cargo") {
- o.log("Warning: cargo not found in PATH after Rust installation, trying to source environment")
- }
-
- return nil
-}
-
-// InstallManualPackages overrides the base implementation to use openSUSE-specific builds
-func (o *OpenSUSEDistribution) InstallManualPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- o.log(fmt.Sprintf("Installing manual packages: %s", strings.Join(packages, ", ")))
-
- // Install Rust if needed for matugen
- for _, pkg := range packages {
- if pkg == "matugen" {
- if err := o.installRust(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install Rust: %w", err)
- }
- break
- }
- }
-
- for _, pkg := range packages {
- if pkg == "quickshell" {
- if err := o.installQuickshell(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install quickshell: %w", err)
- }
- } else {
- // Use the base ManualPackageInstaller for other packages
- if err := o.ManualPackageInstaller.InstallManualPackages(ctx, []string{pkg}, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install %s: %w", pkg, err)
- }
- }
- }
-
- return nil
-}
diff --git a/nix/inputs/dms-cli/internal/distros/osinfo.go b/nix/inputs/dms-cli/internal/distros/osinfo.go
deleted file mode 100644
index 7b86ec9..0000000
--- a/nix/inputs/dms-cli/internal/distros/osinfo.go
+++ /dev/null
@@ -1,115 +0,0 @@
-package distros
-
-import (
- "bufio"
- "fmt"
- "os"
- "runtime"
- "strconv"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/errdefs"
-)
-
-// DistroInfo contains basic information about a distribution
-type DistroInfo struct {
- ID string
- HexColorCode string
-}
-
-// OSInfo contains complete OS information
-type OSInfo struct {
- Distribution DistroInfo
- Version string
- VersionID string
- PrettyName string
- Architecture string
-}
-
-// GetOSInfo detects the current OS and returns information about it
-func GetOSInfo() (*OSInfo, error) {
- if runtime.GOOS != "linux" {
- return nil, errdefs.NewCustomError(errdefs.ErrTypeNotLinux, fmt.Sprintf("Only linux is supported, but I found %s", runtime.GOOS))
- }
-
- if runtime.GOARCH != "amd64" && runtime.GOARCH != "arm64" {
- return nil, errdefs.NewCustomError(errdefs.ErrTypeInvalidArchitecture, fmt.Sprintf("Only amd64 and arm64 are supported, but I found %s", runtime.GOARCH))
- }
-
- info := &OSInfo{
- Architecture: runtime.GOARCH,
- }
-
- file, err := os.Open("/etc/os-release")
- if err != nil {
- return nil, err
- }
- defer file.Close()
-
- scanner := bufio.NewScanner(file)
- for scanner.Scan() {
- line := scanner.Text()
- parts := strings.SplitN(line, "=", 2)
- if len(parts) != 2 {
- continue
- }
-
- key := parts[0]
- value := strings.Trim(parts[1], "\"")
-
- switch key {
- case "ID":
- config, exists := Registry[value]
- if !exists {
- return nil, errdefs.NewCustomError(errdefs.ErrTypeUnsupportedDistribution, fmt.Sprintf("Unsupported distribution: %s", value))
- }
-
- info.Distribution = DistroInfo{
- ID: value, // Use the actual ID from os-release
- HexColorCode: config.ColorHex,
- }
- case "VERSION_ID", "BUILD_ID":
- info.VersionID = value
- case "VERSION":
- info.Version = value
- case "PRETTY_NAME":
- info.PrettyName = value
- }
- }
-
- return info, scanner.Err()
-}
-
-// IsUnsupportedDistro checks if a distribution/version combination is supported
-func IsUnsupportedDistro(distroID, versionID string) bool {
- if !IsDistroSupported(distroID) {
- return true
- }
-
- if distroID == "ubuntu" {
- parts := strings.Split(versionID, ".")
- if len(parts) >= 2 {
- major, err1 := strconv.Atoi(parts[0])
- minor, err2 := strconv.Atoi(parts[1])
-
- if err1 == nil && err2 == nil {
- return major < 25 || (major == 25 && minor < 4)
- }
- }
- return true
- }
-
- if distroID == "debian" {
- if versionID == "" {
- // debian testing/sid have no version ID
- return false
- }
- versionNum, err := strconv.Atoi(versionID)
- if err == nil {
- return versionNum < 12
- }
- return true
- }
-
- return false
-}
diff --git a/nix/inputs/dms-cli/internal/distros/ubuntu.go b/nix/inputs/dms-cli/internal/distros/ubuntu.go
deleted file mode 100644
index 31cbd42..0000000
--- a/nix/inputs/dms-cli/internal/distros/ubuntu.go
+++ /dev/null
@@ -1,758 +0,0 @@
-package distros
-
-import (
- "context"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
-)
-
-func init() {
- Register("ubuntu", "#E95420", FamilyUbuntu, func(config DistroConfig, logChan chan<- string) Distribution {
- return NewUbuntuDistribution(config, logChan)
- })
-}
-
-type UbuntuDistribution struct {
- *BaseDistribution
- *ManualPackageInstaller
- config DistroConfig
-}
-
-func NewUbuntuDistribution(config DistroConfig, logChan chan<- string) *UbuntuDistribution {
- base := NewBaseDistribution(logChan)
- return &UbuntuDistribution{
- BaseDistribution: base,
- ManualPackageInstaller: &ManualPackageInstaller{BaseDistribution: base},
- config: config,
- }
-}
-
-func (u *UbuntuDistribution) GetID() string {
- return u.config.ID
-}
-
-func (u *UbuntuDistribution) GetColorHex() string {
- return u.config.ColorHex
-}
-
-func (u *UbuntuDistribution) GetFamily() DistroFamily {
- return u.config.Family
-}
-
-func (u *UbuntuDistribution) GetPackageManager() PackageManagerType {
- return PackageManagerAPT
-}
-
-func (u *UbuntuDistribution) DetectDependencies(ctx context.Context, wm deps.WindowManager) ([]deps.Dependency, error) {
- return u.DetectDependenciesWithTerminal(ctx, wm, deps.TerminalGhostty)
-}
-
-func (u *UbuntuDistribution) DetectDependenciesWithTerminal(ctx context.Context, wm deps.WindowManager, terminal deps.Terminal) ([]deps.Dependency, error) {
- var dependencies []deps.Dependency
-
- // DMS at the top (shell is prominent)
- dependencies = append(dependencies, u.detectDMS())
-
- // Terminal with choice support
- dependencies = append(dependencies, u.detectSpecificTerminal(terminal))
-
- // Common detections using base methods
- dependencies = append(dependencies, u.detectGit())
- dependencies = append(dependencies, u.detectWindowManager(wm))
- dependencies = append(dependencies, u.detectQuickshell())
- dependencies = append(dependencies, u.detectXDGPortal())
- dependencies = append(dependencies, u.detectPolkitAgent())
- dependencies = append(dependencies, u.detectAccountsService())
-
- // Hyprland-specific tools
- if wm == deps.WindowManagerHyprland {
- dependencies = append(dependencies, u.detectHyprlandTools()...)
- }
-
- // Niri-specific tools
- if wm == deps.WindowManagerNiri {
- dependencies = append(dependencies, u.detectXwaylandSatellite())
- }
-
- // Base detections (common across distros)
- dependencies = append(dependencies, u.detectMatugen())
- dependencies = append(dependencies, u.detectDgop())
- dependencies = append(dependencies, u.detectHyprpicker())
- dependencies = append(dependencies, u.detectClipboardTools()...)
-
- return dependencies, nil
-}
-
-func (u *UbuntuDistribution) detectXDGPortal() deps.Dependency {
- status := deps.StatusMissing
- if u.packageInstalled("xdg-desktop-portal-gtk") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "xdg-desktop-portal-gtk",
- Status: status,
- Description: "Desktop integration portal for GTK",
- Required: true,
- }
-}
-
-func (u *UbuntuDistribution) detectPolkitAgent() deps.Dependency {
- status := deps.StatusMissing
- if u.packageInstalled("mate-polkit") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "mate-polkit",
- Status: status,
- Description: "PolicyKit authentication agent",
- Required: true,
- }
-}
-
-func (u *UbuntuDistribution) detectXwaylandSatellite() deps.Dependency {
- status := deps.StatusMissing
- if u.commandExists("xwayland-satellite") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "xwayland-satellite",
- Status: status,
- Description: "Xwayland support",
- Required: true,
- }
-}
-
-func (u *UbuntuDistribution) detectAccountsService() deps.Dependency {
- status := deps.StatusMissing
- if u.packageInstalled("accountsservice") {
- status = deps.StatusInstalled
- }
-
- return deps.Dependency{
- Name: "accountsservice",
- Status: status,
- Description: "D-Bus interface for user account query and manipulation",
- Required: true,
- }
-}
-
-func (u *UbuntuDistribution) packageInstalled(pkg string) bool {
- cmd := exec.Command("dpkg", "-l", pkg)
- err := cmd.Run()
- return err == nil
-}
-
-func (u *UbuntuDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping {
- packages := map[string]PackageMapping{
- // Standard APT packages
- "git": {Name: "git", Repository: RepoTypeSystem},
- "kitty": {Name: "kitty", Repository: RepoTypeSystem},
- "alacritty": {Name: "alacritty", Repository: RepoTypeSystem},
- "wl-clipboard": {Name: "wl-clipboard", Repository: RepoTypeSystem},
- "xdg-desktop-portal-gtk": {Name: "xdg-desktop-portal-gtk", Repository: RepoTypeSystem},
- "mate-polkit": {Name: "mate-polkit", Repository: RepoTypeSystem},
- "accountsservice": {Name: "accountsservice", Repository: RepoTypeSystem},
- "hyprpicker": {Name: "hyprpicker", Repository: RepoTypePPA, RepoURL: "ppa:cppiber/hyprland"},
-
- // Manual builds (niri and quickshell likely not available in Ubuntu repos or PPAs)
- "dms (DankMaterialShell)": {Name: "dms", Repository: RepoTypeManual, BuildFunc: "installDankMaterialShell"},
- "niri": {Name: "niri", Repository: RepoTypeManual, BuildFunc: "installNiri"},
- "quickshell": {Name: "quickshell", Repository: RepoTypeManual, BuildFunc: "installQuickshell"},
- "ghostty": {Name: "ghostty", Repository: RepoTypeManual, BuildFunc: "installGhostty"},
- "matugen": {Name: "matugen", Repository: RepoTypeManual, BuildFunc: "installMatugen"},
- "dgop": {Name: "dgop", Repository: RepoTypeManual, BuildFunc: "installDgop"},
- "cliphist": {Name: "cliphist", Repository: RepoTypeManual, BuildFunc: "installCliphist"},
- }
-
- switch wm {
- case deps.WindowManagerHyprland:
- // Use the cppiber PPA for Hyprland
- packages["hyprland"] = PackageMapping{Name: "hyprland", Repository: RepoTypePPA, RepoURL: "ppa:cppiber/hyprland"}
- packages["grim"] = PackageMapping{Name: "grim", Repository: RepoTypeSystem}
- packages["slurp"] = PackageMapping{Name: "slurp", Repository: RepoTypeSystem}
- packages["hyprctl"] = PackageMapping{Name: "hyprland", Repository: RepoTypePPA, RepoURL: "ppa:cppiber/hyprland"}
- packages["grimblast"] = PackageMapping{Name: "grimblast", Repository: RepoTypeManual, BuildFunc: "installGrimblast"}
- packages["jq"] = PackageMapping{Name: "jq", Repository: RepoTypeSystem}
- case deps.WindowManagerNiri:
- packages["niri"] = PackageMapping{Name: "niri", Repository: RepoTypeManual, BuildFunc: "installNiri"}
- packages["xwayland-satellite"] = PackageMapping{Name: "xwayland-satellite", Repository: RepoTypeManual, BuildFunc: "installXwaylandSatellite"}
- }
-
- return packages
-}
-
-func (u *UbuntuDistribution) InstallPrerequisites(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.06,
- Step: "Updating package lists...",
- IsComplete: false,
- LogOutput: "Updating APT package lists",
- }
-
- updateCmd := exec.CommandContext(ctx, "bash", "-c", fmt.Sprintf("echo '%s' | sudo -S apt-get update", sudoPassword))
- if err := u.runWithProgress(updateCmd, progressChan, PhasePrerequisites, 0.06, 0.07); err != nil {
- return fmt.Errorf("failed to update package lists: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.08,
- Step: "Installing build-essential...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo apt-get install -y build-essential",
- LogOutput: "Installing build tools",
- }
-
- checkCmd := exec.CommandContext(ctx, "dpkg", "-l", "build-essential")
- if err := checkCmd.Run(); err != nil {
- // Not installed, install it
- cmd := exec.CommandContext(ctx, "bash", "-c", fmt.Sprintf("echo '%s' | sudo -S apt-get install -y build-essential", sudoPassword))
- if err := u.runWithProgress(cmd, progressChan, PhasePrerequisites, 0.08, 0.09); err != nil {
- return fmt.Errorf("failed to install build-essential: %w", err)
- }
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.10,
- Step: "Installing development dependencies...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo apt-get install -y curl wget git cmake ninja-build pkg-config libglib2.0-dev libpolkit-agent-1-dev",
- LogOutput: "Installing additional development tools",
- }
-
- devToolsCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S apt-get install -y curl wget git cmake ninja-build pkg-config libglib2.0-dev libpolkit-agent-1-dev", sudoPassword))
- if err := u.runWithProgress(devToolsCmd, progressChan, PhasePrerequisites, 0.10, 0.12); err != nil {
- return fmt.Errorf("failed to install development tools: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.12,
- Step: "Prerequisites installation complete",
- IsComplete: false,
- LogOutput: "Prerequisites successfully installed",
- }
-
- return nil
-}
-
-func (u *UbuntuDistribution) InstallPackages(ctx context.Context, dependencies []deps.Dependency, wm deps.WindowManager, sudoPassword string, reinstallFlags map[string]bool, progressChan chan<- InstallProgressMsg) error {
- // Phase 1: Check Prerequisites
- progressChan <- InstallProgressMsg{
- Phase: PhasePrerequisites,
- Progress: 0.05,
- Step: "Checking system prerequisites...",
- IsComplete: false,
- LogOutput: "Starting prerequisite check...",
- }
-
- if err := u.InstallPrerequisites(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install prerequisites: %w", err)
- }
-
- systemPkgs, ppaPkgs, manualPkgs := u.categorizePackages(dependencies, wm, reinstallFlags)
-
- // Phase 2: Enable PPA repositories
- if len(ppaPkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.15,
- Step: "Enabling PPA repositories...",
- IsComplete: false,
- LogOutput: "Setting up PPA repositories for additional packages",
- }
- if err := u.enablePPARepos(ctx, ppaPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to enable PPA repositories: %w", err)
- }
- }
-
- // Phase 3: System Packages (APT)
- if len(systemPkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.35,
- Step: fmt.Sprintf("Installing %d system packages...", len(systemPkgs)),
- IsComplete: false,
- NeedsSudo: true,
- LogOutput: fmt.Sprintf("Installing system packages: %s", strings.Join(systemPkgs, ", ")),
- }
- if err := u.installAPTPackages(ctx, systemPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install APT packages: %w", err)
- }
- }
-
- // Phase 4: PPA Packages
- ppaPkgNames := u.extractPackageNames(ppaPkgs)
- if len(ppaPkgNames) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages, // Reusing AUR phase for PPA
- Progress: 0.65,
- Step: fmt.Sprintf("Installing %d PPA packages...", len(ppaPkgNames)),
- IsComplete: false,
- LogOutput: fmt.Sprintf("Installing PPA packages: %s", strings.Join(ppaPkgNames, ", ")),
- }
- if err := u.installPPAPackages(ctx, ppaPkgNames, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install PPA packages: %w", err)
- }
- }
-
- // Phase 5: Manual Builds
- if len(manualPkgs) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.80,
- Step: "Installing build dependencies...",
- IsComplete: false,
- LogOutput: "Installing build tools for manual compilation",
- }
- if err := u.installBuildDependencies(ctx, manualPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install build dependencies: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.85,
- Step: fmt.Sprintf("Building %d packages from source...", len(manualPkgs)),
- IsComplete: false,
- LogOutput: fmt.Sprintf("Building from source: %s", strings.Join(manualPkgs, ", ")),
- }
- if err := u.InstallManualPackages(ctx, manualPkgs, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install manual packages: %w", err)
- }
- }
-
- // Phase 6: Configuration
- progressChan <- InstallProgressMsg{
- Phase: PhaseConfiguration,
- Progress: 0.90,
- Step: "Configuring system...",
- IsComplete: false,
- LogOutput: "Starting post-installation configuration...",
- }
-
- // Phase 7: Complete
- progressChan <- InstallProgressMsg{
- Phase: PhaseComplete,
- Progress: 1.0,
- Step: "Installation complete!",
- IsComplete: true,
- LogOutput: "All packages installed and configured successfully",
- }
-
- return nil
-}
-
-func (u *UbuntuDistribution) categorizePackages(dependencies []deps.Dependency, wm deps.WindowManager, reinstallFlags map[string]bool) ([]string, []PackageMapping, []string) {
- systemPkgs := []string{}
- ppaPkgs := []PackageMapping{}
- manualPkgs := []string{}
-
- packageMap := u.GetPackageMapping(wm)
-
- for _, dep := range dependencies {
- // Skip installed packages unless marked for reinstall
- if dep.Status == deps.StatusInstalled && !reinstallFlags[dep.Name] {
- continue
- }
-
- pkgInfo, exists := packageMap[dep.Name]
- if !exists {
- u.log(fmt.Sprintf("Warning: No package mapping for %s", dep.Name))
- continue
- }
-
- switch pkgInfo.Repository {
- case RepoTypeSystem:
- systemPkgs = append(systemPkgs, pkgInfo.Name)
- case RepoTypePPA:
- ppaPkgs = append(ppaPkgs, pkgInfo)
- case RepoTypeManual:
- manualPkgs = append(manualPkgs, dep.Name)
- }
- }
-
- return systemPkgs, ppaPkgs, manualPkgs
-}
-
-func (u *UbuntuDistribution) extractPackageNames(packages []PackageMapping) []string {
- names := make([]string, len(packages))
- for i, pkg := range packages {
- names[i] = pkg.Name
- }
- return names
-}
-
-func (u *UbuntuDistribution) enablePPARepos(ctx context.Context, ppaPkgs []PackageMapping, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- enabledRepos := make(map[string]bool)
-
- installPPACmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S apt-get install -y software-properties-common", sudoPassword))
- if err := u.runWithProgress(installPPACmd, progressChan, PhaseSystemPackages, 0.15, 0.17); err != nil {
- return fmt.Errorf("failed to install software-properties-common: %w", err)
- }
-
- for _, pkg := range ppaPkgs {
- if pkg.RepoURL != "" && !enabledRepos[pkg.RepoURL] {
- u.log(fmt.Sprintf("Enabling PPA repository: %s", pkg.RepoURL))
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.20,
- Step: fmt.Sprintf("Enabling PPA repo %s...", pkg.RepoURL),
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo add-apt-repository -y %s", pkg.RepoURL),
- }
-
- cmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S add-apt-repository -y %s", sudoPassword, pkg.RepoURL))
- if err := u.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.20, 0.22); err != nil {
- u.logError(fmt.Sprintf("failed to enable PPA repo %s", pkg.RepoURL), err)
- return fmt.Errorf("failed to enable PPA repo %s: %w", pkg.RepoURL, err)
- }
- u.log(fmt.Sprintf("PPA repo %s enabled successfully", pkg.RepoURL))
- enabledRepos[pkg.RepoURL] = true
- }
- }
-
- if len(enabledRepos) > 0 {
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.25,
- Step: "Updating package lists...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo apt-get update",
- }
-
- updateCmd := exec.CommandContext(ctx, "bash", "-c", fmt.Sprintf("echo '%s' | sudo -S apt-get update", sudoPassword))
- if err := u.runWithProgress(updateCmd, progressChan, PhaseSystemPackages, 0.25, 0.27); err != nil {
- return fmt.Errorf("failed to update package lists after adding PPAs: %w", err)
- }
- }
-
- return nil
-}
-
-func (u *UbuntuDistribution) installAPTPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- u.log(fmt.Sprintf("Installing APT packages: %s", strings.Join(packages, ", ")))
-
- args := []string{"apt-get", "install", "-y"}
- args = append(args, packages...)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.40,
- Step: "Installing system packages...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")),
- }
-
- cmdStr := fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, strings.Join(args, " "))
- cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
- return u.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.40, 0.60)
-}
-
-func (u *UbuntuDistribution) installPPAPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- u.log(fmt.Sprintf("Installing PPA packages: %s", strings.Join(packages, ", ")))
-
- args := []string{"apt-get", "install", "-y"}
- args = append(args, packages...)
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseAURPackages,
- Progress: 0.70,
- Step: "Installing PPA packages...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: fmt.Sprintf("sudo %s", strings.Join(args, " ")),
- }
-
- cmdStr := fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, strings.Join(args, " "))
- cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
- return u.runWithProgress(cmd, progressChan, PhaseAURPackages, 0.70, 0.85)
-}
-
-func (u *UbuntuDistribution) installBuildDependencies(ctx context.Context, manualPkgs []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- buildDeps := make(map[string]bool)
-
- for _, pkg := range manualPkgs {
- switch pkg {
- case "niri":
- buildDeps["curl"] = true
- buildDeps["libxkbcommon-dev"] = true
- buildDeps["libwayland-dev"] = true
- buildDeps["libudev-dev"] = true
- buildDeps["libinput-dev"] = true
- buildDeps["libdisplay-info-dev"] = true
- buildDeps["libpango1.0-dev"] = true
- buildDeps["libcairo-dev"] = true
- buildDeps["libpipewire-0.3-dev"] = true
- buildDeps["libc6-dev"] = true
- buildDeps["clang"] = true
- buildDeps["libseat-dev"] = true
- buildDeps["libgbm-dev"] = true
- buildDeps["alacritty"] = true
- buildDeps["fuzzel"] = true
- buildDeps["libxcb-cursor-dev"] = true
- case "quickshell":
- buildDeps["qt6-base-dev"] = true
- buildDeps["qt6-base-private-dev"] = true
- buildDeps["qt6-declarative-dev"] = true
- buildDeps["qt6-declarative-private-dev"] = true
- buildDeps["qt6-wayland-dev"] = true
- buildDeps["qt6-wayland-private-dev"] = true
- buildDeps["qt6-tools-dev"] = true
- buildDeps["libqt6svg6-dev"] = true
- buildDeps["qt6-shadertools-dev"] = true
- buildDeps["spirv-tools"] = true
- buildDeps["libcli11-dev"] = true
- buildDeps["libjemalloc-dev"] = true
- buildDeps["libwayland-dev"] = true
- buildDeps["wayland-protocols"] = true
- buildDeps["libdrm-dev"] = true
- buildDeps["libgbm-dev"] = true
- buildDeps["libegl-dev"] = true
- buildDeps["libgles2-mesa-dev"] = true
- buildDeps["libgl1-mesa-dev"] = true
- buildDeps["libxcb1-dev"] = true
- buildDeps["libpipewire-0.3-dev"] = true
- buildDeps["libpam0g-dev"] = true
- case "ghostty":
- buildDeps["curl"] = true
- buildDeps["libgtk-4-dev"] = true
- buildDeps["libadwaita-1-dev"] = true
- case "matugen":
- buildDeps["curl"] = true
- case "cliphist":
- // Go will be installed separately with PPA
- }
- }
-
- for _, pkg := range manualPkgs {
- switch pkg {
- case "niri", "matugen":
- if err := u.installRust(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install Rust: %w", err)
- }
- case "ghostty":
- if err := u.installZig(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install Zig: %w", err)
- }
- case "cliphist", "dgop":
- if err := u.installGo(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install Go: %w", err)
- }
- }
- }
-
- if len(buildDeps) == 0 {
- return nil
- }
-
- depList := make([]string, 0, len(buildDeps))
- for dep := range buildDeps {
- depList = append(depList, dep)
- }
-
- args := []string{"apt-get", "install", "-y"}
- args = append(args, depList...)
-
- cmdStr := fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, strings.Join(args, " "))
- cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
- return u.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.80, 0.82)
-}
-
-func (u *UbuntuDistribution) installRust(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if u.commandExists("cargo") {
- return nil
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.82,
- Step: "Installing rustup...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo apt-get install rustup",
- }
-
- rustupInstallCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S apt-get install -y rustup", sudoPassword))
- if err := u.runWithProgress(rustupInstallCmd, progressChan, PhaseSystemPackages, 0.82, 0.83); err != nil {
- return fmt.Errorf("failed to install rustup: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.83,
- Step: "Installing stable Rust toolchain...",
- IsComplete: false,
- CommandInfo: "rustup install stable",
- }
-
- rustInstallCmd := exec.CommandContext(ctx, "bash", "-c", "rustup install stable && rustup default stable")
- if err := u.runWithProgress(rustInstallCmd, progressChan, PhaseSystemPackages, 0.83, 0.84); err != nil {
- return fmt.Errorf("failed to install Rust toolchain: %w", err)
- }
-
- // Verify cargo is now available
- if !u.commandExists("cargo") {
- u.log("Warning: cargo not found in PATH after Rust installation, trying to source environment")
- }
-
- return nil
-}
-
-func (u *UbuntuDistribution) installZig(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if u.commandExists("zig") {
- return nil
- }
-
- homeDir, err := os.UserHomeDir()
- if err != nil {
- return fmt.Errorf("failed to get user home directory: %w", err)
- }
-
- cacheDir := filepath.Join(homeDir, ".cache", "dankinstall")
- if err := os.MkdirAll(cacheDir, 0755); err != nil {
- return fmt.Errorf("failed to create cache directory: %w", err)
- }
-
- zigUrl := "https://ziglang.org/download/0.11.0/zig-linux-x86_64-0.11.0.tar.xz"
- zigTmp := filepath.Join(cacheDir, "zig.tar.xz")
-
- downloadCmd := exec.CommandContext(ctx, "curl", "-L", zigUrl, "-o", zigTmp)
- if err := u.runWithProgress(downloadCmd, progressChan, PhaseSystemPackages, 0.84, 0.85); err != nil {
- return fmt.Errorf("failed to download Zig: %w", err)
- }
-
- extractCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S tar -xf %s -C /opt/", sudoPassword, zigTmp))
- if err := u.runWithProgress(extractCmd, progressChan, PhaseSystemPackages, 0.85, 0.86); err != nil {
- return fmt.Errorf("failed to extract Zig: %w", err)
- }
-
- linkCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S ln -sf /opt/zig-linux-x86_64-0.11.0/zig /usr/local/bin/zig", sudoPassword))
- return u.runWithProgress(linkCmd, progressChan, PhaseSystemPackages, 0.86, 0.87)
-}
-
-func (u *UbuntuDistribution) installGo(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if u.commandExists("go") {
- return nil
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.87,
- Step: "Adding Go PPA repository...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo add-apt-repository ppa:longsleep/golang-backports",
- }
-
- addPPACmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S add-apt-repository -y ppa:longsleep/golang-backports", sudoPassword))
- if err := u.runWithProgress(addPPACmd, progressChan, PhaseSystemPackages, 0.87, 0.88); err != nil {
- return fmt.Errorf("failed to add Go PPA: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.88,
- Step: "Updating package lists...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo apt-get update",
- }
-
- updateCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S apt-get update", sudoPassword))
- if err := u.runWithProgress(updateCmd, progressChan, PhaseSystemPackages, 0.88, 0.89); err != nil {
- return fmt.Errorf("failed to update package lists after adding Go PPA: %w", err)
- }
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.89,
- Step: "Installing Go...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "sudo apt-get install golang-go",
- }
-
- installCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S apt-get install -y golang-go", sudoPassword))
- return u.runWithProgress(installCmd, progressChan, PhaseSystemPackages, 0.89, 0.90)
-}
-
-func (u *UbuntuDistribution) installGhosttyUbuntu(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- u.log("Installing Ghostty using Ubuntu installer script...")
-
- progressChan <- InstallProgressMsg{
- Phase: PhaseSystemPackages,
- Progress: 0.1,
- Step: "Running Ghostty Ubuntu installer...",
- IsComplete: false,
- NeedsSudo: true,
- CommandInfo: "curl -fsSL https://raw.githubusercontent.com/mkasberg/ghostty-ubuntu/HEAD/install.sh | sudo bash",
- LogOutput: "Installing Ghostty using pre-built Ubuntu package",
- }
-
- installCmd := exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/mkasberg/ghostty-ubuntu/HEAD/install.sh)\"", sudoPassword))
-
- if err := u.runWithProgress(installCmd, progressChan, PhaseSystemPackages, 0.1, 0.9); err != nil {
- return fmt.Errorf("failed to install Ghostty: %w", err)
- }
-
- u.log("Ghostty installed successfully using Ubuntu installer")
- return nil
-}
-
-// Override InstallManualPackages for Ubuntu to handle Ubuntu-specific installations
-func (u *UbuntuDistribution) InstallManualPackages(ctx context.Context, packages []string, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
- if len(packages) == 0 {
- return nil
- }
-
- u.log(fmt.Sprintf("Installing manual packages: %s", strings.Join(packages, ", ")))
-
- for _, pkg := range packages {
- switch pkg {
- case "ghostty":
- if err := u.installGhosttyUbuntu(ctx, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install ghostty: %w", err)
- }
- default:
- // Use the base ManualPackageInstaller for other packages
- if err := u.ManualPackageInstaller.InstallManualPackages(ctx, []string{pkg}, sudoPassword, progressChan); err != nil {
- return fmt.Errorf("failed to install %s: %w", pkg, err)
- }
- }
- }
-
- return nil
-}
diff --git a/nix/inputs/dms-cli/internal/dms/app.go b/nix/inputs/dms-cli/internal/dms/app.go
deleted file mode 100644
index fcf90fe..0000000
--- a/nix/inputs/dms-cli/internal/dms/app.go
+++ /dev/null
@@ -1,438 +0,0 @@
-//go:build !distro_binary
-
-package dms
-
-import (
- "os/exec"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
- tea "github.com/charmbracelet/bubbletea"
-)
-
-type AppState int
-
-const (
- StateMainMenu AppState = iota
- StateUpdate
- StateUpdatePassword
- StateUpdateProgress
- StateShell
- StatePluginsMenu
- StatePluginsBrowse
- StatePluginDetail
- StatePluginSearch
- StatePluginsInstalled
- StatePluginInstalledDetail
- StateGreeterMenu
- StateGreeterCompositorSelect
- StateGreeterPassword
- StateGreeterInstalling
- StateAbout
-)
-
-type Model struct {
- version string
- detector *Detector
- dependencies []DependencyInfo
- state AppState
- selectedItem int
- width int
- height int
-
- // Menu items
- menuItems []MenuItem
-
- updateDeps []DependencyInfo
- selectedUpdateDep int
- updateToggles map[string]bool
-
- updateProgressChan chan updateProgressMsg
- updateProgress updateProgressMsg
- updateLogs []string
- sudoPassword string
- passwordInput string
- passwordError string
-
- // Window manager states
- hyprlandInstalled bool
- niriInstalled bool
-
- selectedGreeterItem int
- greeterInstallChan chan greeterProgressMsg
- greeterProgress greeterProgressMsg
- greeterLogs []string
- greeterPasswordInput string
- greeterPasswordError string
- greeterSudoPassword string
- greeterCompositors []string
- greeterSelectedComp int
- greeterChosenCompositor string
-
- pluginsMenuItems []MenuItem
- selectedPluginsMenuItem int
- pluginsList []pluginInfo
- filteredPluginsList []pluginInfo
- selectedPluginIndex int
- pluginsLoading bool
- pluginsError string
- pluginSearchQuery string
- installedPluginsList []pluginInfo
- selectedInstalledIndex int
- installedPluginsLoading bool
- installedPluginsError string
- pluginInstallStatus map[string]bool
-}
-
-type pluginInfo struct {
- ID string
- Name string
- Category string
- Author string
- Description string
- Repo string
- Path string
- Capabilities []string
- Compositors []string
- Dependencies []string
- FirstParty bool
-}
-
-type MenuItem struct {
- Label string
- Action AppState
-}
-
-func NewModel(version string) Model {
- detector, _ := NewDetector()
- dependencies := detector.GetInstalledComponents()
-
- // Use the proper detection method for both window managers
- hyprlandInstalled, niriInstalled, err := detector.GetWindowManagerStatus()
- if err != nil {
- // Fallback to false if detection fails
- hyprlandInstalled = false
- niriInstalled = false
- }
-
- updateToggles := make(map[string]bool)
- for _, dep := range dependencies {
- if dep.Name == "dms (DankMaterialShell)" && dep.Status == deps.StatusNeedsUpdate {
- updateToggles[dep.Name] = true
- break
- }
- }
-
- m := Model{
- version: version,
- detector: detector,
- dependencies: dependencies,
- state: StateMainMenu,
- selectedItem: 0,
- updateToggles: updateToggles,
- updateDeps: dependencies,
- updateProgressChan: make(chan updateProgressMsg, 100),
- hyprlandInstalled: hyprlandInstalled,
- niriInstalled: niriInstalled,
- greeterInstallChan: make(chan greeterProgressMsg, 100),
- pluginInstallStatus: make(map[string]bool),
- }
-
- m.menuItems = m.buildMenuItems()
- return m
-}
-
-func (m *Model) buildMenuItems() []MenuItem {
- items := []MenuItem{
- {Label: "Update", Action: StateUpdate},
- }
-
- // Shell management
- if m.isShellRunning() {
- items = append(items, MenuItem{Label: "Terminate Shell", Action: StateShell})
- } else {
- items = append(items, MenuItem{Label: "Start Shell (Daemon)", Action: StateShell})
- }
-
- // Plugins management
- items = append(items, MenuItem{Label: "Plugins", Action: StatePluginsMenu})
-
- // Greeter management
- items = append(items, MenuItem{Label: "Greeter", Action: StateGreeterMenu})
-
- items = append(items, MenuItem{Label: "About", Action: StateAbout})
-
- return items
-}
-
-func (m *Model) buildPluginsMenuItems() []MenuItem {
- return []MenuItem{
- {Label: "Browse Plugins", Action: StatePluginsBrowse},
- {Label: "View Installed", Action: StatePluginsInstalled},
- }
-}
-
-func (m *Model) isShellRunning() bool {
- // Check for both -c and -p flag patterns since quickshell can be started either way
- // -c dms: config name mode
- // -p /dms: path mode (used when installed via system packages)
- cmd := exec.Command("pgrep", "-f", "qs.*dms")
- err := cmd.Run()
- return err == nil
-}
-
-func (m Model) Init() tea.Cmd {
- return nil
-}
-
-func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
- switch msg := msg.(type) {
- case tea.WindowSizeMsg:
- m.width = msg.Width
- m.height = msg.Height
- case shellStartedMsg:
- m.menuItems = m.buildMenuItems()
- if m.selectedItem >= len(m.menuItems) {
- m.selectedItem = len(m.menuItems) - 1
- }
- return m, nil
- case updateProgressMsg:
- m.updateProgress = msg
- if msg.logOutput != "" {
- m.updateLogs = append(m.updateLogs, msg.logOutput)
- }
- return m, m.waitForProgress()
- case updateCompleteMsg:
- m.updateProgress.complete = true
- m.updateProgress.err = msg.err
- m.dependencies = m.detector.GetInstalledComponents()
- m.updateDeps = m.dependencies
- m.menuItems = m.buildMenuItems()
-
- // Restart shell if update was successful and shell is running
- if msg.err == nil && m.isShellRunning() {
- restartShell()
- }
- return m, nil
- case greeterProgressMsg:
- m.greeterProgress = msg
- if msg.logOutput != "" {
- m.greeterLogs = append(m.greeterLogs, msg.logOutput)
- }
- return m, m.waitForGreeterProgress()
- case pluginsLoadedMsg:
- m.pluginsLoading = false
- if msg.err != nil {
- m.pluginsError = msg.err.Error()
- } else {
- m.pluginsList = make([]pluginInfo, len(msg.plugins))
- for i, p := range msg.plugins {
- m.pluginsList[i] = pluginInfo{
- ID: p.ID,
- Name: p.Name,
- Category: p.Category,
- Author: p.Author,
- Description: p.Description,
- Repo: p.Repo,
- Path: p.Path,
- Capabilities: p.Capabilities,
- Compositors: p.Compositors,
- Dependencies: p.Dependencies,
- FirstParty: strings.HasPrefix(p.Repo, "https://github.com/AvengeMedia"),
- }
- }
- m.filteredPluginsList = m.pluginsList
- m.selectedPluginIndex = 0
- m.updatePluginInstallStatus()
- }
- return m, nil
- case installedPluginsLoadedMsg:
- m.installedPluginsLoading = false
- if msg.err != nil {
- m.installedPluginsError = msg.err.Error()
- } else {
- m.installedPluginsList = make([]pluginInfo, len(msg.plugins))
- for i, p := range msg.plugins {
- m.installedPluginsList[i] = pluginInfo{
- ID: p.ID,
- Name: p.Name,
- Category: p.Category,
- Author: p.Author,
- Description: p.Description,
- Repo: p.Repo,
- Path: p.Path,
- Capabilities: p.Capabilities,
- Compositors: p.Compositors,
- Dependencies: p.Dependencies,
- FirstParty: strings.HasPrefix(p.Repo, "https://github.com/AvengeMedia"),
- }
- }
- m.selectedInstalledIndex = 0
- }
- return m, nil
- case pluginUninstalledMsg:
- if msg.err != nil {
- m.installedPluginsError = msg.err.Error()
- m.state = StatePluginInstalledDetail
- } else {
- m.state = StatePluginsInstalled
- m.installedPluginsLoading = true
- m.installedPluginsError = ""
- return m, loadInstalledPlugins
- }
- return m, nil
- case pluginInstalledMsg:
- if msg.err != nil {
- m.pluginsError = msg.err.Error()
- } else {
- m.pluginInstallStatus[msg.pluginName] = true
- m.pluginsError = ""
- }
- return m, nil
- case greeterPasswordValidMsg:
- if msg.valid {
- m.greeterSudoPassword = msg.password
- m.greeterPasswordInput = ""
- m.greeterPasswordError = ""
- m.state = StateGreeterInstalling
- m.greeterProgress = greeterProgressMsg{step: "Starting greeter installation..."}
- m.greeterLogs = []string{}
- return m, tea.Batch(m.performGreeterInstall(), m.waitForGreeterProgress())
- } else {
- m.greeterPasswordError = "Incorrect password. Please try again."
- m.greeterPasswordInput = ""
- }
- return m, nil
- case passwordValidMsg:
- if msg.valid {
- m.sudoPassword = msg.password
- m.passwordInput = ""
- m.passwordError = ""
- m.state = StateUpdateProgress
- m.updateProgress = updateProgressMsg{progress: 0.0, step: "Starting update..."}
- m.updateLogs = []string{}
- return m, tea.Batch(m.performUpdate(), m.waitForProgress())
- } else {
- m.passwordError = "Incorrect password. Please try again."
- m.passwordInput = ""
- }
- return m, nil
- case tea.KeyMsg:
- switch m.state {
- case StateMainMenu:
- return m.updateMainMenu(msg)
- case StateUpdate:
- return m.updateUpdateView(msg)
- case StateUpdatePassword:
- return m.updatePasswordView(msg)
- case StateUpdateProgress:
- return m.updateProgressView(msg)
- case StateShell:
- return m.updateShellView(msg)
- case StatePluginsMenu:
- return m.updatePluginsMenu(msg)
- case StatePluginsBrowse:
- return m.updatePluginsBrowse(msg)
- case StatePluginDetail:
- return m.updatePluginDetail(msg)
- case StatePluginSearch:
- return m.updatePluginSearch(msg)
- case StatePluginsInstalled:
- return m.updatePluginsInstalled(msg)
- case StatePluginInstalledDetail:
- return m.updatePluginInstalledDetail(msg)
- case StateGreeterMenu:
- return m.updateGreeterMenu(msg)
- case StateGreeterCompositorSelect:
- return m.updateGreeterCompositorSelect(msg)
- case StateGreeterPassword:
- return m.updateGreeterPasswordView(msg)
- case StateGreeterInstalling:
- return m.updateGreeterInstalling(msg)
- case StateAbout:
- return m.updateAboutView(msg)
- }
- }
-
- return m, nil
-}
-
-type updateProgressMsg struct {
- progress float64
- step string
- complete bool
- err error
- logOutput string
-}
-
-type updateCompleteMsg struct {
- err error
-}
-
-type passwordValidMsg struct {
- password string
- valid bool
-}
-
-type greeterProgressMsg struct {
- step string
- complete bool
- err error
- logOutput string
-}
-
-type greeterPasswordValidMsg struct {
- password string
- valid bool
-}
-
-func (m Model) waitForProgress() tea.Cmd {
- return func() tea.Msg {
- return <-m.updateProgressChan
- }
-}
-
-func (m Model) waitForGreeterProgress() tea.Cmd {
- return func() tea.Msg {
- return <-m.greeterInstallChan
- }
-}
-
-func (m Model) View() string {
- switch m.state {
- case StateMainMenu:
- return m.renderMainMenu()
- case StateUpdate:
- return m.renderUpdateView()
- case StateUpdatePassword:
- return m.renderPasswordView()
- case StateUpdateProgress:
- return m.renderProgressView()
- case StateShell:
- return m.renderShellView()
- case StatePluginsMenu:
- return m.renderPluginsMenu()
- case StatePluginsBrowse:
- return m.renderPluginsBrowse()
- case StatePluginDetail:
- return m.renderPluginDetail()
- case StatePluginSearch:
- return m.renderPluginSearch()
- case StatePluginsInstalled:
- return m.renderPluginsInstalled()
- case StatePluginInstalledDetail:
- return m.renderPluginInstalledDetail()
- case StateGreeterMenu:
- return m.renderGreeterMenu()
- case StateGreeterCompositorSelect:
- return m.renderGreeterCompositorSelect()
- case StateGreeterPassword:
- return m.renderGreeterPasswordView()
- case StateGreeterInstalling:
- return m.renderGreeterInstalling()
- case StateAbout:
- return m.renderAboutView()
- default:
- return m.renderMainMenu()
- }
-}
diff --git a/nix/inputs/dms-cli/internal/dms/app_distro.go b/nix/inputs/dms-cli/internal/dms/app_distro.go
deleted file mode 100644
index 2875d2b..0000000
--- a/nix/inputs/dms-cli/internal/dms/app_distro.go
+++ /dev/null
@@ -1,261 +0,0 @@
-//go:build distro_binary
-
-package dms
-
-import (
- "os/exec"
- "strings"
-
- tea "github.com/charmbracelet/bubbletea"
-)
-
-type AppState int
-
-const (
- StateMainMenu AppState = iota
- StateShell
- StatePluginsMenu
- StatePluginsBrowse
- StatePluginDetail
- StatePluginSearch
- StatePluginsInstalled
- StatePluginInstalledDetail
- StateAbout
-)
-
-type Model struct {
- version string
- detector *Detector
- dependencies []DependencyInfo
- state AppState
- selectedItem int
- width int
- height int
-
- // Menu items
- menuItems []MenuItem
-
- // Window manager states
- hyprlandInstalled bool
- niriInstalled bool
-
- pluginsMenuItems []MenuItem
- selectedPluginsMenuItem int
- pluginsList []pluginInfo
- filteredPluginsList []pluginInfo
- selectedPluginIndex int
- pluginsLoading bool
- pluginsError string
- pluginSearchQuery string
- installedPluginsList []pluginInfo
- selectedInstalledIndex int
- installedPluginsLoading bool
- installedPluginsError string
- pluginInstallStatus map[string]bool
-}
-
-type pluginInfo struct {
- ID string
- Name string
- Category string
- Author string
- Description string
- Repo string
- Path string
- Capabilities []string
- Compositors []string
- Dependencies []string
- FirstParty bool
-}
-
-type MenuItem struct {
- Label string
- Action AppState
-}
-
-func NewModel(version string) Model {
- detector, _ := NewDetector()
- dependencies := detector.GetInstalledComponents()
-
- // Use the proper detection method for both window managers
- hyprlandInstalled, niriInstalled, err := detector.GetWindowManagerStatus()
- if err != nil {
- // Fallback to false if detection fails
- hyprlandInstalled = false
- niriInstalled = false
- }
-
- m := Model{
- version: version,
- detector: detector,
- dependencies: dependencies,
- state: StateMainMenu,
- selectedItem: 0,
- hyprlandInstalled: hyprlandInstalled,
- niriInstalled: niriInstalled,
- pluginInstallStatus: make(map[string]bool),
- }
-
- m.menuItems = m.buildMenuItems()
- return m
-}
-
-func (m *Model) buildMenuItems() []MenuItem {
- items := []MenuItem{}
-
- // Shell management
- if m.isShellRunning() {
- items = append(items, MenuItem{Label: "Terminate Shell", Action: StateShell})
- } else {
- items = append(items, MenuItem{Label: "Start Shell (Daemon)", Action: StateShell})
- }
-
- // Plugins management
- items = append(items, MenuItem{Label: "Plugins", Action: StatePluginsMenu})
-
- items = append(items, MenuItem{Label: "About", Action: StateAbout})
-
- return items
-}
-
-func (m *Model) buildPluginsMenuItems() []MenuItem {
- return []MenuItem{
- {Label: "Browse Plugins", Action: StatePluginsBrowse},
- {Label: "View Installed", Action: StatePluginsInstalled},
- }
-}
-
-func (m *Model) isShellRunning() bool {
- cmd := exec.Command("pgrep", "-f", "qs -c dms")
- err := cmd.Run()
- return err == nil
-}
-
-func (m Model) Init() tea.Cmd {
- return nil
-}
-
-func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
- switch msg := msg.(type) {
- case tea.WindowSizeMsg:
- m.width = msg.Width
- m.height = msg.Height
- case pluginsLoadedMsg:
- m.pluginsLoading = false
- if msg.err != nil {
- m.pluginsError = msg.err.Error()
- } else {
- m.pluginsList = make([]pluginInfo, len(msg.plugins))
- for i, p := range msg.plugins {
- m.pluginsList[i] = pluginInfo{
- ID: p.ID,
- Name: p.Name,
- Category: p.Category,
- Author: p.Author,
- Description: p.Description,
- Repo: p.Repo,
- Path: p.Path,
- Capabilities: p.Capabilities,
- Compositors: p.Compositors,
- Dependencies: p.Dependencies,
- FirstParty: strings.HasPrefix(p.Repo, "https://github.com/AvengeMedia"),
- }
- }
- m.filteredPluginsList = m.pluginsList
- m.selectedPluginIndex = 0
- m.updatePluginInstallStatus()
- }
- return m, nil
- case installedPluginsLoadedMsg:
- m.installedPluginsLoading = false
- if msg.err != nil {
- m.installedPluginsError = msg.err.Error()
- } else {
- m.installedPluginsList = make([]pluginInfo, len(msg.plugins))
- for i, p := range msg.plugins {
- m.installedPluginsList[i] = pluginInfo{
- ID: p.ID,
- Name: p.Name,
- Category: p.Category,
- Author: p.Author,
- Description: p.Description,
- Repo: p.Repo,
- Path: p.Path,
- Capabilities: p.Capabilities,
- Compositors: p.Compositors,
- Dependencies: p.Dependencies,
- FirstParty: strings.HasPrefix(p.Repo, "https://github.com/AvengeMedia"),
- }
- }
- m.selectedInstalledIndex = 0
- }
- return m, nil
- case pluginUninstalledMsg:
- if msg.err != nil {
- m.installedPluginsError = msg.err.Error()
- m.state = StatePluginInstalledDetail
- } else {
- m.state = StatePluginsInstalled
- m.installedPluginsLoading = true
- m.installedPluginsError = ""
- return m, loadInstalledPlugins
- }
- return m, nil
- case pluginInstalledMsg:
- if msg.err != nil {
- m.pluginsError = msg.err.Error()
- } else {
- m.pluginInstallStatus[msg.pluginName] = true
- m.pluginsError = ""
- }
- return m, nil
- case tea.KeyMsg:
- switch m.state {
- case StateMainMenu:
- return m.updateMainMenu(msg)
- case StateShell:
- return m.updateShellView(msg)
- case StatePluginsMenu:
- return m.updatePluginsMenu(msg)
- case StatePluginsBrowse:
- return m.updatePluginsBrowse(msg)
- case StatePluginDetail:
- return m.updatePluginDetail(msg)
- case StatePluginSearch:
- return m.updatePluginSearch(msg)
- case StatePluginsInstalled:
- return m.updatePluginsInstalled(msg)
- case StatePluginInstalledDetail:
- return m.updatePluginInstalledDetail(msg)
- case StateAbout:
- return m.updateAboutView(msg)
- }
- }
-
- return m, nil
-}
-
-func (m Model) View() string {
- switch m.state {
- case StateMainMenu:
- return m.renderMainMenu()
- case StateShell:
- return m.renderShellView()
- case StatePluginsMenu:
- return m.renderPluginsMenu()
- case StatePluginsBrowse:
- return m.renderPluginsBrowse()
- case StatePluginDetail:
- return m.renderPluginDetail()
- case StatePluginSearch:
- return m.renderPluginSearch()
- case StatePluginsInstalled:
- return m.renderPluginsInstalled()
- case StatePluginInstalledDetail:
- return m.renderPluginInstalledDetail()
- case StateAbout:
- return m.renderAboutView()
- default:
- return m.renderMainMenu()
- }
-}
diff --git a/nix/inputs/dms-cli/internal/dms/detector.go b/nix/inputs/dms-cli/internal/dms/detector.go
deleted file mode 100644
index a56b1be..0000000
--- a/nix/inputs/dms-cli/internal/dms/detector.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package dms
-
-import (
- "context"
- "os"
- "os/exec"
-
- "github.com/AvengeMedia/danklinux/internal/config"
- "github.com/AvengeMedia/danklinux/internal/deps"
- "github.com/AvengeMedia/danklinux/internal/distros"
-)
-
-type Detector struct {
- homeDir string
- distribution distros.Distribution
-}
-
-func (d *Detector) GetDistribution() distros.Distribution {
- return d.distribution
-}
-
-func NewDetector() (*Detector, error) {
- homeDir, err := os.UserHomeDir()
- if err != nil {
- return nil, err
- }
-
- logChan := make(chan string, 100)
- go func() {
- for range logChan {
- }
- }()
-
- osInfo, err := distros.GetOSInfo()
- if err != nil {
- return nil, err
- }
-
- dist, err := distros.NewDistribution(osInfo.Distribution.ID, logChan)
- if err != nil {
- return nil, err
- }
-
- return &Detector{
- homeDir: homeDir,
- distribution: dist,
- }, nil
-}
-
-func (d *Detector) IsDMSInstalled() bool {
- _, err := config.LocateDMSConfig()
- return err == nil
-}
-
-func (d *Detector) GetDependencyStatus() ([]deps.Dependency, error) {
- hyprlandDeps, err := d.distribution.DetectDependencies(context.Background(), deps.WindowManagerHyprland)
- if err != nil {
- return nil, err
- }
-
- niriDeps, err := d.distribution.DetectDependencies(context.Background(), deps.WindowManagerNiri)
- if err != nil {
- return nil, err
- }
-
- // Combine dependencies and deduplicate
- depMap := make(map[string]deps.Dependency)
-
- for _, dep := range hyprlandDeps {
- depMap[dep.Name] = dep
- }
-
- for _, dep := range niriDeps {
- // If dependency already exists, keep the one that's installed or needs update
- if existing, exists := depMap[dep.Name]; exists {
- if dep.Status > existing.Status {
- depMap[dep.Name] = dep
- }
- } else {
- depMap[dep.Name] = dep
- }
- }
-
- // Convert map back to slice
- var allDeps []deps.Dependency
- for _, dep := range depMap {
- allDeps = append(allDeps, dep)
- }
-
- return allDeps, nil
-}
-
-func (d *Detector) GetWindowManagerStatus() (bool, bool, error) {
- // Reuse the existing command detection logic from BaseDistribution
- // Since all distros embed BaseDistribution, we can access it via interface
- type CommandChecker interface {
- CommandExists(string) bool
- }
-
- checker, ok := d.distribution.(CommandChecker)
- if !ok {
- // Fallback to direct command check if interface not available
- hyprlandInstalled := d.commandExists("hyprland") || d.commandExists("Hyprland")
- niriInstalled := d.commandExists("niri")
- return hyprlandInstalled, niriInstalled, nil
- }
-
- hyprlandInstalled := checker.CommandExists("hyprland") || checker.CommandExists("Hyprland")
- niriInstalled := checker.CommandExists("niri")
-
- return hyprlandInstalled, niriInstalled, nil
-}
-
-func (d *Detector) commandExists(cmd string) bool {
- _, err := exec.LookPath(cmd)
- return err == nil
-}
-
-func (d *Detector) GetInstalledComponents() []DependencyInfo {
- dependencies, err := d.GetDependencyStatus()
- if err != nil {
- return []DependencyInfo{}
- }
-
- isNixOS := d.isNixOS()
-
- var components []DependencyInfo
- for _, dep := range dependencies {
- // On NixOS, filter out the window managers themselves but keep their components
- if isNixOS && (dep.Name == "hyprland" || dep.Name == "niri") {
- continue
- }
-
- components = append(components, DependencyInfo{
- Name: dep.Name,
- Status: dep.Status,
- Description: dep.Description,
- Required: dep.Required,
- })
- }
-
- return components
-}
-
-func (d *Detector) isNixOS() bool {
- _, err := os.Stat("/etc/nixos")
- if err == nil {
- return true
- }
-
- // Alternative check
- if _, err := os.Stat("/nix/store"); err == nil {
- // Also check for nixos-version command
- if d.commandExists("nixos-version") {
- return true
- }
- }
-
- return false
-}
-
-type DependencyInfo struct {
- Name string
- Status deps.DependencyStatus
- Description string
- Required bool
-}
diff --git a/nix/inputs/dms-cli/internal/dms/handlers_common.go b/nix/inputs/dms-cli/internal/dms/handlers_common.go
deleted file mode 100644
index cea5c26..0000000
--- a/nix/inputs/dms-cli/internal/dms/handlers_common.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package dms
-
-import (
- "os/exec"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- tea "github.com/charmbracelet/bubbletea"
-)
-
-func (m Model) updateShellView(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- switch msg.String() {
- case "ctrl+c", "q":
- return m, tea.Quit
- case "esc":
- m.state = StateMainMenu
- default:
- return m, tea.Quit
- }
- return m, nil
-}
-
-func (m Model) updateAboutView(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- switch msg.String() {
- case "ctrl+c", "q", "esc":
- if msg.String() == "esc" {
- m.state = StateMainMenu
- } else {
- return m, tea.Quit
- }
- }
- return m, nil
-}
-
-func terminateShell() {
- patterns := []string{"dms run", "qs -c dms"}
- for _, pattern := range patterns {
- cmd := exec.Command("pkill", "-f", pattern)
- cmd.Run()
- }
-}
-
-func startShellDaemon() {
- cmd := exec.Command("dms", "run", "-d")
- if err := cmd.Start(); err != nil {
- log.Errorf("Error starting daemon: %v", err)
- }
-}
-
-func restartShell() {
- terminateShell()
- time.Sleep(500 * time.Millisecond)
- startShellDaemon()
-}
diff --git a/nix/inputs/dms-cli/internal/dms/handlers_features.go b/nix/inputs/dms-cli/internal/dms/handlers_features.go
deleted file mode 100644
index b6f16db..0000000
--- a/nix/inputs/dms-cli/internal/dms/handlers_features.go
+++ /dev/null
@@ -1,391 +0,0 @@
-//go:build !distro_binary
-
-package dms
-
-import (
- "context"
- "fmt"
- "os/exec"
- "strings"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
- "github.com/AvengeMedia/danklinux/internal/distros"
- "github.com/AvengeMedia/danklinux/internal/greeter"
- tea "github.com/charmbracelet/bubbletea"
-)
-
-func (m Model) updateUpdateView(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- filteredDeps := m.getFilteredDeps()
- maxIndex := len(filteredDeps) - 1
-
- switch msg.String() {
- case "ctrl+c", "q":
- return m, tea.Quit
- case "esc":
- m.state = StateMainMenu
- case "up", "k":
- if m.selectedUpdateDep > 0 {
- m.selectedUpdateDep--
- }
- case "down", "j":
- if m.selectedUpdateDep < maxIndex {
- m.selectedUpdateDep++
- }
- case " ":
- if dep := m.getDepAtVisualIndex(m.selectedUpdateDep); dep != nil {
- m.updateToggles[dep.Name] = !m.updateToggles[dep.Name]
- }
- case "enter":
- hasSelected := false
- for _, toggle := range m.updateToggles {
- if toggle {
- hasSelected = true
- break
- }
- }
-
- if !hasSelected {
- m.state = StateMainMenu
- return m, nil
- }
-
- m.state = StateUpdatePassword
- m.passwordInput = ""
- m.passwordError = ""
- return m, nil
- }
- return m, nil
-}
-
-func (m Model) updatePasswordView(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- switch msg.String() {
- case "ctrl+c":
- return m, tea.Quit
- case "esc":
- m.state = StateUpdate
- m.passwordInput = ""
- m.passwordError = ""
- return m, nil
- case "enter":
- if m.passwordInput == "" {
- return m, nil
- }
- return m, m.validatePassword(m.passwordInput)
- case "backspace":
- if len(m.passwordInput) > 0 {
- m.passwordInput = m.passwordInput[:len(m.passwordInput)-1]
- }
- default:
- if len(msg.String()) == 1 && msg.String()[0] >= 32 && msg.String()[0] <= 126 {
- m.passwordInput += msg.String()
- }
- }
- return m, nil
-}
-
-func (m Model) updateProgressView(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- switch msg.String() {
- case "ctrl+c", "q":
- return m, tea.Quit
- case "esc":
- if m.updateProgress.complete {
- m.state = StateMainMenu
- m.updateProgress = updateProgressMsg{}
- m.updateLogs = []string{}
- }
- }
- return m, nil
-}
-
-func (m Model) validatePassword(password string) tea.Cmd {
- return func() tea.Msg {
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- defer cancel()
-
- cmd := exec.CommandContext(ctx, "sudo", "-S", "-v")
- stdin, err := cmd.StdinPipe()
- if err != nil {
- return passwordValidMsg{password: "", valid: false}
- }
-
- go func() {
- defer stdin.Close()
- fmt.Fprintf(stdin, "%s\n", password)
- }()
-
- output, err := cmd.CombinedOutput()
- outputStr := string(output)
-
- if err != nil {
- if strings.Contains(outputStr, "Sorry, try again") ||
- strings.Contains(outputStr, "incorrect password") ||
- strings.Contains(outputStr, "authentication failure") {
- return passwordValidMsg{password: "", valid: false}
- }
- return passwordValidMsg{password: "", valid: false}
- }
-
- return passwordValidMsg{password: password, valid: true}
- }
-}
-
-func (m Model) performUpdate() tea.Cmd {
- var depsToUpdate []deps.Dependency
-
- for _, depInfo := range m.updateDeps {
- if m.updateToggles[depInfo.Name] {
- depsToUpdate = append(depsToUpdate, deps.Dependency{
- Name: depInfo.Name,
- Status: depInfo.Status,
- Description: depInfo.Description,
- Required: depInfo.Required,
- })
- }
- }
-
- if len(depsToUpdate) == 0 {
- return func() tea.Msg {
- return updateCompleteMsg{err: nil}
- }
- }
-
- wm := deps.WindowManagerHyprland
- if m.niriInstalled {
- wm = deps.WindowManagerNiri
- }
-
- sudoPassword := m.sudoPassword
- reinstallFlags := make(map[string]bool)
- for name, toggled := range m.updateToggles {
- if toggled {
- reinstallFlags[name] = true
- }
- }
-
- distribution := m.detector.GetDistribution()
- progressChan := m.updateProgressChan
-
- return func() tea.Msg {
- installerChan := make(chan distros.InstallProgressMsg, 100)
-
- go func() {
- ctx := context.Background()
- err := distribution.InstallPackages(ctx, depsToUpdate, wm, sudoPassword, reinstallFlags, installerChan)
- close(installerChan)
-
- if err != nil {
- progressChan <- updateProgressMsg{complete: true, err: err}
- } else {
- progressChan <- updateProgressMsg{complete: true}
- }
- }()
-
- go func() {
- for msg := range installerChan {
- progressChan <- updateProgressMsg{
- progress: msg.Progress,
- step: msg.Step,
- complete: msg.IsComplete,
- err: msg.Error,
- logOutput: msg.LogOutput,
- }
- }
- }()
-
- return nil
- }
-}
-
-func (m Model) updateGreeterMenu(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- greeterMenuItems := []string{"Install Greeter"}
-
- switch msg.String() {
- case "ctrl+c", "q":
- return m, tea.Quit
- case "esc":
- m.state = StateMainMenu
- case "up", "k":
- if m.selectedGreeterItem > 0 {
- m.selectedGreeterItem--
- }
- case "down", "j":
- if m.selectedGreeterItem < len(greeterMenuItems)-1 {
- m.selectedGreeterItem++
- }
- case "enter", " ":
- if m.selectedGreeterItem == 0 {
- compositors := greeter.DetectCompositors()
- if len(compositors) == 0 {
- return m, nil
- }
-
- m.greeterCompositors = compositors
-
- if len(compositors) > 1 {
- m.state = StateGreeterCompositorSelect
- m.greeterSelectedComp = 0
- return m, nil
- } else {
- m.greeterChosenCompositor = compositors[0]
- m.state = StateGreeterPassword
- m.greeterPasswordInput = ""
- m.greeterPasswordError = ""
- return m, nil
- }
- }
- }
- return m, nil
-}
-
-func (m Model) updateGreeterCompositorSelect(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- switch msg.String() {
- case "ctrl+c", "q":
- return m, tea.Quit
- case "esc":
- m.state = StateGreeterMenu
- return m, nil
- case "up", "k":
- if m.greeterSelectedComp > 0 {
- m.greeterSelectedComp--
- }
- case "down", "j":
- if m.greeterSelectedComp < len(m.greeterCompositors)-1 {
- m.greeterSelectedComp++
- }
- case "enter", " ":
- m.greeterChosenCompositor = m.greeterCompositors[m.greeterSelectedComp]
- m.state = StateGreeterPassword
- m.greeterPasswordInput = ""
- m.greeterPasswordError = ""
- return m, nil
- }
- return m, nil
-}
-
-func (m Model) updateGreeterPasswordView(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- switch msg.String() {
- case "ctrl+c":
- return m, tea.Quit
- case "esc":
- m.state = StateGreeterMenu
- m.greeterPasswordInput = ""
- m.greeterPasswordError = ""
- return m, nil
- case "enter":
- if m.greeterPasswordInput == "" {
- return m, nil
- }
- return m, m.validateGreeterPassword(m.greeterPasswordInput)
- case "backspace":
- if len(m.greeterPasswordInput) > 0 {
- m.greeterPasswordInput = m.greeterPasswordInput[:len(m.greeterPasswordInput)-1]
- }
- default:
- if len(msg.String()) == 1 && msg.String()[0] >= 32 && msg.String()[0] <= 126 {
- m.greeterPasswordInput += msg.String()
- }
- }
- return m, nil
-}
-
-func (m Model) updateGreeterInstalling(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- switch msg.String() {
- case "ctrl+c", "q":
- return m, tea.Quit
- case "esc":
- if m.greeterProgress.complete {
- m.state = StateMainMenu
- m.greeterProgress = greeterProgressMsg{}
- m.greeterLogs = []string{}
- }
- }
- return m, nil
-}
-
-func (m Model) performGreeterInstall() tea.Cmd {
- progressChan := m.greeterInstallChan
- sudoPassword := m.greeterSudoPassword
- compositor := m.greeterChosenCompositor
-
- return func() tea.Msg {
- go func() {
- logFunc := func(msg string) {
- progressChan <- greeterProgressMsg{step: msg, logOutput: msg}
- }
-
- progressChan <- greeterProgressMsg{step: "Checking greetd installation..."}
- if err := performGreeterInstallSteps(progressChan, logFunc, sudoPassword, compositor); err != nil {
- progressChan <- greeterProgressMsg{step: "Installation failed", complete: true, err: err}
- return
- }
-
- progressChan <- greeterProgressMsg{step: "Installation complete", complete: true}
- }()
- return nil
- }
-}
-
-func (m Model) validateGreeterPassword(password string) tea.Cmd {
- return func() tea.Msg {
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- defer cancel()
-
- cmd := exec.CommandContext(ctx, "sudo", "-S", "-v")
- stdin, err := cmd.StdinPipe()
- if err != nil {
- return greeterPasswordValidMsg{password: "", valid: false}
- }
-
- go func() {
- defer stdin.Close()
- fmt.Fprintf(stdin, "%s\n", password)
- }()
-
- output, err := cmd.CombinedOutput()
- outputStr := string(output)
-
- if err != nil {
- if strings.Contains(outputStr, "Sorry, try again") ||
- strings.Contains(outputStr, "incorrect password") ||
- strings.Contains(outputStr, "authentication failure") {
- return greeterPasswordValidMsg{password: "", valid: false}
- }
- return greeterPasswordValidMsg{password: "", valid: false}
- }
-
- return greeterPasswordValidMsg{password: password, valid: true}
- }
-}
-
-func performGreeterInstallSteps(progressChan chan greeterProgressMsg, logFunc func(string), sudoPassword string, compositor string) error {
- if err := greeter.EnsureGreetdInstalled(logFunc, sudoPassword); err != nil {
- return err
- }
-
- progressChan <- greeterProgressMsg{step: "Detecting DMS installation..."}
- dmsPath, err := greeter.DetectDMSPath()
- if err != nil {
- return err
- }
- logFunc(fmt.Sprintf("✓ Found DMS at: %s", dmsPath))
-
- logFunc(fmt.Sprintf("✓ Selected compositor: %s", compositor))
-
- progressChan <- greeterProgressMsg{step: "Copying greeter files..."}
- if err := greeter.CopyGreeterFiles(dmsPath, compositor, logFunc, sudoPassword); err != nil {
- return err
- }
-
- progressChan <- greeterProgressMsg{step: "Configuring greetd..."}
- if err := greeter.ConfigureGreetd(dmsPath, compositor, logFunc, sudoPassword); err != nil {
- return err
- }
-
- progressChan <- greeterProgressMsg{step: "Synchronizing DMS configurations..."}
- if err := greeter.SyncDMSConfigs(dmsPath, logFunc, sudoPassword); err != nil {
- return err
- }
-
- return nil
-}
diff --git a/nix/inputs/dms-cli/internal/dms/handlers_mainmenu.go b/nix/inputs/dms-cli/internal/dms/handlers_mainmenu.go
deleted file mode 100644
index 6a2b941..0000000
--- a/nix/inputs/dms-cli/internal/dms/handlers_mainmenu.go
+++ /dev/null
@@ -1,61 +0,0 @@
-//go:build !distro_binary
-
-package dms
-
-import (
- "time"
-
- tea "github.com/charmbracelet/bubbletea"
-)
-
-type shellStartedMsg struct{}
-
-func (m Model) updateMainMenu(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- switch msg.String() {
- case "ctrl+c", "q", "esc":
- return m, tea.Quit
- case "up", "k":
- if m.selectedItem > 0 {
- m.selectedItem--
- }
- case "down", "j":
- if m.selectedItem < len(m.menuItems)-1 {
- m.selectedItem++
- }
- case "enter", " ":
- if m.selectedItem < len(m.menuItems) {
- selectedAction := m.menuItems[m.selectedItem].Action
- selectedLabel := m.menuItems[m.selectedItem].Label
-
- switch selectedAction {
- case StateUpdate:
- m.state = StateUpdate
- m.selectedUpdateDep = 0
- case StateShell:
- if selectedLabel == "Terminate Shell" {
- terminateShell()
- m.menuItems = m.buildMenuItems()
- if m.selectedItem >= len(m.menuItems) {
- m.selectedItem = len(m.menuItems) - 1
- }
- } else {
- startShellDaemon()
- // Wait a moment for the daemon to actually start before checking status
- return m, tea.Tick(300*time.Millisecond, func(t time.Time) tea.Msg {
- return shellStartedMsg{}
- })
- }
- case StatePluginsMenu:
- m.state = StatePluginsMenu
- m.selectedPluginsMenuItem = 0
- m.pluginsMenuItems = m.buildPluginsMenuItems()
- case StateGreeterMenu:
- m.state = StateGreeterMenu
- m.selectedGreeterItem = 0
- case StateAbout:
- m.state = StateAbout
- }
- }
- }
- return m, nil
-}
diff --git a/nix/inputs/dms-cli/internal/dms/handlers_mainmenu_distro.go b/nix/inputs/dms-cli/internal/dms/handlers_mainmenu_distro.go
deleted file mode 100644
index a2b2190..0000000
--- a/nix/inputs/dms-cli/internal/dms/handlers_mainmenu_distro.go
+++ /dev/null
@@ -1,55 +0,0 @@
-//go:build distro_binary
-
-package dms
-
-import (
- "time"
-
- tea "github.com/charmbracelet/bubbletea"
-)
-
-type shellStartedMsg struct{}
-
-func (m Model) updateMainMenu(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- switch msg.String() {
- case "ctrl+c", "q", "esc":
- return m, tea.Quit
- case "up", "k":
- if m.selectedItem > 0 {
- m.selectedItem--
- }
- case "down", "j":
- if m.selectedItem < len(m.menuItems)-1 {
- m.selectedItem++
- }
- case "enter", " ":
- if m.selectedItem < len(m.menuItems) {
- selectedAction := m.menuItems[m.selectedItem].Action
- selectedLabel := m.menuItems[m.selectedItem].Label
-
- switch selectedAction {
- case StateShell:
- if selectedLabel == "Terminate Shell" {
- terminateShell()
- m.menuItems = m.buildMenuItems()
- if m.selectedItem >= len(m.menuItems) {
- m.selectedItem = len(m.menuItems) - 1
- }
- } else {
- startShellDaemon()
- // Wait a moment for the daemon to actually start before checking status
- return m, tea.Tick(300*time.Millisecond, func(t time.Time) tea.Msg {
- return shellStartedMsg{}
- })
- }
- case StatePluginsMenu:
- m.state = StatePluginsMenu
- m.selectedPluginsMenuItem = 0
- m.pluginsMenuItems = m.buildPluginsMenuItems()
- case StateAbout:
- m.state = StateAbout
- }
- }
- }
- return m, nil
-}
diff --git a/nix/inputs/dms-cli/internal/dms/plugins_handlers.go b/nix/inputs/dms-cli/internal/dms/plugins_handlers.go
deleted file mode 100644
index 1b3132b..0000000
--- a/nix/inputs/dms-cli/internal/dms/plugins_handlers.go
+++ /dev/null
@@ -1,339 +0,0 @@
-package dms
-
-import (
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/plugins"
- tea "github.com/charmbracelet/bubbletea"
-)
-
-func (m Model) updatePluginsMenu(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- switch msg.String() {
- case "ctrl+c", "q":
- return m, tea.Quit
- case "esc":
- m.state = StateMainMenu
- case "up", "k":
- if m.selectedPluginsMenuItem > 0 {
- m.selectedPluginsMenuItem--
- }
- case "down", "j":
- if m.selectedPluginsMenuItem < len(m.pluginsMenuItems)-1 {
- m.selectedPluginsMenuItem++
- }
- case "enter", " ":
- if m.selectedPluginsMenuItem < len(m.pluginsMenuItems) {
- selectedAction := m.pluginsMenuItems[m.selectedPluginsMenuItem].Action
- switch selectedAction {
- case StatePluginsBrowse:
- m.state = StatePluginsBrowse
- m.pluginsLoading = true
- m.pluginsError = ""
- m.pluginsList = nil
- return m, loadPlugins
- case StatePluginsInstalled:
- m.state = StatePluginsInstalled
- m.installedPluginsLoading = true
- m.installedPluginsError = ""
- m.installedPluginsList = nil
- return m, loadInstalledPlugins
- }
- }
- }
- return m, nil
-}
-
-func (m Model) updatePluginsBrowse(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- switch msg.String() {
- case "ctrl+c", "q":
- return m, tea.Quit
- case "esc":
- m.state = StatePluginsMenu
- m.pluginSearchQuery = ""
- m.filteredPluginsList = m.pluginsList
- m.selectedPluginIndex = 0
- case "up", "k":
- if m.selectedPluginIndex > 0 {
- m.selectedPluginIndex--
- }
- case "down", "j":
- if m.selectedPluginIndex < len(m.filteredPluginsList)-1 {
- m.selectedPluginIndex++
- }
- case "enter", " ":
- if m.selectedPluginIndex < len(m.filteredPluginsList) {
- m.state = StatePluginDetail
- }
- case "/":
- m.state = StatePluginSearch
- m.pluginSearchQuery = ""
- }
- return m, nil
-}
-
-func (m Model) updatePluginDetail(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- switch msg.String() {
- case "ctrl+c", "q":
- return m, tea.Quit
- case "esc":
- m.state = StatePluginsBrowse
- case "i":
- if m.selectedPluginIndex < len(m.filteredPluginsList) {
- plugin := m.filteredPluginsList[m.selectedPluginIndex]
- installed := m.pluginInstallStatus[plugin.Name]
- if !installed {
- return m, installPlugin(plugin)
- }
- }
- }
- return m, nil
-}
-
-func (m Model) updatePluginSearch(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- switch msg.String() {
- case "ctrl+c":
- return m, tea.Quit
- case "esc":
- m.state = StatePluginsBrowse
- m.pluginSearchQuery = ""
- m.filteredPluginsList = m.pluginsList
- m.selectedPluginIndex = 0
- case "enter":
- m.state = StatePluginsBrowse
- m.filterPlugins()
- case "backspace":
- if len(m.pluginSearchQuery) > 0 {
- m.pluginSearchQuery = m.pluginSearchQuery[:len(m.pluginSearchQuery)-1]
- }
- default:
- if len(msg.String()) == 1 {
- m.pluginSearchQuery += msg.String()
- }
- }
- return m, nil
-}
-
-func (m *Model) filterPlugins() {
- if m.pluginSearchQuery == "" {
- m.filteredPluginsList = m.pluginsList
- m.selectedPluginIndex = 0
- return
- }
-
- rawPlugins := make([]plugins.Plugin, len(m.pluginsList))
- for i, p := range m.pluginsList {
- rawPlugins[i] = plugins.Plugin{
- ID: p.ID,
- Name: p.Name,
- Category: p.Category,
- Author: p.Author,
- Description: p.Description,
- Repo: p.Repo,
- Path: p.Path,
- Capabilities: p.Capabilities,
- Compositors: p.Compositors,
- Dependencies: p.Dependencies,
- }
- }
-
- searchResults := plugins.FuzzySearch(m.pluginSearchQuery, rawPlugins)
- searchResults = plugins.SortByFirstParty(searchResults)
-
- filtered := make([]pluginInfo, len(searchResults))
- for i, p := range searchResults {
- filtered[i] = pluginInfo{
- ID: p.ID,
- Name: p.Name,
- Category: p.Category,
- Author: p.Author,
- Description: p.Description,
- Repo: p.Repo,
- Path: p.Path,
- Capabilities: p.Capabilities,
- Compositors: p.Compositors,
- Dependencies: p.Dependencies,
- FirstParty: strings.HasPrefix(p.Repo, "https://github.com/AvengeMedia"),
- }
- }
-
- m.filteredPluginsList = filtered
- m.selectedPluginIndex = 0
-}
-
-type pluginsLoadedMsg struct {
- plugins []plugins.Plugin
- err error
-}
-
-func loadPlugins() tea.Msg {
- registry, err := plugins.NewRegistry()
- if err != nil {
- return pluginsLoadedMsg{err: err}
- }
-
- pluginList, err := registry.List()
- if err != nil {
- return pluginsLoadedMsg{err: err}
- }
-
- return pluginsLoadedMsg{plugins: pluginList}
-}
-
-func (m *Model) updatePluginInstallStatus() {
- manager, err := plugins.NewManager()
- if err != nil {
- return
- }
-
- for _, plugin := range m.pluginsList {
- p := plugins.Plugin{ID: plugin.ID}
- installed, err := manager.IsInstalled(p)
- if err == nil {
- m.pluginInstallStatus[plugin.Name] = installed
- }
- }
-}
-
-func (m Model) updatePluginsInstalled(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- switch msg.String() {
- case "ctrl+c", "q":
- return m, tea.Quit
- case "esc":
- m.state = StatePluginsMenu
- case "up", "k":
- if m.selectedInstalledIndex > 0 {
- m.selectedInstalledIndex--
- }
- case "down", "j":
- if m.selectedInstalledIndex < len(m.installedPluginsList)-1 {
- m.selectedInstalledIndex++
- }
- case "enter", " ":
- if m.selectedInstalledIndex < len(m.installedPluginsList) {
- m.state = StatePluginInstalledDetail
- }
- }
- return m, nil
-}
-
-func (m Model) updatePluginInstalledDetail(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
- switch msg.String() {
- case "ctrl+c", "q":
- return m, tea.Quit
- case "esc":
- m.state = StatePluginsInstalled
- case "u":
- if m.selectedInstalledIndex < len(m.installedPluginsList) {
- plugin := m.installedPluginsList[m.selectedInstalledIndex]
- return m, uninstallPlugin(plugin)
- }
- }
- return m, nil
-}
-
-type installedPluginsLoadedMsg struct {
- plugins []plugins.Plugin
- err error
-}
-
-type pluginUninstalledMsg struct {
- pluginName string
- err error
-}
-
-type pluginInstalledMsg struct {
- pluginName string
- err error
-}
-
-func loadInstalledPlugins() tea.Msg {
- manager, err := plugins.NewManager()
- if err != nil {
- return installedPluginsLoadedMsg{err: err}
- }
-
- registry, err := plugins.NewRegistry()
- if err != nil {
- return installedPluginsLoadedMsg{err: err}
- }
-
- installedNames, err := manager.ListInstalled()
- if err != nil {
- return installedPluginsLoadedMsg{err: err}
- }
-
- allPlugins, err := registry.List()
- if err != nil {
- return installedPluginsLoadedMsg{err: err}
- }
-
- var installed []plugins.Plugin
- for _, id := range installedNames {
- for _, p := range allPlugins {
- if p.ID == id {
- installed = append(installed, p)
- break
- }
- }
- }
-
- installed = plugins.SortByFirstParty(installed)
-
- return installedPluginsLoadedMsg{plugins: installed}
-}
-
-func installPlugin(plugin pluginInfo) tea.Cmd {
- return func() tea.Msg {
- manager, err := plugins.NewManager()
- if err != nil {
- return pluginInstalledMsg{pluginName: plugin.Name, err: err}
- }
-
- p := plugins.Plugin{
- ID: plugin.ID,
- Name: plugin.Name,
- Category: plugin.Category,
- Author: plugin.Author,
- Description: plugin.Description,
- Repo: plugin.Repo,
- Path: plugin.Path,
- Capabilities: plugin.Capabilities,
- Compositors: plugin.Compositors,
- Dependencies: plugin.Dependencies,
- }
-
- if err := manager.Install(p); err != nil {
- return pluginInstalledMsg{pluginName: plugin.Name, err: err}
- }
-
- return pluginInstalledMsg{pluginName: plugin.Name}
- }
-}
-
-func uninstallPlugin(plugin pluginInfo) tea.Cmd {
- return func() tea.Msg {
- manager, err := plugins.NewManager()
- if err != nil {
- return pluginUninstalledMsg{pluginName: plugin.Name, err: err}
- }
-
- p := plugins.Plugin{
- ID: plugin.ID,
- Name: plugin.Name,
- Category: plugin.Category,
- Author: plugin.Author,
- Description: plugin.Description,
- Repo: plugin.Repo,
- Path: plugin.Path,
- Capabilities: plugin.Capabilities,
- Compositors: plugin.Compositors,
- Dependencies: plugin.Dependencies,
- }
-
- if err := manager.Uninstall(p); err != nil {
- return pluginUninstalledMsg{pluginName: plugin.Name, err: err}
- }
-
- return pluginUninstalledMsg{pluginName: plugin.Name}
- }
-}
diff --git a/nix/inputs/dms-cli/internal/dms/plugins_views.go b/nix/inputs/dms-cli/internal/dms/plugins_views.go
deleted file mode 100644
index cfcfe0e..0000000
--- a/nix/inputs/dms-cli/internal/dms/plugins_views.go
+++ /dev/null
@@ -1,367 +0,0 @@
-package dms
-
-import (
- "fmt"
- "strings"
-
- "github.com/charmbracelet/lipgloss"
-)
-
-func (m Model) renderPluginsMenu() string {
- var b strings.Builder
-
- titleStyle := lipgloss.NewStyle().
- Bold(true).
- Foreground(lipgloss.Color("#00D4AA"))
-
- normalStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF"))
-
- selectedStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#00D4AA")).
- Bold(true)
-
- b.WriteString(titleStyle.Render("Plugins"))
- b.WriteString("\n\n")
-
- for i, item := range m.pluginsMenuItems {
- if i == m.selectedPluginsMenuItem {
- b.WriteString(selectedStyle.Render(fmt.Sprintf("→ %s", item.Label)))
- } else {
- b.WriteString(normalStyle.Render(fmt.Sprintf(" %s", item.Label)))
- }
- b.WriteString("\n")
- }
-
- b.WriteString("\n")
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888"))
- b.WriteString(instructionStyle.Render("↑/↓: Navigate | Enter: Select | Esc: Back | q: Quit"))
-
- return b.String()
-}
-
-func (m Model) renderPluginsBrowse() string {
- var b strings.Builder
-
- titleStyle := lipgloss.NewStyle().
- Bold(true).
- Foreground(lipgloss.Color("#00D4AA"))
-
- normalStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF"))
-
- errorStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FF0000"))
-
- selectedStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#00D4AA")).
- Bold(true)
-
- b.WriteString(titleStyle.Render("Browse Plugins"))
- b.WriteString("\n\n")
-
- if m.pluginsLoading {
- b.WriteString(normalStyle.Render("Fetching plugins from registry..."))
- } else if m.pluginsError != "" {
- b.WriteString(errorStyle.Render(fmt.Sprintf("Error: %s", m.pluginsError)))
- } else if len(m.filteredPluginsList) == 0 {
- if m.pluginSearchQuery != "" {
- b.WriteString(normalStyle.Render(fmt.Sprintf("No plugins match '%s'", m.pluginSearchQuery)))
- } else {
- b.WriteString(normalStyle.Render("No plugins found in registry."))
- }
- } else {
- installedStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888"))
-
- for i, plugin := range m.filteredPluginsList {
- installed := m.pluginInstallStatus[plugin.Name]
- installMarker := ""
- if installed {
- installMarker = " [Installed]"
- }
-
- if i == m.selectedPluginIndex {
- b.WriteString(selectedStyle.Render(fmt.Sprintf("→ %s", plugin.Name)))
- if installed {
- b.WriteString(installedStyle.Render(installMarker))
- }
- } else {
- b.WriteString(normalStyle.Render(fmt.Sprintf(" %s", plugin.Name)))
- if installed {
- b.WriteString(installedStyle.Render(installMarker))
- }
- }
- b.WriteString("\n")
- }
- }
-
- b.WriteString("\n")
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888"))
-
- if m.pluginsLoading || m.pluginsError != "" {
- b.WriteString(instructionStyle.Render("Esc: Back | q: Quit"))
- } else {
- b.WriteString(instructionStyle.Render("↑/↓: Navigate | Enter: View/Install | /: Search | Esc: Back | q: Quit"))
- }
-
- return b.String()
-}
-
-func (m Model) renderPluginDetail() string {
- var b strings.Builder
-
- titleStyle := lipgloss.NewStyle().
- Bold(true).
- Foreground(lipgloss.Color("#00D4AA"))
-
- normalStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF"))
-
- labelStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888"))
-
- if m.selectedPluginIndex >= len(m.filteredPluginsList) {
- return "No plugin selected"
- }
-
- plugin := m.filteredPluginsList[m.selectedPluginIndex]
-
- b.WriteString(titleStyle.Render(plugin.Name))
- b.WriteString("\n\n")
-
- b.WriteString(labelStyle.Render("ID: "))
- b.WriteString(normalStyle.Render(plugin.ID))
- b.WriteString("\n\n")
-
- b.WriteString(labelStyle.Render("Category: "))
- b.WriteString(normalStyle.Render(plugin.Category))
- b.WriteString("\n\n")
-
- b.WriteString(labelStyle.Render("Author: "))
- b.WriteString(normalStyle.Render(plugin.Author))
- b.WriteString("\n\n")
-
- b.WriteString(labelStyle.Render("Description:"))
- b.WriteString("\n")
- wrapped := wrapText(plugin.Description, 60)
- b.WriteString(normalStyle.Render(wrapped))
- b.WriteString("\n\n")
-
- b.WriteString(labelStyle.Render("Repository: "))
- b.WriteString(normalStyle.Render(plugin.Repo))
- b.WriteString("\n\n")
-
- if len(plugin.Capabilities) > 0 {
- b.WriteString(labelStyle.Render("Capabilities: "))
- b.WriteString(normalStyle.Render(strings.Join(plugin.Capabilities, ", ")))
- b.WriteString("\n\n")
- }
-
- if len(plugin.Compositors) > 0 {
- b.WriteString(labelStyle.Render("Compositors: "))
- b.WriteString(normalStyle.Render(strings.Join(plugin.Compositors, ", ")))
- b.WriteString("\n\n")
- }
-
- if len(plugin.Dependencies) > 0 {
- b.WriteString(labelStyle.Render("Dependencies: "))
- b.WriteString(normalStyle.Render(strings.Join(plugin.Dependencies, ", ")))
- b.WriteString("\n\n")
- }
-
- installed := m.pluginInstallStatus[plugin.Name]
- if installed {
- b.WriteString(labelStyle.Render("Status: "))
- installedStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#00D4AA"))
- b.WriteString(installedStyle.Render("Installed"))
- b.WriteString("\n\n")
- }
-
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888"))
-
- if installed {
- b.WriteString(instructionStyle.Render("Esc: Back | q: Quit"))
- } else {
- b.WriteString(instructionStyle.Render("i: Install | Esc: Back | q: Quit"))
- }
-
- return b.String()
-}
-
-func (m Model) renderPluginSearch() string {
- var b strings.Builder
-
- titleStyle := lipgloss.NewStyle().
- Bold(true).
- Foreground(lipgloss.Color("#00D4AA"))
-
- normalStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF"))
-
- b.WriteString(titleStyle.Render("Search Plugins"))
- b.WriteString("\n\n")
-
- b.WriteString(normalStyle.Render("Query: "))
- b.WriteString(titleStyle.Render(m.pluginSearchQuery + "▌"))
- b.WriteString("\n\n")
-
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888"))
- b.WriteString(instructionStyle.Render("Enter: Search | Esc: Cancel"))
-
- return b.String()
-}
-
-func (m Model) renderPluginsInstalled() string {
- var b strings.Builder
-
- titleStyle := lipgloss.NewStyle().
- Bold(true).
- Foreground(lipgloss.Color("#00D4AA"))
-
- normalStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF"))
-
- errorStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FF0000"))
-
- selectedStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#00D4AA")).
- Bold(true)
-
- b.WriteString(titleStyle.Render("Installed Plugins"))
- b.WriteString("\n\n")
-
- if m.installedPluginsLoading {
- b.WriteString(normalStyle.Render("Loading installed plugins..."))
- } else if m.installedPluginsError != "" {
- b.WriteString(errorStyle.Render(fmt.Sprintf("Error: %s", m.installedPluginsError)))
- } else if len(m.installedPluginsList) == 0 {
- b.WriteString(normalStyle.Render("No plugins installed."))
- } else {
- for i, plugin := range m.installedPluginsList {
- if i == m.selectedInstalledIndex {
- b.WriteString(selectedStyle.Render(fmt.Sprintf("→ %s", plugin.Name)))
- } else {
- b.WriteString(normalStyle.Render(fmt.Sprintf(" %s", plugin.Name)))
- }
- b.WriteString("\n")
- }
- }
-
- b.WriteString("\n")
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888"))
-
- if m.installedPluginsLoading || m.installedPluginsError != "" {
- b.WriteString(instructionStyle.Render("Esc: Back | q: Quit"))
- } else {
- b.WriteString(instructionStyle.Render("↑/↓: Navigate | Enter: Details | Esc: Back | q: Quit"))
- }
-
- return b.String()
-}
-
-func (m Model) renderPluginInstalledDetail() string {
- var b strings.Builder
-
- titleStyle := lipgloss.NewStyle().
- Bold(true).
- Foreground(lipgloss.Color("#00D4AA"))
-
- normalStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF"))
-
- labelStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888"))
-
- errorStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FF0000"))
-
- if m.selectedInstalledIndex >= len(m.installedPluginsList) {
- return "No plugin selected"
- }
-
- plugin := m.installedPluginsList[m.selectedInstalledIndex]
-
- b.WriteString(titleStyle.Render(plugin.Name))
- b.WriteString("\n\n")
-
- b.WriteString(labelStyle.Render("ID: "))
- b.WriteString(normalStyle.Render(plugin.ID))
- b.WriteString("\n\n")
-
- b.WriteString(labelStyle.Render("Category: "))
- b.WriteString(normalStyle.Render(plugin.Category))
- b.WriteString("\n\n")
-
- b.WriteString(labelStyle.Render("Author: "))
- b.WriteString(normalStyle.Render(plugin.Author))
- b.WriteString("\n\n")
-
- b.WriteString(labelStyle.Render("Description:"))
- b.WriteString("\n")
- wrapped := wrapText(plugin.Description, 60)
- b.WriteString(normalStyle.Render(wrapped))
- b.WriteString("\n\n")
-
- b.WriteString(labelStyle.Render("Repository: "))
- b.WriteString(normalStyle.Render(plugin.Repo))
- b.WriteString("\n\n")
-
- if len(plugin.Capabilities) > 0 {
- b.WriteString(labelStyle.Render("Capabilities: "))
- b.WriteString(normalStyle.Render(strings.Join(plugin.Capabilities, ", ")))
- b.WriteString("\n\n")
- }
-
- if len(plugin.Compositors) > 0 {
- b.WriteString(labelStyle.Render("Compositors: "))
- b.WriteString(normalStyle.Render(strings.Join(plugin.Compositors, ", ")))
- b.WriteString("\n\n")
- }
-
- if len(plugin.Dependencies) > 0 {
- b.WriteString(labelStyle.Render("Dependencies: "))
- b.WriteString(normalStyle.Render(strings.Join(plugin.Dependencies, ", ")))
- b.WriteString("\n\n")
- }
-
- if m.installedPluginsError != "" {
- b.WriteString(errorStyle.Render(fmt.Sprintf("Error: %s", m.installedPluginsError)))
- b.WriteString("\n\n")
- }
-
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888"))
- b.WriteString(instructionStyle.Render("u: Uninstall | Esc: Back | q: Quit"))
-
- return b.String()
-}
-
-func wrapText(text string, width int) string {
- words := strings.Fields(text)
- if len(words) == 0 {
- return text
- }
-
- var lines []string
- currentLine := words[0]
-
- for _, word := range words[1:] {
- if len(currentLine)+1+len(word) <= width {
- currentLine += " " + word
- } else {
- lines = append(lines, currentLine)
- currentLine = word
- }
- }
- lines = append(lines, currentLine)
-
- return strings.Join(lines, "\n")
-}
diff --git a/nix/inputs/dms-cli/internal/dms/views_common.go b/nix/inputs/dms-cli/internal/dms/views_common.go
deleted file mode 100644
index 9dba99b..0000000
--- a/nix/inputs/dms-cli/internal/dms/views_common.go
+++ /dev/null
@@ -1,149 +0,0 @@
-package dms
-
-import (
- "fmt"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/tui"
- "github.com/charmbracelet/lipgloss"
-)
-
-func (m Model) renderMainMenu() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- headerStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF")).
- Bold(true).
- MarginBottom(1)
-
- b.WriteString(headerStyle.Render("dms"))
- b.WriteString("\n")
-
- selectedStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#00D4AA")).
- Bold(true)
-
- normalStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF"))
-
- for i, item := range m.menuItems {
- if i == m.selectedItem {
- b.WriteString(selectedStyle.Render(fmt.Sprintf("▶ %s", item.Label)))
- } else {
- b.WriteString(normalStyle.Render(fmt.Sprintf(" %s", item.Label)))
- }
- b.WriteString("\n")
- }
-
- b.WriteString("\n")
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888")).
- MarginTop(1)
-
- instructions := "↑/↓: Navigate, Enter: Select, q/Esc: Exit"
- b.WriteString(instructionStyle.Render(instructions))
-
- return b.String()
-}
-
-func (m Model) renderShellView() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- headerStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF")).
- Bold(true).
- MarginBottom(1)
-
- b.WriteString(headerStyle.Render("Shell"))
- b.WriteString("\n\n")
-
- normalStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF"))
-
- b.WriteString(normalStyle.Render("Opening interactive shell..."))
- b.WriteString("\n")
- b.WriteString(normalStyle.Render("This will launch a shell with DMS environment loaded."))
- b.WriteString("\n\n")
-
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888")).
- MarginTop(1)
-
- instructions := "Press any key to launch shell, Esc: Back"
- b.WriteString(instructionStyle.Render(instructions))
-
- return b.String()
-}
-
-func (m Model) renderAboutView() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- headerStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF")).
- Bold(true).
- MarginBottom(1)
-
- b.WriteString(headerStyle.Render("About DankMaterialShell"))
- b.WriteString("\n\n")
-
- normalStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF"))
-
- b.WriteString(normalStyle.Render(fmt.Sprintf("DMS Management Interface %s", m.version)))
- b.WriteString("\n\n")
- b.WriteString(normalStyle.Render("DankMaterialShell is a comprehensive desktop environment"))
- b.WriteString("\n")
- b.WriteString(normalStyle.Render("built around Quickshell, providing a modern Material Design"))
- b.WriteString("\n")
- b.WriteString(normalStyle.Render("experience for Wayland compositors."))
- b.WriteString("\n\n")
-
- b.WriteString(normalStyle.Render("Components:"))
- b.WriteString("\n")
- for _, dep := range m.dependencies {
- status := "✗"
- if dep.Status == 1 {
- status = "✓"
- }
- b.WriteString(normalStyle.Render(fmt.Sprintf(" %s %s", status, dep.Name)))
- b.WriteString("\n")
- }
-
- b.WriteString("\n")
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888")).
- MarginTop(1)
-
- instructions := "Esc: Back to main menu"
- b.WriteString(instructionStyle.Render(instructions))
-
- return b.String()
-}
-
-func (m Model) renderBanner() string {
- theme := tui.TerminalTheme()
-
- logo := `
-██████╗ █████╗ ███╗ ██╗██╗ ██╗
-██╔══██╗██╔══██╗████╗ ██║██║ ██╔╝
-██║ ██║███████║██╔██╗ ██║█████╔╝
-██║ ██║██╔══██║██║╚██╗██║██╔═██╗
-██████╔╝██║ ██║██║ ╚████║██║ ██╗
-╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝`
-
- titleStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)).
- Bold(true).
- MarginBottom(1)
-
- return titleStyle.Render(logo)
-}
diff --git a/nix/inputs/dms-cli/internal/dms/views_features.go b/nix/inputs/dms-cli/internal/dms/views_features.go
deleted file mode 100644
index eda4da6..0000000
--- a/nix/inputs/dms-cli/internal/dms/views_features.go
+++ /dev/null
@@ -1,529 +0,0 @@
-//go:build !distro_binary
-
-package dms
-
-import (
- "fmt"
- "strings"
-
- "github.com/charmbracelet/lipgloss"
-)
-
-func (m Model) renderUpdateView() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- headerStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF")).
- Bold(true).
- MarginBottom(1)
-
- b.WriteString(headerStyle.Render("Update Dependencies"))
- b.WriteString("\n")
-
- if len(m.updateDeps) == 0 {
- b.WriteString("Loading dependencies...\n")
- return b.String()
- }
-
- categories := m.categorizeDependencies()
- currentIndex := 0
-
- for _, category := range []string{"Shell", "Shared Components", "Hyprland Components", "Niri Components"} {
- deps, exists := categories[category]
- if !exists || len(deps) == 0 {
- continue
- }
-
- categoryStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#7060ac")).
- Bold(true).
- MarginTop(1)
-
- b.WriteString(categoryStyle.Render(category + ":"))
- b.WriteString("\n")
-
- for _, dep := range deps {
- var statusText, icon, reinstallMarker string
- var style lipgloss.Style
-
- if m.updateToggles[dep.Name] {
- reinstallMarker = "🔄 "
- if dep.Status == 0 {
- statusText = "Will be installed"
- } else {
- statusText = "Will be upgraded"
- }
- style = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFA500"))
- } else {
- switch dep.Status {
- case 1:
- icon = "✓"
- statusText = "Installed"
- style = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFFFFF"))
- case 0:
- icon = "○"
- statusText = "Not installed"
- style = lipgloss.NewStyle().Foreground(lipgloss.Color("#888888"))
- case 2:
- icon = "△"
- statusText = "Needs update"
- style = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFA500"))
- case 3:
- icon = "!"
- statusText = "Needs reinstall"
- style = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFA500"))
- }
- }
-
- line := fmt.Sprintf("%s%s%-25s %s", reinstallMarker, icon, dep.Name, statusText)
-
- if currentIndex == m.selectedUpdateDep {
- line = "▶ " + line
- selectedStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#7060ac")).Bold(true)
- b.WriteString(selectedStyle.Render(line))
- } else {
- line = " " + line
- b.WriteString(style.Render(line))
- }
- b.WriteString("\n")
- currentIndex++
- }
- }
-
- b.WriteString("\n")
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888")).
- MarginTop(1)
-
- instructions := "↑/↓: Navigate, Space: Toggle, Enter: Update Selected, Esc: Back"
- b.WriteString(instructionStyle.Render(instructions))
-
- return b.String()
-}
-
-func (m Model) renderPasswordView() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- headerStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF")).
- Bold(true).
- MarginBottom(1)
-
- b.WriteString(headerStyle.Render("Sudo Authentication"))
- b.WriteString("\n\n")
-
- normalStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF"))
-
- b.WriteString(normalStyle.Render("Package installation requires sudo privileges."))
- b.WriteString("\n")
- b.WriteString(normalStyle.Render("Please enter your password to continue:"))
- b.WriteString("\n\n")
-
- inputStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#00D4AA"))
-
- maskedPassword := strings.Repeat("*", len(m.passwordInput))
- b.WriteString(inputStyle.Render("Password: " + maskedPassword))
- b.WriteString("\n")
-
- if m.passwordError != "" {
- errorStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FF0000"))
- b.WriteString(errorStyle.Render("✗ " + m.passwordError))
- b.WriteString("\n")
- }
-
- b.WriteString("\n")
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888")).
- MarginTop(1)
-
- instructions := "Enter: Continue, Esc: Back, Ctrl+C: Cancel"
- b.WriteString(instructionStyle.Render(instructions))
-
- return b.String()
-}
-
-func (m Model) renderProgressView() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- headerStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF")).
- Bold(true).
- MarginBottom(1)
-
- b.WriteString(headerStyle.Render("Updating Packages"))
- b.WriteString("\n\n")
-
- if !m.updateProgress.complete {
- progressStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#00D4AA"))
-
- b.WriteString(progressStyle.Render(m.updateProgress.step))
- b.WriteString("\n\n")
-
- progressBar := fmt.Sprintf("[%s%s] %.0f%%",
- strings.Repeat("█", int(m.updateProgress.progress*30)),
- strings.Repeat("░", 30-int(m.updateProgress.progress*30)),
- m.updateProgress.progress*100)
- b.WriteString(lipgloss.NewStyle().Foreground(lipgloss.Color("#FFFFFF")).Render(progressBar))
- b.WriteString("\n")
-
- if len(m.updateLogs) > 0 {
- b.WriteString("\n")
- logHeader := lipgloss.NewStyle().Foreground(lipgloss.Color("#888888")).Render("Live Output:")
- b.WriteString(logHeader)
- b.WriteString("\n")
-
- maxLines := 8
- startIdx := 0
- if len(m.updateLogs) > maxLines {
- startIdx = len(m.updateLogs) - maxLines
- }
-
- logStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#888888"))
- for i := startIdx; i < len(m.updateLogs); i++ {
- if m.updateLogs[i] != "" {
- b.WriteString(logStyle.Render(" " + m.updateLogs[i]))
- b.WriteString("\n")
- }
- }
- }
- }
-
- if m.updateProgress.err != nil {
- errorStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FF0000"))
-
- b.WriteString("\n")
- b.WriteString(errorStyle.Render(fmt.Sprintf("✗ Update failed: %v", m.updateProgress.err)))
- b.WriteString("\n")
-
- if len(m.updateLogs) > 0 {
- b.WriteString("\n")
- logHeader := lipgloss.NewStyle().Foreground(lipgloss.Color("#888888")).Render("Error Logs:")
- b.WriteString(logHeader)
- b.WriteString("\n")
-
- maxLines := 15
- startIdx := 0
- if len(m.updateLogs) > maxLines {
- startIdx = len(m.updateLogs) - maxLines
- }
-
- logStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#888888"))
- for i := startIdx; i < len(m.updateLogs); i++ {
- if m.updateLogs[i] != "" {
- b.WriteString(logStyle.Render(" " + m.updateLogs[i]))
- b.WriteString("\n")
- }
- }
- }
-
- b.WriteString("\n")
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888"))
- b.WriteString(instructionStyle.Render("Press Esc to go back"))
- } else if m.updateProgress.complete {
- successStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#00D4AA"))
-
- b.WriteString("\n")
- b.WriteString(successStyle.Render("✓ Update complete!"))
- b.WriteString("\n\n")
-
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888"))
- b.WriteString(instructionStyle.Render("Press Esc to return to main menu"))
- }
-
- return b.String()
-}
-
-func (m Model) getFilteredDeps() []DependencyInfo {
- categories := m.categorizeDependencies()
- var filtered []DependencyInfo
-
- for _, category := range []string{"Shell", "Shared Components", "Hyprland Components", "Niri Components"} {
- deps, exists := categories[category]
- if exists {
- filtered = append(filtered, deps...)
- }
- }
-
- return filtered
-}
-
-func (m Model) getDepAtVisualIndex(index int) *DependencyInfo {
- filtered := m.getFilteredDeps()
- if index >= 0 && index < len(filtered) {
- return &filtered[index]
- }
- return nil
-}
-
-func (m Model) renderGreeterPasswordView() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- headerStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF")).
- Bold(true).
- MarginBottom(1)
-
- b.WriteString(headerStyle.Render("Sudo Authentication"))
- b.WriteString("\n\n")
-
- normalStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF"))
-
- b.WriteString(normalStyle.Render("Greeter installation requires sudo privileges."))
- b.WriteString("\n")
- b.WriteString(normalStyle.Render("Please enter your password to continue:"))
- b.WriteString("\n\n")
-
- inputStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#00D4AA"))
-
- maskedPassword := strings.Repeat("*", len(m.greeterPasswordInput))
- b.WriteString(inputStyle.Render("Password: " + maskedPassword))
- b.WriteString("\n")
-
- if m.greeterPasswordError != "" {
- errorStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FF0000"))
- b.WriteString(errorStyle.Render("✗ " + m.greeterPasswordError))
- b.WriteString("\n")
- }
-
- b.WriteString("\n")
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888")).
- MarginTop(1)
-
- instructions := "Enter: Continue, Esc: Back, Ctrl+C: Cancel"
- b.WriteString(instructionStyle.Render(instructions))
-
- return b.String()
-}
-
-func (m Model) renderGreeterCompositorSelect() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- headerStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF")).
- Bold(true).
- MarginBottom(1)
-
- b.WriteString(headerStyle.Render("Select Compositor"))
- b.WriteString("\n\n")
-
- normalStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF"))
-
- b.WriteString(normalStyle.Render("Multiple compositors detected. Choose which one to use for the greeter:"))
- b.WriteString("\n\n")
-
- selectedStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#00D4AA")).
- Bold(true)
-
- for i, comp := range m.greeterCompositors {
- if i == m.greeterSelectedComp {
- b.WriteString(selectedStyle.Render(fmt.Sprintf("▶ %s", comp)))
- } else {
- b.WriteString(normalStyle.Render(fmt.Sprintf(" %s", comp)))
- }
- b.WriteString("\n")
- }
-
- b.WriteString("\n")
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888")).
- MarginTop(1)
-
- instructions := "↑/↓: Navigate, Enter: Select, Esc: Back"
- b.WriteString(instructionStyle.Render(instructions))
-
- return b.String()
-}
-
-func (m Model) renderGreeterMenu() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- headerStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF")).
- Bold(true).
- MarginBottom(1)
-
- b.WriteString(headerStyle.Render("Greeter Management"))
- b.WriteString("\n")
-
- greeterMenuItems := []string{"Install Greeter"}
-
- selectedStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#00D4AA")).
- Bold(true)
-
- normalStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF"))
-
- for i, item := range greeterMenuItems {
- if i == m.selectedGreeterItem {
- b.WriteString(selectedStyle.Render(fmt.Sprintf("▶ %s", item)))
- } else {
- b.WriteString(normalStyle.Render(fmt.Sprintf(" %s", item)))
- }
- b.WriteString("\n")
- }
-
- b.WriteString("\n")
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888")).
- MarginTop(1)
-
- instructions := "↑/↓: Navigate, Enter: Select, Esc: Back"
- b.WriteString(instructionStyle.Render(instructions))
-
- return b.String()
-}
-
-func (m Model) renderGreeterInstalling() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- headerStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF")).
- Bold(true).
- MarginBottom(1)
-
- b.WriteString(headerStyle.Render("Installing Greeter"))
- b.WriteString("\n\n")
-
- if !m.greeterProgress.complete {
- progressStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#00D4AA"))
-
- b.WriteString(progressStyle.Render(m.greeterProgress.step))
- b.WriteString("\n\n")
-
- if len(m.greeterLogs) > 0 {
- b.WriteString("\n")
- logHeader := lipgloss.NewStyle().Foreground(lipgloss.Color("#888888")).Render("Output:")
- b.WriteString(logHeader)
- b.WriteString("\n")
-
- maxLines := 10
- startIdx := 0
- if len(m.greeterLogs) > maxLines {
- startIdx = len(m.greeterLogs) - maxLines
- }
-
- logStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#888888"))
- for i := startIdx; i < len(m.greeterLogs); i++ {
- if m.greeterLogs[i] != "" {
- b.WriteString(logStyle.Render(" " + m.greeterLogs[i]))
- b.WriteString("\n")
- }
- }
- }
- }
-
- if m.greeterProgress.err != nil {
- errorStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FF0000"))
-
- b.WriteString("\n")
- b.WriteString(errorStyle.Render(fmt.Sprintf("✗ Installation failed: %v", m.greeterProgress.err)))
- b.WriteString("\n\n")
-
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888"))
- b.WriteString(instructionStyle.Render("Press Esc to go back"))
- } else if m.greeterProgress.complete {
- successStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#00D4AA"))
-
- b.WriteString("\n")
- b.WriteString(successStyle.Render("✓ Greeter installation complete!"))
- b.WriteString("\n\n")
-
- normalStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FFFFFF"))
-
- b.WriteString(normalStyle.Render("To test the greeter, run:"))
- b.WriteString("\n")
- b.WriteString(normalStyle.Render(" sudo systemctl start greetd"))
- b.WriteString("\n\n")
- b.WriteString(normalStyle.Render("To enable on boot, run:"))
- b.WriteString("\n")
- b.WriteString(normalStyle.Render(" sudo systemctl enable --now greetd"))
- b.WriteString("\n\n")
-
- instructionStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#888888"))
- b.WriteString(instructionStyle.Render("Press Esc to return to main menu"))
- }
-
- return b.String()
-}
-
-func (m Model) categorizeDependencies() map[string][]DependencyInfo {
- categories := map[string][]DependencyInfo{
- "Shell": {},
- "Shared Components": {},
- "Hyprland Components": {},
- "Niri Components": {},
- }
-
- excludeList := map[string]bool{
- "git": true,
- "polkit-agent": true,
- "jq": true,
- "xdg-desktop-portal": true,
- "xdg-desktop-portal-wlr": true,
- "xdg-desktop-portal-hyprland": true,
- "xdg-desktop-portal-gtk": true,
- }
-
- for _, dep := range m.updateDeps {
- if excludeList[dep.Name] {
- continue
- }
-
- switch dep.Name {
- case "dms (DankMaterialShell)", "quickshell":
- categories["Shell"] = append(categories["Shell"], dep)
- case "hyprland", "grim", "slurp", "hyprctl", "grimblast":
- categories["Hyprland Components"] = append(categories["Hyprland Components"], dep)
- case "niri":
- categories["Niri Components"] = append(categories["Niri Components"], dep)
- case "kitty", "alacritty", "ghostty", "hyprpicker":
- categories["Shared Components"] = append(categories["Shared Components"], dep)
- default:
- categories["Shared Components"] = append(categories["Shared Components"], dep)
- }
- }
-
- return categories
-}
diff --git a/nix/inputs/dms-cli/internal/errdefs/errdefs.go b/nix/inputs/dms-cli/internal/errdefs/errdefs.go
deleted file mode 100644
index 3b5f159..0000000
--- a/nix/inputs/dms-cli/internal/errdefs/errdefs.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package errdefs
-
-type ErrorType int
-
-const (
- ErrTypeNotLinux ErrorType = iota
- ErrTypeInvalidArchitecture
- ErrTypeUnsupportedDistribution
- ErrTypeUnsupportedVersion
- ErrTypeUpdateCancelled
- ErrTypeNoUpdateNeeded
- ErrTypeInvalidTemperature
- ErrTypeInvalidGamma
- ErrTypeInvalidLocation
- ErrTypeInvalidManualTimes
- ErrTypeNoWaylandDisplay
- ErrTypeNoGammaControl
- ErrTypeNotInitialized
- ErrTypeSecretPromptCancelled
- ErrTypeSecretPromptTimeout
- ErrTypeSecretAgentFailed
- ErrTypeGeneric
-)
-
-type CustomError struct {
- Type ErrorType
- Message string
-}
-
-func (e *CustomError) Error() string {
- return e.Message
-}
-
-func NewCustomError(errType ErrorType, message string) error {
- return &CustomError{
- Type: errType,
- Message: message,
- }
-}
-
-const (
- ErrBadCredentials = "bad-credentials"
- ErrNoSuchSSID = "no-such-ssid"
- ErrAssocTimeout = "assoc-timeout"
- ErrDhcpTimeout = "dhcp-timeout"
- ErrUserCanceled = "user-canceled"
- ErrWifiDisabled = "wifi-disabled"
- ErrAlreadyConnected = "already-connected"
- ErrConnectionFailed = "connection-failed"
-)
-
-var (
- ErrUpdateCancelled = NewCustomError(ErrTypeUpdateCancelled, "update cancelled by user")
- ErrNoUpdateNeeded = NewCustomError(ErrTypeNoUpdateNeeded, "no update needed")
- ErrInvalidTemperature = NewCustomError(ErrTypeInvalidTemperature, "temperature must be between 1000 and 10000")
- ErrInvalidGamma = NewCustomError(ErrTypeInvalidGamma, "gamma must be between 0 and 10")
- ErrInvalidLocation = NewCustomError(ErrTypeInvalidLocation, "invalid latitude/longitude")
- ErrInvalidManualTimes = NewCustomError(ErrTypeInvalidManualTimes, "both sunrise and sunset must be set or neither")
- ErrNoWaylandDisplay = NewCustomError(ErrTypeNoWaylandDisplay, "no wayland display available")
- ErrNoGammaControl = NewCustomError(ErrTypeNoGammaControl, "compositor does not support gamma control")
- ErrNotInitialized = NewCustomError(ErrTypeNotInitialized, "manager not initialized")
- ErrSecretPromptCancelled = NewCustomError(ErrTypeSecretPromptCancelled, "secret prompt cancelled by user")
- ErrSecretPromptTimeout = NewCustomError(ErrTypeSecretPromptTimeout, "secret prompt timed out")
- ErrSecretAgentFailed = NewCustomError(ErrTypeSecretAgentFailed, "secret agent operation failed")
-)
diff --git a/nix/inputs/dms-cli/internal/greeter/installer.go b/nix/inputs/dms-cli/internal/greeter/installer.go
deleted file mode 100644
index 2d4ecb2..0000000
--- a/nix/inputs/dms-cli/internal/greeter/installer.go
+++ /dev/null
@@ -1,490 +0,0 @@
-package greeter
-
-import (
- "bufio"
- "context"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/config"
- "github.com/AvengeMedia/danklinux/internal/distros"
-)
-
-// DetectDMSPath checks for DMS installation following XDG Base Directory specification
-func DetectDMSPath() (string, error) {
- return config.LocateDMSConfig()
-}
-
-// DetectCompositors checks which compositors are installed
-func DetectCompositors() []string {
- var compositors []string
-
- if commandExists("niri") {
- compositors = append(compositors, "niri")
- }
- if commandExists("Hyprland") {
- compositors = append(compositors, "Hyprland")
- }
-
- return compositors
-}
-
-// PromptCompositorChoice asks user to choose between compositors
-func PromptCompositorChoice(compositors []string) (string, error) {
- fmt.Println("\nMultiple compositors detected:")
- for i, comp := range compositors {
- fmt.Printf("%d) %s\n", i+1, comp)
- }
-
- reader := bufio.NewReader(os.Stdin)
- fmt.Print("Choose compositor for greeter (1-2): ")
- response, err := reader.ReadString('\n')
- if err != nil {
- return "", fmt.Errorf("error reading input: %w", err)
- }
-
- response = strings.TrimSpace(response)
- switch response {
- case "1":
- return compositors[0], nil
- case "2":
- if len(compositors) > 1 {
- return compositors[1], nil
- }
- return "", fmt.Errorf("invalid choice")
- default:
- return "", fmt.Errorf("invalid choice")
- }
-}
-
-// EnsureGreetdInstalled checks if greetd is installed and installs it if not
-func EnsureGreetdInstalled(logFunc func(string), sudoPassword string) error {
- if commandExists("greetd") {
- logFunc("✓ greetd is already installed")
- return nil
- }
-
- logFunc("greetd is not installed. Installing...")
-
- osInfo, err := distros.GetOSInfo()
- if err != nil {
- return fmt.Errorf("failed to detect OS: %w", err)
- }
-
- config, exists := distros.Registry[osInfo.Distribution.ID]
- if !exists {
- return fmt.Errorf("unsupported distribution for automatic greetd installation: %s", osInfo.Distribution.ID)
- }
-
- ctx := context.Background()
- var installCmd *exec.Cmd
-
- switch config.Family {
- case distros.FamilyArch:
- if sudoPassword != "" {
- installCmd = exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S pacman -S --needed --noconfirm greetd", sudoPassword))
- } else {
- installCmd = exec.CommandContext(ctx, "sudo", "pacman", "-S", "--needed", "--noconfirm", "greetd")
- }
-
- case distros.FamilyFedora:
- if sudoPassword != "" {
- installCmd = exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S dnf install -y greetd", sudoPassword))
- } else {
- installCmd = exec.CommandContext(ctx, "sudo", "dnf", "install", "-y", "greetd")
- }
-
- case distros.FamilySUSE:
- if sudoPassword != "" {
- installCmd = exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S zypper install -y greetd", sudoPassword))
- } else {
- installCmd = exec.CommandContext(ctx, "sudo", "zypper", "install", "-y", "greetd")
- }
-
- case distros.FamilyUbuntu:
- if sudoPassword != "" {
- installCmd = exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S apt-get install -y greetd", sudoPassword))
- } else {
- installCmd = exec.CommandContext(ctx, "sudo", "apt-get", "install", "-y", "greetd")
- }
-
- case distros.FamilyDebian:
- if sudoPassword != "" {
- installCmd = exec.CommandContext(ctx, "bash", "-c",
- fmt.Sprintf("echo '%s' | sudo -S apt-get install -y greetd", sudoPassword))
- } else {
- installCmd = exec.CommandContext(ctx, "sudo", "apt-get", "install", "-y", "greetd")
- }
-
- case distros.FamilyNix:
- return fmt.Errorf("on NixOS, please add greetd to your configuration.nix")
-
- default:
- return fmt.Errorf("unsupported distribution family for automatic greetd installation: %s", config.Family)
- }
-
- installCmd.Stdout = os.Stdout
- installCmd.Stderr = os.Stderr
-
- if err := installCmd.Run(); err != nil {
- return fmt.Errorf("failed to install greetd: %w", err)
- }
-
- logFunc("✓ greetd installed successfully")
- return nil
-}
-
-// CopyGreeterFiles installs the dms-greeter wrapper and sets up cache directory
-func CopyGreeterFiles(dmsPath, compositor string, logFunc func(string), sudoPassword string) error {
- // Check if dms-greeter is already in PATH
- if commandExists("dms-greeter") {
- logFunc("✓ dms-greeter wrapper already installed")
- } else {
- // Install the wrapper script
- assetsDir := filepath.Join(dmsPath, "Modules", "Greetd", "assets")
- wrapperSrc := filepath.Join(assetsDir, "dms-greeter")
-
- if _, err := os.Stat(wrapperSrc); os.IsNotExist(err) {
- return fmt.Errorf("dms-greeter wrapper not found at %s", wrapperSrc)
- }
-
- wrapperDst := "/usr/local/bin/dms-greeter"
- if err := runSudoCmd(sudoPassword, "cp", wrapperSrc, wrapperDst); err != nil {
- return fmt.Errorf("failed to copy dms-greeter wrapper: %w", err)
- }
- logFunc(fmt.Sprintf("✓ Installed dms-greeter wrapper to %s", wrapperDst))
-
- if err := runSudoCmd(sudoPassword, "chmod", "+x", wrapperDst); err != nil {
- return fmt.Errorf("failed to make wrapper executable: %w", err)
- }
-
- // Set SELinux context on Fedora and openSUSE
- osInfo, err := distros.GetOSInfo()
- if err == nil {
- if config, exists := distros.Registry[osInfo.Distribution.ID]; exists && (config.Family == distros.FamilyFedora || config.Family == distros.FamilySUSE) {
- if err := runSudoCmd(sudoPassword, "semanage", "fcontext", "-a", "-t", "bin_t", wrapperDst); err != nil {
- logFunc(fmt.Sprintf("⚠ Warning: Failed to set SELinux fcontext: %v", err))
- } else {
- logFunc("✓ Set SELinux fcontext for dms-greeter")
- }
-
- if err := runSudoCmd(sudoPassword, "restorecon", "-v", wrapperDst); err != nil {
- logFunc(fmt.Sprintf("⚠ Warning: Failed to restore SELinux context: %v", err))
- } else {
- logFunc("✓ Restored SELinux context for dms-greeter")
- }
- }
- }
- }
-
- // Create cache directory with proper permissions
- cacheDir := "/var/cache/dms-greeter"
- if err := runSudoCmd(sudoPassword, "mkdir", "-p", cacheDir); err != nil {
- return fmt.Errorf("failed to create cache directory: %w", err)
- }
-
- if err := runSudoCmd(sudoPassword, "chown", "greeter:greeter", cacheDir); err != nil {
- return fmt.Errorf("failed to set cache directory owner: %w", err)
- }
-
- if err := runSudoCmd(sudoPassword, "chmod", "750", cacheDir); err != nil {
- return fmt.Errorf("failed to set cache directory permissions: %w", err)
- }
- logFunc(fmt.Sprintf("✓ Created cache directory %s (owner: greeter:greeter, permissions: 750)", cacheDir))
-
- return nil
-}
-
-// SetupParentDirectoryACLs sets ACLs on parent directories to allow traversal
-func SetupParentDirectoryACLs(logFunc func(string), sudoPassword string) error {
- if !commandExists("setfacl") {
- logFunc("⚠ Warning: setfacl command not found. ACL support may not be available on this filesystem.")
- logFunc(" If theme sync doesn't work, you may need to install acl package:")
- logFunc(" - Fedora/RHEL: sudo dnf install acl")
- logFunc(" - Debian/Ubuntu: sudo apt-get install acl")
- logFunc(" - Arch: sudo pacman -S acl")
- return nil
- }
-
- homeDir, err := os.UserHomeDir()
- if err != nil {
- return fmt.Errorf("failed to get user home directory: %w", err)
- }
-
- parentDirs := []struct {
- path string
- desc string
- }{
- {homeDir, "home directory"},
- {filepath.Join(homeDir, ".config"), ".config directory"},
- {filepath.Join(homeDir, ".local"), ".local directory"},
- {filepath.Join(homeDir, ".cache"), ".cache directory"},
- {filepath.Join(homeDir, ".local", "state"), ".local/state directory"},
- }
-
- logFunc("\nSetting up parent directory ACLs for greeter user access...")
-
- for _, dir := range parentDirs {
- if _, err := os.Stat(dir.path); os.IsNotExist(err) {
- if err := os.MkdirAll(dir.path, 0755); err != nil {
- logFunc(fmt.Sprintf("⚠ Warning: Could not create %s: %v", dir.desc, err))
- continue
- }
- }
-
- // Set ACL to allow greeter user execute (traverse) permission
- if err := runSudoCmd(sudoPassword, "setfacl", "-m", "u:greeter:x", dir.path); err != nil {
- logFunc(fmt.Sprintf("⚠ Warning: Failed to set ACL on %s: %v", dir.desc, err))
- logFunc(fmt.Sprintf(" You may need to run manually: setfacl -m u:greeter:x %s", dir.path))
- continue
- }
-
- logFunc(fmt.Sprintf("✓ Set ACL on %s", dir.desc))
- }
-
- return nil
-}
-
-func SetupDMSGroup(logFunc func(string), sudoPassword string) error {
- homeDir, err := os.UserHomeDir()
- if err != nil {
- return fmt.Errorf("failed to get user home directory: %w", err)
- }
-
- currentUser := os.Getenv("USER")
- if currentUser == "" {
- currentUser = os.Getenv("LOGNAME")
- }
- if currentUser == "" {
- return fmt.Errorf("failed to determine current user")
- }
-
- // Check if user is already in greeter group
- groupsCmd := exec.Command("groups", currentUser)
- groupsOutput, err := groupsCmd.Output()
- if err == nil && strings.Contains(string(groupsOutput), "greeter") {
- logFunc(fmt.Sprintf("✓ %s is already in greeter group", currentUser))
- } else {
- // Add current user to greeter group for file access permissions
- if err := runSudoCmd(sudoPassword, "usermod", "-aG", "greeter", currentUser); err != nil {
- return fmt.Errorf("failed to add %s to greeter group: %w", currentUser, err)
- }
- logFunc(fmt.Sprintf("✓ Added %s to greeter group (logout/login required for changes to take effect)", currentUser))
- }
-
- configDirs := []struct {
- path string
- desc string
- }{
- {filepath.Join(homeDir, ".config", "DankMaterialShell"), "DankMaterialShell config"},
- {filepath.Join(homeDir, ".local", "state", "DankMaterialShell"), "DankMaterialShell state"},
- {filepath.Join(homeDir, ".cache", "quickshell"), "quickshell cache"},
- {filepath.Join(homeDir, ".config", "quickshell"), "quickshell config"},
- }
-
- for _, dir := range configDirs {
- if _, err := os.Stat(dir.path); os.IsNotExist(err) {
- if err := os.MkdirAll(dir.path, 0755); err != nil {
- logFunc(fmt.Sprintf("⚠ Warning: Could not create %s: %v", dir.path, err))
- continue
- }
- }
-
- if err := runSudoCmd(sudoPassword, "chgrp", "-R", "greeter", dir.path); err != nil {
- logFunc(fmt.Sprintf("⚠ Warning: Failed to set group for %s: %v", dir.desc, err))
- continue
- }
-
- if err := runSudoCmd(sudoPassword, "chmod", "-R", "g+rX", dir.path); err != nil {
- logFunc(fmt.Sprintf("⚠ Warning: Failed to set permissions for %s: %v", dir.desc, err))
- continue
- }
-
- logFunc(fmt.Sprintf("✓ Set group permissions for %s", dir.desc))
- }
-
- // Set up ACLs on parent directories to allow greeter user traversal
- if err := SetupParentDirectoryACLs(logFunc, sudoPassword); err != nil {
- return fmt.Errorf("failed to setup parent directory ACLs: %w", err)
- }
-
- return nil
-}
-
-func SyncDMSConfigs(dmsPath string, logFunc func(string), sudoPassword string) error {
- homeDir, err := os.UserHomeDir()
- if err != nil {
- return fmt.Errorf("failed to get user home directory: %w", err)
- }
-
- cacheDir := "/var/cache/dms-greeter"
-
- symlinks := []struct {
- source string
- target string
- desc string
- }{
- {
- source: filepath.Join(homeDir, ".config", "DankMaterialShell", "settings.json"),
- target: filepath.Join(cacheDir, "settings.json"),
- desc: "core settings (theme, clock formats, etc)",
- },
- {
- source: filepath.Join(homeDir, ".local", "state", "DankMaterialShell", "session.json"),
- target: filepath.Join(cacheDir, "session.json"),
- desc: "state (wallpaper configuration)",
- },
- {
- source: filepath.Join(homeDir, ".cache", "quickshell", "dankshell", "dms-colors.json"),
- target: filepath.Join(cacheDir, "colors.json"),
- desc: "wallpaper based theming",
- },
- }
-
- for _, link := range symlinks {
- sourceDir := filepath.Dir(link.source)
- if _, err := os.Stat(sourceDir); os.IsNotExist(err) {
- if err := os.MkdirAll(sourceDir, 0755); err != nil {
- logFunc(fmt.Sprintf("⚠ Warning: Could not create directory %s: %v", sourceDir, err))
- continue
- }
- }
-
- if _, err := os.Stat(link.source); os.IsNotExist(err) {
- if err := os.WriteFile(link.source, []byte("{}"), 0644); err != nil {
- logFunc(fmt.Sprintf("⚠ Warning: Could not create %s: %v", link.source, err))
- continue
- }
- }
-
- runSudoCmd(sudoPassword, "rm", "-f", link.target)
-
- if err := runSudoCmd(sudoPassword, "ln", "-sf", link.source, link.target); err != nil {
- logFunc(fmt.Sprintf("⚠ Warning: Failed to create symlink for %s: %v", link.desc, err))
- continue
- }
-
- logFunc(fmt.Sprintf("✓ Synced %s", link.desc))
- }
-
- return nil
-}
-
-func ConfigureGreetd(dmsPath, compositor string, logFunc func(string), sudoPassword string) error {
- configPath := "/etc/greetd/config.toml"
-
- if _, err := os.Stat(configPath); err == nil {
- backupPath := configPath + ".backup"
- if err := runSudoCmd(sudoPassword, "cp", configPath, backupPath); err != nil {
- return fmt.Errorf("failed to backup config: %w", err)
- }
- logFunc(fmt.Sprintf("✓ Backed up existing config to %s", backupPath))
- }
-
- var configContent string
- if data, err := os.ReadFile(configPath); err == nil {
- configContent = string(data)
- } else {
- configContent = `[terminal]
-vt = 1
-
-[default_session]
-
-user = "greeter"
-`
- }
-
- lines := strings.Split(configContent, "\n")
- var newLines []string
- for _, line := range lines {
- trimmed := strings.TrimSpace(line)
- if !strings.HasPrefix(trimmed, "command =") && !strings.HasPrefix(trimmed, "command=") {
- if strings.HasPrefix(trimmed, "user =") || strings.HasPrefix(trimmed, "user=") {
- newLines = append(newLines, `user = "greeter"`)
- } else {
- newLines = append(newLines, line)
- }
- }
- }
-
- // Determine wrapper command path
- wrapperCmd := "dms-greeter"
- if !commandExists("dms-greeter") {
- wrapperCmd = "/usr/local/bin/dms-greeter"
- }
-
- // Build command based on compositor and dms path
- compositorLower := strings.ToLower(compositor)
- command := fmt.Sprintf(`command = "%s --command %s -p %s"`, wrapperCmd, compositorLower, dmsPath)
-
- var finalLines []string
- inDefaultSession := false
- commandAdded := false
-
- for _, line := range newLines {
- finalLines = append(finalLines, line)
- trimmed := strings.TrimSpace(line)
-
- if trimmed == "[default_session]" {
- inDefaultSession = true
- }
-
- if inDefaultSession && !commandAdded && trimmed != "" && !strings.HasPrefix(trimmed, "[") {
- if !strings.HasPrefix(trimmed, "#") && !strings.HasPrefix(trimmed, "user") {
- finalLines = append(finalLines, command)
- commandAdded = true
- }
- }
- }
-
- if !commandAdded {
- finalLines = append(finalLines, command)
- }
-
- newConfig := strings.Join(finalLines, "\n")
-
- tmpFile := "/tmp/greetd-config.toml"
- if err := os.WriteFile(tmpFile, []byte(newConfig), 0644); err != nil {
- return fmt.Errorf("failed to write temp config: %w", err)
- }
-
- if err := runSudoCmd(sudoPassword, "mv", tmpFile, configPath); err != nil {
- return fmt.Errorf("failed to move config to /etc/greetd: %w", err)
- }
-
- logFunc(fmt.Sprintf("✓ Updated greetd configuration (user: greeter, command: %s --command %s -p %s)", wrapperCmd, compositorLower, dmsPath))
- return nil
-}
-
-func runSudoCmd(sudoPassword string, command string, args ...string) error {
- var cmd *exec.Cmd
-
- if sudoPassword != "" {
- fullArgs := append([]string{command}, args...)
- quotedArgs := make([]string, len(fullArgs))
- for i, arg := range fullArgs {
- quotedArgs[i] = "'" + strings.ReplaceAll(arg, "'", "'\\''") + "'"
- }
- cmdStr := strings.Join(quotedArgs, " ")
-
- cmd = exec.Command("bash", "-c", fmt.Sprintf("echo '%s' | sudo -S %s", sudoPassword, cmdStr))
- } else {
- cmd = exec.Command("sudo", append([]string{command}, args...)...)
- }
-
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- return cmd.Run()
-}
-
-func commandExists(cmd string) bool {
- _, err := exec.LookPath(cmd)
- return err == nil
-}
diff --git a/nix/inputs/dms-cli/internal/hyprland/keybinds.go b/nix/inputs/dms-cli/internal/hyprland/keybinds.go
deleted file mode 100644
index 598dba7..0000000
--- a/nix/inputs/dms-cli/internal/hyprland/keybinds.go
+++ /dev/null
@@ -1,330 +0,0 @@
-package hyprland
-
-import (
- "os"
- "path/filepath"
- "regexp"
- "strings"
-)
-
-const (
- TitleRegex = "#+!"
- HideComment = "[hidden]"
- CommentBindPattern = "#/#"
-)
-
-var ModSeparators = []rune{'+', ' '}
-
-type KeyBinding struct {
- Mods []string `json:"mods"`
- Key string `json:"key"`
- Dispatcher string `json:"dispatcher"`
- Params string `json:"params"`
- Comment string `json:"comment"`
-}
-
-type Section struct {
- Children []Section `json:"children"`
- Keybinds []KeyBinding `json:"keybinds"`
- Name string `json:"name"`
-}
-
-type Parser struct {
- contentLines []string
- readingLine int
-}
-
-func NewParser() *Parser {
- return &Parser{
- contentLines: []string{},
- readingLine: 0,
- }
-}
-
-func (p *Parser) ReadContent(directory string) error {
- expandedDir := os.ExpandEnv(directory)
- expandedDir = filepath.Clean(expandedDir)
- if strings.HasPrefix(expandedDir, "~") {
- home, err := os.UserHomeDir()
- if err != nil {
- return err
- }
- expandedDir = filepath.Join(home, expandedDir[1:])
- }
-
- info, err := os.Stat(expandedDir)
- if err != nil {
- return err
- }
- if !info.IsDir() {
- return os.ErrNotExist
- }
-
- confFiles, err := filepath.Glob(filepath.Join(expandedDir, "*.conf"))
- if err != nil {
- return err
- }
- if len(confFiles) == 0 {
- return os.ErrNotExist
- }
-
- var combinedContent []string
- for _, confFile := range confFiles {
- if fileInfo, err := os.Stat(confFile); err == nil && fileInfo.Mode().IsRegular() {
- data, err := os.ReadFile(confFile)
- if err == nil {
- combinedContent = append(combinedContent, string(data))
- }
- }
- }
-
- if len(combinedContent) == 0 {
- return os.ErrNotExist
- }
-
- fullContent := strings.Join(combinedContent, "\n")
- p.contentLines = strings.Split(fullContent, "\n")
- return nil
-}
-
-func autogenerateComment(dispatcher, params string) string {
- switch dispatcher {
- case "resizewindow":
- return "Resize window"
-
- case "movewindow":
- if params == "" {
- return "Move window"
- }
- dirMap := map[string]string{
- "l": "left",
- "r": "right",
- "u": "up",
- "d": "down",
- }
- if dir, ok := dirMap[params]; ok {
- return "Window: move in " + dir + " direction"
- }
- return "Window: move in null direction"
-
- case "pin":
- return "Window: pin (show on all workspaces)"
-
- case "splitratio":
- return "Window split ratio " + params
-
- case "togglefloating":
- return "Float/unfloat window"
-
- case "resizeactive":
- return "Resize window by " + params
-
- case "killactive":
- return "Close window"
-
- case "fullscreen":
- fsMap := map[string]string{
- "0": "fullscreen",
- "1": "maximization",
- "2": "fullscreen on Hyprland's side",
- }
- if fs, ok := fsMap[params]; ok {
- return "Toggle " + fs
- }
- return "Toggle null"
-
- case "fakefullscreen":
- return "Toggle fake fullscreen"
-
- case "workspace":
- if params == "+1" {
- return "Workspace: focus right"
- } else if params == "-1" {
- return "Workspace: focus left"
- }
- return "Focus workspace " + params
-
- case "movefocus":
- dirMap := map[string]string{
- "l": "left",
- "r": "right",
- "u": "up",
- "d": "down",
- }
- if dir, ok := dirMap[params]; ok {
- return "Window: move focus " + dir
- }
- return "Window: move focus null"
-
- case "swapwindow":
- dirMap := map[string]string{
- "l": "left",
- "r": "right",
- "u": "up",
- "d": "down",
- }
- if dir, ok := dirMap[params]; ok {
- return "Window: swap in " + dir + " direction"
- }
- return "Window: swap in null direction"
-
- case "movetoworkspace":
- if params == "+1" {
- return "Window: move to right workspace (non-silent)"
- } else if params == "-1" {
- return "Window: move to left workspace (non-silent)"
- }
- return "Window: move to workspace " + params + " (non-silent)"
-
- case "movetoworkspacesilent":
- if params == "+1" {
- return "Window: move to right workspace"
- } else if params == "-1" {
- return "Window: move to right workspace"
- }
- return "Window: move to workspace " + params
-
- case "togglespecialworkspace":
- return "Workspace: toggle special"
-
- case "exec":
- return "Execute: " + params
-
- default:
- return ""
- }
-}
-
-func (p *Parser) getKeybindAtLine(lineNumber int) *KeyBinding {
- line := p.contentLines[lineNumber]
- parts := strings.SplitN(line, "=", 2)
- if len(parts) < 2 {
- return nil
- }
-
- keys := parts[1]
- keyParts := strings.SplitN(keys, "#", 2)
- keys = keyParts[0]
-
- var comment string
- if len(keyParts) > 1 {
- comment = strings.TrimSpace(keyParts[1])
- }
-
- keyFields := strings.SplitN(keys, ",", 5)
- if len(keyFields) < 3 {
- return nil
- }
-
- mods := strings.TrimSpace(keyFields[0])
- key := strings.TrimSpace(keyFields[1])
- dispatcher := strings.TrimSpace(keyFields[2])
-
- var params string
- if len(keyFields) > 3 {
- paramParts := keyFields[3:]
- params = strings.TrimSpace(strings.Join(paramParts, ","))
- }
-
- if comment != "" {
- if strings.HasPrefix(comment, HideComment) {
- return nil
- }
- } else {
- comment = autogenerateComment(dispatcher, params)
- }
-
- var modList []string
- if mods != "" {
- modstring := mods + string(ModSeparators[0])
- p := 0
- for index, char := range modstring {
- isModSep := false
- for _, sep := range ModSeparators {
- if char == sep {
- isModSep = true
- break
- }
- }
- if isModSep {
- if index-p > 1 {
- modList = append(modList, modstring[p:index])
- }
- p = index + 1
- }
- }
- }
-
- return &KeyBinding{
- Mods: modList,
- Key: key,
- Dispatcher: dispatcher,
- Params: params,
- Comment: comment,
- }
-}
-
-func (p *Parser) getBindsRecursive(currentContent *Section, scope int) *Section {
- titleRegex := regexp.MustCompile(TitleRegex)
-
- for p.readingLine < len(p.contentLines) {
- line := p.contentLines[p.readingLine]
-
- loc := titleRegex.FindStringIndex(line)
- if loc != nil && loc[0] == 0 {
- headingScope := strings.Index(line, "!")
-
- if headingScope <= scope {
- p.readingLine--
- return currentContent
- }
-
- sectionName := strings.TrimSpace(line[headingScope+1:])
- p.readingLine++
-
- childSection := &Section{
- Children: []Section{},
- Keybinds: []KeyBinding{},
- Name: sectionName,
- }
- result := p.getBindsRecursive(childSection, headingScope)
- currentContent.Children = append(currentContent.Children, *result)
-
- } else if strings.HasPrefix(line, CommentBindPattern) {
- keybind := p.getKeybindAtLine(p.readingLine)
- if keybind != nil {
- currentContent.Keybinds = append(currentContent.Keybinds, *keybind)
- }
-
- } else if line == "" || !strings.HasPrefix(strings.TrimSpace(line), "bind") {
-
- } else {
- keybind := p.getKeybindAtLine(p.readingLine)
- if keybind != nil {
- currentContent.Keybinds = append(currentContent.Keybinds, *keybind)
- }
- }
-
- p.readingLine++
- }
-
- return currentContent
-}
-
-func (p *Parser) ParseKeys() *Section {
- p.readingLine = 0
- rootSection := &Section{
- Children: []Section{},
- Keybinds: []KeyBinding{},
- Name: "",
- }
- return p.getBindsRecursive(rootSection, 0)
-}
-
-func ParseKeys(path string) (*Section, error) {
- parser := NewParser()
- if err := parser.ReadContent(path); err != nil {
- return nil, err
- }
- return parser.ParseKeys(), nil
-}
diff --git a/nix/inputs/dms-cli/internal/hyprland/keybinds_test.go b/nix/inputs/dms-cli/internal/hyprland/keybinds_test.go
deleted file mode 100644
index 05ced84..0000000
--- a/nix/inputs/dms-cli/internal/hyprland/keybinds_test.go
+++ /dev/null
@@ -1,396 +0,0 @@
-package hyprland
-
-import (
- "os"
- "path/filepath"
- "testing"
-)
-
-func TestAutogenerateComment(t *testing.T) {
- tests := []struct {
- dispatcher string
- params string
- expected string
- }{
- {"resizewindow", "", "Resize window"},
- {"movewindow", "", "Move window"},
- {"movewindow", "l", "Window: move in left direction"},
- {"movewindow", "r", "Window: move in right direction"},
- {"movewindow", "u", "Window: move in up direction"},
- {"movewindow", "d", "Window: move in down direction"},
- {"pin", "", "Window: pin (show on all workspaces)"},
- {"splitratio", "0.5", "Window split ratio 0.5"},
- {"togglefloating", "", "Float/unfloat window"},
- {"resizeactive", "10 20", "Resize window by 10 20"},
- {"killactive", "", "Close window"},
- {"fullscreen", "0", "Toggle fullscreen"},
- {"fullscreen", "1", "Toggle maximization"},
- {"fullscreen", "2", "Toggle fullscreen on Hyprland's side"},
- {"fakefullscreen", "", "Toggle fake fullscreen"},
- {"workspace", "+1", "Workspace: focus right"},
- {"workspace", "-1", "Workspace: focus left"},
- {"workspace", "5", "Focus workspace 5"},
- {"movefocus", "l", "Window: move focus left"},
- {"movefocus", "r", "Window: move focus right"},
- {"movefocus", "u", "Window: move focus up"},
- {"movefocus", "d", "Window: move focus down"},
- {"swapwindow", "l", "Window: swap in left direction"},
- {"swapwindow", "r", "Window: swap in right direction"},
- {"swapwindow", "u", "Window: swap in up direction"},
- {"swapwindow", "d", "Window: swap in down direction"},
- {"movetoworkspace", "+1", "Window: move to right workspace (non-silent)"},
- {"movetoworkspace", "-1", "Window: move to left workspace (non-silent)"},
- {"movetoworkspace", "3", "Window: move to workspace 3 (non-silent)"},
- {"movetoworkspacesilent", "+1", "Window: move to right workspace"},
- {"movetoworkspacesilent", "-1", "Window: move to right workspace"},
- {"movetoworkspacesilent", "2", "Window: move to workspace 2"},
- {"togglespecialworkspace", "", "Workspace: toggle special"},
- {"exec", "firefox", "Execute: firefox"},
- {"unknown", "", ""},
- }
-
- for _, tt := range tests {
- t.Run(tt.dispatcher+"_"+tt.params, func(t *testing.T) {
- result := autogenerateComment(tt.dispatcher, tt.params)
- if result != tt.expected {
- t.Errorf("autogenerateComment(%q, %q) = %q, want %q",
- tt.dispatcher, tt.params, result, tt.expected)
- }
- })
- }
-}
-
-func TestGetKeybindAtLine(t *testing.T) {
- tests := []struct {
- name string
- line string
- expected *KeyBinding
- }{
- {
- name: "basic_keybind",
- line: "bind = SUPER, Q, killactive",
- expected: &KeyBinding{
- Mods: []string{"SUPER"},
- Key: "Q",
- Dispatcher: "killactive",
- Params: "",
- Comment: "Close window",
- },
- },
- {
- name: "keybind_with_params",
- line: "bind = SUPER, left, movefocus, l",
- expected: &KeyBinding{
- Mods: []string{"SUPER"},
- Key: "left",
- Dispatcher: "movefocus",
- Params: "l",
- Comment: "Window: move focus left",
- },
- },
- {
- name: "keybind_with_comment",
- line: "bind = SUPER, T, exec, kitty # Open terminal",
- expected: &KeyBinding{
- Mods: []string{"SUPER"},
- Key: "T",
- Dispatcher: "exec",
- Params: "kitty",
- Comment: "Open terminal",
- },
- },
- {
- name: "keybind_hidden",
- line: "bind = SUPER, H, exec, secret # [hidden]",
- expected: nil,
- },
- {
- name: "keybind_multiple_mods",
- line: "bind = SUPER+SHIFT, F, fullscreen, 0",
- expected: &KeyBinding{
- Mods: []string{"SUPER", "SHIFT"},
- Key: "F",
- Dispatcher: "fullscreen",
- Params: "0",
- Comment: "Toggle fullscreen",
- },
- },
- {
- name: "keybind_no_mods",
- line: "bind = , Print, exec, screenshot",
- expected: &KeyBinding{
- Mods: []string{},
- Key: "Print",
- Dispatcher: "exec",
- Params: "screenshot",
- Comment: "Execute: screenshot",
- },
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- parser := NewParser()
- parser.contentLines = []string{tt.line}
- result := parser.getKeybindAtLine(0)
-
- if tt.expected == nil {
- if result != nil {
- t.Errorf("expected nil, got %+v", result)
- }
- return
- }
-
- if result == nil {
- t.Errorf("expected %+v, got nil", tt.expected)
- return
- }
-
- if result.Key != tt.expected.Key {
- t.Errorf("Key = %q, want %q", result.Key, tt.expected.Key)
- }
- if result.Dispatcher != tt.expected.Dispatcher {
- t.Errorf("Dispatcher = %q, want %q", result.Dispatcher, tt.expected.Dispatcher)
- }
- if result.Params != tt.expected.Params {
- t.Errorf("Params = %q, want %q", result.Params, tt.expected.Params)
- }
- if result.Comment != tt.expected.Comment {
- t.Errorf("Comment = %q, want %q", result.Comment, tt.expected.Comment)
- }
- if len(result.Mods) != len(tt.expected.Mods) {
- t.Errorf("Mods length = %d, want %d", len(result.Mods), len(tt.expected.Mods))
- } else {
- for i := range result.Mods {
- if result.Mods[i] != tt.expected.Mods[i] {
- t.Errorf("Mods[%d] = %q, want %q", i, result.Mods[i], tt.expected.Mods[i])
- }
- }
- }
- })
- }
-}
-
-func TestParseKeysWithSections(t *testing.T) {
- tmpDir := t.TempDir()
- configFile := filepath.Join(tmpDir, "hyprland.conf")
-
- content := `##! Window Management
-bind = SUPER, Q, killactive
-bind = SUPER, F, fullscreen, 0
-
-###! Movement
-bind = SUPER, left, movefocus, l
-bind = SUPER, right, movefocus, r
-
-##! Applications
-bind = SUPER, T, exec, kitty # Terminal
-`
-
- if err := os.WriteFile(configFile, []byte(content), 0644); err != nil {
- t.Fatalf("Failed to write test config: %v", err)
- }
-
- section, err := ParseKeys(tmpDir)
- if err != nil {
- t.Fatalf("ParseKeys failed: %v", err)
- }
-
- if len(section.Children) != 2 {
- t.Errorf("Expected 2 top-level sections, got %d", len(section.Children))
- }
-
- if len(section.Children) >= 1 {
- windowMgmt := section.Children[0]
- if windowMgmt.Name != "Window Management" {
- t.Errorf("First section name = %q, want %q", windowMgmt.Name, "Window Management")
- }
- if len(windowMgmt.Keybinds) != 2 {
- t.Errorf("Window Management keybinds = %d, want 2", len(windowMgmt.Keybinds))
- }
-
- if len(windowMgmt.Children) != 1 {
- t.Errorf("Window Management children = %d, want 1", len(windowMgmt.Children))
- } else {
- movement := windowMgmt.Children[0]
- if movement.Name != "Movement" {
- t.Errorf("Movement section name = %q, want %q", movement.Name, "Movement")
- }
- if len(movement.Keybinds) != 2 {
- t.Errorf("Movement keybinds = %d, want 2", len(movement.Keybinds))
- }
- }
- }
-
- if len(section.Children) >= 2 {
- apps := section.Children[1]
- if apps.Name != "Applications" {
- t.Errorf("Second section name = %q, want %q", apps.Name, "Applications")
- }
- if len(apps.Keybinds) != 1 {
- t.Errorf("Applications keybinds = %d, want 1", len(apps.Keybinds))
- }
- if len(apps.Keybinds) > 0 && apps.Keybinds[0].Comment != "Terminal" {
- t.Errorf("Applications keybind comment = %q, want %q", apps.Keybinds[0].Comment, "Terminal")
- }
- }
-}
-
-func TestParseKeysWithCommentBinds(t *testing.T) {
- tmpDir := t.TempDir()
- configFile := filepath.Join(tmpDir, "test.conf")
-
- content := `#/# = SUPER, A, exec, app1
-bind = SUPER, B, exec, app2
-#/# = SUPER, C, exec, app3 # Custom comment
-`
-
- if err := os.WriteFile(configFile, []byte(content), 0644); err != nil {
- t.Fatalf("Failed to write test config: %v", err)
- }
-
- section, err := ParseKeys(tmpDir)
- if err != nil {
- t.Fatalf("ParseKeys failed: %v", err)
- }
-
- if len(section.Keybinds) != 3 {
- t.Errorf("Expected 3 keybinds, got %d", len(section.Keybinds))
- }
-
- if len(section.Keybinds) > 0 && section.Keybinds[0].Key != "A" {
- t.Errorf("First keybind key = %q, want %q", section.Keybinds[0].Key, "A")
- }
- if len(section.Keybinds) > 1 && section.Keybinds[1].Key != "B" {
- t.Errorf("Second keybind key = %q, want %q", section.Keybinds[1].Key, "B")
- }
- if len(section.Keybinds) > 2 && section.Keybinds[2].Comment != "Custom comment" {
- t.Errorf("Third keybind comment = %q, want %q", section.Keybinds[2].Comment, "Custom comment")
- }
-}
-
-func TestReadContentMultipleFiles(t *testing.T) {
- tmpDir := t.TempDir()
-
- file1 := filepath.Join(tmpDir, "a.conf")
- file2 := filepath.Join(tmpDir, "b.conf")
-
- content1 := "bind = SUPER, Q, killactive\n"
- content2 := "bind = SUPER, T, exec, kitty\n"
-
- if err := os.WriteFile(file1, []byte(content1), 0644); err != nil {
- t.Fatalf("Failed to write file1: %v", err)
- }
- if err := os.WriteFile(file2, []byte(content2), 0644); err != nil {
- t.Fatalf("Failed to write file2: %v", err)
- }
-
- parser := NewParser()
- if err := parser.ReadContent(tmpDir); err != nil {
- t.Fatalf("ReadContent failed: %v", err)
- }
-
- section := parser.ParseKeys()
- if len(section.Keybinds) != 2 {
- t.Errorf("Expected 2 keybinds from multiple files, got %d", len(section.Keybinds))
- }
-}
-
-func TestReadContentErrors(t *testing.T) {
- tests := []struct {
- name string
- path string
- }{
- {
- name: "nonexistent_directory",
- path: "/nonexistent/path/that/does/not/exist",
- },
- {
- name: "empty_directory",
- path: t.TempDir(),
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- _, err := ParseKeys(tt.path)
- if err == nil {
- t.Error("Expected error, got nil")
- }
- })
- }
-}
-
-func TestReadContentWithTildeExpansion(t *testing.T) {
- homeDir, err := os.UserHomeDir()
- if err != nil {
- t.Skip("Cannot get home directory")
- }
-
- tmpSubdir := filepath.Join(homeDir, ".config", "test-hypr-"+t.Name())
- if err := os.MkdirAll(tmpSubdir, 0755); err != nil {
- t.Skip("Cannot create test directory in home")
- }
- defer os.RemoveAll(tmpSubdir)
-
- configFile := filepath.Join(tmpSubdir, "test.conf")
- if err := os.WriteFile(configFile, []byte("bind = SUPER, Q, killactive\n"), 0644); err != nil {
- t.Fatalf("Failed to write test config: %v", err)
- }
-
- relPath, err := filepath.Rel(homeDir, tmpSubdir)
- if err != nil {
- t.Skip("Cannot create relative path")
- }
-
- parser := NewParser()
- tildePathMatch := "~/" + relPath
- err = parser.ReadContent(tildePathMatch)
-
- if err != nil {
- t.Errorf("ReadContent with tilde path failed: %v", err)
- }
-}
-
-func TestKeybindWithParamsContainingCommas(t *testing.T) {
- parser := NewParser()
- parser.contentLines = []string{"bind = SUPER, R, exec, notify-send 'Title' 'Message, with comma'"}
-
- result := parser.getKeybindAtLine(0)
-
- if result == nil {
- t.Fatal("Expected keybind, got nil")
- }
-
- expected := "notify-send 'Title' 'Message, with comma'"
- if result.Params != expected {
- t.Errorf("Params = %q, want %q", result.Params, expected)
- }
-}
-
-func TestEmptyAndCommentLines(t *testing.T) {
- tmpDir := t.TempDir()
- configFile := filepath.Join(tmpDir, "test.conf")
-
- content := `
-# This is a comment
-bind = SUPER, Q, killactive
-
-# Another comment
-
-bind = SUPER, T, exec, kitty
-`
-
- if err := os.WriteFile(configFile, []byte(content), 0644); err != nil {
- t.Fatalf("Failed to write test config: %v", err)
- }
-
- section, err := ParseKeys(tmpDir)
- if err != nil {
- t.Fatalf("ParseKeys failed: %v", err)
- }
-
- if len(section.Keybinds) != 2 {
- t.Errorf("Expected 2 keybinds (comments ignored), got %d", len(section.Keybinds))
- }
-}
diff --git a/nix/inputs/dms-cli/internal/log/log.go b/nix/inputs/dms-cli/internal/log/log.go
deleted file mode 100644
index ba446e0..0000000
--- a/nix/inputs/dms-cli/internal/log/log.go
+++ /dev/null
@@ -1,116 +0,0 @@
-package log
-
-import (
- "os"
- "strings"
- "sync"
-
- "github.com/charmbracelet/lipgloss"
- cblog "github.com/charmbracelet/log"
-)
-
-// Logger embeds the Charm Logger and adds Printf/Fatalf
-type Logger struct{ *cblog.Logger }
-
-// Printf routes goose/info-style logs through Infof.
-func (l *Logger) Printf(format string, v ...interface{}) { l.Infof(format, v...) }
-
-// Fatalf keeps goose’s contract of exiting the program.
-func (l *Logger) Fatalf(format string, v ...interface{}) { l.Logger.Fatalf(format, v...) }
-
-var (
- logger *Logger
- initLogger sync.Once
-)
-
-func parseLogLevel(level string) cblog.Level {
- switch strings.ToLower(level) {
- case "debug":
- return cblog.DebugLevel
- case "info":
- return cblog.InfoLevel
- case "warn", "warning":
- return cblog.WarnLevel
- case "error":
- return cblog.ErrorLevel
- case "fatal":
- return cblog.FatalLevel
- default:
- return cblog.InfoLevel
- }
-}
-
-func GetQtLoggingRules() string {
- level := os.Getenv("DMS_LOG_LEVEL")
- if level == "" {
- level = "info"
- }
-
- var rules []string
- switch strings.ToLower(level) {
- case "fatal":
- rules = []string{"*.debug=false", "*.info=false", "*.warning=false", "*.critical=false"}
- case "error":
- rules = []string{"*.debug=false", "*.info=false", "*.warning=false"}
- case "warn", "warning":
- rules = []string{"*.debug=false", "*.info=false"}
- case "info":
- rules = []string{"*.debug=false"}
- case "debug":
- return ""
- default:
- rules = []string{"*.debug=false"}
- }
-
- return strings.Join(rules, ";")
-}
-
-// GetLogger returns a logger instance
-func GetLogger() *Logger {
- initLogger.Do(func() {
- styles := cblog.DefaultStyles()
- // Attempt to match the colors used by qml/quickshell logs
- styles.Levels[cblog.FatalLevel] = lipgloss.NewStyle().
- SetString(" FATAL").
- Foreground(lipgloss.Color("1"))
- styles.Levels[cblog.ErrorLevel] = lipgloss.NewStyle().
- SetString(" ERROR").
- Foreground(lipgloss.Color("9"))
- styles.Levels[cblog.WarnLevel] = lipgloss.NewStyle().
- SetString(" WARN").
- Foreground(lipgloss.Color("3"))
- styles.Levels[cblog.InfoLevel] = lipgloss.NewStyle().
- SetString(" INFO").
- Foreground(lipgloss.Color("2"))
- styles.Levels[cblog.DebugLevel] = lipgloss.NewStyle().
- SetString(" DEBUG").
- Foreground(lipgloss.Color("4"))
-
- base := cblog.New(os.Stderr)
- base.SetStyles(styles)
- base.SetReportTimestamp(false)
-
- level := cblog.InfoLevel
- if envLevel := os.Getenv("DMS_LOG_LEVEL"); envLevel != "" {
- level = parseLogLevel(envLevel)
- }
- base.SetLevel(level)
- base.SetPrefix(" go")
-
- logger = &Logger{base}
- })
- return logger
-}
-
-// * Convenience wrappers
-
-func Debug(msg interface{}, keyvals ...interface{}) { GetLogger().Logger.Debug(msg, keyvals...) }
-func Debugf(format string, v ...interface{}) { GetLogger().Logger.Debugf(format, v...) }
-func Info(msg interface{}, keyvals ...interface{}) { GetLogger().Logger.Info(msg, keyvals...) }
-func Infof(format string, v ...interface{}) { GetLogger().Logger.Infof(format, v...) }
-func Warn(msg interface{}, keyvals ...interface{}) { GetLogger().Logger.Warn(msg, keyvals...) }
-func Warnf(format string, v ...interface{}) { GetLogger().Logger.Warnf(format, v...) }
-func Error(msg interface{}, keyvals ...interface{}) { GetLogger().Logger.Error(msg, keyvals...) }
-func Errorf(format string, v ...interface{}) { GetLogger().Logger.Errorf(format, v...) }
-func Fatal(msg interface{}, keyvals ...interface{}) { GetLogger().Logger.Fatal(msg, keyvals...) }
-func Fatalf(format string, v ...interface{}) { GetLogger().Logger.Fatalf(format, v...) }
diff --git a/nix/inputs/dms-cli/internal/mocks/brightness/mock_DBusConn.go b/nix/inputs/dms-cli/internal/mocks/brightness/mock_DBusConn.go
deleted file mode 100644
index 63acf4f..0000000
--- a/nix/inputs/dms-cli/internal/mocks/brightness/mock_DBusConn.go
+++ /dev/null
@@ -1,129 +0,0 @@
-// Code generated by mockery v2.53.5. DO NOT EDIT.
-
-package mocks_brightness
-
-import (
- dbus "github.com/godbus/dbus/v5"
- mock "github.com/stretchr/testify/mock"
-)
-
-// MockDBusConn is an autogenerated mock type for the DBusConn type
-type MockDBusConn struct {
- mock.Mock
-}
-
-type MockDBusConn_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *MockDBusConn) EXPECT() *MockDBusConn_Expecter {
- return &MockDBusConn_Expecter{mock: &_m.Mock}
-}
-
-// Close provides a mock function with no fields
-func (_m *MockDBusConn) Close() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for Close")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockDBusConn_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
-type MockDBusConn_Close_Call struct {
- *mock.Call
-}
-
-// Close is a helper method to define mock.On call
-func (_e *MockDBusConn_Expecter) Close() *MockDBusConn_Close_Call {
- return &MockDBusConn_Close_Call{Call: _e.mock.On("Close")}
-}
-
-func (_c *MockDBusConn_Close_Call) Run(run func()) *MockDBusConn_Close_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDBusConn_Close_Call) Return(_a0 error) *MockDBusConn_Close_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockDBusConn_Close_Call) RunAndReturn(run func() error) *MockDBusConn_Close_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Object provides a mock function with given fields: dest, path
-func (_m *MockDBusConn) Object(dest string, path dbus.ObjectPath) dbus.BusObject {
- ret := _m.Called(dest, path)
-
- if len(ret) == 0 {
- panic("no return value specified for Object")
- }
-
- var r0 dbus.BusObject
- if rf, ok := ret.Get(0).(func(string, dbus.ObjectPath) dbus.BusObject); ok {
- r0 = rf(dest, path)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(dbus.BusObject)
- }
- }
-
- return r0
-}
-
-// MockDBusConn_Object_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Object'
-type MockDBusConn_Object_Call struct {
- *mock.Call
-}
-
-// Object is a helper method to define mock.On call
-// - dest string
-// - path dbus.ObjectPath
-func (_e *MockDBusConn_Expecter) Object(dest interface{}, path interface{}) *MockDBusConn_Object_Call {
- return &MockDBusConn_Object_Call{Call: _e.mock.On("Object", dest, path)}
-}
-
-func (_c *MockDBusConn_Object_Call) Run(run func(dest string, path dbus.ObjectPath)) *MockDBusConn_Object_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string), args[1].(dbus.ObjectPath))
- })
- return _c
-}
-
-func (_c *MockDBusConn_Object_Call) Return(_a0 dbus.BusObject) *MockDBusConn_Object_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockDBusConn_Object_Call) RunAndReturn(run func(string, dbus.ObjectPath) dbus.BusObject) *MockDBusConn_Object_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// NewMockDBusConn creates a new instance of MockDBusConn. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewMockDBusConn(t interface {
- mock.TestingT
- Cleanup(func())
-}) *MockDBusConn {
- mock := &MockDBusConn{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/nix/inputs/dms-cli/internal/mocks/cups/mock_CUPSClientInterface.go b/nix/inputs/dms-cli/internal/mocks/cups/mock_CUPSClientInterface.go
deleted file mode 100644
index a5dcd90..0000000
--- a/nix/inputs/dms-cli/internal/mocks/cups/mock_CUPSClientInterface.go
+++ /dev/null
@@ -1,405 +0,0 @@
-// Code generated by mockery v2.53.5. DO NOT EDIT.
-
-package mocks_cups
-
-import (
- io "io"
-
- ipp "github.com/AvengeMedia/danklinux/pkg/ipp"
- mock "github.com/stretchr/testify/mock"
-)
-
-// MockCUPSClientInterface is an autogenerated mock type for the CUPSClientInterface type
-type MockCUPSClientInterface struct {
- mock.Mock
-}
-
-type MockCUPSClientInterface_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *MockCUPSClientInterface) EXPECT() *MockCUPSClientInterface_Expecter {
- return &MockCUPSClientInterface_Expecter{mock: &_m.Mock}
-}
-
-// CancelAllJob provides a mock function with given fields: printer, purge
-func (_m *MockCUPSClientInterface) CancelAllJob(printer string, purge bool) error {
- ret := _m.Called(printer, purge)
-
- if len(ret) == 0 {
- panic("no return value specified for CancelAllJob")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string, bool) error); ok {
- r0 = rf(printer, purge)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockCUPSClientInterface_CancelAllJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CancelAllJob'
-type MockCUPSClientInterface_CancelAllJob_Call struct {
- *mock.Call
-}
-
-// CancelAllJob is a helper method to define mock.On call
-// - printer string
-// - purge bool
-func (_e *MockCUPSClientInterface_Expecter) CancelAllJob(printer interface{}, purge interface{}) *MockCUPSClientInterface_CancelAllJob_Call {
- return &MockCUPSClientInterface_CancelAllJob_Call{Call: _e.mock.On("CancelAllJob", printer, purge)}
-}
-
-func (_c *MockCUPSClientInterface_CancelAllJob_Call) Run(run func(printer string, purge bool)) *MockCUPSClientInterface_CancelAllJob_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string), args[1].(bool))
- })
- return _c
-}
-
-func (_c *MockCUPSClientInterface_CancelAllJob_Call) Return(_a0 error) *MockCUPSClientInterface_CancelAllJob_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockCUPSClientInterface_CancelAllJob_Call) RunAndReturn(run func(string, bool) error) *MockCUPSClientInterface_CancelAllJob_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// CancelJob provides a mock function with given fields: jobID, purge
-func (_m *MockCUPSClientInterface) CancelJob(jobID int, purge bool) error {
- ret := _m.Called(jobID, purge)
-
- if len(ret) == 0 {
- panic("no return value specified for CancelJob")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(int, bool) error); ok {
- r0 = rf(jobID, purge)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockCUPSClientInterface_CancelJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CancelJob'
-type MockCUPSClientInterface_CancelJob_Call struct {
- *mock.Call
-}
-
-// CancelJob is a helper method to define mock.On call
-// - jobID int
-// - purge bool
-func (_e *MockCUPSClientInterface_Expecter) CancelJob(jobID interface{}, purge interface{}) *MockCUPSClientInterface_CancelJob_Call {
- return &MockCUPSClientInterface_CancelJob_Call{Call: _e.mock.On("CancelJob", jobID, purge)}
-}
-
-func (_c *MockCUPSClientInterface_CancelJob_Call) Run(run func(jobID int, purge bool)) *MockCUPSClientInterface_CancelJob_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(int), args[1].(bool))
- })
- return _c
-}
-
-func (_c *MockCUPSClientInterface_CancelJob_Call) Return(_a0 error) *MockCUPSClientInterface_CancelJob_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockCUPSClientInterface_CancelJob_Call) RunAndReturn(run func(int, bool) error) *MockCUPSClientInterface_CancelJob_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetJobs provides a mock function with given fields: printer, class, whichJobs, myJobs, firstJobId, limit, attributes
-func (_m *MockCUPSClientInterface) GetJobs(printer string, class string, whichJobs string, myJobs bool, firstJobId int, limit int, attributes []string) (map[int]ipp.Attributes, error) {
- ret := _m.Called(printer, class, whichJobs, myJobs, firstJobId, limit, attributes)
-
- if len(ret) == 0 {
- panic("no return value specified for GetJobs")
- }
-
- var r0 map[int]ipp.Attributes
- var r1 error
- if rf, ok := ret.Get(0).(func(string, string, string, bool, int, int, []string) (map[int]ipp.Attributes, error)); ok {
- return rf(printer, class, whichJobs, myJobs, firstJobId, limit, attributes)
- }
- if rf, ok := ret.Get(0).(func(string, string, string, bool, int, int, []string) map[int]ipp.Attributes); ok {
- r0 = rf(printer, class, whichJobs, myJobs, firstJobId, limit, attributes)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(map[int]ipp.Attributes)
- }
- }
-
- if rf, ok := ret.Get(1).(func(string, string, string, bool, int, int, []string) error); ok {
- r1 = rf(printer, class, whichJobs, myJobs, firstJobId, limit, attributes)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockCUPSClientInterface_GetJobs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetJobs'
-type MockCUPSClientInterface_GetJobs_Call struct {
- *mock.Call
-}
-
-// GetJobs is a helper method to define mock.On call
-// - printer string
-// - class string
-// - whichJobs string
-// - myJobs bool
-// - firstJobId int
-// - limit int
-// - attributes []string
-func (_e *MockCUPSClientInterface_Expecter) GetJobs(printer interface{}, class interface{}, whichJobs interface{}, myJobs interface{}, firstJobId interface{}, limit interface{}, attributes interface{}) *MockCUPSClientInterface_GetJobs_Call {
- return &MockCUPSClientInterface_GetJobs_Call{Call: _e.mock.On("GetJobs", printer, class, whichJobs, myJobs, firstJobId, limit, attributes)}
-}
-
-func (_c *MockCUPSClientInterface_GetJobs_Call) Run(run func(printer string, class string, whichJobs string, myJobs bool, firstJobId int, limit int, attributes []string)) *MockCUPSClientInterface_GetJobs_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string), args[1].(string), args[2].(string), args[3].(bool), args[4].(int), args[5].(int), args[6].([]string))
- })
- return _c
-}
-
-func (_c *MockCUPSClientInterface_GetJobs_Call) Return(_a0 map[int]ipp.Attributes, _a1 error) *MockCUPSClientInterface_GetJobs_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockCUPSClientInterface_GetJobs_Call) RunAndReturn(run func(string, string, string, bool, int, int, []string) (map[int]ipp.Attributes, error)) *MockCUPSClientInterface_GetJobs_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPrinters provides a mock function with given fields: attributes
-func (_m *MockCUPSClientInterface) GetPrinters(attributes []string) (map[string]ipp.Attributes, error) {
- ret := _m.Called(attributes)
-
- if len(ret) == 0 {
- panic("no return value specified for GetPrinters")
- }
-
- var r0 map[string]ipp.Attributes
- var r1 error
- if rf, ok := ret.Get(0).(func([]string) (map[string]ipp.Attributes, error)); ok {
- return rf(attributes)
- }
- if rf, ok := ret.Get(0).(func([]string) map[string]ipp.Attributes); ok {
- r0 = rf(attributes)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(map[string]ipp.Attributes)
- }
- }
-
- if rf, ok := ret.Get(1).(func([]string) error); ok {
- r1 = rf(attributes)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockCUPSClientInterface_GetPrinters_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPrinters'
-type MockCUPSClientInterface_GetPrinters_Call struct {
- *mock.Call
-}
-
-// GetPrinters is a helper method to define mock.On call
-// - attributes []string
-func (_e *MockCUPSClientInterface_Expecter) GetPrinters(attributes interface{}) *MockCUPSClientInterface_GetPrinters_Call {
- return &MockCUPSClientInterface_GetPrinters_Call{Call: _e.mock.On("GetPrinters", attributes)}
-}
-
-func (_c *MockCUPSClientInterface_GetPrinters_Call) Run(run func(attributes []string)) *MockCUPSClientInterface_GetPrinters_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].([]string))
- })
- return _c
-}
-
-func (_c *MockCUPSClientInterface_GetPrinters_Call) Return(_a0 map[string]ipp.Attributes, _a1 error) *MockCUPSClientInterface_GetPrinters_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockCUPSClientInterface_GetPrinters_Call) RunAndReturn(run func([]string) (map[string]ipp.Attributes, error)) *MockCUPSClientInterface_GetPrinters_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// PausePrinter provides a mock function with given fields: printer
-func (_m *MockCUPSClientInterface) PausePrinter(printer string) error {
- ret := _m.Called(printer)
-
- if len(ret) == 0 {
- panic("no return value specified for PausePrinter")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string) error); ok {
- r0 = rf(printer)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockCUPSClientInterface_PausePrinter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PausePrinter'
-type MockCUPSClientInterface_PausePrinter_Call struct {
- *mock.Call
-}
-
-// PausePrinter is a helper method to define mock.On call
-// - printer string
-func (_e *MockCUPSClientInterface_Expecter) PausePrinter(printer interface{}) *MockCUPSClientInterface_PausePrinter_Call {
- return &MockCUPSClientInterface_PausePrinter_Call{Call: _e.mock.On("PausePrinter", printer)}
-}
-
-func (_c *MockCUPSClientInterface_PausePrinter_Call) Run(run func(printer string)) *MockCUPSClientInterface_PausePrinter_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockCUPSClientInterface_PausePrinter_Call) Return(_a0 error) *MockCUPSClientInterface_PausePrinter_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockCUPSClientInterface_PausePrinter_Call) RunAndReturn(run func(string) error) *MockCUPSClientInterface_PausePrinter_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// ResumePrinter provides a mock function with given fields: printer
-func (_m *MockCUPSClientInterface) ResumePrinter(printer string) error {
- ret := _m.Called(printer)
-
- if len(ret) == 0 {
- panic("no return value specified for ResumePrinter")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string) error); ok {
- r0 = rf(printer)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockCUPSClientInterface_ResumePrinter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResumePrinter'
-type MockCUPSClientInterface_ResumePrinter_Call struct {
- *mock.Call
-}
-
-// ResumePrinter is a helper method to define mock.On call
-// - printer string
-func (_e *MockCUPSClientInterface_Expecter) ResumePrinter(printer interface{}) *MockCUPSClientInterface_ResumePrinter_Call {
- return &MockCUPSClientInterface_ResumePrinter_Call{Call: _e.mock.On("ResumePrinter", printer)}
-}
-
-func (_c *MockCUPSClientInterface_ResumePrinter_Call) Run(run func(printer string)) *MockCUPSClientInterface_ResumePrinter_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockCUPSClientInterface_ResumePrinter_Call) Return(_a0 error) *MockCUPSClientInterface_ResumePrinter_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockCUPSClientInterface_ResumePrinter_Call) RunAndReturn(run func(string) error) *MockCUPSClientInterface_ResumePrinter_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SendRequest provides a mock function with given fields: url, req, additionalResponseData
-func (_m *MockCUPSClientInterface) SendRequest(url string, req *ipp.Request, additionalResponseData io.Writer) (*ipp.Response, error) {
- ret := _m.Called(url, req, additionalResponseData)
-
- if len(ret) == 0 {
- panic("no return value specified for SendRequest")
- }
-
- var r0 *ipp.Response
- var r1 error
- if rf, ok := ret.Get(0).(func(string, *ipp.Request, io.Writer) (*ipp.Response, error)); ok {
- return rf(url, req, additionalResponseData)
- }
- if rf, ok := ret.Get(0).(func(string, *ipp.Request, io.Writer) *ipp.Response); ok {
- r0 = rf(url, req, additionalResponseData)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*ipp.Response)
- }
- }
-
- if rf, ok := ret.Get(1).(func(string, *ipp.Request, io.Writer) error); ok {
- r1 = rf(url, req, additionalResponseData)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockCUPSClientInterface_SendRequest_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendRequest'
-type MockCUPSClientInterface_SendRequest_Call struct {
- *mock.Call
-}
-
-// SendRequest is a helper method to define mock.On call
-// - url string
-// - req *ipp.Request
-// - additionalResponseData io.Writer
-func (_e *MockCUPSClientInterface_Expecter) SendRequest(url interface{}, req interface{}, additionalResponseData interface{}) *MockCUPSClientInterface_SendRequest_Call {
- return &MockCUPSClientInterface_SendRequest_Call{Call: _e.mock.On("SendRequest", url, req, additionalResponseData)}
-}
-
-func (_c *MockCUPSClientInterface_SendRequest_Call) Run(run func(url string, req *ipp.Request, additionalResponseData io.Writer)) *MockCUPSClientInterface_SendRequest_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string), args[1].(*ipp.Request), args[2].(io.Writer))
- })
- return _c
-}
-
-func (_c *MockCUPSClientInterface_SendRequest_Call) Return(_a0 *ipp.Response, _a1 error) *MockCUPSClientInterface_SendRequest_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockCUPSClientInterface_SendRequest_Call) RunAndReturn(run func(string, *ipp.Request, io.Writer) (*ipp.Response, error)) *MockCUPSClientInterface_SendRequest_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// NewMockCUPSClientInterface creates a new instance of MockCUPSClientInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewMockCUPSClientInterface(t interface {
- mock.TestingT
- Cleanup(func())
-}) *MockCUPSClientInterface {
- mock := &MockCUPSClientInterface{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_AccessPoint.go b/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_AccessPoint.go
deleted file mode 100644
index ae5124d..0000000
--- a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_AccessPoint.go
+++ /dev/null
@@ -1,689 +0,0 @@
-// Code generated by mockery v2.53.5. DO NOT EDIT.
-
-package gonetworkmanager
-
-import (
- gonetworkmanager "github.com/Wifx/gonetworkmanager/v2"
- dbus "github.com/godbus/dbus/v5"
-
- mock "github.com/stretchr/testify/mock"
-)
-
-// MockAccessPoint is an autogenerated mock type for the AccessPoint type
-type MockAccessPoint struct {
- mock.Mock
-}
-
-type MockAccessPoint_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *MockAccessPoint) EXPECT() *MockAccessPoint_Expecter {
- return &MockAccessPoint_Expecter{mock: &_m.Mock}
-}
-
-// GetPath provides a mock function with no fields
-func (_m *MockAccessPoint) GetPath() dbus.ObjectPath {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPath")
- }
-
- var r0 dbus.ObjectPath
- if rf, ok := ret.Get(0).(func() dbus.ObjectPath); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(dbus.ObjectPath)
- }
-
- return r0
-}
-
-// MockAccessPoint_GetPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPath'
-type MockAccessPoint_GetPath_Call struct {
- *mock.Call
-}
-
-// GetPath is a helper method to define mock.On call
-func (_e *MockAccessPoint_Expecter) GetPath() *MockAccessPoint_GetPath_Call {
- return &MockAccessPoint_GetPath_Call{Call: _e.mock.On("GetPath")}
-}
-
-func (_c *MockAccessPoint_GetPath_Call) Run(run func()) *MockAccessPoint_GetPath_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockAccessPoint_GetPath_Call) Return(_a0 dbus.ObjectPath) *MockAccessPoint_GetPath_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockAccessPoint_GetPath_Call) RunAndReturn(run func() dbus.ObjectPath) *MockAccessPoint_GetPath_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyFlags provides a mock function with no fields
-func (_m *MockAccessPoint) GetPropertyFlags() (uint32, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyFlags")
- }
-
- var r0 uint32
- var r1 error
- if rf, ok := ret.Get(0).(func() (uint32, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() uint32); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(uint32)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockAccessPoint_GetPropertyFlags_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFlags'
-type MockAccessPoint_GetPropertyFlags_Call struct {
- *mock.Call
-}
-
-// GetPropertyFlags is a helper method to define mock.On call
-func (_e *MockAccessPoint_Expecter) GetPropertyFlags() *MockAccessPoint_GetPropertyFlags_Call {
- return &MockAccessPoint_GetPropertyFlags_Call{Call: _e.mock.On("GetPropertyFlags")}
-}
-
-func (_c *MockAccessPoint_GetPropertyFlags_Call) Run(run func()) *MockAccessPoint_GetPropertyFlags_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyFlags_Call) Return(_a0 uint32, _a1 error) *MockAccessPoint_GetPropertyFlags_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyFlags_Call) RunAndReturn(run func() (uint32, error)) *MockAccessPoint_GetPropertyFlags_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyFrequency provides a mock function with no fields
-func (_m *MockAccessPoint) GetPropertyFrequency() (uint32, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyFrequency")
- }
-
- var r0 uint32
- var r1 error
- if rf, ok := ret.Get(0).(func() (uint32, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() uint32); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(uint32)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockAccessPoint_GetPropertyFrequency_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFrequency'
-type MockAccessPoint_GetPropertyFrequency_Call struct {
- *mock.Call
-}
-
-// GetPropertyFrequency is a helper method to define mock.On call
-func (_e *MockAccessPoint_Expecter) GetPropertyFrequency() *MockAccessPoint_GetPropertyFrequency_Call {
- return &MockAccessPoint_GetPropertyFrequency_Call{Call: _e.mock.On("GetPropertyFrequency")}
-}
-
-func (_c *MockAccessPoint_GetPropertyFrequency_Call) Run(run func()) *MockAccessPoint_GetPropertyFrequency_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyFrequency_Call) Return(_a0 uint32, _a1 error) *MockAccessPoint_GetPropertyFrequency_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyFrequency_Call) RunAndReturn(run func() (uint32, error)) *MockAccessPoint_GetPropertyFrequency_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyHWAddress provides a mock function with no fields
-func (_m *MockAccessPoint) GetPropertyHWAddress() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyHWAddress")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockAccessPoint_GetPropertyHWAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyHWAddress'
-type MockAccessPoint_GetPropertyHWAddress_Call struct {
- *mock.Call
-}
-
-// GetPropertyHWAddress is a helper method to define mock.On call
-func (_e *MockAccessPoint_Expecter) GetPropertyHWAddress() *MockAccessPoint_GetPropertyHWAddress_Call {
- return &MockAccessPoint_GetPropertyHWAddress_Call{Call: _e.mock.On("GetPropertyHWAddress")}
-}
-
-func (_c *MockAccessPoint_GetPropertyHWAddress_Call) Run(run func()) *MockAccessPoint_GetPropertyHWAddress_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyHWAddress_Call) Return(_a0 string, _a1 error) *MockAccessPoint_GetPropertyHWAddress_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyHWAddress_Call) RunAndReturn(run func() (string, error)) *MockAccessPoint_GetPropertyHWAddress_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyLastSeen provides a mock function with no fields
-func (_m *MockAccessPoint) GetPropertyLastSeen() (int32, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyLastSeen")
- }
-
- var r0 int32
- var r1 error
- if rf, ok := ret.Get(0).(func() (int32, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() int32); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(int32)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockAccessPoint_GetPropertyLastSeen_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyLastSeen'
-type MockAccessPoint_GetPropertyLastSeen_Call struct {
- *mock.Call
-}
-
-// GetPropertyLastSeen is a helper method to define mock.On call
-func (_e *MockAccessPoint_Expecter) GetPropertyLastSeen() *MockAccessPoint_GetPropertyLastSeen_Call {
- return &MockAccessPoint_GetPropertyLastSeen_Call{Call: _e.mock.On("GetPropertyLastSeen")}
-}
-
-func (_c *MockAccessPoint_GetPropertyLastSeen_Call) Run(run func()) *MockAccessPoint_GetPropertyLastSeen_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyLastSeen_Call) Return(_a0 int32, _a1 error) *MockAccessPoint_GetPropertyLastSeen_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyLastSeen_Call) RunAndReturn(run func() (int32, error)) *MockAccessPoint_GetPropertyLastSeen_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyMaxBitrate provides a mock function with no fields
-func (_m *MockAccessPoint) GetPropertyMaxBitrate() (uint32, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyMaxBitrate")
- }
-
- var r0 uint32
- var r1 error
- if rf, ok := ret.Get(0).(func() (uint32, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() uint32); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(uint32)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockAccessPoint_GetPropertyMaxBitrate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyMaxBitrate'
-type MockAccessPoint_GetPropertyMaxBitrate_Call struct {
- *mock.Call
-}
-
-// GetPropertyMaxBitrate is a helper method to define mock.On call
-func (_e *MockAccessPoint_Expecter) GetPropertyMaxBitrate() *MockAccessPoint_GetPropertyMaxBitrate_Call {
- return &MockAccessPoint_GetPropertyMaxBitrate_Call{Call: _e.mock.On("GetPropertyMaxBitrate")}
-}
-
-func (_c *MockAccessPoint_GetPropertyMaxBitrate_Call) Run(run func()) *MockAccessPoint_GetPropertyMaxBitrate_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyMaxBitrate_Call) Return(_a0 uint32, _a1 error) *MockAccessPoint_GetPropertyMaxBitrate_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyMaxBitrate_Call) RunAndReturn(run func() (uint32, error)) *MockAccessPoint_GetPropertyMaxBitrate_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyMode provides a mock function with no fields
-func (_m *MockAccessPoint) GetPropertyMode() (gonetworkmanager.Nm80211Mode, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyMode")
- }
-
- var r0 gonetworkmanager.Nm80211Mode
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.Nm80211Mode, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.Nm80211Mode); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(gonetworkmanager.Nm80211Mode)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockAccessPoint_GetPropertyMode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyMode'
-type MockAccessPoint_GetPropertyMode_Call struct {
- *mock.Call
-}
-
-// GetPropertyMode is a helper method to define mock.On call
-func (_e *MockAccessPoint_Expecter) GetPropertyMode() *MockAccessPoint_GetPropertyMode_Call {
- return &MockAccessPoint_GetPropertyMode_Call{Call: _e.mock.On("GetPropertyMode")}
-}
-
-func (_c *MockAccessPoint_GetPropertyMode_Call) Run(run func()) *MockAccessPoint_GetPropertyMode_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyMode_Call) Return(_a0 gonetworkmanager.Nm80211Mode, _a1 error) *MockAccessPoint_GetPropertyMode_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyMode_Call) RunAndReturn(run func() (gonetworkmanager.Nm80211Mode, error)) *MockAccessPoint_GetPropertyMode_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyRSNFlags provides a mock function with no fields
-func (_m *MockAccessPoint) GetPropertyRSNFlags() (uint32, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyRSNFlags")
- }
-
- var r0 uint32
- var r1 error
- if rf, ok := ret.Get(0).(func() (uint32, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() uint32); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(uint32)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockAccessPoint_GetPropertyRSNFlags_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyRSNFlags'
-type MockAccessPoint_GetPropertyRSNFlags_Call struct {
- *mock.Call
-}
-
-// GetPropertyRSNFlags is a helper method to define mock.On call
-func (_e *MockAccessPoint_Expecter) GetPropertyRSNFlags() *MockAccessPoint_GetPropertyRSNFlags_Call {
- return &MockAccessPoint_GetPropertyRSNFlags_Call{Call: _e.mock.On("GetPropertyRSNFlags")}
-}
-
-func (_c *MockAccessPoint_GetPropertyRSNFlags_Call) Run(run func()) *MockAccessPoint_GetPropertyRSNFlags_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyRSNFlags_Call) Return(_a0 uint32, _a1 error) *MockAccessPoint_GetPropertyRSNFlags_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyRSNFlags_Call) RunAndReturn(run func() (uint32, error)) *MockAccessPoint_GetPropertyRSNFlags_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertySSID provides a mock function with no fields
-func (_m *MockAccessPoint) GetPropertySSID() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertySSID")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockAccessPoint_GetPropertySSID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertySSID'
-type MockAccessPoint_GetPropertySSID_Call struct {
- *mock.Call
-}
-
-// GetPropertySSID is a helper method to define mock.On call
-func (_e *MockAccessPoint_Expecter) GetPropertySSID() *MockAccessPoint_GetPropertySSID_Call {
- return &MockAccessPoint_GetPropertySSID_Call{Call: _e.mock.On("GetPropertySSID")}
-}
-
-func (_c *MockAccessPoint_GetPropertySSID_Call) Run(run func()) *MockAccessPoint_GetPropertySSID_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertySSID_Call) Return(_a0 string, _a1 error) *MockAccessPoint_GetPropertySSID_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertySSID_Call) RunAndReturn(run func() (string, error)) *MockAccessPoint_GetPropertySSID_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyStrength provides a mock function with no fields
-func (_m *MockAccessPoint) GetPropertyStrength() (uint8, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyStrength")
- }
-
- var r0 uint8
- var r1 error
- if rf, ok := ret.Get(0).(func() (uint8, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() uint8); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(uint8)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockAccessPoint_GetPropertyStrength_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyStrength'
-type MockAccessPoint_GetPropertyStrength_Call struct {
- *mock.Call
-}
-
-// GetPropertyStrength is a helper method to define mock.On call
-func (_e *MockAccessPoint_Expecter) GetPropertyStrength() *MockAccessPoint_GetPropertyStrength_Call {
- return &MockAccessPoint_GetPropertyStrength_Call{Call: _e.mock.On("GetPropertyStrength")}
-}
-
-func (_c *MockAccessPoint_GetPropertyStrength_Call) Run(run func()) *MockAccessPoint_GetPropertyStrength_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyStrength_Call) Return(_a0 uint8, _a1 error) *MockAccessPoint_GetPropertyStrength_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyStrength_Call) RunAndReturn(run func() (uint8, error)) *MockAccessPoint_GetPropertyStrength_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyWPAFlags provides a mock function with no fields
-func (_m *MockAccessPoint) GetPropertyWPAFlags() (uint32, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyWPAFlags")
- }
-
- var r0 uint32
- var r1 error
- if rf, ok := ret.Get(0).(func() (uint32, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() uint32); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(uint32)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockAccessPoint_GetPropertyWPAFlags_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWPAFlags'
-type MockAccessPoint_GetPropertyWPAFlags_Call struct {
- *mock.Call
-}
-
-// GetPropertyWPAFlags is a helper method to define mock.On call
-func (_e *MockAccessPoint_Expecter) GetPropertyWPAFlags() *MockAccessPoint_GetPropertyWPAFlags_Call {
- return &MockAccessPoint_GetPropertyWPAFlags_Call{Call: _e.mock.On("GetPropertyWPAFlags")}
-}
-
-func (_c *MockAccessPoint_GetPropertyWPAFlags_Call) Run(run func()) *MockAccessPoint_GetPropertyWPAFlags_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyWPAFlags_Call) Return(_a0 uint32, _a1 error) *MockAccessPoint_GetPropertyWPAFlags_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockAccessPoint_GetPropertyWPAFlags_Call) RunAndReturn(run func() (uint32, error)) *MockAccessPoint_GetPropertyWPAFlags_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// MarshalJSON provides a mock function with no fields
-func (_m *MockAccessPoint) MarshalJSON() ([]byte, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for MarshalJSON")
- }
-
- var r0 []byte
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]byte, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []byte); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]byte)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockAccessPoint_MarshalJSON_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarshalJSON'
-type MockAccessPoint_MarshalJSON_Call struct {
- *mock.Call
-}
-
-// MarshalJSON is a helper method to define mock.On call
-func (_e *MockAccessPoint_Expecter) MarshalJSON() *MockAccessPoint_MarshalJSON_Call {
- return &MockAccessPoint_MarshalJSON_Call{Call: _e.mock.On("MarshalJSON")}
-}
-
-func (_c *MockAccessPoint_MarshalJSON_Call) Run(run func()) *MockAccessPoint_MarshalJSON_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockAccessPoint_MarshalJSON_Call) Return(_a0 []byte, _a1 error) *MockAccessPoint_MarshalJSON_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockAccessPoint_MarshalJSON_Call) RunAndReturn(run func() ([]byte, error)) *MockAccessPoint_MarshalJSON_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// NewMockAccessPoint creates a new instance of MockAccessPoint. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewMockAccessPoint(t interface {
- mock.TestingT
- Cleanup(func())
-}) *MockAccessPoint {
- mock := &MockAccessPoint{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_ActiveConnection.go b/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_ActiveConnection.go
deleted file mode 100644
index a4e3344..0000000
--- a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_ActiveConnection.go
+++ /dev/null
@@ -1,1025 +0,0 @@
-// Code generated by mockery v2.53.5. DO NOT EDIT.
-
-package gonetworkmanager
-
-import (
- gonetworkmanager "github.com/Wifx/gonetworkmanager/v2"
- dbus "github.com/godbus/dbus/v5"
-
- mock "github.com/stretchr/testify/mock"
-)
-
-// MockActiveConnection is an autogenerated mock type for the ActiveConnection type
-type MockActiveConnection struct {
- mock.Mock
-}
-
-type MockActiveConnection_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *MockActiveConnection) EXPECT() *MockActiveConnection_Expecter {
- return &MockActiveConnection_Expecter{mock: &_m.Mock}
-}
-
-// GetPath provides a mock function with no fields
-func (_m *MockActiveConnection) GetPath() dbus.ObjectPath {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPath")
- }
-
- var r0 dbus.ObjectPath
- if rf, ok := ret.Get(0).(func() dbus.ObjectPath); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(dbus.ObjectPath)
- }
-
- return r0
-}
-
-// MockActiveConnection_GetPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPath'
-type MockActiveConnection_GetPath_Call struct {
- *mock.Call
-}
-
-// GetPath is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPath() *MockActiveConnection_GetPath_Call {
- return &MockActiveConnection_GetPath_Call{Call: _e.mock.On("GetPath")}
-}
-
-func (_c *MockActiveConnection_GetPath_Call) Run(run func()) *MockActiveConnection_GetPath_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPath_Call) Return(_a0 dbus.ObjectPath) *MockActiveConnection_GetPath_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPath_Call) RunAndReturn(run func() dbus.ObjectPath) *MockActiveConnection_GetPath_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyConnection provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertyConnection() (gonetworkmanager.Connection, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyConnection")
- }
-
- var r0 gonetworkmanager.Connection
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.Connection, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.Connection); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.Connection)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertyConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyConnection'
-type MockActiveConnection_GetPropertyConnection_Call struct {
- *mock.Call
-}
-
-// GetPropertyConnection is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertyConnection() *MockActiveConnection_GetPropertyConnection_Call {
- return &MockActiveConnection_GetPropertyConnection_Call{Call: _e.mock.On("GetPropertyConnection")}
-}
-
-func (_c *MockActiveConnection_GetPropertyConnection_Call) Run(run func()) *MockActiveConnection_GetPropertyConnection_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyConnection_Call) Return(_a0 gonetworkmanager.Connection, _a1 error) *MockActiveConnection_GetPropertyConnection_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyConnection_Call) RunAndReturn(run func() (gonetworkmanager.Connection, error)) *MockActiveConnection_GetPropertyConnection_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDHCP4Config provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertyDHCP4Config() (gonetworkmanager.DHCP4Config, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDHCP4Config")
- }
-
- var r0 gonetworkmanager.DHCP4Config
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.DHCP4Config, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.DHCP4Config); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.DHCP4Config)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertyDHCP4Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDHCP4Config'
-type MockActiveConnection_GetPropertyDHCP4Config_Call struct {
- *mock.Call
-}
-
-// GetPropertyDHCP4Config is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertyDHCP4Config() *MockActiveConnection_GetPropertyDHCP4Config_Call {
- return &MockActiveConnection_GetPropertyDHCP4Config_Call{Call: _e.mock.On("GetPropertyDHCP4Config")}
-}
-
-func (_c *MockActiveConnection_GetPropertyDHCP4Config_Call) Run(run func()) *MockActiveConnection_GetPropertyDHCP4Config_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyDHCP4Config_Call) Return(_a0 gonetworkmanager.DHCP4Config, _a1 error) *MockActiveConnection_GetPropertyDHCP4Config_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyDHCP4Config_Call) RunAndReturn(run func() (gonetworkmanager.DHCP4Config, error)) *MockActiveConnection_GetPropertyDHCP4Config_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDHCP6Config provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertyDHCP6Config() (gonetworkmanager.DHCP6Config, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDHCP6Config")
- }
-
- var r0 gonetworkmanager.DHCP6Config
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.DHCP6Config, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.DHCP6Config); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.DHCP6Config)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertyDHCP6Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDHCP6Config'
-type MockActiveConnection_GetPropertyDHCP6Config_Call struct {
- *mock.Call
-}
-
-// GetPropertyDHCP6Config is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertyDHCP6Config() *MockActiveConnection_GetPropertyDHCP6Config_Call {
- return &MockActiveConnection_GetPropertyDHCP6Config_Call{Call: _e.mock.On("GetPropertyDHCP6Config")}
-}
-
-func (_c *MockActiveConnection_GetPropertyDHCP6Config_Call) Run(run func()) *MockActiveConnection_GetPropertyDHCP6Config_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyDHCP6Config_Call) Return(_a0 gonetworkmanager.DHCP6Config, _a1 error) *MockActiveConnection_GetPropertyDHCP6Config_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyDHCP6Config_Call) RunAndReturn(run func() (gonetworkmanager.DHCP6Config, error)) *MockActiveConnection_GetPropertyDHCP6Config_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDefault provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertyDefault() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDefault")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertyDefault_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDefault'
-type MockActiveConnection_GetPropertyDefault_Call struct {
- *mock.Call
-}
-
-// GetPropertyDefault is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertyDefault() *MockActiveConnection_GetPropertyDefault_Call {
- return &MockActiveConnection_GetPropertyDefault_Call{Call: _e.mock.On("GetPropertyDefault")}
-}
-
-func (_c *MockActiveConnection_GetPropertyDefault_Call) Run(run func()) *MockActiveConnection_GetPropertyDefault_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyDefault_Call) Return(_a0 bool, _a1 error) *MockActiveConnection_GetPropertyDefault_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyDefault_Call) RunAndReturn(run func() (bool, error)) *MockActiveConnection_GetPropertyDefault_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDefault6 provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertyDefault6() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDefault6")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertyDefault6_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDefault6'
-type MockActiveConnection_GetPropertyDefault6_Call struct {
- *mock.Call
-}
-
-// GetPropertyDefault6 is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertyDefault6() *MockActiveConnection_GetPropertyDefault6_Call {
- return &MockActiveConnection_GetPropertyDefault6_Call{Call: _e.mock.On("GetPropertyDefault6")}
-}
-
-func (_c *MockActiveConnection_GetPropertyDefault6_Call) Run(run func()) *MockActiveConnection_GetPropertyDefault6_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyDefault6_Call) Return(_a0 bool, _a1 error) *MockActiveConnection_GetPropertyDefault6_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyDefault6_Call) RunAndReturn(run func() (bool, error)) *MockActiveConnection_GetPropertyDefault6_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDevices provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertyDevices() ([]gonetworkmanager.Device, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDevices")
- }
-
- var r0 []gonetworkmanager.Device
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Device, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.Device); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.Device)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertyDevices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDevices'
-type MockActiveConnection_GetPropertyDevices_Call struct {
- *mock.Call
-}
-
-// GetPropertyDevices is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertyDevices() *MockActiveConnection_GetPropertyDevices_Call {
- return &MockActiveConnection_GetPropertyDevices_Call{Call: _e.mock.On("GetPropertyDevices")}
-}
-
-func (_c *MockActiveConnection_GetPropertyDevices_Call) Run(run func()) *MockActiveConnection_GetPropertyDevices_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyDevices_Call) Return(_a0 []gonetworkmanager.Device, _a1 error) *MockActiveConnection_GetPropertyDevices_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyDevices_Call) RunAndReturn(run func() ([]gonetworkmanager.Device, error)) *MockActiveConnection_GetPropertyDevices_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyID provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertyID() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyID")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertyID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyID'
-type MockActiveConnection_GetPropertyID_Call struct {
- *mock.Call
-}
-
-// GetPropertyID is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertyID() *MockActiveConnection_GetPropertyID_Call {
- return &MockActiveConnection_GetPropertyID_Call{Call: _e.mock.On("GetPropertyID")}
-}
-
-func (_c *MockActiveConnection_GetPropertyID_Call) Run(run func()) *MockActiveConnection_GetPropertyID_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyID_Call) Return(_a0 string, _a1 error) *MockActiveConnection_GetPropertyID_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyID_Call) RunAndReturn(run func() (string, error)) *MockActiveConnection_GetPropertyID_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyIP4Config provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertyIP4Config() (gonetworkmanager.IP4Config, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyIP4Config")
- }
-
- var r0 gonetworkmanager.IP4Config
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.IP4Config, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.IP4Config); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.IP4Config)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertyIP4Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIP4Config'
-type MockActiveConnection_GetPropertyIP4Config_Call struct {
- *mock.Call
-}
-
-// GetPropertyIP4Config is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertyIP4Config() *MockActiveConnection_GetPropertyIP4Config_Call {
- return &MockActiveConnection_GetPropertyIP4Config_Call{Call: _e.mock.On("GetPropertyIP4Config")}
-}
-
-func (_c *MockActiveConnection_GetPropertyIP4Config_Call) Run(run func()) *MockActiveConnection_GetPropertyIP4Config_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyIP4Config_Call) Return(_a0 gonetworkmanager.IP4Config, _a1 error) *MockActiveConnection_GetPropertyIP4Config_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyIP4Config_Call) RunAndReturn(run func() (gonetworkmanager.IP4Config, error)) *MockActiveConnection_GetPropertyIP4Config_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyIP6Config provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertyIP6Config() (gonetworkmanager.IP6Config, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyIP6Config")
- }
-
- var r0 gonetworkmanager.IP6Config
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.IP6Config, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.IP6Config); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.IP6Config)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertyIP6Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIP6Config'
-type MockActiveConnection_GetPropertyIP6Config_Call struct {
- *mock.Call
-}
-
-// GetPropertyIP6Config is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertyIP6Config() *MockActiveConnection_GetPropertyIP6Config_Call {
- return &MockActiveConnection_GetPropertyIP6Config_Call{Call: _e.mock.On("GetPropertyIP6Config")}
-}
-
-func (_c *MockActiveConnection_GetPropertyIP6Config_Call) Run(run func()) *MockActiveConnection_GetPropertyIP6Config_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyIP6Config_Call) Return(_a0 gonetworkmanager.IP6Config, _a1 error) *MockActiveConnection_GetPropertyIP6Config_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyIP6Config_Call) RunAndReturn(run func() (gonetworkmanager.IP6Config, error)) *MockActiveConnection_GetPropertyIP6Config_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyMaster provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertyMaster() (gonetworkmanager.Device, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyMaster")
- }
-
- var r0 gonetworkmanager.Device
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.Device, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.Device); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.Device)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertyMaster_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyMaster'
-type MockActiveConnection_GetPropertyMaster_Call struct {
- *mock.Call
-}
-
-// GetPropertyMaster is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertyMaster() *MockActiveConnection_GetPropertyMaster_Call {
- return &MockActiveConnection_GetPropertyMaster_Call{Call: _e.mock.On("GetPropertyMaster")}
-}
-
-func (_c *MockActiveConnection_GetPropertyMaster_Call) Run(run func()) *MockActiveConnection_GetPropertyMaster_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyMaster_Call) Return(_a0 gonetworkmanager.Device, _a1 error) *MockActiveConnection_GetPropertyMaster_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyMaster_Call) RunAndReturn(run func() (gonetworkmanager.Device, error)) *MockActiveConnection_GetPropertyMaster_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertySpecificObject provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertySpecificObject() (gonetworkmanager.AccessPoint, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertySpecificObject")
- }
-
- var r0 gonetworkmanager.AccessPoint
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.AccessPoint, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.AccessPoint); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.AccessPoint)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertySpecificObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertySpecificObject'
-type MockActiveConnection_GetPropertySpecificObject_Call struct {
- *mock.Call
-}
-
-// GetPropertySpecificObject is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertySpecificObject() *MockActiveConnection_GetPropertySpecificObject_Call {
- return &MockActiveConnection_GetPropertySpecificObject_Call{Call: _e.mock.On("GetPropertySpecificObject")}
-}
-
-func (_c *MockActiveConnection_GetPropertySpecificObject_Call) Run(run func()) *MockActiveConnection_GetPropertySpecificObject_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertySpecificObject_Call) Return(_a0 gonetworkmanager.AccessPoint, _a1 error) *MockActiveConnection_GetPropertySpecificObject_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertySpecificObject_Call) RunAndReturn(run func() (gonetworkmanager.AccessPoint, error)) *MockActiveConnection_GetPropertySpecificObject_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyState provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertyState() (gonetworkmanager.NmActiveConnectionState, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyState")
- }
-
- var r0 gonetworkmanager.NmActiveConnectionState
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmActiveConnectionState, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.NmActiveConnectionState); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(gonetworkmanager.NmActiveConnectionState)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertyState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyState'
-type MockActiveConnection_GetPropertyState_Call struct {
- *mock.Call
-}
-
-// GetPropertyState is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertyState() *MockActiveConnection_GetPropertyState_Call {
- return &MockActiveConnection_GetPropertyState_Call{Call: _e.mock.On("GetPropertyState")}
-}
-
-func (_c *MockActiveConnection_GetPropertyState_Call) Run(run func()) *MockActiveConnection_GetPropertyState_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyState_Call) Return(_a0 gonetworkmanager.NmActiveConnectionState, _a1 error) *MockActiveConnection_GetPropertyState_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyState_Call) RunAndReturn(run func() (gonetworkmanager.NmActiveConnectionState, error)) *MockActiveConnection_GetPropertyState_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyStateFlags provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertyStateFlags() (uint32, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyStateFlags")
- }
-
- var r0 uint32
- var r1 error
- if rf, ok := ret.Get(0).(func() (uint32, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() uint32); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(uint32)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertyStateFlags_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyStateFlags'
-type MockActiveConnection_GetPropertyStateFlags_Call struct {
- *mock.Call
-}
-
-// GetPropertyStateFlags is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertyStateFlags() *MockActiveConnection_GetPropertyStateFlags_Call {
- return &MockActiveConnection_GetPropertyStateFlags_Call{Call: _e.mock.On("GetPropertyStateFlags")}
-}
-
-func (_c *MockActiveConnection_GetPropertyStateFlags_Call) Run(run func()) *MockActiveConnection_GetPropertyStateFlags_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyStateFlags_Call) Return(_a0 uint32, _a1 error) *MockActiveConnection_GetPropertyStateFlags_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyStateFlags_Call) RunAndReturn(run func() (uint32, error)) *MockActiveConnection_GetPropertyStateFlags_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyType provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertyType() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyType")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertyType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyType'
-type MockActiveConnection_GetPropertyType_Call struct {
- *mock.Call
-}
-
-// GetPropertyType is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertyType() *MockActiveConnection_GetPropertyType_Call {
- return &MockActiveConnection_GetPropertyType_Call{Call: _e.mock.On("GetPropertyType")}
-}
-
-func (_c *MockActiveConnection_GetPropertyType_Call) Run(run func()) *MockActiveConnection_GetPropertyType_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyType_Call) Return(_a0 string, _a1 error) *MockActiveConnection_GetPropertyType_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyType_Call) RunAndReturn(run func() (string, error)) *MockActiveConnection_GetPropertyType_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyUUID provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertyUUID() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyUUID")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertyUUID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyUUID'
-type MockActiveConnection_GetPropertyUUID_Call struct {
- *mock.Call
-}
-
-// GetPropertyUUID is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertyUUID() *MockActiveConnection_GetPropertyUUID_Call {
- return &MockActiveConnection_GetPropertyUUID_Call{Call: _e.mock.On("GetPropertyUUID")}
-}
-
-func (_c *MockActiveConnection_GetPropertyUUID_Call) Run(run func()) *MockActiveConnection_GetPropertyUUID_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyUUID_Call) Return(_a0 string, _a1 error) *MockActiveConnection_GetPropertyUUID_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyUUID_Call) RunAndReturn(run func() (string, error)) *MockActiveConnection_GetPropertyUUID_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyVPN provides a mock function with no fields
-func (_m *MockActiveConnection) GetPropertyVPN() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyVPN")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockActiveConnection_GetPropertyVPN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyVPN'
-type MockActiveConnection_GetPropertyVPN_Call struct {
- *mock.Call
-}
-
-// GetPropertyVPN is a helper method to define mock.On call
-func (_e *MockActiveConnection_Expecter) GetPropertyVPN() *MockActiveConnection_GetPropertyVPN_Call {
- return &MockActiveConnection_GetPropertyVPN_Call{Call: _e.mock.On("GetPropertyVPN")}
-}
-
-func (_c *MockActiveConnection_GetPropertyVPN_Call) Run(run func()) *MockActiveConnection_GetPropertyVPN_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyVPN_Call) Return(_a0 bool, _a1 error) *MockActiveConnection_GetPropertyVPN_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockActiveConnection_GetPropertyVPN_Call) RunAndReturn(run func() (bool, error)) *MockActiveConnection_GetPropertyVPN_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SubscribeState provides a mock function with given fields: receiver, exit
-func (_m *MockActiveConnection) SubscribeState(receiver chan gonetworkmanager.StateChange, exit chan struct{}) error {
- ret := _m.Called(receiver, exit)
-
- if len(ret) == 0 {
- panic("no return value specified for SubscribeState")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(chan gonetworkmanager.StateChange, chan struct{}) error); ok {
- r0 = rf(receiver, exit)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockActiveConnection_SubscribeState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeState'
-type MockActiveConnection_SubscribeState_Call struct {
- *mock.Call
-}
-
-// SubscribeState is a helper method to define mock.On call
-// - receiver chan gonetworkmanager.StateChange
-// - exit chan struct{}
-func (_e *MockActiveConnection_Expecter) SubscribeState(receiver interface{}, exit interface{}) *MockActiveConnection_SubscribeState_Call {
- return &MockActiveConnection_SubscribeState_Call{Call: _e.mock.On("SubscribeState", receiver, exit)}
-}
-
-func (_c *MockActiveConnection_SubscribeState_Call) Run(run func(receiver chan gonetworkmanager.StateChange, exit chan struct{})) *MockActiveConnection_SubscribeState_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(chan gonetworkmanager.StateChange), args[1].(chan struct{}))
- })
- return _c
-}
-
-func (_c *MockActiveConnection_SubscribeState_Call) Return(err error) *MockActiveConnection_SubscribeState_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *MockActiveConnection_SubscribeState_Call) RunAndReturn(run func(chan gonetworkmanager.StateChange, chan struct{}) error) *MockActiveConnection_SubscribeState_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// NewMockActiveConnection creates a new instance of MockActiveConnection. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewMockActiveConnection(t interface {
- mock.TestingT
- Cleanup(func())
-}) *MockActiveConnection {
- mock := &MockActiveConnection{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Connection.go b/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Connection.go
deleted file mode 100644
index 84f59e1..0000000
--- a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Connection.go
+++ /dev/null
@@ -1,646 +0,0 @@
-// Code generated by mockery v2.53.5. DO NOT EDIT.
-
-package gonetworkmanager
-
-import (
- gonetworkmanager "github.com/Wifx/gonetworkmanager/v2"
- dbus "github.com/godbus/dbus/v5"
-
- mock "github.com/stretchr/testify/mock"
-)
-
-// MockConnection is an autogenerated mock type for the Connection type
-type MockConnection struct {
- mock.Mock
-}
-
-type MockConnection_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *MockConnection) EXPECT() *MockConnection_Expecter {
- return &MockConnection_Expecter{mock: &_m.Mock}
-}
-
-// ClearSecrets provides a mock function with no fields
-func (_m *MockConnection) ClearSecrets() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for ClearSecrets")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockConnection_ClearSecrets_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClearSecrets'
-type MockConnection_ClearSecrets_Call struct {
- *mock.Call
-}
-
-// ClearSecrets is a helper method to define mock.On call
-func (_e *MockConnection_Expecter) ClearSecrets() *MockConnection_ClearSecrets_Call {
- return &MockConnection_ClearSecrets_Call{Call: _e.mock.On("ClearSecrets")}
-}
-
-func (_c *MockConnection_ClearSecrets_Call) Run(run func()) *MockConnection_ClearSecrets_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockConnection_ClearSecrets_Call) Return(_a0 error) *MockConnection_ClearSecrets_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockConnection_ClearSecrets_Call) RunAndReturn(run func() error) *MockConnection_ClearSecrets_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Delete provides a mock function with no fields
-func (_m *MockConnection) Delete() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for Delete")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockConnection_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete'
-type MockConnection_Delete_Call struct {
- *mock.Call
-}
-
-// Delete is a helper method to define mock.On call
-func (_e *MockConnection_Expecter) Delete() *MockConnection_Delete_Call {
- return &MockConnection_Delete_Call{Call: _e.mock.On("Delete")}
-}
-
-func (_c *MockConnection_Delete_Call) Run(run func()) *MockConnection_Delete_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockConnection_Delete_Call) Return(_a0 error) *MockConnection_Delete_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockConnection_Delete_Call) RunAndReturn(run func() error) *MockConnection_Delete_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPath provides a mock function with no fields
-func (_m *MockConnection) GetPath() dbus.ObjectPath {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPath")
- }
-
- var r0 dbus.ObjectPath
- if rf, ok := ret.Get(0).(func() dbus.ObjectPath); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(dbus.ObjectPath)
- }
-
- return r0
-}
-
-// MockConnection_GetPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPath'
-type MockConnection_GetPath_Call struct {
- *mock.Call
-}
-
-// GetPath is a helper method to define mock.On call
-func (_e *MockConnection_Expecter) GetPath() *MockConnection_GetPath_Call {
- return &MockConnection_GetPath_Call{Call: _e.mock.On("GetPath")}
-}
-
-func (_c *MockConnection_GetPath_Call) Run(run func()) *MockConnection_GetPath_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockConnection_GetPath_Call) Return(_a0 dbus.ObjectPath) *MockConnection_GetPath_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockConnection_GetPath_Call) RunAndReturn(run func() dbus.ObjectPath) *MockConnection_GetPath_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyFilename provides a mock function with no fields
-func (_m *MockConnection) GetPropertyFilename() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyFilename")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockConnection_GetPropertyFilename_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFilename'
-type MockConnection_GetPropertyFilename_Call struct {
- *mock.Call
-}
-
-// GetPropertyFilename is a helper method to define mock.On call
-func (_e *MockConnection_Expecter) GetPropertyFilename() *MockConnection_GetPropertyFilename_Call {
- return &MockConnection_GetPropertyFilename_Call{Call: _e.mock.On("GetPropertyFilename")}
-}
-
-func (_c *MockConnection_GetPropertyFilename_Call) Run(run func()) *MockConnection_GetPropertyFilename_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockConnection_GetPropertyFilename_Call) Return(_a0 string, _a1 error) *MockConnection_GetPropertyFilename_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockConnection_GetPropertyFilename_Call) RunAndReturn(run func() (string, error)) *MockConnection_GetPropertyFilename_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyFlags provides a mock function with no fields
-func (_m *MockConnection) GetPropertyFlags() (uint32, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyFlags")
- }
-
- var r0 uint32
- var r1 error
- if rf, ok := ret.Get(0).(func() (uint32, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() uint32); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(uint32)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockConnection_GetPropertyFlags_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFlags'
-type MockConnection_GetPropertyFlags_Call struct {
- *mock.Call
-}
-
-// GetPropertyFlags is a helper method to define mock.On call
-func (_e *MockConnection_Expecter) GetPropertyFlags() *MockConnection_GetPropertyFlags_Call {
- return &MockConnection_GetPropertyFlags_Call{Call: _e.mock.On("GetPropertyFlags")}
-}
-
-func (_c *MockConnection_GetPropertyFlags_Call) Run(run func()) *MockConnection_GetPropertyFlags_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockConnection_GetPropertyFlags_Call) Return(_a0 uint32, _a1 error) *MockConnection_GetPropertyFlags_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockConnection_GetPropertyFlags_Call) RunAndReturn(run func() (uint32, error)) *MockConnection_GetPropertyFlags_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyUnsaved provides a mock function with no fields
-func (_m *MockConnection) GetPropertyUnsaved() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyUnsaved")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockConnection_GetPropertyUnsaved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyUnsaved'
-type MockConnection_GetPropertyUnsaved_Call struct {
- *mock.Call
-}
-
-// GetPropertyUnsaved is a helper method to define mock.On call
-func (_e *MockConnection_Expecter) GetPropertyUnsaved() *MockConnection_GetPropertyUnsaved_Call {
- return &MockConnection_GetPropertyUnsaved_Call{Call: _e.mock.On("GetPropertyUnsaved")}
-}
-
-func (_c *MockConnection_GetPropertyUnsaved_Call) Run(run func()) *MockConnection_GetPropertyUnsaved_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockConnection_GetPropertyUnsaved_Call) Return(_a0 bool, _a1 error) *MockConnection_GetPropertyUnsaved_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockConnection_GetPropertyUnsaved_Call) RunAndReturn(run func() (bool, error)) *MockConnection_GetPropertyUnsaved_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetSecrets provides a mock function with given fields: settingName
-func (_m *MockConnection) GetSecrets(settingName string) (gonetworkmanager.ConnectionSettings, error) {
- ret := _m.Called(settingName)
-
- if len(ret) == 0 {
- panic("no return value specified for GetSecrets")
- }
-
- var r0 gonetworkmanager.ConnectionSettings
- var r1 error
- if rf, ok := ret.Get(0).(func(string) (gonetworkmanager.ConnectionSettings, error)); ok {
- return rf(settingName)
- }
- if rf, ok := ret.Get(0).(func(string) gonetworkmanager.ConnectionSettings); ok {
- r0 = rf(settingName)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.ConnectionSettings)
- }
- }
-
- if rf, ok := ret.Get(1).(func(string) error); ok {
- r1 = rf(settingName)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockConnection_GetSecrets_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSecrets'
-type MockConnection_GetSecrets_Call struct {
- *mock.Call
-}
-
-// GetSecrets is a helper method to define mock.On call
-// - settingName string
-func (_e *MockConnection_Expecter) GetSecrets(settingName interface{}) *MockConnection_GetSecrets_Call {
- return &MockConnection_GetSecrets_Call{Call: _e.mock.On("GetSecrets", settingName)}
-}
-
-func (_c *MockConnection_GetSecrets_Call) Run(run func(settingName string)) *MockConnection_GetSecrets_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockConnection_GetSecrets_Call) Return(_a0 gonetworkmanager.ConnectionSettings, _a1 error) *MockConnection_GetSecrets_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockConnection_GetSecrets_Call) RunAndReturn(run func(string) (gonetworkmanager.ConnectionSettings, error)) *MockConnection_GetSecrets_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetSettings provides a mock function with no fields
-func (_m *MockConnection) GetSettings() (gonetworkmanager.ConnectionSettings, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetSettings")
- }
-
- var r0 gonetworkmanager.ConnectionSettings
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.ConnectionSettings, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.ConnectionSettings); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.ConnectionSettings)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockConnection_GetSettings_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSettings'
-type MockConnection_GetSettings_Call struct {
- *mock.Call
-}
-
-// GetSettings is a helper method to define mock.On call
-func (_e *MockConnection_Expecter) GetSettings() *MockConnection_GetSettings_Call {
- return &MockConnection_GetSettings_Call{Call: _e.mock.On("GetSettings")}
-}
-
-func (_c *MockConnection_GetSettings_Call) Run(run func()) *MockConnection_GetSettings_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockConnection_GetSettings_Call) Return(_a0 gonetworkmanager.ConnectionSettings, _a1 error) *MockConnection_GetSettings_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockConnection_GetSettings_Call) RunAndReturn(run func() (gonetworkmanager.ConnectionSettings, error)) *MockConnection_GetSettings_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// MarshalJSON provides a mock function with no fields
-func (_m *MockConnection) MarshalJSON() ([]byte, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for MarshalJSON")
- }
-
- var r0 []byte
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]byte, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []byte); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]byte)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockConnection_MarshalJSON_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarshalJSON'
-type MockConnection_MarshalJSON_Call struct {
- *mock.Call
-}
-
-// MarshalJSON is a helper method to define mock.On call
-func (_e *MockConnection_Expecter) MarshalJSON() *MockConnection_MarshalJSON_Call {
- return &MockConnection_MarshalJSON_Call{Call: _e.mock.On("MarshalJSON")}
-}
-
-func (_c *MockConnection_MarshalJSON_Call) Run(run func()) *MockConnection_MarshalJSON_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockConnection_MarshalJSON_Call) Return(_a0 []byte, _a1 error) *MockConnection_MarshalJSON_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockConnection_MarshalJSON_Call) RunAndReturn(run func() ([]byte, error)) *MockConnection_MarshalJSON_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Save provides a mock function with no fields
-func (_m *MockConnection) Save() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for Save")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockConnection_Save_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Save'
-type MockConnection_Save_Call struct {
- *mock.Call
-}
-
-// Save is a helper method to define mock.On call
-func (_e *MockConnection_Expecter) Save() *MockConnection_Save_Call {
- return &MockConnection_Save_Call{Call: _e.mock.On("Save")}
-}
-
-func (_c *MockConnection_Save_Call) Run(run func()) *MockConnection_Save_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockConnection_Save_Call) Return(_a0 error) *MockConnection_Save_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockConnection_Save_Call) RunAndReturn(run func() error) *MockConnection_Save_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Update provides a mock function with given fields: settings
-func (_m *MockConnection) Update(settings gonetworkmanager.ConnectionSettings) error {
- ret := _m.Called(settings)
-
- if len(ret) == 0 {
- panic("no return value specified for Update")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(gonetworkmanager.ConnectionSettings) error); ok {
- r0 = rf(settings)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockConnection_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update'
-type MockConnection_Update_Call struct {
- *mock.Call
-}
-
-// Update is a helper method to define mock.On call
-// - settings gonetworkmanager.ConnectionSettings
-func (_e *MockConnection_Expecter) Update(settings interface{}) *MockConnection_Update_Call {
- return &MockConnection_Update_Call{Call: _e.mock.On("Update", settings)}
-}
-
-func (_c *MockConnection_Update_Call) Run(run func(settings gonetworkmanager.ConnectionSettings)) *MockConnection_Update_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(gonetworkmanager.ConnectionSettings))
- })
- return _c
-}
-
-func (_c *MockConnection_Update_Call) Return(_a0 error) *MockConnection_Update_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockConnection_Update_Call) RunAndReturn(run func(gonetworkmanager.ConnectionSettings) error) *MockConnection_Update_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// UpdateUnsaved provides a mock function with given fields: settings
-func (_m *MockConnection) UpdateUnsaved(settings gonetworkmanager.ConnectionSettings) error {
- ret := _m.Called(settings)
-
- if len(ret) == 0 {
- panic("no return value specified for UpdateUnsaved")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(gonetworkmanager.ConnectionSettings) error); ok {
- r0 = rf(settings)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockConnection_UpdateUnsaved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateUnsaved'
-type MockConnection_UpdateUnsaved_Call struct {
- *mock.Call
-}
-
-// UpdateUnsaved is a helper method to define mock.On call
-// - settings gonetworkmanager.ConnectionSettings
-func (_e *MockConnection_Expecter) UpdateUnsaved(settings interface{}) *MockConnection_UpdateUnsaved_Call {
- return &MockConnection_UpdateUnsaved_Call{Call: _e.mock.On("UpdateUnsaved", settings)}
-}
-
-func (_c *MockConnection_UpdateUnsaved_Call) Run(run func(settings gonetworkmanager.ConnectionSettings)) *MockConnection_UpdateUnsaved_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(gonetworkmanager.ConnectionSettings))
- })
- return _c
-}
-
-func (_c *MockConnection_UpdateUnsaved_Call) Return(_a0 error) *MockConnection_UpdateUnsaved_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockConnection_UpdateUnsaved_Call) RunAndReturn(run func(gonetworkmanager.ConnectionSettings) error) *MockConnection_UpdateUnsaved_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// NewMockConnection creates a new instance of MockConnection. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewMockConnection(t interface {
- mock.TestingT
- Cleanup(func())
-}) *MockConnection {
- mock := &MockConnection{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Device.go b/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Device.go
deleted file mode 100644
index b2fc0b5..0000000
--- a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Device.go
+++ /dev/null
@@ -1,1638 +0,0 @@
-// Code generated by mockery v2.53.5. DO NOT EDIT.
-
-package gonetworkmanager
-
-import (
- gonetworkmanager "github.com/Wifx/gonetworkmanager/v2"
- dbus "github.com/godbus/dbus/v5"
-
- mock "github.com/stretchr/testify/mock"
-)
-
-// MockDevice is an autogenerated mock type for the Device type
-type MockDevice struct {
- mock.Mock
-}
-
-type MockDevice_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *MockDevice) EXPECT() *MockDevice_Expecter {
- return &MockDevice_Expecter{mock: &_m.Mock}
-}
-
-// Delete provides a mock function with no fields
-func (_m *MockDevice) Delete() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for Delete")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockDevice_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete'
-type MockDevice_Delete_Call struct {
- *mock.Call
-}
-
-// Delete is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) Delete() *MockDevice_Delete_Call {
- return &MockDevice_Delete_Call{Call: _e.mock.On("Delete")}
-}
-
-func (_c *MockDevice_Delete_Call) Run(run func()) *MockDevice_Delete_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_Delete_Call) Return(_a0 error) *MockDevice_Delete_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockDevice_Delete_Call) RunAndReturn(run func() error) *MockDevice_Delete_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Disconnect provides a mock function with no fields
-func (_m *MockDevice) Disconnect() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for Disconnect")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockDevice_Disconnect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Disconnect'
-type MockDevice_Disconnect_Call struct {
- *mock.Call
-}
-
-// Disconnect is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) Disconnect() *MockDevice_Disconnect_Call {
- return &MockDevice_Disconnect_Call{Call: _e.mock.On("Disconnect")}
-}
-
-func (_c *MockDevice_Disconnect_Call) Run(run func()) *MockDevice_Disconnect_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_Disconnect_Call) Return(_a0 error) *MockDevice_Disconnect_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockDevice_Disconnect_Call) RunAndReturn(run func() error) *MockDevice_Disconnect_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPath provides a mock function with no fields
-func (_m *MockDevice) GetPath() dbus.ObjectPath {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPath")
- }
-
- var r0 dbus.ObjectPath
- if rf, ok := ret.Get(0).(func() dbus.ObjectPath); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(dbus.ObjectPath)
- }
-
- return r0
-}
-
-// MockDevice_GetPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPath'
-type MockDevice_GetPath_Call struct {
- *mock.Call
-}
-
-// GetPath is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPath() *MockDevice_GetPath_Call {
- return &MockDevice_GetPath_Call{Call: _e.mock.On("GetPath")}
-}
-
-func (_c *MockDevice_GetPath_Call) Run(run func()) *MockDevice_GetPath_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPath_Call) Return(_a0 dbus.ObjectPath) *MockDevice_GetPath_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockDevice_GetPath_Call) RunAndReturn(run func() dbus.ObjectPath) *MockDevice_GetPath_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyActiveConnection provides a mock function with no fields
-func (_m *MockDevice) GetPropertyActiveConnection() (gonetworkmanager.ActiveConnection, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyActiveConnection")
- }
-
- var r0 gonetworkmanager.ActiveConnection
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.ActiveConnection, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.ActiveConnection); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.ActiveConnection)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyActiveConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyActiveConnection'
-type MockDevice_GetPropertyActiveConnection_Call struct {
- *mock.Call
-}
-
-// GetPropertyActiveConnection is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyActiveConnection() *MockDevice_GetPropertyActiveConnection_Call {
- return &MockDevice_GetPropertyActiveConnection_Call{Call: _e.mock.On("GetPropertyActiveConnection")}
-}
-
-func (_c *MockDevice_GetPropertyActiveConnection_Call) Run(run func()) *MockDevice_GetPropertyActiveConnection_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyActiveConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockDevice_GetPropertyActiveConnection_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyActiveConnection_Call) RunAndReturn(run func() (gonetworkmanager.ActiveConnection, error)) *MockDevice_GetPropertyActiveConnection_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyAutoConnect provides a mock function with no fields
-func (_m *MockDevice) GetPropertyAutoConnect() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyAutoConnect")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyAutoConnect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAutoConnect'
-type MockDevice_GetPropertyAutoConnect_Call struct {
- *mock.Call
-}
-
-// GetPropertyAutoConnect is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyAutoConnect() *MockDevice_GetPropertyAutoConnect_Call {
- return &MockDevice_GetPropertyAutoConnect_Call{Call: _e.mock.On("GetPropertyAutoConnect")}
-}
-
-func (_c *MockDevice_GetPropertyAutoConnect_Call) Run(run func()) *MockDevice_GetPropertyAutoConnect_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyAutoConnect_Call) Return(_a0 bool, _a1 error) *MockDevice_GetPropertyAutoConnect_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyAutoConnect_Call) RunAndReturn(run func() (bool, error)) *MockDevice_GetPropertyAutoConnect_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyAvailableConnections provides a mock function with no fields
-func (_m *MockDevice) GetPropertyAvailableConnections() ([]gonetworkmanager.Connection, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyAvailableConnections")
- }
-
- var r0 []gonetworkmanager.Connection
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Connection, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.Connection); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.Connection)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyAvailableConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAvailableConnections'
-type MockDevice_GetPropertyAvailableConnections_Call struct {
- *mock.Call
-}
-
-// GetPropertyAvailableConnections is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyAvailableConnections() *MockDevice_GetPropertyAvailableConnections_Call {
- return &MockDevice_GetPropertyAvailableConnections_Call{Call: _e.mock.On("GetPropertyAvailableConnections")}
-}
-
-func (_c *MockDevice_GetPropertyAvailableConnections_Call) Run(run func()) *MockDevice_GetPropertyAvailableConnections_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyAvailableConnections_Call) Return(_a0 []gonetworkmanager.Connection, _a1 error) *MockDevice_GetPropertyAvailableConnections_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyAvailableConnections_Call) RunAndReturn(run func() ([]gonetworkmanager.Connection, error)) *MockDevice_GetPropertyAvailableConnections_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDHCP4Config provides a mock function with no fields
-func (_m *MockDevice) GetPropertyDHCP4Config() (gonetworkmanager.DHCP4Config, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDHCP4Config")
- }
-
- var r0 gonetworkmanager.DHCP4Config
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.DHCP4Config, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.DHCP4Config); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.DHCP4Config)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyDHCP4Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDHCP4Config'
-type MockDevice_GetPropertyDHCP4Config_Call struct {
- *mock.Call
-}
-
-// GetPropertyDHCP4Config is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyDHCP4Config() *MockDevice_GetPropertyDHCP4Config_Call {
- return &MockDevice_GetPropertyDHCP4Config_Call{Call: _e.mock.On("GetPropertyDHCP4Config")}
-}
-
-func (_c *MockDevice_GetPropertyDHCP4Config_Call) Run(run func()) *MockDevice_GetPropertyDHCP4Config_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyDHCP4Config_Call) Return(_a0 gonetworkmanager.DHCP4Config, _a1 error) *MockDevice_GetPropertyDHCP4Config_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyDHCP4Config_Call) RunAndReturn(run func() (gonetworkmanager.DHCP4Config, error)) *MockDevice_GetPropertyDHCP4Config_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDHCP6Config provides a mock function with no fields
-func (_m *MockDevice) GetPropertyDHCP6Config() (gonetworkmanager.DHCP6Config, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDHCP6Config")
- }
-
- var r0 gonetworkmanager.DHCP6Config
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.DHCP6Config, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.DHCP6Config); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.DHCP6Config)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyDHCP6Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDHCP6Config'
-type MockDevice_GetPropertyDHCP6Config_Call struct {
- *mock.Call
-}
-
-// GetPropertyDHCP6Config is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyDHCP6Config() *MockDevice_GetPropertyDHCP6Config_Call {
- return &MockDevice_GetPropertyDHCP6Config_Call{Call: _e.mock.On("GetPropertyDHCP6Config")}
-}
-
-func (_c *MockDevice_GetPropertyDHCP6Config_Call) Run(run func()) *MockDevice_GetPropertyDHCP6Config_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyDHCP6Config_Call) Return(_a0 gonetworkmanager.DHCP6Config, _a1 error) *MockDevice_GetPropertyDHCP6Config_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyDHCP6Config_Call) RunAndReturn(run func() (gonetworkmanager.DHCP6Config, error)) *MockDevice_GetPropertyDHCP6Config_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDeviceType provides a mock function with no fields
-func (_m *MockDevice) GetPropertyDeviceType() (gonetworkmanager.NmDeviceType, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDeviceType")
- }
-
- var r0 gonetworkmanager.NmDeviceType
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmDeviceType, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.NmDeviceType); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(gonetworkmanager.NmDeviceType)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyDeviceType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDeviceType'
-type MockDevice_GetPropertyDeviceType_Call struct {
- *mock.Call
-}
-
-// GetPropertyDeviceType is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyDeviceType() *MockDevice_GetPropertyDeviceType_Call {
- return &MockDevice_GetPropertyDeviceType_Call{Call: _e.mock.On("GetPropertyDeviceType")}
-}
-
-func (_c *MockDevice_GetPropertyDeviceType_Call) Run(run func()) *MockDevice_GetPropertyDeviceType_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyDeviceType_Call) Return(_a0 gonetworkmanager.NmDeviceType, _a1 error) *MockDevice_GetPropertyDeviceType_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyDeviceType_Call) RunAndReturn(run func() (gonetworkmanager.NmDeviceType, error)) *MockDevice_GetPropertyDeviceType_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDriver provides a mock function with no fields
-func (_m *MockDevice) GetPropertyDriver() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDriver")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyDriver_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDriver'
-type MockDevice_GetPropertyDriver_Call struct {
- *mock.Call
-}
-
-// GetPropertyDriver is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyDriver() *MockDevice_GetPropertyDriver_Call {
- return &MockDevice_GetPropertyDriver_Call{Call: _e.mock.On("GetPropertyDriver")}
-}
-
-func (_c *MockDevice_GetPropertyDriver_Call) Run(run func()) *MockDevice_GetPropertyDriver_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyDriver_Call) Return(_a0 string, _a1 error) *MockDevice_GetPropertyDriver_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyDriver_Call) RunAndReturn(run func() (string, error)) *MockDevice_GetPropertyDriver_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDriverVersion provides a mock function with no fields
-func (_m *MockDevice) GetPropertyDriverVersion() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDriverVersion")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyDriverVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDriverVersion'
-type MockDevice_GetPropertyDriverVersion_Call struct {
- *mock.Call
-}
-
-// GetPropertyDriverVersion is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyDriverVersion() *MockDevice_GetPropertyDriverVersion_Call {
- return &MockDevice_GetPropertyDriverVersion_Call{Call: _e.mock.On("GetPropertyDriverVersion")}
-}
-
-func (_c *MockDevice_GetPropertyDriverVersion_Call) Run(run func()) *MockDevice_GetPropertyDriverVersion_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyDriverVersion_Call) Return(_a0 string, _a1 error) *MockDevice_GetPropertyDriverVersion_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyDriverVersion_Call) RunAndReturn(run func() (string, error)) *MockDevice_GetPropertyDriverVersion_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyFirmwareMissing provides a mock function with no fields
-func (_m *MockDevice) GetPropertyFirmwareMissing() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyFirmwareMissing")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyFirmwareMissing_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFirmwareMissing'
-type MockDevice_GetPropertyFirmwareMissing_Call struct {
- *mock.Call
-}
-
-// GetPropertyFirmwareMissing is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyFirmwareMissing() *MockDevice_GetPropertyFirmwareMissing_Call {
- return &MockDevice_GetPropertyFirmwareMissing_Call{Call: _e.mock.On("GetPropertyFirmwareMissing")}
-}
-
-func (_c *MockDevice_GetPropertyFirmwareMissing_Call) Run(run func()) *MockDevice_GetPropertyFirmwareMissing_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyFirmwareMissing_Call) Return(_a0 bool, _a1 error) *MockDevice_GetPropertyFirmwareMissing_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyFirmwareMissing_Call) RunAndReturn(run func() (bool, error)) *MockDevice_GetPropertyFirmwareMissing_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyFirmwareVersion provides a mock function with no fields
-func (_m *MockDevice) GetPropertyFirmwareVersion() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyFirmwareVersion")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyFirmwareVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFirmwareVersion'
-type MockDevice_GetPropertyFirmwareVersion_Call struct {
- *mock.Call
-}
-
-// GetPropertyFirmwareVersion is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyFirmwareVersion() *MockDevice_GetPropertyFirmwareVersion_Call {
- return &MockDevice_GetPropertyFirmwareVersion_Call{Call: _e.mock.On("GetPropertyFirmwareVersion")}
-}
-
-func (_c *MockDevice_GetPropertyFirmwareVersion_Call) Run(run func()) *MockDevice_GetPropertyFirmwareVersion_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyFirmwareVersion_Call) Return(_a0 string, _a1 error) *MockDevice_GetPropertyFirmwareVersion_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyFirmwareVersion_Call) RunAndReturn(run func() (string, error)) *MockDevice_GetPropertyFirmwareVersion_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyIP4Config provides a mock function with no fields
-func (_m *MockDevice) GetPropertyIP4Config() (gonetworkmanager.IP4Config, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyIP4Config")
- }
-
- var r0 gonetworkmanager.IP4Config
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.IP4Config, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.IP4Config); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.IP4Config)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyIP4Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIP4Config'
-type MockDevice_GetPropertyIP4Config_Call struct {
- *mock.Call
-}
-
-// GetPropertyIP4Config is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyIP4Config() *MockDevice_GetPropertyIP4Config_Call {
- return &MockDevice_GetPropertyIP4Config_Call{Call: _e.mock.On("GetPropertyIP4Config")}
-}
-
-func (_c *MockDevice_GetPropertyIP4Config_Call) Run(run func()) *MockDevice_GetPropertyIP4Config_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyIP4Config_Call) Return(_a0 gonetworkmanager.IP4Config, _a1 error) *MockDevice_GetPropertyIP4Config_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyIP4Config_Call) RunAndReturn(run func() (gonetworkmanager.IP4Config, error)) *MockDevice_GetPropertyIP4Config_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyIP6Config provides a mock function with no fields
-func (_m *MockDevice) GetPropertyIP6Config() (gonetworkmanager.IP6Config, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyIP6Config")
- }
-
- var r0 gonetworkmanager.IP6Config
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.IP6Config, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.IP6Config); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.IP6Config)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyIP6Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIP6Config'
-type MockDevice_GetPropertyIP6Config_Call struct {
- *mock.Call
-}
-
-// GetPropertyIP6Config is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyIP6Config() *MockDevice_GetPropertyIP6Config_Call {
- return &MockDevice_GetPropertyIP6Config_Call{Call: _e.mock.On("GetPropertyIP6Config")}
-}
-
-func (_c *MockDevice_GetPropertyIP6Config_Call) Run(run func()) *MockDevice_GetPropertyIP6Config_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyIP6Config_Call) Return(_a0 gonetworkmanager.IP6Config, _a1 error) *MockDevice_GetPropertyIP6Config_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyIP6Config_Call) RunAndReturn(run func() (gonetworkmanager.IP6Config, error)) *MockDevice_GetPropertyIP6Config_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyInterface provides a mock function with no fields
-func (_m *MockDevice) GetPropertyInterface() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyInterface")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyInterface_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyInterface'
-type MockDevice_GetPropertyInterface_Call struct {
- *mock.Call
-}
-
-// GetPropertyInterface is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyInterface() *MockDevice_GetPropertyInterface_Call {
- return &MockDevice_GetPropertyInterface_Call{Call: _e.mock.On("GetPropertyInterface")}
-}
-
-func (_c *MockDevice_GetPropertyInterface_Call) Run(run func()) *MockDevice_GetPropertyInterface_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyInterface_Call) Return(_a0 string, _a1 error) *MockDevice_GetPropertyInterface_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyInterface_Call) RunAndReturn(run func() (string, error)) *MockDevice_GetPropertyInterface_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyIp4Connectivity provides a mock function with no fields
-func (_m *MockDevice) GetPropertyIp4Connectivity() (gonetworkmanager.NmConnectivity, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyIp4Connectivity")
- }
-
- var r0 gonetworkmanager.NmConnectivity
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmConnectivity, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.NmConnectivity); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(gonetworkmanager.NmConnectivity)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyIp4Connectivity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIp4Connectivity'
-type MockDevice_GetPropertyIp4Connectivity_Call struct {
- *mock.Call
-}
-
-// GetPropertyIp4Connectivity is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyIp4Connectivity() *MockDevice_GetPropertyIp4Connectivity_Call {
- return &MockDevice_GetPropertyIp4Connectivity_Call{Call: _e.mock.On("GetPropertyIp4Connectivity")}
-}
-
-func (_c *MockDevice_GetPropertyIp4Connectivity_Call) Run(run func()) *MockDevice_GetPropertyIp4Connectivity_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyIp4Connectivity_Call) Return(_a0 gonetworkmanager.NmConnectivity, _a1 error) *MockDevice_GetPropertyIp4Connectivity_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyIp4Connectivity_Call) RunAndReturn(run func() (gonetworkmanager.NmConnectivity, error)) *MockDevice_GetPropertyIp4Connectivity_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyIpInterface provides a mock function with no fields
-func (_m *MockDevice) GetPropertyIpInterface() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyIpInterface")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyIpInterface_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIpInterface'
-type MockDevice_GetPropertyIpInterface_Call struct {
- *mock.Call
-}
-
-// GetPropertyIpInterface is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyIpInterface() *MockDevice_GetPropertyIpInterface_Call {
- return &MockDevice_GetPropertyIpInterface_Call{Call: _e.mock.On("GetPropertyIpInterface")}
-}
-
-func (_c *MockDevice_GetPropertyIpInterface_Call) Run(run func()) *MockDevice_GetPropertyIpInterface_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyIpInterface_Call) Return(_a0 string, _a1 error) *MockDevice_GetPropertyIpInterface_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyIpInterface_Call) RunAndReturn(run func() (string, error)) *MockDevice_GetPropertyIpInterface_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyManaged provides a mock function with no fields
-func (_m *MockDevice) GetPropertyManaged() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyManaged")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyManaged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyManaged'
-type MockDevice_GetPropertyManaged_Call struct {
- *mock.Call
-}
-
-// GetPropertyManaged is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyManaged() *MockDevice_GetPropertyManaged_Call {
- return &MockDevice_GetPropertyManaged_Call{Call: _e.mock.On("GetPropertyManaged")}
-}
-
-func (_c *MockDevice_GetPropertyManaged_Call) Run(run func()) *MockDevice_GetPropertyManaged_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyManaged_Call) Return(_a0 bool, _a1 error) *MockDevice_GetPropertyManaged_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyManaged_Call) RunAndReturn(run func() (bool, error)) *MockDevice_GetPropertyManaged_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyMtu provides a mock function with no fields
-func (_m *MockDevice) GetPropertyMtu() (uint32, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyMtu")
- }
-
- var r0 uint32
- var r1 error
- if rf, ok := ret.Get(0).(func() (uint32, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() uint32); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(uint32)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyMtu_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyMtu'
-type MockDevice_GetPropertyMtu_Call struct {
- *mock.Call
-}
-
-// GetPropertyMtu is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyMtu() *MockDevice_GetPropertyMtu_Call {
- return &MockDevice_GetPropertyMtu_Call{Call: _e.mock.On("GetPropertyMtu")}
-}
-
-func (_c *MockDevice_GetPropertyMtu_Call) Run(run func()) *MockDevice_GetPropertyMtu_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyMtu_Call) Return(_a0 uint32, _a1 error) *MockDevice_GetPropertyMtu_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyMtu_Call) RunAndReturn(run func() (uint32, error)) *MockDevice_GetPropertyMtu_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyNmPluginMissing provides a mock function with no fields
-func (_m *MockDevice) GetPropertyNmPluginMissing() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyNmPluginMissing")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyNmPluginMissing_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyNmPluginMissing'
-type MockDevice_GetPropertyNmPluginMissing_Call struct {
- *mock.Call
-}
-
-// GetPropertyNmPluginMissing is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyNmPluginMissing() *MockDevice_GetPropertyNmPluginMissing_Call {
- return &MockDevice_GetPropertyNmPluginMissing_Call{Call: _e.mock.On("GetPropertyNmPluginMissing")}
-}
-
-func (_c *MockDevice_GetPropertyNmPluginMissing_Call) Run(run func()) *MockDevice_GetPropertyNmPluginMissing_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyNmPluginMissing_Call) Return(_a0 bool, _a1 error) *MockDevice_GetPropertyNmPluginMissing_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyNmPluginMissing_Call) RunAndReturn(run func() (bool, error)) *MockDevice_GetPropertyNmPluginMissing_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyPhysicalPortId provides a mock function with no fields
-func (_m *MockDevice) GetPropertyPhysicalPortId() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyPhysicalPortId")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyPhysicalPortId_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyPhysicalPortId'
-type MockDevice_GetPropertyPhysicalPortId_Call struct {
- *mock.Call
-}
-
-// GetPropertyPhysicalPortId is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyPhysicalPortId() *MockDevice_GetPropertyPhysicalPortId_Call {
- return &MockDevice_GetPropertyPhysicalPortId_Call{Call: _e.mock.On("GetPropertyPhysicalPortId")}
-}
-
-func (_c *MockDevice_GetPropertyPhysicalPortId_Call) Run(run func()) *MockDevice_GetPropertyPhysicalPortId_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyPhysicalPortId_Call) Return(_a0 string, _a1 error) *MockDevice_GetPropertyPhysicalPortId_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyPhysicalPortId_Call) RunAndReturn(run func() (string, error)) *MockDevice_GetPropertyPhysicalPortId_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyReal provides a mock function with no fields
-func (_m *MockDevice) GetPropertyReal() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyReal")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyReal_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyReal'
-type MockDevice_GetPropertyReal_Call struct {
- *mock.Call
-}
-
-// GetPropertyReal is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyReal() *MockDevice_GetPropertyReal_Call {
- return &MockDevice_GetPropertyReal_Call{Call: _e.mock.On("GetPropertyReal")}
-}
-
-func (_c *MockDevice_GetPropertyReal_Call) Run(run func()) *MockDevice_GetPropertyReal_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyReal_Call) Return(_a0 bool, _a1 error) *MockDevice_GetPropertyReal_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyReal_Call) RunAndReturn(run func() (bool, error)) *MockDevice_GetPropertyReal_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyState provides a mock function with no fields
-func (_m *MockDevice) GetPropertyState() (gonetworkmanager.NmDeviceState, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyState")
- }
-
- var r0 gonetworkmanager.NmDeviceState
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmDeviceState, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.NmDeviceState); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(gonetworkmanager.NmDeviceState)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyState'
-type MockDevice_GetPropertyState_Call struct {
- *mock.Call
-}
-
-// GetPropertyState is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyState() *MockDevice_GetPropertyState_Call {
- return &MockDevice_GetPropertyState_Call{Call: _e.mock.On("GetPropertyState")}
-}
-
-func (_c *MockDevice_GetPropertyState_Call) Run(run func()) *MockDevice_GetPropertyState_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyState_Call) Return(_a0 gonetworkmanager.NmDeviceState, _a1 error) *MockDevice_GetPropertyState_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyState_Call) RunAndReturn(run func() (gonetworkmanager.NmDeviceState, error)) *MockDevice_GetPropertyState_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyUdi provides a mock function with no fields
-func (_m *MockDevice) GetPropertyUdi() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyUdi")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_GetPropertyUdi_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyUdi'
-type MockDevice_GetPropertyUdi_Call struct {
- *mock.Call
-}
-
-// GetPropertyUdi is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) GetPropertyUdi() *MockDevice_GetPropertyUdi_Call {
- return &MockDevice_GetPropertyUdi_Call{Call: _e.mock.On("GetPropertyUdi")}
-}
-
-func (_c *MockDevice_GetPropertyUdi_Call) Run(run func()) *MockDevice_GetPropertyUdi_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_GetPropertyUdi_Call) Return(_a0 string, _a1 error) *MockDevice_GetPropertyUdi_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_GetPropertyUdi_Call) RunAndReturn(run func() (string, error)) *MockDevice_GetPropertyUdi_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// MarshalJSON provides a mock function with no fields
-func (_m *MockDevice) MarshalJSON() ([]byte, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for MarshalJSON")
- }
-
- var r0 []byte
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]byte, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []byte); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]byte)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDevice_MarshalJSON_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarshalJSON'
-type MockDevice_MarshalJSON_Call struct {
- *mock.Call
-}
-
-// MarshalJSON is a helper method to define mock.On call
-func (_e *MockDevice_Expecter) MarshalJSON() *MockDevice_MarshalJSON_Call {
- return &MockDevice_MarshalJSON_Call{Call: _e.mock.On("MarshalJSON")}
-}
-
-func (_c *MockDevice_MarshalJSON_Call) Run(run func()) *MockDevice_MarshalJSON_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDevice_MarshalJSON_Call) Return(_a0 []byte, _a1 error) *MockDevice_MarshalJSON_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDevice_MarshalJSON_Call) RunAndReturn(run func() ([]byte, error)) *MockDevice_MarshalJSON_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Reapply provides a mock function with given fields: connection, versionId, flags
-func (_m *MockDevice) Reapply(connection gonetworkmanager.Connection, versionId uint64, flags uint32) error {
- ret := _m.Called(connection, versionId, flags)
-
- if len(ret) == 0 {
- panic("no return value specified for Reapply")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(gonetworkmanager.Connection, uint64, uint32) error); ok {
- r0 = rf(connection, versionId, flags)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockDevice_Reapply_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Reapply'
-type MockDevice_Reapply_Call struct {
- *mock.Call
-}
-
-// Reapply is a helper method to define mock.On call
-// - connection gonetworkmanager.Connection
-// - versionId uint64
-// - flags uint32
-func (_e *MockDevice_Expecter) Reapply(connection interface{}, versionId interface{}, flags interface{}) *MockDevice_Reapply_Call {
- return &MockDevice_Reapply_Call{Call: _e.mock.On("Reapply", connection, versionId, flags)}
-}
-
-func (_c *MockDevice_Reapply_Call) Run(run func(connection gonetworkmanager.Connection, versionId uint64, flags uint32)) *MockDevice_Reapply_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(gonetworkmanager.Connection), args[1].(uint64), args[2].(uint32))
- })
- return _c
-}
-
-func (_c *MockDevice_Reapply_Call) Return(_a0 error) *MockDevice_Reapply_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockDevice_Reapply_Call) RunAndReturn(run func(gonetworkmanager.Connection, uint64, uint32) error) *MockDevice_Reapply_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetPropertyAutoConnect provides a mock function with given fields: _a0
-func (_m *MockDevice) SetPropertyAutoConnect(_a0 bool) error {
- ret := _m.Called(_a0)
-
- if len(ret) == 0 {
- panic("no return value specified for SetPropertyAutoConnect")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(bool) error); ok {
- r0 = rf(_a0)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockDevice_SetPropertyAutoConnect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPropertyAutoConnect'
-type MockDevice_SetPropertyAutoConnect_Call struct {
- *mock.Call
-}
-
-// SetPropertyAutoConnect is a helper method to define mock.On call
-// - _a0 bool
-func (_e *MockDevice_Expecter) SetPropertyAutoConnect(_a0 interface{}) *MockDevice_SetPropertyAutoConnect_Call {
- return &MockDevice_SetPropertyAutoConnect_Call{Call: _e.mock.On("SetPropertyAutoConnect", _a0)}
-}
-
-func (_c *MockDevice_SetPropertyAutoConnect_Call) Run(run func(_a0 bool)) *MockDevice_SetPropertyAutoConnect_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(bool))
- })
- return _c
-}
-
-func (_c *MockDevice_SetPropertyAutoConnect_Call) Return(_a0 error) *MockDevice_SetPropertyAutoConnect_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockDevice_SetPropertyAutoConnect_Call) RunAndReturn(run func(bool) error) *MockDevice_SetPropertyAutoConnect_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetPropertyManaged provides a mock function with given fields: _a0
-func (_m *MockDevice) SetPropertyManaged(_a0 bool) error {
- ret := _m.Called(_a0)
-
- if len(ret) == 0 {
- panic("no return value specified for SetPropertyManaged")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(bool) error); ok {
- r0 = rf(_a0)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockDevice_SetPropertyManaged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPropertyManaged'
-type MockDevice_SetPropertyManaged_Call struct {
- *mock.Call
-}
-
-// SetPropertyManaged is a helper method to define mock.On call
-// - _a0 bool
-func (_e *MockDevice_Expecter) SetPropertyManaged(_a0 interface{}) *MockDevice_SetPropertyManaged_Call {
- return &MockDevice_SetPropertyManaged_Call{Call: _e.mock.On("SetPropertyManaged", _a0)}
-}
-
-func (_c *MockDevice_SetPropertyManaged_Call) Run(run func(_a0 bool)) *MockDevice_SetPropertyManaged_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(bool))
- })
- return _c
-}
-
-func (_c *MockDevice_SetPropertyManaged_Call) Return(_a0 error) *MockDevice_SetPropertyManaged_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockDevice_SetPropertyManaged_Call) RunAndReturn(run func(bool) error) *MockDevice_SetPropertyManaged_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SubscribeState provides a mock function with given fields: receiver, exit
-func (_m *MockDevice) SubscribeState(receiver chan gonetworkmanager.DeviceStateChange, exit chan struct{}) error {
- ret := _m.Called(receiver, exit)
-
- if len(ret) == 0 {
- panic("no return value specified for SubscribeState")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(chan gonetworkmanager.DeviceStateChange, chan struct{}) error); ok {
- r0 = rf(receiver, exit)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockDevice_SubscribeState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeState'
-type MockDevice_SubscribeState_Call struct {
- *mock.Call
-}
-
-// SubscribeState is a helper method to define mock.On call
-// - receiver chan gonetworkmanager.DeviceStateChange
-// - exit chan struct{}
-func (_e *MockDevice_Expecter) SubscribeState(receiver interface{}, exit interface{}) *MockDevice_SubscribeState_Call {
- return &MockDevice_SubscribeState_Call{Call: _e.mock.On("SubscribeState", receiver, exit)}
-}
-
-func (_c *MockDevice_SubscribeState_Call) Run(run func(receiver chan gonetworkmanager.DeviceStateChange, exit chan struct{})) *MockDevice_SubscribeState_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(chan gonetworkmanager.DeviceStateChange), args[1].(chan struct{}))
- })
- return _c
-}
-
-func (_c *MockDevice_SubscribeState_Call) Return(err error) *MockDevice_SubscribeState_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *MockDevice_SubscribeState_Call) RunAndReturn(run func(chan gonetworkmanager.DeviceStateChange, chan struct{}) error) *MockDevice_SubscribeState_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// NewMockDevice creates a new instance of MockDevice. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewMockDevice(t interface {
- mock.TestingT
- Cleanup(func())
-}) *MockDevice {
- mock := &MockDevice{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_DeviceWireless.go b/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_DeviceWireless.go
deleted file mode 100644
index d2d3f2d..0000000
--- a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_DeviceWireless.go
+++ /dev/null
@@ -1,2241 +0,0 @@
-// Code generated by mockery v2.53.5. DO NOT EDIT.
-
-package gonetworkmanager
-
-import (
- gonetworkmanager "github.com/Wifx/gonetworkmanager/v2"
- dbus "github.com/godbus/dbus/v5"
-
- mock "github.com/stretchr/testify/mock"
-)
-
-// MockDeviceWireless is an autogenerated mock type for the DeviceWireless type
-type MockDeviceWireless struct {
- mock.Mock
-}
-
-type MockDeviceWireless_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *MockDeviceWireless) EXPECT() *MockDeviceWireless_Expecter {
- return &MockDeviceWireless_Expecter{mock: &_m.Mock}
-}
-
-// Delete provides a mock function with no fields
-func (_m *MockDeviceWireless) Delete() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for Delete")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockDeviceWireless_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete'
-type MockDeviceWireless_Delete_Call struct {
- *mock.Call
-}
-
-// Delete is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) Delete() *MockDeviceWireless_Delete_Call {
- return &MockDeviceWireless_Delete_Call{Call: _e.mock.On("Delete")}
-}
-
-func (_c *MockDeviceWireless_Delete_Call) Run(run func()) *MockDeviceWireless_Delete_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_Delete_Call) Return(_a0 error) *MockDeviceWireless_Delete_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockDeviceWireless_Delete_Call) RunAndReturn(run func() error) *MockDeviceWireless_Delete_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Disconnect provides a mock function with no fields
-func (_m *MockDeviceWireless) Disconnect() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for Disconnect")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockDeviceWireless_Disconnect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Disconnect'
-type MockDeviceWireless_Disconnect_Call struct {
- *mock.Call
-}
-
-// Disconnect is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) Disconnect() *MockDeviceWireless_Disconnect_Call {
- return &MockDeviceWireless_Disconnect_Call{Call: _e.mock.On("Disconnect")}
-}
-
-func (_c *MockDeviceWireless_Disconnect_Call) Run(run func()) *MockDeviceWireless_Disconnect_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_Disconnect_Call) Return(_a0 error) *MockDeviceWireless_Disconnect_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockDeviceWireless_Disconnect_Call) RunAndReturn(run func() error) *MockDeviceWireless_Disconnect_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetAccessPoints provides a mock function with no fields
-func (_m *MockDeviceWireless) GetAccessPoints() ([]gonetworkmanager.AccessPoint, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetAccessPoints")
- }
-
- var r0 []gonetworkmanager.AccessPoint
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.AccessPoint, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.AccessPoint); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.AccessPoint)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetAccessPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAccessPoints'
-type MockDeviceWireless_GetAccessPoints_Call struct {
- *mock.Call
-}
-
-// GetAccessPoints is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetAccessPoints() *MockDeviceWireless_GetAccessPoints_Call {
- return &MockDeviceWireless_GetAccessPoints_Call{Call: _e.mock.On("GetAccessPoints")}
-}
-
-func (_c *MockDeviceWireless_GetAccessPoints_Call) Run(run func()) *MockDeviceWireless_GetAccessPoints_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetAccessPoints_Call) Return(_a0 []gonetworkmanager.AccessPoint, _a1 error) *MockDeviceWireless_GetAccessPoints_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetAccessPoints_Call) RunAndReturn(run func() ([]gonetworkmanager.AccessPoint, error)) *MockDeviceWireless_GetAccessPoints_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetAllAccessPoints provides a mock function with no fields
-func (_m *MockDeviceWireless) GetAllAccessPoints() ([]gonetworkmanager.AccessPoint, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetAllAccessPoints")
- }
-
- var r0 []gonetworkmanager.AccessPoint
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.AccessPoint, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.AccessPoint); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.AccessPoint)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetAllAccessPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllAccessPoints'
-type MockDeviceWireless_GetAllAccessPoints_Call struct {
- *mock.Call
-}
-
-// GetAllAccessPoints is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetAllAccessPoints() *MockDeviceWireless_GetAllAccessPoints_Call {
- return &MockDeviceWireless_GetAllAccessPoints_Call{Call: _e.mock.On("GetAllAccessPoints")}
-}
-
-func (_c *MockDeviceWireless_GetAllAccessPoints_Call) Run(run func()) *MockDeviceWireless_GetAllAccessPoints_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetAllAccessPoints_Call) Return(_a0 []gonetworkmanager.AccessPoint, _a1 error) *MockDeviceWireless_GetAllAccessPoints_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetAllAccessPoints_Call) RunAndReturn(run func() ([]gonetworkmanager.AccessPoint, error)) *MockDeviceWireless_GetAllAccessPoints_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPath provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPath() dbus.ObjectPath {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPath")
- }
-
- var r0 dbus.ObjectPath
- if rf, ok := ret.Get(0).(func() dbus.ObjectPath); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(dbus.ObjectPath)
- }
-
- return r0
-}
-
-// MockDeviceWireless_GetPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPath'
-type MockDeviceWireless_GetPath_Call struct {
- *mock.Call
-}
-
-// GetPath is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPath() *MockDeviceWireless_GetPath_Call {
- return &MockDeviceWireless_GetPath_Call{Call: _e.mock.On("GetPath")}
-}
-
-func (_c *MockDeviceWireless_GetPath_Call) Run(run func()) *MockDeviceWireless_GetPath_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPath_Call) Return(_a0 dbus.ObjectPath) *MockDeviceWireless_GetPath_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPath_Call) RunAndReturn(run func() dbus.ObjectPath) *MockDeviceWireless_GetPath_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyAccessPoints provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyAccessPoints() ([]gonetworkmanager.AccessPoint, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyAccessPoints")
- }
-
- var r0 []gonetworkmanager.AccessPoint
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.AccessPoint, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.AccessPoint); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.AccessPoint)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyAccessPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAccessPoints'
-type MockDeviceWireless_GetPropertyAccessPoints_Call struct {
- *mock.Call
-}
-
-// GetPropertyAccessPoints is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyAccessPoints() *MockDeviceWireless_GetPropertyAccessPoints_Call {
- return &MockDeviceWireless_GetPropertyAccessPoints_Call{Call: _e.mock.On("GetPropertyAccessPoints")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyAccessPoints_Call) Run(run func()) *MockDeviceWireless_GetPropertyAccessPoints_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyAccessPoints_Call) Return(_a0 []gonetworkmanager.AccessPoint, _a1 error) *MockDeviceWireless_GetPropertyAccessPoints_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyAccessPoints_Call) RunAndReturn(run func() ([]gonetworkmanager.AccessPoint, error)) *MockDeviceWireless_GetPropertyAccessPoints_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyActiveAccessPoint provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyActiveAccessPoint() (gonetworkmanager.AccessPoint, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyActiveAccessPoint")
- }
-
- var r0 gonetworkmanager.AccessPoint
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.AccessPoint, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.AccessPoint); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.AccessPoint)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyActiveAccessPoint_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyActiveAccessPoint'
-type MockDeviceWireless_GetPropertyActiveAccessPoint_Call struct {
- *mock.Call
-}
-
-// GetPropertyActiveAccessPoint is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyActiveAccessPoint() *MockDeviceWireless_GetPropertyActiveAccessPoint_Call {
- return &MockDeviceWireless_GetPropertyActiveAccessPoint_Call{Call: _e.mock.On("GetPropertyActiveAccessPoint")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyActiveAccessPoint_Call) Run(run func()) *MockDeviceWireless_GetPropertyActiveAccessPoint_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyActiveAccessPoint_Call) Return(_a0 gonetworkmanager.AccessPoint, _a1 error) *MockDeviceWireless_GetPropertyActiveAccessPoint_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyActiveAccessPoint_Call) RunAndReturn(run func() (gonetworkmanager.AccessPoint, error)) *MockDeviceWireless_GetPropertyActiveAccessPoint_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyActiveConnection provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyActiveConnection() (gonetworkmanager.ActiveConnection, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyActiveConnection")
- }
-
- var r0 gonetworkmanager.ActiveConnection
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.ActiveConnection, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.ActiveConnection); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.ActiveConnection)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyActiveConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyActiveConnection'
-type MockDeviceWireless_GetPropertyActiveConnection_Call struct {
- *mock.Call
-}
-
-// GetPropertyActiveConnection is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyActiveConnection() *MockDeviceWireless_GetPropertyActiveConnection_Call {
- return &MockDeviceWireless_GetPropertyActiveConnection_Call{Call: _e.mock.On("GetPropertyActiveConnection")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyActiveConnection_Call) Run(run func()) *MockDeviceWireless_GetPropertyActiveConnection_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyActiveConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockDeviceWireless_GetPropertyActiveConnection_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyActiveConnection_Call) RunAndReturn(run func() (gonetworkmanager.ActiveConnection, error)) *MockDeviceWireless_GetPropertyActiveConnection_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyAutoConnect provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyAutoConnect() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyAutoConnect")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyAutoConnect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAutoConnect'
-type MockDeviceWireless_GetPropertyAutoConnect_Call struct {
- *mock.Call
-}
-
-// GetPropertyAutoConnect is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyAutoConnect() *MockDeviceWireless_GetPropertyAutoConnect_Call {
- return &MockDeviceWireless_GetPropertyAutoConnect_Call{Call: _e.mock.On("GetPropertyAutoConnect")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyAutoConnect_Call) Run(run func()) *MockDeviceWireless_GetPropertyAutoConnect_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyAutoConnect_Call) Return(_a0 bool, _a1 error) *MockDeviceWireless_GetPropertyAutoConnect_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyAutoConnect_Call) RunAndReturn(run func() (bool, error)) *MockDeviceWireless_GetPropertyAutoConnect_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyAvailableConnections provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyAvailableConnections() ([]gonetworkmanager.Connection, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyAvailableConnections")
- }
-
- var r0 []gonetworkmanager.Connection
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Connection, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.Connection); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.Connection)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyAvailableConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAvailableConnections'
-type MockDeviceWireless_GetPropertyAvailableConnections_Call struct {
- *mock.Call
-}
-
-// GetPropertyAvailableConnections is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyAvailableConnections() *MockDeviceWireless_GetPropertyAvailableConnections_Call {
- return &MockDeviceWireless_GetPropertyAvailableConnections_Call{Call: _e.mock.On("GetPropertyAvailableConnections")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyAvailableConnections_Call) Run(run func()) *MockDeviceWireless_GetPropertyAvailableConnections_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyAvailableConnections_Call) Return(_a0 []gonetworkmanager.Connection, _a1 error) *MockDeviceWireless_GetPropertyAvailableConnections_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyAvailableConnections_Call) RunAndReturn(run func() ([]gonetworkmanager.Connection, error)) *MockDeviceWireless_GetPropertyAvailableConnections_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyBitrate provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyBitrate() (uint32, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyBitrate")
- }
-
- var r0 uint32
- var r1 error
- if rf, ok := ret.Get(0).(func() (uint32, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() uint32); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(uint32)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyBitrate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyBitrate'
-type MockDeviceWireless_GetPropertyBitrate_Call struct {
- *mock.Call
-}
-
-// GetPropertyBitrate is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyBitrate() *MockDeviceWireless_GetPropertyBitrate_Call {
- return &MockDeviceWireless_GetPropertyBitrate_Call{Call: _e.mock.On("GetPropertyBitrate")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyBitrate_Call) Run(run func()) *MockDeviceWireless_GetPropertyBitrate_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyBitrate_Call) Return(_a0 uint32, _a1 error) *MockDeviceWireless_GetPropertyBitrate_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyBitrate_Call) RunAndReturn(run func() (uint32, error)) *MockDeviceWireless_GetPropertyBitrate_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDHCP4Config provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyDHCP4Config() (gonetworkmanager.DHCP4Config, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDHCP4Config")
- }
-
- var r0 gonetworkmanager.DHCP4Config
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.DHCP4Config, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.DHCP4Config); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.DHCP4Config)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyDHCP4Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDHCP4Config'
-type MockDeviceWireless_GetPropertyDHCP4Config_Call struct {
- *mock.Call
-}
-
-// GetPropertyDHCP4Config is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyDHCP4Config() *MockDeviceWireless_GetPropertyDHCP4Config_Call {
- return &MockDeviceWireless_GetPropertyDHCP4Config_Call{Call: _e.mock.On("GetPropertyDHCP4Config")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyDHCP4Config_Call) Run(run func()) *MockDeviceWireless_GetPropertyDHCP4Config_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyDHCP4Config_Call) Return(_a0 gonetworkmanager.DHCP4Config, _a1 error) *MockDeviceWireless_GetPropertyDHCP4Config_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyDHCP4Config_Call) RunAndReturn(run func() (gonetworkmanager.DHCP4Config, error)) *MockDeviceWireless_GetPropertyDHCP4Config_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDHCP6Config provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyDHCP6Config() (gonetworkmanager.DHCP6Config, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDHCP6Config")
- }
-
- var r0 gonetworkmanager.DHCP6Config
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.DHCP6Config, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.DHCP6Config); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.DHCP6Config)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyDHCP6Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDHCP6Config'
-type MockDeviceWireless_GetPropertyDHCP6Config_Call struct {
- *mock.Call
-}
-
-// GetPropertyDHCP6Config is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyDHCP6Config() *MockDeviceWireless_GetPropertyDHCP6Config_Call {
- return &MockDeviceWireless_GetPropertyDHCP6Config_Call{Call: _e.mock.On("GetPropertyDHCP6Config")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyDHCP6Config_Call) Run(run func()) *MockDeviceWireless_GetPropertyDHCP6Config_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyDHCP6Config_Call) Return(_a0 gonetworkmanager.DHCP6Config, _a1 error) *MockDeviceWireless_GetPropertyDHCP6Config_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyDHCP6Config_Call) RunAndReturn(run func() (gonetworkmanager.DHCP6Config, error)) *MockDeviceWireless_GetPropertyDHCP6Config_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDeviceType provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyDeviceType() (gonetworkmanager.NmDeviceType, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDeviceType")
- }
-
- var r0 gonetworkmanager.NmDeviceType
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmDeviceType, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.NmDeviceType); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(gonetworkmanager.NmDeviceType)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyDeviceType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDeviceType'
-type MockDeviceWireless_GetPropertyDeviceType_Call struct {
- *mock.Call
-}
-
-// GetPropertyDeviceType is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyDeviceType() *MockDeviceWireless_GetPropertyDeviceType_Call {
- return &MockDeviceWireless_GetPropertyDeviceType_Call{Call: _e.mock.On("GetPropertyDeviceType")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyDeviceType_Call) Run(run func()) *MockDeviceWireless_GetPropertyDeviceType_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyDeviceType_Call) Return(_a0 gonetworkmanager.NmDeviceType, _a1 error) *MockDeviceWireless_GetPropertyDeviceType_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyDeviceType_Call) RunAndReturn(run func() (gonetworkmanager.NmDeviceType, error)) *MockDeviceWireless_GetPropertyDeviceType_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDriver provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyDriver() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDriver")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyDriver_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDriver'
-type MockDeviceWireless_GetPropertyDriver_Call struct {
- *mock.Call
-}
-
-// GetPropertyDriver is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyDriver() *MockDeviceWireless_GetPropertyDriver_Call {
- return &MockDeviceWireless_GetPropertyDriver_Call{Call: _e.mock.On("GetPropertyDriver")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyDriver_Call) Run(run func()) *MockDeviceWireless_GetPropertyDriver_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyDriver_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyDriver_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyDriver_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyDriver_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDriverVersion provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyDriverVersion() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDriverVersion")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyDriverVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDriverVersion'
-type MockDeviceWireless_GetPropertyDriverVersion_Call struct {
- *mock.Call
-}
-
-// GetPropertyDriverVersion is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyDriverVersion() *MockDeviceWireless_GetPropertyDriverVersion_Call {
- return &MockDeviceWireless_GetPropertyDriverVersion_Call{Call: _e.mock.On("GetPropertyDriverVersion")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyDriverVersion_Call) Run(run func()) *MockDeviceWireless_GetPropertyDriverVersion_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyDriverVersion_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyDriverVersion_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyDriverVersion_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyDriverVersion_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyFirmwareMissing provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyFirmwareMissing() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyFirmwareMissing")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyFirmwareMissing_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFirmwareMissing'
-type MockDeviceWireless_GetPropertyFirmwareMissing_Call struct {
- *mock.Call
-}
-
-// GetPropertyFirmwareMissing is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyFirmwareMissing() *MockDeviceWireless_GetPropertyFirmwareMissing_Call {
- return &MockDeviceWireless_GetPropertyFirmwareMissing_Call{Call: _e.mock.On("GetPropertyFirmwareMissing")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyFirmwareMissing_Call) Run(run func()) *MockDeviceWireless_GetPropertyFirmwareMissing_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyFirmwareMissing_Call) Return(_a0 bool, _a1 error) *MockDeviceWireless_GetPropertyFirmwareMissing_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyFirmwareMissing_Call) RunAndReturn(run func() (bool, error)) *MockDeviceWireless_GetPropertyFirmwareMissing_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyFirmwareVersion provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyFirmwareVersion() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyFirmwareVersion")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyFirmwareVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyFirmwareVersion'
-type MockDeviceWireless_GetPropertyFirmwareVersion_Call struct {
- *mock.Call
-}
-
-// GetPropertyFirmwareVersion is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyFirmwareVersion() *MockDeviceWireless_GetPropertyFirmwareVersion_Call {
- return &MockDeviceWireless_GetPropertyFirmwareVersion_Call{Call: _e.mock.On("GetPropertyFirmwareVersion")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyFirmwareVersion_Call) Run(run func()) *MockDeviceWireless_GetPropertyFirmwareVersion_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyFirmwareVersion_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyFirmwareVersion_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyFirmwareVersion_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyFirmwareVersion_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyHwAddress provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyHwAddress() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyHwAddress")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyHwAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyHwAddress'
-type MockDeviceWireless_GetPropertyHwAddress_Call struct {
- *mock.Call
-}
-
-// GetPropertyHwAddress is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyHwAddress() *MockDeviceWireless_GetPropertyHwAddress_Call {
- return &MockDeviceWireless_GetPropertyHwAddress_Call{Call: _e.mock.On("GetPropertyHwAddress")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyHwAddress_Call) Run(run func()) *MockDeviceWireless_GetPropertyHwAddress_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyHwAddress_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyHwAddress_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyHwAddress_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyHwAddress_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyIP4Config provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyIP4Config() (gonetworkmanager.IP4Config, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyIP4Config")
- }
-
- var r0 gonetworkmanager.IP4Config
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.IP4Config, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.IP4Config); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.IP4Config)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyIP4Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIP4Config'
-type MockDeviceWireless_GetPropertyIP4Config_Call struct {
- *mock.Call
-}
-
-// GetPropertyIP4Config is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyIP4Config() *MockDeviceWireless_GetPropertyIP4Config_Call {
- return &MockDeviceWireless_GetPropertyIP4Config_Call{Call: _e.mock.On("GetPropertyIP4Config")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyIP4Config_Call) Run(run func()) *MockDeviceWireless_GetPropertyIP4Config_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyIP4Config_Call) Return(_a0 gonetworkmanager.IP4Config, _a1 error) *MockDeviceWireless_GetPropertyIP4Config_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyIP4Config_Call) RunAndReturn(run func() (gonetworkmanager.IP4Config, error)) *MockDeviceWireless_GetPropertyIP4Config_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyIP6Config provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyIP6Config() (gonetworkmanager.IP6Config, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyIP6Config")
- }
-
- var r0 gonetworkmanager.IP6Config
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.IP6Config, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.IP6Config); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.IP6Config)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyIP6Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIP6Config'
-type MockDeviceWireless_GetPropertyIP6Config_Call struct {
- *mock.Call
-}
-
-// GetPropertyIP6Config is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyIP6Config() *MockDeviceWireless_GetPropertyIP6Config_Call {
- return &MockDeviceWireless_GetPropertyIP6Config_Call{Call: _e.mock.On("GetPropertyIP6Config")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyIP6Config_Call) Run(run func()) *MockDeviceWireless_GetPropertyIP6Config_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyIP6Config_Call) Return(_a0 gonetworkmanager.IP6Config, _a1 error) *MockDeviceWireless_GetPropertyIP6Config_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyIP6Config_Call) RunAndReturn(run func() (gonetworkmanager.IP6Config, error)) *MockDeviceWireless_GetPropertyIP6Config_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyInterface provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyInterface() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyInterface")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyInterface_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyInterface'
-type MockDeviceWireless_GetPropertyInterface_Call struct {
- *mock.Call
-}
-
-// GetPropertyInterface is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyInterface() *MockDeviceWireless_GetPropertyInterface_Call {
- return &MockDeviceWireless_GetPropertyInterface_Call{Call: _e.mock.On("GetPropertyInterface")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyInterface_Call) Run(run func()) *MockDeviceWireless_GetPropertyInterface_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyInterface_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyInterface_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyInterface_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyInterface_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyIp4Connectivity provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyIp4Connectivity() (gonetworkmanager.NmConnectivity, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyIp4Connectivity")
- }
-
- var r0 gonetworkmanager.NmConnectivity
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmConnectivity, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.NmConnectivity); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(gonetworkmanager.NmConnectivity)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyIp4Connectivity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIp4Connectivity'
-type MockDeviceWireless_GetPropertyIp4Connectivity_Call struct {
- *mock.Call
-}
-
-// GetPropertyIp4Connectivity is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyIp4Connectivity() *MockDeviceWireless_GetPropertyIp4Connectivity_Call {
- return &MockDeviceWireless_GetPropertyIp4Connectivity_Call{Call: _e.mock.On("GetPropertyIp4Connectivity")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyIp4Connectivity_Call) Run(run func()) *MockDeviceWireless_GetPropertyIp4Connectivity_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyIp4Connectivity_Call) Return(_a0 gonetworkmanager.NmConnectivity, _a1 error) *MockDeviceWireless_GetPropertyIp4Connectivity_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyIp4Connectivity_Call) RunAndReturn(run func() (gonetworkmanager.NmConnectivity, error)) *MockDeviceWireless_GetPropertyIp4Connectivity_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyIpInterface provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyIpInterface() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyIpInterface")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyIpInterface_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyIpInterface'
-type MockDeviceWireless_GetPropertyIpInterface_Call struct {
- *mock.Call
-}
-
-// GetPropertyIpInterface is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyIpInterface() *MockDeviceWireless_GetPropertyIpInterface_Call {
- return &MockDeviceWireless_GetPropertyIpInterface_Call{Call: _e.mock.On("GetPropertyIpInterface")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyIpInterface_Call) Run(run func()) *MockDeviceWireless_GetPropertyIpInterface_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyIpInterface_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyIpInterface_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyIpInterface_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyIpInterface_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyLastScan provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyLastScan() (int64, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyLastScan")
- }
-
- var r0 int64
- var r1 error
- if rf, ok := ret.Get(0).(func() (int64, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() int64); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(int64)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyLastScan_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyLastScan'
-type MockDeviceWireless_GetPropertyLastScan_Call struct {
- *mock.Call
-}
-
-// GetPropertyLastScan is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyLastScan() *MockDeviceWireless_GetPropertyLastScan_Call {
- return &MockDeviceWireless_GetPropertyLastScan_Call{Call: _e.mock.On("GetPropertyLastScan")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyLastScan_Call) Run(run func()) *MockDeviceWireless_GetPropertyLastScan_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyLastScan_Call) Return(_a0 int64, _a1 error) *MockDeviceWireless_GetPropertyLastScan_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyLastScan_Call) RunAndReturn(run func() (int64, error)) *MockDeviceWireless_GetPropertyLastScan_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyManaged provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyManaged() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyManaged")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyManaged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyManaged'
-type MockDeviceWireless_GetPropertyManaged_Call struct {
- *mock.Call
-}
-
-// GetPropertyManaged is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyManaged() *MockDeviceWireless_GetPropertyManaged_Call {
- return &MockDeviceWireless_GetPropertyManaged_Call{Call: _e.mock.On("GetPropertyManaged")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyManaged_Call) Run(run func()) *MockDeviceWireless_GetPropertyManaged_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyManaged_Call) Return(_a0 bool, _a1 error) *MockDeviceWireless_GetPropertyManaged_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyManaged_Call) RunAndReturn(run func() (bool, error)) *MockDeviceWireless_GetPropertyManaged_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyMode provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyMode() (gonetworkmanager.Nm80211Mode, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyMode")
- }
-
- var r0 gonetworkmanager.Nm80211Mode
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.Nm80211Mode, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.Nm80211Mode); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(gonetworkmanager.Nm80211Mode)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyMode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyMode'
-type MockDeviceWireless_GetPropertyMode_Call struct {
- *mock.Call
-}
-
-// GetPropertyMode is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyMode() *MockDeviceWireless_GetPropertyMode_Call {
- return &MockDeviceWireless_GetPropertyMode_Call{Call: _e.mock.On("GetPropertyMode")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyMode_Call) Run(run func()) *MockDeviceWireless_GetPropertyMode_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyMode_Call) Return(_a0 gonetworkmanager.Nm80211Mode, _a1 error) *MockDeviceWireless_GetPropertyMode_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyMode_Call) RunAndReturn(run func() (gonetworkmanager.Nm80211Mode, error)) *MockDeviceWireless_GetPropertyMode_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyMtu provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyMtu() (uint32, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyMtu")
- }
-
- var r0 uint32
- var r1 error
- if rf, ok := ret.Get(0).(func() (uint32, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() uint32); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(uint32)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyMtu_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyMtu'
-type MockDeviceWireless_GetPropertyMtu_Call struct {
- *mock.Call
-}
-
-// GetPropertyMtu is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyMtu() *MockDeviceWireless_GetPropertyMtu_Call {
- return &MockDeviceWireless_GetPropertyMtu_Call{Call: _e.mock.On("GetPropertyMtu")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyMtu_Call) Run(run func()) *MockDeviceWireless_GetPropertyMtu_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyMtu_Call) Return(_a0 uint32, _a1 error) *MockDeviceWireless_GetPropertyMtu_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyMtu_Call) RunAndReturn(run func() (uint32, error)) *MockDeviceWireless_GetPropertyMtu_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyNmPluginMissing provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyNmPluginMissing() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyNmPluginMissing")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyNmPluginMissing_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyNmPluginMissing'
-type MockDeviceWireless_GetPropertyNmPluginMissing_Call struct {
- *mock.Call
-}
-
-// GetPropertyNmPluginMissing is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyNmPluginMissing() *MockDeviceWireless_GetPropertyNmPluginMissing_Call {
- return &MockDeviceWireless_GetPropertyNmPluginMissing_Call{Call: _e.mock.On("GetPropertyNmPluginMissing")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyNmPluginMissing_Call) Run(run func()) *MockDeviceWireless_GetPropertyNmPluginMissing_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyNmPluginMissing_Call) Return(_a0 bool, _a1 error) *MockDeviceWireless_GetPropertyNmPluginMissing_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyNmPluginMissing_Call) RunAndReturn(run func() (bool, error)) *MockDeviceWireless_GetPropertyNmPluginMissing_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyPermHwAddress provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyPermHwAddress() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyPermHwAddress")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyPermHwAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyPermHwAddress'
-type MockDeviceWireless_GetPropertyPermHwAddress_Call struct {
- *mock.Call
-}
-
-// GetPropertyPermHwAddress is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyPermHwAddress() *MockDeviceWireless_GetPropertyPermHwAddress_Call {
- return &MockDeviceWireless_GetPropertyPermHwAddress_Call{Call: _e.mock.On("GetPropertyPermHwAddress")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyPermHwAddress_Call) Run(run func()) *MockDeviceWireless_GetPropertyPermHwAddress_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyPermHwAddress_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyPermHwAddress_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyPermHwAddress_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyPermHwAddress_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyPhysicalPortId provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyPhysicalPortId() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyPhysicalPortId")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyPhysicalPortId_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyPhysicalPortId'
-type MockDeviceWireless_GetPropertyPhysicalPortId_Call struct {
- *mock.Call
-}
-
-// GetPropertyPhysicalPortId is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyPhysicalPortId() *MockDeviceWireless_GetPropertyPhysicalPortId_Call {
- return &MockDeviceWireless_GetPropertyPhysicalPortId_Call{Call: _e.mock.On("GetPropertyPhysicalPortId")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyPhysicalPortId_Call) Run(run func()) *MockDeviceWireless_GetPropertyPhysicalPortId_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyPhysicalPortId_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyPhysicalPortId_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyPhysicalPortId_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyPhysicalPortId_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyReal provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyReal() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyReal")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyReal_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyReal'
-type MockDeviceWireless_GetPropertyReal_Call struct {
- *mock.Call
-}
-
-// GetPropertyReal is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyReal() *MockDeviceWireless_GetPropertyReal_Call {
- return &MockDeviceWireless_GetPropertyReal_Call{Call: _e.mock.On("GetPropertyReal")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyReal_Call) Run(run func()) *MockDeviceWireless_GetPropertyReal_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyReal_Call) Return(_a0 bool, _a1 error) *MockDeviceWireless_GetPropertyReal_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyReal_Call) RunAndReturn(run func() (bool, error)) *MockDeviceWireless_GetPropertyReal_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyState provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyState() (gonetworkmanager.NmDeviceState, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyState")
- }
-
- var r0 gonetworkmanager.NmDeviceState
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmDeviceState, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.NmDeviceState); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(gonetworkmanager.NmDeviceState)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyState'
-type MockDeviceWireless_GetPropertyState_Call struct {
- *mock.Call
-}
-
-// GetPropertyState is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyState() *MockDeviceWireless_GetPropertyState_Call {
- return &MockDeviceWireless_GetPropertyState_Call{Call: _e.mock.On("GetPropertyState")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyState_Call) Run(run func()) *MockDeviceWireless_GetPropertyState_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyState_Call) Return(_a0 gonetworkmanager.NmDeviceState, _a1 error) *MockDeviceWireless_GetPropertyState_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyState_Call) RunAndReturn(run func() (gonetworkmanager.NmDeviceState, error)) *MockDeviceWireless_GetPropertyState_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyUdi provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyUdi() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyUdi")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyUdi_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyUdi'
-type MockDeviceWireless_GetPropertyUdi_Call struct {
- *mock.Call
-}
-
-// GetPropertyUdi is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyUdi() *MockDeviceWireless_GetPropertyUdi_Call {
- return &MockDeviceWireless_GetPropertyUdi_Call{Call: _e.mock.On("GetPropertyUdi")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyUdi_Call) Run(run func()) *MockDeviceWireless_GetPropertyUdi_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyUdi_Call) Return(_a0 string, _a1 error) *MockDeviceWireless_GetPropertyUdi_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyUdi_Call) RunAndReturn(run func() (string, error)) *MockDeviceWireless_GetPropertyUdi_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyWirelessCapabilities provides a mock function with no fields
-func (_m *MockDeviceWireless) GetPropertyWirelessCapabilities() (uint32, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyWirelessCapabilities")
- }
-
- var r0 uint32
- var r1 error
- if rf, ok := ret.Get(0).(func() (uint32, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() uint32); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(uint32)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_GetPropertyWirelessCapabilities_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWirelessCapabilities'
-type MockDeviceWireless_GetPropertyWirelessCapabilities_Call struct {
- *mock.Call
-}
-
-// GetPropertyWirelessCapabilities is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) GetPropertyWirelessCapabilities() *MockDeviceWireless_GetPropertyWirelessCapabilities_Call {
- return &MockDeviceWireless_GetPropertyWirelessCapabilities_Call{Call: _e.mock.On("GetPropertyWirelessCapabilities")}
-}
-
-func (_c *MockDeviceWireless_GetPropertyWirelessCapabilities_Call) Run(run func()) *MockDeviceWireless_GetPropertyWirelessCapabilities_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyWirelessCapabilities_Call) Return(_a0 uint32, _a1 error) *MockDeviceWireless_GetPropertyWirelessCapabilities_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_GetPropertyWirelessCapabilities_Call) RunAndReturn(run func() (uint32, error)) *MockDeviceWireless_GetPropertyWirelessCapabilities_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// MarshalJSON provides a mock function with no fields
-func (_m *MockDeviceWireless) MarshalJSON() ([]byte, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for MarshalJSON")
- }
-
- var r0 []byte
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]byte, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []byte); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]byte)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockDeviceWireless_MarshalJSON_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarshalJSON'
-type MockDeviceWireless_MarshalJSON_Call struct {
- *mock.Call
-}
-
-// MarshalJSON is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) MarshalJSON() *MockDeviceWireless_MarshalJSON_Call {
- return &MockDeviceWireless_MarshalJSON_Call{Call: _e.mock.On("MarshalJSON")}
-}
-
-func (_c *MockDeviceWireless_MarshalJSON_Call) Run(run func()) *MockDeviceWireless_MarshalJSON_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_MarshalJSON_Call) Return(_a0 []byte, _a1 error) *MockDeviceWireless_MarshalJSON_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockDeviceWireless_MarshalJSON_Call) RunAndReturn(run func() ([]byte, error)) *MockDeviceWireless_MarshalJSON_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Reapply provides a mock function with given fields: connection, versionId, flags
-func (_m *MockDeviceWireless) Reapply(connection gonetworkmanager.Connection, versionId uint64, flags uint32) error {
- ret := _m.Called(connection, versionId, flags)
-
- if len(ret) == 0 {
- panic("no return value specified for Reapply")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(gonetworkmanager.Connection, uint64, uint32) error); ok {
- r0 = rf(connection, versionId, flags)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockDeviceWireless_Reapply_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Reapply'
-type MockDeviceWireless_Reapply_Call struct {
- *mock.Call
-}
-
-// Reapply is a helper method to define mock.On call
-// - connection gonetworkmanager.Connection
-// - versionId uint64
-// - flags uint32
-func (_e *MockDeviceWireless_Expecter) Reapply(connection interface{}, versionId interface{}, flags interface{}) *MockDeviceWireless_Reapply_Call {
- return &MockDeviceWireless_Reapply_Call{Call: _e.mock.On("Reapply", connection, versionId, flags)}
-}
-
-func (_c *MockDeviceWireless_Reapply_Call) Run(run func(connection gonetworkmanager.Connection, versionId uint64, flags uint32)) *MockDeviceWireless_Reapply_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(gonetworkmanager.Connection), args[1].(uint64), args[2].(uint32))
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_Reapply_Call) Return(_a0 error) *MockDeviceWireless_Reapply_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockDeviceWireless_Reapply_Call) RunAndReturn(run func(gonetworkmanager.Connection, uint64, uint32) error) *MockDeviceWireless_Reapply_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// RequestScan provides a mock function with no fields
-func (_m *MockDeviceWireless) RequestScan() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for RequestScan")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockDeviceWireless_RequestScan_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestScan'
-type MockDeviceWireless_RequestScan_Call struct {
- *mock.Call
-}
-
-// RequestScan is a helper method to define mock.On call
-func (_e *MockDeviceWireless_Expecter) RequestScan() *MockDeviceWireless_RequestScan_Call {
- return &MockDeviceWireless_RequestScan_Call{Call: _e.mock.On("RequestScan")}
-}
-
-func (_c *MockDeviceWireless_RequestScan_Call) Run(run func()) *MockDeviceWireless_RequestScan_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_RequestScan_Call) Return(_a0 error) *MockDeviceWireless_RequestScan_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockDeviceWireless_RequestScan_Call) RunAndReturn(run func() error) *MockDeviceWireless_RequestScan_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetPropertyAutoConnect provides a mock function with given fields: _a0
-func (_m *MockDeviceWireless) SetPropertyAutoConnect(_a0 bool) error {
- ret := _m.Called(_a0)
-
- if len(ret) == 0 {
- panic("no return value specified for SetPropertyAutoConnect")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(bool) error); ok {
- r0 = rf(_a0)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockDeviceWireless_SetPropertyAutoConnect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPropertyAutoConnect'
-type MockDeviceWireless_SetPropertyAutoConnect_Call struct {
- *mock.Call
-}
-
-// SetPropertyAutoConnect is a helper method to define mock.On call
-// - _a0 bool
-func (_e *MockDeviceWireless_Expecter) SetPropertyAutoConnect(_a0 interface{}) *MockDeviceWireless_SetPropertyAutoConnect_Call {
- return &MockDeviceWireless_SetPropertyAutoConnect_Call{Call: _e.mock.On("SetPropertyAutoConnect", _a0)}
-}
-
-func (_c *MockDeviceWireless_SetPropertyAutoConnect_Call) Run(run func(_a0 bool)) *MockDeviceWireless_SetPropertyAutoConnect_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(bool))
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_SetPropertyAutoConnect_Call) Return(_a0 error) *MockDeviceWireless_SetPropertyAutoConnect_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockDeviceWireless_SetPropertyAutoConnect_Call) RunAndReturn(run func(bool) error) *MockDeviceWireless_SetPropertyAutoConnect_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetPropertyManaged provides a mock function with given fields: _a0
-func (_m *MockDeviceWireless) SetPropertyManaged(_a0 bool) error {
- ret := _m.Called(_a0)
-
- if len(ret) == 0 {
- panic("no return value specified for SetPropertyManaged")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(bool) error); ok {
- r0 = rf(_a0)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockDeviceWireless_SetPropertyManaged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPropertyManaged'
-type MockDeviceWireless_SetPropertyManaged_Call struct {
- *mock.Call
-}
-
-// SetPropertyManaged is a helper method to define mock.On call
-// - _a0 bool
-func (_e *MockDeviceWireless_Expecter) SetPropertyManaged(_a0 interface{}) *MockDeviceWireless_SetPropertyManaged_Call {
- return &MockDeviceWireless_SetPropertyManaged_Call{Call: _e.mock.On("SetPropertyManaged", _a0)}
-}
-
-func (_c *MockDeviceWireless_SetPropertyManaged_Call) Run(run func(_a0 bool)) *MockDeviceWireless_SetPropertyManaged_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(bool))
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_SetPropertyManaged_Call) Return(_a0 error) *MockDeviceWireless_SetPropertyManaged_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockDeviceWireless_SetPropertyManaged_Call) RunAndReturn(run func(bool) error) *MockDeviceWireless_SetPropertyManaged_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SubscribeState provides a mock function with given fields: receiver, exit
-func (_m *MockDeviceWireless) SubscribeState(receiver chan gonetworkmanager.DeviceStateChange, exit chan struct{}) error {
- ret := _m.Called(receiver, exit)
-
- if len(ret) == 0 {
- panic("no return value specified for SubscribeState")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(chan gonetworkmanager.DeviceStateChange, chan struct{}) error); ok {
- r0 = rf(receiver, exit)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockDeviceWireless_SubscribeState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeState'
-type MockDeviceWireless_SubscribeState_Call struct {
- *mock.Call
-}
-
-// SubscribeState is a helper method to define mock.On call
-// - receiver chan gonetworkmanager.DeviceStateChange
-// - exit chan struct{}
-func (_e *MockDeviceWireless_Expecter) SubscribeState(receiver interface{}, exit interface{}) *MockDeviceWireless_SubscribeState_Call {
- return &MockDeviceWireless_SubscribeState_Call{Call: _e.mock.On("SubscribeState", receiver, exit)}
-}
-
-func (_c *MockDeviceWireless_SubscribeState_Call) Run(run func(receiver chan gonetworkmanager.DeviceStateChange, exit chan struct{})) *MockDeviceWireless_SubscribeState_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(chan gonetworkmanager.DeviceStateChange), args[1].(chan struct{}))
- })
- return _c
-}
-
-func (_c *MockDeviceWireless_SubscribeState_Call) Return(err error) *MockDeviceWireless_SubscribeState_Call {
- _c.Call.Return(err)
- return _c
-}
-
-func (_c *MockDeviceWireless_SubscribeState_Call) RunAndReturn(run func(chan gonetworkmanager.DeviceStateChange, chan struct{}) error) *MockDeviceWireless_SubscribeState_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// NewMockDeviceWireless creates a new instance of MockDeviceWireless. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewMockDeviceWireless(t interface {
- mock.TestingT
- Cleanup(func())
-}) *MockDeviceWireless {
- mock := &MockDeviceWireless{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_IP4Config.go b/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_IP4Config.go
deleted file mode 100644
index 235be86..0000000
--- a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_IP4Config.go
+++ /dev/null
@@ -1,772 +0,0 @@
-// Code generated by mockery v2.53.5. DO NOT EDIT.
-
-package gonetworkmanager
-
-import (
- gonetworkmanager "github.com/Wifx/gonetworkmanager/v2"
- mock "github.com/stretchr/testify/mock"
-)
-
-// MockIP4Config is an autogenerated mock type for the IP4Config type
-type MockIP4Config struct {
- mock.Mock
-}
-
-type MockIP4Config_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *MockIP4Config) EXPECT() *MockIP4Config_Expecter {
- return &MockIP4Config_Expecter{mock: &_m.Mock}
-}
-
-// GetPropertyAddressData provides a mock function with no fields
-func (_m *MockIP4Config) GetPropertyAddressData() ([]gonetworkmanager.IP4AddressData, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyAddressData")
- }
-
- var r0 []gonetworkmanager.IP4AddressData
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.IP4AddressData, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.IP4AddressData); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.IP4AddressData)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockIP4Config_GetPropertyAddressData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAddressData'
-type MockIP4Config_GetPropertyAddressData_Call struct {
- *mock.Call
-}
-
-// GetPropertyAddressData is a helper method to define mock.On call
-func (_e *MockIP4Config_Expecter) GetPropertyAddressData() *MockIP4Config_GetPropertyAddressData_Call {
- return &MockIP4Config_GetPropertyAddressData_Call{Call: _e.mock.On("GetPropertyAddressData")}
-}
-
-func (_c *MockIP4Config_GetPropertyAddressData_Call) Run(run func()) *MockIP4Config_GetPropertyAddressData_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyAddressData_Call) Return(_a0 []gonetworkmanager.IP4AddressData, _a1 error) *MockIP4Config_GetPropertyAddressData_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyAddressData_Call) RunAndReturn(run func() ([]gonetworkmanager.IP4AddressData, error)) *MockIP4Config_GetPropertyAddressData_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyAddresses provides a mock function with no fields
-func (_m *MockIP4Config) GetPropertyAddresses() ([]gonetworkmanager.IP4Address, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyAddresses")
- }
-
- var r0 []gonetworkmanager.IP4Address
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.IP4Address, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.IP4Address); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.IP4Address)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockIP4Config_GetPropertyAddresses_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAddresses'
-type MockIP4Config_GetPropertyAddresses_Call struct {
- *mock.Call
-}
-
-// GetPropertyAddresses is a helper method to define mock.On call
-func (_e *MockIP4Config_Expecter) GetPropertyAddresses() *MockIP4Config_GetPropertyAddresses_Call {
- return &MockIP4Config_GetPropertyAddresses_Call{Call: _e.mock.On("GetPropertyAddresses")}
-}
-
-func (_c *MockIP4Config_GetPropertyAddresses_Call) Run(run func()) *MockIP4Config_GetPropertyAddresses_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyAddresses_Call) Return(_a0 []gonetworkmanager.IP4Address, _a1 error) *MockIP4Config_GetPropertyAddresses_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyAddresses_Call) RunAndReturn(run func() ([]gonetworkmanager.IP4Address, error)) *MockIP4Config_GetPropertyAddresses_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDnsOptions provides a mock function with no fields
-func (_m *MockIP4Config) GetPropertyDnsOptions() ([]string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDnsOptions")
- }
-
- var r0 []string
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []string); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]string)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockIP4Config_GetPropertyDnsOptions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDnsOptions'
-type MockIP4Config_GetPropertyDnsOptions_Call struct {
- *mock.Call
-}
-
-// GetPropertyDnsOptions is a helper method to define mock.On call
-func (_e *MockIP4Config_Expecter) GetPropertyDnsOptions() *MockIP4Config_GetPropertyDnsOptions_Call {
- return &MockIP4Config_GetPropertyDnsOptions_Call{Call: _e.mock.On("GetPropertyDnsOptions")}
-}
-
-func (_c *MockIP4Config_GetPropertyDnsOptions_Call) Run(run func()) *MockIP4Config_GetPropertyDnsOptions_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyDnsOptions_Call) Return(_a0 []string, _a1 error) *MockIP4Config_GetPropertyDnsOptions_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyDnsOptions_Call) RunAndReturn(run func() ([]string, error)) *MockIP4Config_GetPropertyDnsOptions_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDnsPriority provides a mock function with no fields
-func (_m *MockIP4Config) GetPropertyDnsPriority() (uint32, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDnsPriority")
- }
-
- var r0 uint32
- var r1 error
- if rf, ok := ret.Get(0).(func() (uint32, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() uint32); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(uint32)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockIP4Config_GetPropertyDnsPriority_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDnsPriority'
-type MockIP4Config_GetPropertyDnsPriority_Call struct {
- *mock.Call
-}
-
-// GetPropertyDnsPriority is a helper method to define mock.On call
-func (_e *MockIP4Config_Expecter) GetPropertyDnsPriority() *MockIP4Config_GetPropertyDnsPriority_Call {
- return &MockIP4Config_GetPropertyDnsPriority_Call{Call: _e.mock.On("GetPropertyDnsPriority")}
-}
-
-func (_c *MockIP4Config_GetPropertyDnsPriority_Call) Run(run func()) *MockIP4Config_GetPropertyDnsPriority_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyDnsPriority_Call) Return(_a0 uint32, _a1 error) *MockIP4Config_GetPropertyDnsPriority_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyDnsPriority_Call) RunAndReturn(run func() (uint32, error)) *MockIP4Config_GetPropertyDnsPriority_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDomains provides a mock function with no fields
-func (_m *MockIP4Config) GetPropertyDomains() ([]string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDomains")
- }
-
- var r0 []string
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []string); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]string)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockIP4Config_GetPropertyDomains_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDomains'
-type MockIP4Config_GetPropertyDomains_Call struct {
- *mock.Call
-}
-
-// GetPropertyDomains is a helper method to define mock.On call
-func (_e *MockIP4Config_Expecter) GetPropertyDomains() *MockIP4Config_GetPropertyDomains_Call {
- return &MockIP4Config_GetPropertyDomains_Call{Call: _e.mock.On("GetPropertyDomains")}
-}
-
-func (_c *MockIP4Config_GetPropertyDomains_Call) Run(run func()) *MockIP4Config_GetPropertyDomains_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyDomains_Call) Return(_a0 []string, _a1 error) *MockIP4Config_GetPropertyDomains_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyDomains_Call) RunAndReturn(run func() ([]string, error)) *MockIP4Config_GetPropertyDomains_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyGateway provides a mock function with no fields
-func (_m *MockIP4Config) GetPropertyGateway() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyGateway")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockIP4Config_GetPropertyGateway_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyGateway'
-type MockIP4Config_GetPropertyGateway_Call struct {
- *mock.Call
-}
-
-// GetPropertyGateway is a helper method to define mock.On call
-func (_e *MockIP4Config_Expecter) GetPropertyGateway() *MockIP4Config_GetPropertyGateway_Call {
- return &MockIP4Config_GetPropertyGateway_Call{Call: _e.mock.On("GetPropertyGateway")}
-}
-
-func (_c *MockIP4Config_GetPropertyGateway_Call) Run(run func()) *MockIP4Config_GetPropertyGateway_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyGateway_Call) Return(_a0 string, _a1 error) *MockIP4Config_GetPropertyGateway_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyGateway_Call) RunAndReturn(run func() (string, error)) *MockIP4Config_GetPropertyGateway_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyNameserverData provides a mock function with no fields
-func (_m *MockIP4Config) GetPropertyNameserverData() ([]gonetworkmanager.IP4NameserverData, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyNameserverData")
- }
-
- var r0 []gonetworkmanager.IP4NameserverData
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.IP4NameserverData, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.IP4NameserverData); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.IP4NameserverData)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockIP4Config_GetPropertyNameserverData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyNameserverData'
-type MockIP4Config_GetPropertyNameserverData_Call struct {
- *mock.Call
-}
-
-// GetPropertyNameserverData is a helper method to define mock.On call
-func (_e *MockIP4Config_Expecter) GetPropertyNameserverData() *MockIP4Config_GetPropertyNameserverData_Call {
- return &MockIP4Config_GetPropertyNameserverData_Call{Call: _e.mock.On("GetPropertyNameserverData")}
-}
-
-func (_c *MockIP4Config_GetPropertyNameserverData_Call) Run(run func()) *MockIP4Config_GetPropertyNameserverData_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyNameserverData_Call) Return(_a0 []gonetworkmanager.IP4NameserverData, _a1 error) *MockIP4Config_GetPropertyNameserverData_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyNameserverData_Call) RunAndReturn(run func() ([]gonetworkmanager.IP4NameserverData, error)) *MockIP4Config_GetPropertyNameserverData_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyNameservers provides a mock function with no fields
-func (_m *MockIP4Config) GetPropertyNameservers() ([]string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyNameservers")
- }
-
- var r0 []string
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []string); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]string)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockIP4Config_GetPropertyNameservers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyNameservers'
-type MockIP4Config_GetPropertyNameservers_Call struct {
- *mock.Call
-}
-
-// GetPropertyNameservers is a helper method to define mock.On call
-func (_e *MockIP4Config_Expecter) GetPropertyNameservers() *MockIP4Config_GetPropertyNameservers_Call {
- return &MockIP4Config_GetPropertyNameservers_Call{Call: _e.mock.On("GetPropertyNameservers")}
-}
-
-func (_c *MockIP4Config_GetPropertyNameservers_Call) Run(run func()) *MockIP4Config_GetPropertyNameservers_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyNameservers_Call) Return(_a0 []string, _a1 error) *MockIP4Config_GetPropertyNameservers_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyNameservers_Call) RunAndReturn(run func() ([]string, error)) *MockIP4Config_GetPropertyNameservers_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyRouteData provides a mock function with no fields
-func (_m *MockIP4Config) GetPropertyRouteData() ([]gonetworkmanager.IP4RouteData, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyRouteData")
- }
-
- var r0 []gonetworkmanager.IP4RouteData
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.IP4RouteData, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.IP4RouteData); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.IP4RouteData)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockIP4Config_GetPropertyRouteData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyRouteData'
-type MockIP4Config_GetPropertyRouteData_Call struct {
- *mock.Call
-}
-
-// GetPropertyRouteData is a helper method to define mock.On call
-func (_e *MockIP4Config_Expecter) GetPropertyRouteData() *MockIP4Config_GetPropertyRouteData_Call {
- return &MockIP4Config_GetPropertyRouteData_Call{Call: _e.mock.On("GetPropertyRouteData")}
-}
-
-func (_c *MockIP4Config_GetPropertyRouteData_Call) Run(run func()) *MockIP4Config_GetPropertyRouteData_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyRouteData_Call) Return(_a0 []gonetworkmanager.IP4RouteData, _a1 error) *MockIP4Config_GetPropertyRouteData_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyRouteData_Call) RunAndReturn(run func() ([]gonetworkmanager.IP4RouteData, error)) *MockIP4Config_GetPropertyRouteData_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyRoutes provides a mock function with no fields
-func (_m *MockIP4Config) GetPropertyRoutes() ([]gonetworkmanager.IP4Route, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyRoutes")
- }
-
- var r0 []gonetworkmanager.IP4Route
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.IP4Route, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.IP4Route); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.IP4Route)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockIP4Config_GetPropertyRoutes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyRoutes'
-type MockIP4Config_GetPropertyRoutes_Call struct {
- *mock.Call
-}
-
-// GetPropertyRoutes is a helper method to define mock.On call
-func (_e *MockIP4Config_Expecter) GetPropertyRoutes() *MockIP4Config_GetPropertyRoutes_Call {
- return &MockIP4Config_GetPropertyRoutes_Call{Call: _e.mock.On("GetPropertyRoutes")}
-}
-
-func (_c *MockIP4Config_GetPropertyRoutes_Call) Run(run func()) *MockIP4Config_GetPropertyRoutes_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyRoutes_Call) Return(_a0 []gonetworkmanager.IP4Route, _a1 error) *MockIP4Config_GetPropertyRoutes_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyRoutes_Call) RunAndReturn(run func() ([]gonetworkmanager.IP4Route, error)) *MockIP4Config_GetPropertyRoutes_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertySearches provides a mock function with no fields
-func (_m *MockIP4Config) GetPropertySearches() ([]string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertySearches")
- }
-
- var r0 []string
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []string); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]string)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockIP4Config_GetPropertySearches_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertySearches'
-type MockIP4Config_GetPropertySearches_Call struct {
- *mock.Call
-}
-
-// GetPropertySearches is a helper method to define mock.On call
-func (_e *MockIP4Config_Expecter) GetPropertySearches() *MockIP4Config_GetPropertySearches_Call {
- return &MockIP4Config_GetPropertySearches_Call{Call: _e.mock.On("GetPropertySearches")}
-}
-
-func (_c *MockIP4Config_GetPropertySearches_Call) Run(run func()) *MockIP4Config_GetPropertySearches_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertySearches_Call) Return(_a0 []string, _a1 error) *MockIP4Config_GetPropertySearches_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertySearches_Call) RunAndReturn(run func() ([]string, error)) *MockIP4Config_GetPropertySearches_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyWinsServerData provides a mock function with no fields
-func (_m *MockIP4Config) GetPropertyWinsServerData() ([]string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyWinsServerData")
- }
-
- var r0 []string
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []string); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]string)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockIP4Config_GetPropertyWinsServerData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWinsServerData'
-type MockIP4Config_GetPropertyWinsServerData_Call struct {
- *mock.Call
-}
-
-// GetPropertyWinsServerData is a helper method to define mock.On call
-func (_e *MockIP4Config_Expecter) GetPropertyWinsServerData() *MockIP4Config_GetPropertyWinsServerData_Call {
- return &MockIP4Config_GetPropertyWinsServerData_Call{Call: _e.mock.On("GetPropertyWinsServerData")}
-}
-
-func (_c *MockIP4Config_GetPropertyWinsServerData_Call) Run(run func()) *MockIP4Config_GetPropertyWinsServerData_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyWinsServerData_Call) Return(_a0 []string, _a1 error) *MockIP4Config_GetPropertyWinsServerData_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockIP4Config_GetPropertyWinsServerData_Call) RunAndReturn(run func() ([]string, error)) *MockIP4Config_GetPropertyWinsServerData_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// MarshalJSON provides a mock function with no fields
-func (_m *MockIP4Config) MarshalJSON() ([]byte, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for MarshalJSON")
- }
-
- var r0 []byte
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]byte, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []byte); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]byte)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockIP4Config_MarshalJSON_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarshalJSON'
-type MockIP4Config_MarshalJSON_Call struct {
- *mock.Call
-}
-
-// MarshalJSON is a helper method to define mock.On call
-func (_e *MockIP4Config_Expecter) MarshalJSON() *MockIP4Config_MarshalJSON_Call {
- return &MockIP4Config_MarshalJSON_Call{Call: _e.mock.On("MarshalJSON")}
-}
-
-func (_c *MockIP4Config_MarshalJSON_Call) Run(run func()) *MockIP4Config_MarshalJSON_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockIP4Config_MarshalJSON_Call) Return(_a0 []byte, _a1 error) *MockIP4Config_MarshalJSON_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockIP4Config_MarshalJSON_Call) RunAndReturn(run func() ([]byte, error)) *MockIP4Config_MarshalJSON_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// NewMockIP4Config creates a new instance of MockIP4Config. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewMockIP4Config(t interface {
- mock.TestingT
- Cleanup(func())
-}) *MockIP4Config {
- mock := &MockIP4Config{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_NetworkManager.go b/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_NetworkManager.go
deleted file mode 100644
index e74ffb0..0000000
--- a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_NetworkManager.go
+++ /dev/null
@@ -1,2349 +0,0 @@
-// Code generated by mockery v2.53.5. DO NOT EDIT.
-
-package gonetworkmanager
-
-import (
- gonetworkmanager "github.com/Wifx/gonetworkmanager/v2"
- dbus "github.com/godbus/dbus/v5"
-
- mock "github.com/stretchr/testify/mock"
-)
-
-// MockNetworkManager is an autogenerated mock type for the NetworkManager type
-type MockNetworkManager struct {
- mock.Mock
-}
-
-type MockNetworkManager_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *MockNetworkManager) EXPECT() *MockNetworkManager_Expecter {
- return &MockNetworkManager_Expecter{mock: &_m.Mock}
-}
-
-// ActivateConnection provides a mock function with given fields: connection, device, specificObject
-func (_m *MockNetworkManager) ActivateConnection(connection gonetworkmanager.Connection, device gonetworkmanager.Device, specificObject *dbus.Object) (gonetworkmanager.ActiveConnection, error) {
- ret := _m.Called(connection, device, specificObject)
-
- if len(ret) == 0 {
- panic("no return value specified for ActivateConnection")
- }
-
- var r0 gonetworkmanager.ActiveConnection
- var r1 error
- if rf, ok := ret.Get(0).(func(gonetworkmanager.Connection, gonetworkmanager.Device, *dbus.Object) (gonetworkmanager.ActiveConnection, error)); ok {
- return rf(connection, device, specificObject)
- }
- if rf, ok := ret.Get(0).(func(gonetworkmanager.Connection, gonetworkmanager.Device, *dbus.Object) gonetworkmanager.ActiveConnection); ok {
- r0 = rf(connection, device, specificObject)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.ActiveConnection)
- }
- }
-
- if rf, ok := ret.Get(1).(func(gonetworkmanager.Connection, gonetworkmanager.Device, *dbus.Object) error); ok {
- r1 = rf(connection, device, specificObject)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_ActivateConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ActivateConnection'
-type MockNetworkManager_ActivateConnection_Call struct {
- *mock.Call
-}
-
-// ActivateConnection is a helper method to define mock.On call
-// - connection gonetworkmanager.Connection
-// - device gonetworkmanager.Device
-// - specificObject *dbus.Object
-func (_e *MockNetworkManager_Expecter) ActivateConnection(connection interface{}, device interface{}, specificObject interface{}) *MockNetworkManager_ActivateConnection_Call {
- return &MockNetworkManager_ActivateConnection_Call{Call: _e.mock.On("ActivateConnection", connection, device, specificObject)}
-}
-
-func (_c *MockNetworkManager_ActivateConnection_Call) Run(run func(connection gonetworkmanager.Connection, device gonetworkmanager.Device, specificObject *dbus.Object)) *MockNetworkManager_ActivateConnection_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(gonetworkmanager.Connection), args[1].(gonetworkmanager.Device), args[2].(*dbus.Object))
- })
- return _c
-}
-
-func (_c *MockNetworkManager_ActivateConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockNetworkManager_ActivateConnection_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_ActivateConnection_Call) RunAndReturn(run func(gonetworkmanager.Connection, gonetworkmanager.Device, *dbus.Object) (gonetworkmanager.ActiveConnection, error)) *MockNetworkManager_ActivateConnection_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// ActivateWirelessConnection provides a mock function with given fields: connection, device, accessPoint
-func (_m *MockNetworkManager) ActivateWirelessConnection(connection gonetworkmanager.Connection, device gonetworkmanager.Device, accessPoint gonetworkmanager.AccessPoint) (gonetworkmanager.ActiveConnection, error) {
- ret := _m.Called(connection, device, accessPoint)
-
- if len(ret) == 0 {
- panic("no return value specified for ActivateWirelessConnection")
- }
-
- var r0 gonetworkmanager.ActiveConnection
- var r1 error
- if rf, ok := ret.Get(0).(func(gonetworkmanager.Connection, gonetworkmanager.Device, gonetworkmanager.AccessPoint) (gonetworkmanager.ActiveConnection, error)); ok {
- return rf(connection, device, accessPoint)
- }
- if rf, ok := ret.Get(0).(func(gonetworkmanager.Connection, gonetworkmanager.Device, gonetworkmanager.AccessPoint) gonetworkmanager.ActiveConnection); ok {
- r0 = rf(connection, device, accessPoint)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.ActiveConnection)
- }
- }
-
- if rf, ok := ret.Get(1).(func(gonetworkmanager.Connection, gonetworkmanager.Device, gonetworkmanager.AccessPoint) error); ok {
- r1 = rf(connection, device, accessPoint)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_ActivateWirelessConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ActivateWirelessConnection'
-type MockNetworkManager_ActivateWirelessConnection_Call struct {
- *mock.Call
-}
-
-// ActivateWirelessConnection is a helper method to define mock.On call
-// - connection gonetworkmanager.Connection
-// - device gonetworkmanager.Device
-// - accessPoint gonetworkmanager.AccessPoint
-func (_e *MockNetworkManager_Expecter) ActivateWirelessConnection(connection interface{}, device interface{}, accessPoint interface{}) *MockNetworkManager_ActivateWirelessConnection_Call {
- return &MockNetworkManager_ActivateWirelessConnection_Call{Call: _e.mock.On("ActivateWirelessConnection", connection, device, accessPoint)}
-}
-
-func (_c *MockNetworkManager_ActivateWirelessConnection_Call) Run(run func(connection gonetworkmanager.Connection, device gonetworkmanager.Device, accessPoint gonetworkmanager.AccessPoint)) *MockNetworkManager_ActivateWirelessConnection_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(gonetworkmanager.Connection), args[1].(gonetworkmanager.Device), args[2].(gonetworkmanager.AccessPoint))
- })
- return _c
-}
-
-func (_c *MockNetworkManager_ActivateWirelessConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockNetworkManager_ActivateWirelessConnection_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_ActivateWirelessConnection_Call) RunAndReturn(run func(gonetworkmanager.Connection, gonetworkmanager.Device, gonetworkmanager.AccessPoint) (gonetworkmanager.ActiveConnection, error)) *MockNetworkManager_ActivateWirelessConnection_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// AddAndActivateConnection provides a mock function with given fields: connection, device
-func (_m *MockNetworkManager) AddAndActivateConnection(connection map[string]map[string]interface{}, device gonetworkmanager.Device) (gonetworkmanager.ActiveConnection, error) {
- ret := _m.Called(connection, device)
-
- if len(ret) == 0 {
- panic("no return value specified for AddAndActivateConnection")
- }
-
- var r0 gonetworkmanager.ActiveConnection
- var r1 error
- if rf, ok := ret.Get(0).(func(map[string]map[string]interface{}, gonetworkmanager.Device) (gonetworkmanager.ActiveConnection, error)); ok {
- return rf(connection, device)
- }
- if rf, ok := ret.Get(0).(func(map[string]map[string]interface{}, gonetworkmanager.Device) gonetworkmanager.ActiveConnection); ok {
- r0 = rf(connection, device)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.ActiveConnection)
- }
- }
-
- if rf, ok := ret.Get(1).(func(map[string]map[string]interface{}, gonetworkmanager.Device) error); ok {
- r1 = rf(connection, device)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_AddAndActivateConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddAndActivateConnection'
-type MockNetworkManager_AddAndActivateConnection_Call struct {
- *mock.Call
-}
-
-// AddAndActivateConnection is a helper method to define mock.On call
-// - connection map[string]map[string]interface{}
-// - device gonetworkmanager.Device
-func (_e *MockNetworkManager_Expecter) AddAndActivateConnection(connection interface{}, device interface{}) *MockNetworkManager_AddAndActivateConnection_Call {
- return &MockNetworkManager_AddAndActivateConnection_Call{Call: _e.mock.On("AddAndActivateConnection", connection, device)}
-}
-
-func (_c *MockNetworkManager_AddAndActivateConnection_Call) Run(run func(connection map[string]map[string]interface{}, device gonetworkmanager.Device)) *MockNetworkManager_AddAndActivateConnection_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(map[string]map[string]interface{}), args[1].(gonetworkmanager.Device))
- })
- return _c
-}
-
-func (_c *MockNetworkManager_AddAndActivateConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockNetworkManager_AddAndActivateConnection_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_AddAndActivateConnection_Call) RunAndReturn(run func(map[string]map[string]interface{}, gonetworkmanager.Device) (gonetworkmanager.ActiveConnection, error)) *MockNetworkManager_AddAndActivateConnection_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// AddAndActivateWirelessConnection provides a mock function with given fields: connection, device, accessPoint
-func (_m *MockNetworkManager) AddAndActivateWirelessConnection(connection map[string]map[string]interface{}, device gonetworkmanager.Device, accessPoint gonetworkmanager.AccessPoint) (gonetworkmanager.ActiveConnection, error) {
- ret := _m.Called(connection, device, accessPoint)
-
- if len(ret) == 0 {
- panic("no return value specified for AddAndActivateWirelessConnection")
- }
-
- var r0 gonetworkmanager.ActiveConnection
- var r1 error
- if rf, ok := ret.Get(0).(func(map[string]map[string]interface{}, gonetworkmanager.Device, gonetworkmanager.AccessPoint) (gonetworkmanager.ActiveConnection, error)); ok {
- return rf(connection, device, accessPoint)
- }
- if rf, ok := ret.Get(0).(func(map[string]map[string]interface{}, gonetworkmanager.Device, gonetworkmanager.AccessPoint) gonetworkmanager.ActiveConnection); ok {
- r0 = rf(connection, device, accessPoint)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.ActiveConnection)
- }
- }
-
- if rf, ok := ret.Get(1).(func(map[string]map[string]interface{}, gonetworkmanager.Device, gonetworkmanager.AccessPoint) error); ok {
- r1 = rf(connection, device, accessPoint)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_AddAndActivateWirelessConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddAndActivateWirelessConnection'
-type MockNetworkManager_AddAndActivateWirelessConnection_Call struct {
- *mock.Call
-}
-
-// AddAndActivateWirelessConnection is a helper method to define mock.On call
-// - connection map[string]map[string]interface{}
-// - device gonetworkmanager.Device
-// - accessPoint gonetworkmanager.AccessPoint
-func (_e *MockNetworkManager_Expecter) AddAndActivateWirelessConnection(connection interface{}, device interface{}, accessPoint interface{}) *MockNetworkManager_AddAndActivateWirelessConnection_Call {
- return &MockNetworkManager_AddAndActivateWirelessConnection_Call{Call: _e.mock.On("AddAndActivateWirelessConnection", connection, device, accessPoint)}
-}
-
-func (_c *MockNetworkManager_AddAndActivateWirelessConnection_Call) Run(run func(connection map[string]map[string]interface{}, device gonetworkmanager.Device, accessPoint gonetworkmanager.AccessPoint)) *MockNetworkManager_AddAndActivateWirelessConnection_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(map[string]map[string]interface{}), args[1].(gonetworkmanager.Device), args[2].(gonetworkmanager.AccessPoint))
- })
- return _c
-}
-
-func (_c *MockNetworkManager_AddAndActivateWirelessConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockNetworkManager_AddAndActivateWirelessConnection_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_AddAndActivateWirelessConnection_Call) RunAndReturn(run func(map[string]map[string]interface{}, gonetworkmanager.Device, gonetworkmanager.AccessPoint) (gonetworkmanager.ActiveConnection, error)) *MockNetworkManager_AddAndActivateWirelessConnection_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// CheckConnectivity provides a mock function with no fields
-func (_m *MockNetworkManager) CheckConnectivity() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for CheckConnectivity")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockNetworkManager_CheckConnectivity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckConnectivity'
-type MockNetworkManager_CheckConnectivity_Call struct {
- *mock.Call
-}
-
-// CheckConnectivity is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) CheckConnectivity() *MockNetworkManager_CheckConnectivity_Call {
- return &MockNetworkManager_CheckConnectivity_Call{Call: _e.mock.On("CheckConnectivity")}
-}
-
-func (_c *MockNetworkManager_CheckConnectivity_Call) Run(run func()) *MockNetworkManager_CheckConnectivity_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_CheckConnectivity_Call) Return(_a0 error) *MockNetworkManager_CheckConnectivity_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockNetworkManager_CheckConnectivity_Call) RunAndReturn(run func() error) *MockNetworkManager_CheckConnectivity_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// CheckpointAdjustRollbackTimeout provides a mock function with given fields: checkpoint, addTimeout
-func (_m *MockNetworkManager) CheckpointAdjustRollbackTimeout(checkpoint gonetworkmanager.Checkpoint, addTimeout uint32) error {
- ret := _m.Called(checkpoint, addTimeout)
-
- if len(ret) == 0 {
- panic("no return value specified for CheckpointAdjustRollbackTimeout")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(gonetworkmanager.Checkpoint, uint32) error); ok {
- r0 = rf(checkpoint, addTimeout)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockNetworkManager_CheckpointAdjustRollbackTimeout_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckpointAdjustRollbackTimeout'
-type MockNetworkManager_CheckpointAdjustRollbackTimeout_Call struct {
- *mock.Call
-}
-
-// CheckpointAdjustRollbackTimeout is a helper method to define mock.On call
-// - checkpoint gonetworkmanager.Checkpoint
-// - addTimeout uint32
-func (_e *MockNetworkManager_Expecter) CheckpointAdjustRollbackTimeout(checkpoint interface{}, addTimeout interface{}) *MockNetworkManager_CheckpointAdjustRollbackTimeout_Call {
- return &MockNetworkManager_CheckpointAdjustRollbackTimeout_Call{Call: _e.mock.On("CheckpointAdjustRollbackTimeout", checkpoint, addTimeout)}
-}
-
-func (_c *MockNetworkManager_CheckpointAdjustRollbackTimeout_Call) Run(run func(checkpoint gonetworkmanager.Checkpoint, addTimeout uint32)) *MockNetworkManager_CheckpointAdjustRollbackTimeout_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(gonetworkmanager.Checkpoint), args[1].(uint32))
- })
- return _c
-}
-
-func (_c *MockNetworkManager_CheckpointAdjustRollbackTimeout_Call) Return(_a0 error) *MockNetworkManager_CheckpointAdjustRollbackTimeout_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockNetworkManager_CheckpointAdjustRollbackTimeout_Call) RunAndReturn(run func(gonetworkmanager.Checkpoint, uint32) error) *MockNetworkManager_CheckpointAdjustRollbackTimeout_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// CheckpointCreate provides a mock function with given fields: devices, rollbackTimeout, flags
-func (_m *MockNetworkManager) CheckpointCreate(devices []gonetworkmanager.Device, rollbackTimeout uint32, flags uint32) (gonetworkmanager.Checkpoint, error) {
- ret := _m.Called(devices, rollbackTimeout, flags)
-
- if len(ret) == 0 {
- panic("no return value specified for CheckpointCreate")
- }
-
- var r0 gonetworkmanager.Checkpoint
- var r1 error
- if rf, ok := ret.Get(0).(func([]gonetworkmanager.Device, uint32, uint32) (gonetworkmanager.Checkpoint, error)); ok {
- return rf(devices, rollbackTimeout, flags)
- }
- if rf, ok := ret.Get(0).(func([]gonetworkmanager.Device, uint32, uint32) gonetworkmanager.Checkpoint); ok {
- r0 = rf(devices, rollbackTimeout, flags)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.Checkpoint)
- }
- }
-
- if rf, ok := ret.Get(1).(func([]gonetworkmanager.Device, uint32, uint32) error); ok {
- r1 = rf(devices, rollbackTimeout, flags)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_CheckpointCreate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckpointCreate'
-type MockNetworkManager_CheckpointCreate_Call struct {
- *mock.Call
-}
-
-// CheckpointCreate is a helper method to define mock.On call
-// - devices []gonetworkmanager.Device
-// - rollbackTimeout uint32
-// - flags uint32
-func (_e *MockNetworkManager_Expecter) CheckpointCreate(devices interface{}, rollbackTimeout interface{}, flags interface{}) *MockNetworkManager_CheckpointCreate_Call {
- return &MockNetworkManager_CheckpointCreate_Call{Call: _e.mock.On("CheckpointCreate", devices, rollbackTimeout, flags)}
-}
-
-func (_c *MockNetworkManager_CheckpointCreate_Call) Run(run func(devices []gonetworkmanager.Device, rollbackTimeout uint32, flags uint32)) *MockNetworkManager_CheckpointCreate_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].([]gonetworkmanager.Device), args[1].(uint32), args[2].(uint32))
- })
- return _c
-}
-
-func (_c *MockNetworkManager_CheckpointCreate_Call) Return(_a0 gonetworkmanager.Checkpoint, _a1 error) *MockNetworkManager_CheckpointCreate_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_CheckpointCreate_Call) RunAndReturn(run func([]gonetworkmanager.Device, uint32, uint32) (gonetworkmanager.Checkpoint, error)) *MockNetworkManager_CheckpointCreate_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// CheckpointDestroy provides a mock function with given fields: checkpoint
-func (_m *MockNetworkManager) CheckpointDestroy(checkpoint gonetworkmanager.Checkpoint) error {
- ret := _m.Called(checkpoint)
-
- if len(ret) == 0 {
- panic("no return value specified for CheckpointDestroy")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(gonetworkmanager.Checkpoint) error); ok {
- r0 = rf(checkpoint)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockNetworkManager_CheckpointDestroy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckpointDestroy'
-type MockNetworkManager_CheckpointDestroy_Call struct {
- *mock.Call
-}
-
-// CheckpointDestroy is a helper method to define mock.On call
-// - checkpoint gonetworkmanager.Checkpoint
-func (_e *MockNetworkManager_Expecter) CheckpointDestroy(checkpoint interface{}) *MockNetworkManager_CheckpointDestroy_Call {
- return &MockNetworkManager_CheckpointDestroy_Call{Call: _e.mock.On("CheckpointDestroy", checkpoint)}
-}
-
-func (_c *MockNetworkManager_CheckpointDestroy_Call) Run(run func(checkpoint gonetworkmanager.Checkpoint)) *MockNetworkManager_CheckpointDestroy_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(gonetworkmanager.Checkpoint))
- })
- return _c
-}
-
-func (_c *MockNetworkManager_CheckpointDestroy_Call) Return(_a0 error) *MockNetworkManager_CheckpointDestroy_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockNetworkManager_CheckpointDestroy_Call) RunAndReturn(run func(gonetworkmanager.Checkpoint) error) *MockNetworkManager_CheckpointDestroy_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// CheckpointRollback provides a mock function with given fields: checkpoint
-func (_m *MockNetworkManager) CheckpointRollback(checkpoint gonetworkmanager.Checkpoint) (map[dbus.ObjectPath]gonetworkmanager.NmRollbackResult, error) {
- ret := _m.Called(checkpoint)
-
- if len(ret) == 0 {
- panic("no return value specified for CheckpointRollback")
- }
-
- var r0 map[dbus.ObjectPath]gonetworkmanager.NmRollbackResult
- var r1 error
- if rf, ok := ret.Get(0).(func(gonetworkmanager.Checkpoint) (map[dbus.ObjectPath]gonetworkmanager.NmRollbackResult, error)); ok {
- return rf(checkpoint)
- }
- if rf, ok := ret.Get(0).(func(gonetworkmanager.Checkpoint) map[dbus.ObjectPath]gonetworkmanager.NmRollbackResult); ok {
- r0 = rf(checkpoint)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(map[dbus.ObjectPath]gonetworkmanager.NmRollbackResult)
- }
- }
-
- if rf, ok := ret.Get(1).(func(gonetworkmanager.Checkpoint) error); ok {
- r1 = rf(checkpoint)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_CheckpointRollback_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckpointRollback'
-type MockNetworkManager_CheckpointRollback_Call struct {
- *mock.Call
-}
-
-// CheckpointRollback is a helper method to define mock.On call
-// - checkpoint gonetworkmanager.Checkpoint
-func (_e *MockNetworkManager_Expecter) CheckpointRollback(checkpoint interface{}) *MockNetworkManager_CheckpointRollback_Call {
- return &MockNetworkManager_CheckpointRollback_Call{Call: _e.mock.On("CheckpointRollback", checkpoint)}
-}
-
-func (_c *MockNetworkManager_CheckpointRollback_Call) Run(run func(checkpoint gonetworkmanager.Checkpoint)) *MockNetworkManager_CheckpointRollback_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(gonetworkmanager.Checkpoint))
- })
- return _c
-}
-
-func (_c *MockNetworkManager_CheckpointRollback_Call) Return(result map[dbus.ObjectPath]gonetworkmanager.NmRollbackResult, err error) *MockNetworkManager_CheckpointRollback_Call {
- _c.Call.Return(result, err)
- return _c
-}
-
-func (_c *MockNetworkManager_CheckpointRollback_Call) RunAndReturn(run func(gonetworkmanager.Checkpoint) (map[dbus.ObjectPath]gonetworkmanager.NmRollbackResult, error)) *MockNetworkManager_CheckpointRollback_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// DeactivateConnection provides a mock function with given fields: connection
-func (_m *MockNetworkManager) DeactivateConnection(connection gonetworkmanager.ActiveConnection) error {
- ret := _m.Called(connection)
-
- if len(ret) == 0 {
- panic("no return value specified for DeactivateConnection")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(gonetworkmanager.ActiveConnection) error); ok {
- r0 = rf(connection)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockNetworkManager_DeactivateConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeactivateConnection'
-type MockNetworkManager_DeactivateConnection_Call struct {
- *mock.Call
-}
-
-// DeactivateConnection is a helper method to define mock.On call
-// - connection gonetworkmanager.ActiveConnection
-func (_e *MockNetworkManager_Expecter) DeactivateConnection(connection interface{}) *MockNetworkManager_DeactivateConnection_Call {
- return &MockNetworkManager_DeactivateConnection_Call{Call: _e.mock.On("DeactivateConnection", connection)}
-}
-
-func (_c *MockNetworkManager_DeactivateConnection_Call) Run(run func(connection gonetworkmanager.ActiveConnection)) *MockNetworkManager_DeactivateConnection_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(gonetworkmanager.ActiveConnection))
- })
- return _c
-}
-
-func (_c *MockNetworkManager_DeactivateConnection_Call) Return(_a0 error) *MockNetworkManager_DeactivateConnection_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockNetworkManager_DeactivateConnection_Call) RunAndReturn(run func(gonetworkmanager.ActiveConnection) error) *MockNetworkManager_DeactivateConnection_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Enable provides a mock function with given fields: enableNDisable
-func (_m *MockNetworkManager) Enable(enableNDisable bool) error {
- ret := _m.Called(enableNDisable)
-
- if len(ret) == 0 {
- panic("no return value specified for Enable")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(bool) error); ok {
- r0 = rf(enableNDisable)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockNetworkManager_Enable_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Enable'
-type MockNetworkManager_Enable_Call struct {
- *mock.Call
-}
-
-// Enable is a helper method to define mock.On call
-// - enableNDisable bool
-func (_e *MockNetworkManager_Expecter) Enable(enableNDisable interface{}) *MockNetworkManager_Enable_Call {
- return &MockNetworkManager_Enable_Call{Call: _e.mock.On("Enable", enableNDisable)}
-}
-
-func (_c *MockNetworkManager_Enable_Call) Run(run func(enableNDisable bool)) *MockNetworkManager_Enable_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(bool))
- })
- return _c
-}
-
-func (_c *MockNetworkManager_Enable_Call) Return(_a0 error) *MockNetworkManager_Enable_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockNetworkManager_Enable_Call) RunAndReturn(run func(bool) error) *MockNetworkManager_Enable_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetAllDevices provides a mock function with no fields
-func (_m *MockNetworkManager) GetAllDevices() ([]gonetworkmanager.Device, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetAllDevices")
- }
-
- var r0 []gonetworkmanager.Device
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Device, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.Device); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.Device)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetAllDevices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllDevices'
-type MockNetworkManager_GetAllDevices_Call struct {
- *mock.Call
-}
-
-// GetAllDevices is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetAllDevices() *MockNetworkManager_GetAllDevices_Call {
- return &MockNetworkManager_GetAllDevices_Call{Call: _e.mock.On("GetAllDevices")}
-}
-
-func (_c *MockNetworkManager_GetAllDevices_Call) Run(run func()) *MockNetworkManager_GetAllDevices_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetAllDevices_Call) Return(_a0 []gonetworkmanager.Device, _a1 error) *MockNetworkManager_GetAllDevices_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetAllDevices_Call) RunAndReturn(run func() ([]gonetworkmanager.Device, error)) *MockNetworkManager_GetAllDevices_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetDeviceByIpIface provides a mock function with given fields: interfaceId
-func (_m *MockNetworkManager) GetDeviceByIpIface(interfaceId string) (gonetworkmanager.Device, error) {
- ret := _m.Called(interfaceId)
-
- if len(ret) == 0 {
- panic("no return value specified for GetDeviceByIpIface")
- }
-
- var r0 gonetworkmanager.Device
- var r1 error
- if rf, ok := ret.Get(0).(func(string) (gonetworkmanager.Device, error)); ok {
- return rf(interfaceId)
- }
- if rf, ok := ret.Get(0).(func(string) gonetworkmanager.Device); ok {
- r0 = rf(interfaceId)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.Device)
- }
- }
-
- if rf, ok := ret.Get(1).(func(string) error); ok {
- r1 = rf(interfaceId)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetDeviceByIpIface_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDeviceByIpIface'
-type MockNetworkManager_GetDeviceByIpIface_Call struct {
- *mock.Call
-}
-
-// GetDeviceByIpIface is a helper method to define mock.On call
-// - interfaceId string
-func (_e *MockNetworkManager_Expecter) GetDeviceByIpIface(interfaceId interface{}) *MockNetworkManager_GetDeviceByIpIface_Call {
- return &MockNetworkManager_GetDeviceByIpIface_Call{Call: _e.mock.On("GetDeviceByIpIface", interfaceId)}
-}
-
-func (_c *MockNetworkManager_GetDeviceByIpIface_Call) Run(run func(interfaceId string)) *MockNetworkManager_GetDeviceByIpIface_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetDeviceByIpIface_Call) Return(_a0 gonetworkmanager.Device, _a1 error) *MockNetworkManager_GetDeviceByIpIface_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetDeviceByIpIface_Call) RunAndReturn(run func(string) (gonetworkmanager.Device, error)) *MockNetworkManager_GetDeviceByIpIface_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetDevices provides a mock function with no fields
-func (_m *MockNetworkManager) GetDevices() ([]gonetworkmanager.Device, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetDevices")
- }
-
- var r0 []gonetworkmanager.Device
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Device, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.Device); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.Device)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetDevices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDevices'
-type MockNetworkManager_GetDevices_Call struct {
- *mock.Call
-}
-
-// GetDevices is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetDevices() *MockNetworkManager_GetDevices_Call {
- return &MockNetworkManager_GetDevices_Call{Call: _e.mock.On("GetDevices")}
-}
-
-func (_c *MockNetworkManager_GetDevices_Call) Run(run func()) *MockNetworkManager_GetDevices_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetDevices_Call) Return(_a0 []gonetworkmanager.Device, _a1 error) *MockNetworkManager_GetDevices_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetDevices_Call) RunAndReturn(run func() ([]gonetworkmanager.Device, error)) *MockNetworkManager_GetDevices_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyActivatingConnection provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyActivatingConnection() (gonetworkmanager.ActiveConnection, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyActivatingConnection")
- }
-
- var r0 gonetworkmanager.ActiveConnection
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.ActiveConnection, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.ActiveConnection); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.ActiveConnection)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyActivatingConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyActivatingConnection'
-type MockNetworkManager_GetPropertyActivatingConnection_Call struct {
- *mock.Call
-}
-
-// GetPropertyActivatingConnection is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyActivatingConnection() *MockNetworkManager_GetPropertyActivatingConnection_Call {
- return &MockNetworkManager_GetPropertyActivatingConnection_Call{Call: _e.mock.On("GetPropertyActivatingConnection")}
-}
-
-func (_c *MockNetworkManager_GetPropertyActivatingConnection_Call) Run(run func()) *MockNetworkManager_GetPropertyActivatingConnection_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyActivatingConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockNetworkManager_GetPropertyActivatingConnection_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyActivatingConnection_Call) RunAndReturn(run func() (gonetworkmanager.ActiveConnection, error)) *MockNetworkManager_GetPropertyActivatingConnection_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyActiveConnections provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyActiveConnections() ([]gonetworkmanager.ActiveConnection, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyActiveConnections")
- }
-
- var r0 []gonetworkmanager.ActiveConnection
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.ActiveConnection, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.ActiveConnection); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.ActiveConnection)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyActiveConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyActiveConnections'
-type MockNetworkManager_GetPropertyActiveConnections_Call struct {
- *mock.Call
-}
-
-// GetPropertyActiveConnections is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyActiveConnections() *MockNetworkManager_GetPropertyActiveConnections_Call {
- return &MockNetworkManager_GetPropertyActiveConnections_Call{Call: _e.mock.On("GetPropertyActiveConnections")}
-}
-
-func (_c *MockNetworkManager_GetPropertyActiveConnections_Call) Run(run func()) *MockNetworkManager_GetPropertyActiveConnections_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyActiveConnections_Call) Return(_a0 []gonetworkmanager.ActiveConnection, _a1 error) *MockNetworkManager_GetPropertyActiveConnections_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyActiveConnections_Call) RunAndReturn(run func() ([]gonetworkmanager.ActiveConnection, error)) *MockNetworkManager_GetPropertyActiveConnections_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyAllDevices provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyAllDevices() ([]gonetworkmanager.Device, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyAllDevices")
- }
-
- var r0 []gonetworkmanager.Device
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Device, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.Device); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.Device)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyAllDevices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyAllDevices'
-type MockNetworkManager_GetPropertyAllDevices_Call struct {
- *mock.Call
-}
-
-// GetPropertyAllDevices is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyAllDevices() *MockNetworkManager_GetPropertyAllDevices_Call {
- return &MockNetworkManager_GetPropertyAllDevices_Call{Call: _e.mock.On("GetPropertyAllDevices")}
-}
-
-func (_c *MockNetworkManager_GetPropertyAllDevices_Call) Run(run func()) *MockNetworkManager_GetPropertyAllDevices_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyAllDevices_Call) Return(_a0 []gonetworkmanager.Device, _a1 error) *MockNetworkManager_GetPropertyAllDevices_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyAllDevices_Call) RunAndReturn(run func() ([]gonetworkmanager.Device, error)) *MockNetworkManager_GetPropertyAllDevices_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyCapabilities provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyCapabilities() ([]gonetworkmanager.NmCapability, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyCapabilities")
- }
-
- var r0 []gonetworkmanager.NmCapability
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.NmCapability, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.NmCapability); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.NmCapability)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyCapabilities_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyCapabilities'
-type MockNetworkManager_GetPropertyCapabilities_Call struct {
- *mock.Call
-}
-
-// GetPropertyCapabilities is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyCapabilities() *MockNetworkManager_GetPropertyCapabilities_Call {
- return &MockNetworkManager_GetPropertyCapabilities_Call{Call: _e.mock.On("GetPropertyCapabilities")}
-}
-
-func (_c *MockNetworkManager_GetPropertyCapabilities_Call) Run(run func()) *MockNetworkManager_GetPropertyCapabilities_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyCapabilities_Call) Return(_a0 []gonetworkmanager.NmCapability, _a1 error) *MockNetworkManager_GetPropertyCapabilities_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyCapabilities_Call) RunAndReturn(run func() ([]gonetworkmanager.NmCapability, error)) *MockNetworkManager_GetPropertyCapabilities_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyCheckpoints provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyCheckpoints() ([]gonetworkmanager.Checkpoint, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyCheckpoints")
- }
-
- var r0 []gonetworkmanager.Checkpoint
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Checkpoint, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.Checkpoint); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.Checkpoint)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyCheckpoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyCheckpoints'
-type MockNetworkManager_GetPropertyCheckpoints_Call struct {
- *mock.Call
-}
-
-// GetPropertyCheckpoints is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyCheckpoints() *MockNetworkManager_GetPropertyCheckpoints_Call {
- return &MockNetworkManager_GetPropertyCheckpoints_Call{Call: _e.mock.On("GetPropertyCheckpoints")}
-}
-
-func (_c *MockNetworkManager_GetPropertyCheckpoints_Call) Run(run func()) *MockNetworkManager_GetPropertyCheckpoints_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyCheckpoints_Call) Return(_a0 []gonetworkmanager.Checkpoint, _a1 error) *MockNetworkManager_GetPropertyCheckpoints_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyCheckpoints_Call) RunAndReturn(run func() ([]gonetworkmanager.Checkpoint, error)) *MockNetworkManager_GetPropertyCheckpoints_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyConnectivity provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyConnectivity() (gonetworkmanager.NmConnectivity, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyConnectivity")
- }
-
- var r0 gonetworkmanager.NmConnectivity
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmConnectivity, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.NmConnectivity); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(gonetworkmanager.NmConnectivity)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyConnectivity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyConnectivity'
-type MockNetworkManager_GetPropertyConnectivity_Call struct {
- *mock.Call
-}
-
-// GetPropertyConnectivity is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyConnectivity() *MockNetworkManager_GetPropertyConnectivity_Call {
- return &MockNetworkManager_GetPropertyConnectivity_Call{Call: _e.mock.On("GetPropertyConnectivity")}
-}
-
-func (_c *MockNetworkManager_GetPropertyConnectivity_Call) Run(run func()) *MockNetworkManager_GetPropertyConnectivity_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyConnectivity_Call) Return(_a0 gonetworkmanager.NmConnectivity, _a1 error) *MockNetworkManager_GetPropertyConnectivity_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyConnectivity_Call) RunAndReturn(run func() (gonetworkmanager.NmConnectivity, error)) *MockNetworkManager_GetPropertyConnectivity_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyConnectivityCheckAvailable provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyConnectivityCheckAvailable() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyConnectivityCheckAvailable")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyConnectivityCheckAvailable'
-type MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call struct {
- *mock.Call
-}
-
-// GetPropertyConnectivityCheckAvailable is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyConnectivityCheckAvailable() *MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call {
- return &MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call{Call: _e.mock.On("GetPropertyConnectivityCheckAvailable")}
-}
-
-func (_c *MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call) Run(run func()) *MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyConnectivityCheckAvailable_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyConnectivityCheckEnabled provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyConnectivityCheckEnabled() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyConnectivityCheckEnabled")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyConnectivityCheckEnabled'
-type MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call struct {
- *mock.Call
-}
-
-// GetPropertyConnectivityCheckEnabled is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyConnectivityCheckEnabled() *MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call {
- return &MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call{Call: _e.mock.On("GetPropertyConnectivityCheckEnabled")}
-}
-
-func (_c *MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyConnectivityCheckEnabled_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyDevices provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyDevices() ([]gonetworkmanager.Device, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyDevices")
- }
-
- var r0 []gonetworkmanager.Device
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Device, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.Device); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.Device)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyDevices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyDevices'
-type MockNetworkManager_GetPropertyDevices_Call struct {
- *mock.Call
-}
-
-// GetPropertyDevices is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyDevices() *MockNetworkManager_GetPropertyDevices_Call {
- return &MockNetworkManager_GetPropertyDevices_Call{Call: _e.mock.On("GetPropertyDevices")}
-}
-
-func (_c *MockNetworkManager_GetPropertyDevices_Call) Run(run func()) *MockNetworkManager_GetPropertyDevices_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyDevices_Call) Return(_a0 []gonetworkmanager.Device, _a1 error) *MockNetworkManager_GetPropertyDevices_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyDevices_Call) RunAndReturn(run func() ([]gonetworkmanager.Device, error)) *MockNetworkManager_GetPropertyDevices_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyMetered provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyMetered() (gonetworkmanager.NmMetered, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyMetered")
- }
-
- var r0 gonetworkmanager.NmMetered
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmMetered, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.NmMetered); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(gonetworkmanager.NmMetered)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyMetered_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyMetered'
-type MockNetworkManager_GetPropertyMetered_Call struct {
- *mock.Call
-}
-
-// GetPropertyMetered is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyMetered() *MockNetworkManager_GetPropertyMetered_Call {
- return &MockNetworkManager_GetPropertyMetered_Call{Call: _e.mock.On("GetPropertyMetered")}
-}
-
-func (_c *MockNetworkManager_GetPropertyMetered_Call) Run(run func()) *MockNetworkManager_GetPropertyMetered_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyMetered_Call) Return(_a0 gonetworkmanager.NmMetered, _a1 error) *MockNetworkManager_GetPropertyMetered_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyMetered_Call) RunAndReturn(run func() (gonetworkmanager.NmMetered, error)) *MockNetworkManager_GetPropertyMetered_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyNetworkingEnabled provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyNetworkingEnabled() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyNetworkingEnabled")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyNetworkingEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyNetworkingEnabled'
-type MockNetworkManager_GetPropertyNetworkingEnabled_Call struct {
- *mock.Call
-}
-
-// GetPropertyNetworkingEnabled is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyNetworkingEnabled() *MockNetworkManager_GetPropertyNetworkingEnabled_Call {
- return &MockNetworkManager_GetPropertyNetworkingEnabled_Call{Call: _e.mock.On("GetPropertyNetworkingEnabled")}
-}
-
-func (_c *MockNetworkManager_GetPropertyNetworkingEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyNetworkingEnabled_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyNetworkingEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyNetworkingEnabled_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyNetworkingEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyNetworkingEnabled_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyPrimaryConnection provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyPrimaryConnection() (gonetworkmanager.ActiveConnection, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyPrimaryConnection")
- }
-
- var r0 gonetworkmanager.ActiveConnection
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.ActiveConnection, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.ActiveConnection); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.ActiveConnection)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyPrimaryConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyPrimaryConnection'
-type MockNetworkManager_GetPropertyPrimaryConnection_Call struct {
- *mock.Call
-}
-
-// GetPropertyPrimaryConnection is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyPrimaryConnection() *MockNetworkManager_GetPropertyPrimaryConnection_Call {
- return &MockNetworkManager_GetPropertyPrimaryConnection_Call{Call: _e.mock.On("GetPropertyPrimaryConnection")}
-}
-
-func (_c *MockNetworkManager_GetPropertyPrimaryConnection_Call) Run(run func()) *MockNetworkManager_GetPropertyPrimaryConnection_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyPrimaryConnection_Call) Return(_a0 gonetworkmanager.ActiveConnection, _a1 error) *MockNetworkManager_GetPropertyPrimaryConnection_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyPrimaryConnection_Call) RunAndReturn(run func() (gonetworkmanager.ActiveConnection, error)) *MockNetworkManager_GetPropertyPrimaryConnection_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyPrimaryConnectionType provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyPrimaryConnectionType() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyPrimaryConnectionType")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyPrimaryConnectionType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyPrimaryConnectionType'
-type MockNetworkManager_GetPropertyPrimaryConnectionType_Call struct {
- *mock.Call
-}
-
-// GetPropertyPrimaryConnectionType is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyPrimaryConnectionType() *MockNetworkManager_GetPropertyPrimaryConnectionType_Call {
- return &MockNetworkManager_GetPropertyPrimaryConnectionType_Call{Call: _e.mock.On("GetPropertyPrimaryConnectionType")}
-}
-
-func (_c *MockNetworkManager_GetPropertyPrimaryConnectionType_Call) Run(run func()) *MockNetworkManager_GetPropertyPrimaryConnectionType_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyPrimaryConnectionType_Call) Return(_a0 string, _a1 error) *MockNetworkManager_GetPropertyPrimaryConnectionType_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyPrimaryConnectionType_Call) RunAndReturn(run func() (string, error)) *MockNetworkManager_GetPropertyPrimaryConnectionType_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyStartup provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyStartup() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyStartup")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyStartup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyStartup'
-type MockNetworkManager_GetPropertyStartup_Call struct {
- *mock.Call
-}
-
-// GetPropertyStartup is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyStartup() *MockNetworkManager_GetPropertyStartup_Call {
- return &MockNetworkManager_GetPropertyStartup_Call{Call: _e.mock.On("GetPropertyStartup")}
-}
-
-func (_c *MockNetworkManager_GetPropertyStartup_Call) Run(run func()) *MockNetworkManager_GetPropertyStartup_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyStartup_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyStartup_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyStartup_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyStartup_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyState provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyState() (gonetworkmanager.NmState, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyState")
- }
-
- var r0 gonetworkmanager.NmState
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmState, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.NmState); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(gonetworkmanager.NmState)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyState'
-type MockNetworkManager_GetPropertyState_Call struct {
- *mock.Call
-}
-
-// GetPropertyState is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyState() *MockNetworkManager_GetPropertyState_Call {
- return &MockNetworkManager_GetPropertyState_Call{Call: _e.mock.On("GetPropertyState")}
-}
-
-func (_c *MockNetworkManager_GetPropertyState_Call) Run(run func()) *MockNetworkManager_GetPropertyState_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyState_Call) Return(_a0 gonetworkmanager.NmState, _a1 error) *MockNetworkManager_GetPropertyState_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyState_Call) RunAndReturn(run func() (gonetworkmanager.NmState, error)) *MockNetworkManager_GetPropertyState_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyVersion provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyVersion() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyVersion")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyVersion'
-type MockNetworkManager_GetPropertyVersion_Call struct {
- *mock.Call
-}
-
-// GetPropertyVersion is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyVersion() *MockNetworkManager_GetPropertyVersion_Call {
- return &MockNetworkManager_GetPropertyVersion_Call{Call: _e.mock.On("GetPropertyVersion")}
-}
-
-func (_c *MockNetworkManager_GetPropertyVersion_Call) Run(run func()) *MockNetworkManager_GetPropertyVersion_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyVersion_Call) Return(_a0 string, _a1 error) *MockNetworkManager_GetPropertyVersion_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyVersion_Call) RunAndReturn(run func() (string, error)) *MockNetworkManager_GetPropertyVersion_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyWimaxEnabled provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyWimaxEnabled() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyWimaxEnabled")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyWimaxEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWimaxEnabled'
-type MockNetworkManager_GetPropertyWimaxEnabled_Call struct {
- *mock.Call
-}
-
-// GetPropertyWimaxEnabled is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyWimaxEnabled() *MockNetworkManager_GetPropertyWimaxEnabled_Call {
- return &MockNetworkManager_GetPropertyWimaxEnabled_Call{Call: _e.mock.On("GetPropertyWimaxEnabled")}
-}
-
-func (_c *MockNetworkManager_GetPropertyWimaxEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyWimaxEnabled_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyWimaxEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyWimaxEnabled_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyWimaxEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyWimaxEnabled_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyWimaxHardwareEnabled provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyWimaxHardwareEnabled() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyWimaxHardwareEnabled")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWimaxHardwareEnabled'
-type MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call struct {
- *mock.Call
-}
-
-// GetPropertyWimaxHardwareEnabled is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyWimaxHardwareEnabled() *MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call {
- return &MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call{Call: _e.mock.On("GetPropertyWimaxHardwareEnabled")}
-}
-
-func (_c *MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyWimaxHardwareEnabled_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyWirelessEnabled provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyWirelessEnabled() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyWirelessEnabled")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyWirelessEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWirelessEnabled'
-type MockNetworkManager_GetPropertyWirelessEnabled_Call struct {
- *mock.Call
-}
-
-// GetPropertyWirelessEnabled is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyWirelessEnabled() *MockNetworkManager_GetPropertyWirelessEnabled_Call {
- return &MockNetworkManager_GetPropertyWirelessEnabled_Call{Call: _e.mock.On("GetPropertyWirelessEnabled")}
-}
-
-func (_c *MockNetworkManager_GetPropertyWirelessEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyWirelessEnabled_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyWirelessEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyWirelessEnabled_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyWirelessEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyWirelessEnabled_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyWirelessHardwareEnabled provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyWirelessHardwareEnabled() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyWirelessHardwareEnabled")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWirelessHardwareEnabled'
-type MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call struct {
- *mock.Call
-}
-
-// GetPropertyWirelessHardwareEnabled is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyWirelessHardwareEnabled() *MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call {
- return &MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call{Call: _e.mock.On("GetPropertyWirelessHardwareEnabled")}
-}
-
-func (_c *MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyWirelessHardwareEnabled_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyWwanEnabled provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyWwanEnabled() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyWwanEnabled")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyWwanEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWwanEnabled'
-type MockNetworkManager_GetPropertyWwanEnabled_Call struct {
- *mock.Call
-}
-
-// GetPropertyWwanEnabled is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyWwanEnabled() *MockNetworkManager_GetPropertyWwanEnabled_Call {
- return &MockNetworkManager_GetPropertyWwanEnabled_Call{Call: _e.mock.On("GetPropertyWwanEnabled")}
-}
-
-func (_c *MockNetworkManager_GetPropertyWwanEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyWwanEnabled_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyWwanEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyWwanEnabled_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyWwanEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyWwanEnabled_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyWwanHardwareEnabled provides a mock function with no fields
-func (_m *MockNetworkManager) GetPropertyWwanHardwareEnabled() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyWwanHardwareEnabled")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_GetPropertyWwanHardwareEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyWwanHardwareEnabled'
-type MockNetworkManager_GetPropertyWwanHardwareEnabled_Call struct {
- *mock.Call
-}
-
-// GetPropertyWwanHardwareEnabled is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) GetPropertyWwanHardwareEnabled() *MockNetworkManager_GetPropertyWwanHardwareEnabled_Call {
- return &MockNetworkManager_GetPropertyWwanHardwareEnabled_Call{Call: _e.mock.On("GetPropertyWwanHardwareEnabled")}
-}
-
-func (_c *MockNetworkManager_GetPropertyWwanHardwareEnabled_Call) Run(run func()) *MockNetworkManager_GetPropertyWwanHardwareEnabled_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyWwanHardwareEnabled_Call) Return(_a0 bool, _a1 error) *MockNetworkManager_GetPropertyWwanHardwareEnabled_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_GetPropertyWwanHardwareEnabled_Call) RunAndReturn(run func() (bool, error)) *MockNetworkManager_GetPropertyWwanHardwareEnabled_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// MarshalJSON provides a mock function with no fields
-func (_m *MockNetworkManager) MarshalJSON() ([]byte, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for MarshalJSON")
- }
-
- var r0 []byte
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]byte, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []byte); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]byte)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_MarshalJSON_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarshalJSON'
-type MockNetworkManager_MarshalJSON_Call struct {
- *mock.Call
-}
-
-// MarshalJSON is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) MarshalJSON() *MockNetworkManager_MarshalJSON_Call {
- return &MockNetworkManager_MarshalJSON_Call{Call: _e.mock.On("MarshalJSON")}
-}
-
-func (_c *MockNetworkManager_MarshalJSON_Call) Run(run func()) *MockNetworkManager_MarshalJSON_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_MarshalJSON_Call) Return(_a0 []byte, _a1 error) *MockNetworkManager_MarshalJSON_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_MarshalJSON_Call) RunAndReturn(run func() ([]byte, error)) *MockNetworkManager_MarshalJSON_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Reload provides a mock function with given fields: flags
-func (_m *MockNetworkManager) Reload(flags uint32) error {
- ret := _m.Called(flags)
-
- if len(ret) == 0 {
- panic("no return value specified for Reload")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(uint32) error); ok {
- r0 = rf(flags)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockNetworkManager_Reload_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Reload'
-type MockNetworkManager_Reload_Call struct {
- *mock.Call
-}
-
-// Reload is a helper method to define mock.On call
-// - flags uint32
-func (_e *MockNetworkManager_Expecter) Reload(flags interface{}) *MockNetworkManager_Reload_Call {
- return &MockNetworkManager_Reload_Call{Call: _e.mock.On("Reload", flags)}
-}
-
-func (_c *MockNetworkManager_Reload_Call) Run(run func(flags uint32)) *MockNetworkManager_Reload_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(uint32))
- })
- return _c
-}
-
-func (_c *MockNetworkManager_Reload_Call) Return(_a0 error) *MockNetworkManager_Reload_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockNetworkManager_Reload_Call) RunAndReturn(run func(uint32) error) *MockNetworkManager_Reload_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetPropertyWirelessEnabled provides a mock function with given fields: _a0
-func (_m *MockNetworkManager) SetPropertyWirelessEnabled(_a0 bool) error {
- ret := _m.Called(_a0)
-
- if len(ret) == 0 {
- panic("no return value specified for SetPropertyWirelessEnabled")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(bool) error); ok {
- r0 = rf(_a0)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockNetworkManager_SetPropertyWirelessEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPropertyWirelessEnabled'
-type MockNetworkManager_SetPropertyWirelessEnabled_Call struct {
- *mock.Call
-}
-
-// SetPropertyWirelessEnabled is a helper method to define mock.On call
-// - _a0 bool
-func (_e *MockNetworkManager_Expecter) SetPropertyWirelessEnabled(_a0 interface{}) *MockNetworkManager_SetPropertyWirelessEnabled_Call {
- return &MockNetworkManager_SetPropertyWirelessEnabled_Call{Call: _e.mock.On("SetPropertyWirelessEnabled", _a0)}
-}
-
-func (_c *MockNetworkManager_SetPropertyWirelessEnabled_Call) Run(run func(_a0 bool)) *MockNetworkManager_SetPropertyWirelessEnabled_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(bool))
- })
- return _c
-}
-
-func (_c *MockNetworkManager_SetPropertyWirelessEnabled_Call) Return(_a0 error) *MockNetworkManager_SetPropertyWirelessEnabled_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockNetworkManager_SetPropertyWirelessEnabled_Call) RunAndReturn(run func(bool) error) *MockNetworkManager_SetPropertyWirelessEnabled_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Sleep provides a mock function with given fields: sleepNWake
-func (_m *MockNetworkManager) Sleep(sleepNWake bool) error {
- ret := _m.Called(sleepNWake)
-
- if len(ret) == 0 {
- panic("no return value specified for Sleep")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(bool) error); ok {
- r0 = rf(sleepNWake)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockNetworkManager_Sleep_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Sleep'
-type MockNetworkManager_Sleep_Call struct {
- *mock.Call
-}
-
-// Sleep is a helper method to define mock.On call
-// - sleepNWake bool
-func (_e *MockNetworkManager_Expecter) Sleep(sleepNWake interface{}) *MockNetworkManager_Sleep_Call {
- return &MockNetworkManager_Sleep_Call{Call: _e.mock.On("Sleep", sleepNWake)}
-}
-
-func (_c *MockNetworkManager_Sleep_Call) Run(run func(sleepNWake bool)) *MockNetworkManager_Sleep_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(bool))
- })
- return _c
-}
-
-func (_c *MockNetworkManager_Sleep_Call) Return(_a0 error) *MockNetworkManager_Sleep_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockNetworkManager_Sleep_Call) RunAndReturn(run func(bool) error) *MockNetworkManager_Sleep_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// State provides a mock function with no fields
-func (_m *MockNetworkManager) State() (gonetworkmanager.NmState, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for State")
- }
-
- var r0 gonetworkmanager.NmState
- var r1 error
- if rf, ok := ret.Get(0).(func() (gonetworkmanager.NmState, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() gonetworkmanager.NmState); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(gonetworkmanager.NmState)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockNetworkManager_State_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'State'
-type MockNetworkManager_State_Call struct {
- *mock.Call
-}
-
-// State is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) State() *MockNetworkManager_State_Call {
- return &MockNetworkManager_State_Call{Call: _e.mock.On("State")}
-}
-
-func (_c *MockNetworkManager_State_Call) Run(run func()) *MockNetworkManager_State_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_State_Call) Return(_a0 gonetworkmanager.NmState, _a1 error) *MockNetworkManager_State_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockNetworkManager_State_Call) RunAndReturn(run func() (gonetworkmanager.NmState, error)) *MockNetworkManager_State_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Subscribe provides a mock function with no fields
-func (_m *MockNetworkManager) Subscribe() <-chan *dbus.Signal {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for Subscribe")
- }
-
- var r0 <-chan *dbus.Signal
- if rf, ok := ret.Get(0).(func() <-chan *dbus.Signal); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(<-chan *dbus.Signal)
- }
- }
-
- return r0
-}
-
-// MockNetworkManager_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe'
-type MockNetworkManager_Subscribe_Call struct {
- *mock.Call
-}
-
-// Subscribe is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) Subscribe() *MockNetworkManager_Subscribe_Call {
- return &MockNetworkManager_Subscribe_Call{Call: _e.mock.On("Subscribe")}
-}
-
-func (_c *MockNetworkManager_Subscribe_Call) Run(run func()) *MockNetworkManager_Subscribe_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_Subscribe_Call) Return(_a0 <-chan *dbus.Signal) *MockNetworkManager_Subscribe_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockNetworkManager_Subscribe_Call) RunAndReturn(run func() <-chan *dbus.Signal) *MockNetworkManager_Subscribe_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Unsubscribe provides a mock function with no fields
-func (_m *MockNetworkManager) Unsubscribe() {
- _m.Called()
-}
-
-// MockNetworkManager_Unsubscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unsubscribe'
-type MockNetworkManager_Unsubscribe_Call struct {
- *mock.Call
-}
-
-// Unsubscribe is a helper method to define mock.On call
-func (_e *MockNetworkManager_Expecter) Unsubscribe() *MockNetworkManager_Unsubscribe_Call {
- return &MockNetworkManager_Unsubscribe_Call{Call: _e.mock.On("Unsubscribe")}
-}
-
-func (_c *MockNetworkManager_Unsubscribe_Call) Run(run func()) *MockNetworkManager_Unsubscribe_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockNetworkManager_Unsubscribe_Call) Return() *MockNetworkManager_Unsubscribe_Call {
- _c.Call.Return()
- return _c
-}
-
-func (_c *MockNetworkManager_Unsubscribe_Call) RunAndReturn(run func()) *MockNetworkManager_Unsubscribe_Call {
- _c.Run(run)
- return _c
-}
-
-// NewMockNetworkManager creates a new instance of MockNetworkManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewMockNetworkManager(t interface {
- mock.TestingT
- Cleanup(func())
-}) *MockNetworkManager {
- mock := &MockNetworkManager{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Settings.go b/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Settings.go
deleted file mode 100644
index 20f488e..0000000
--- a/nix/inputs/dms-cli/internal/mocks/github.com/Wifx/gonetworkmanager/v2/mock_Settings.go
+++ /dev/null
@@ -1,467 +0,0 @@
-// Code generated by mockery v2.53.5. DO NOT EDIT.
-
-package gonetworkmanager
-
-import (
- gonetworkmanager "github.com/Wifx/gonetworkmanager/v2"
- mock "github.com/stretchr/testify/mock"
-)
-
-// MockSettings is an autogenerated mock type for the Settings type
-type MockSettings struct {
- mock.Mock
-}
-
-type MockSettings_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *MockSettings) EXPECT() *MockSettings_Expecter {
- return &MockSettings_Expecter{mock: &_m.Mock}
-}
-
-// AddConnection provides a mock function with given fields: settings
-func (_m *MockSettings) AddConnection(settings gonetworkmanager.ConnectionSettings) (gonetworkmanager.Connection, error) {
- ret := _m.Called(settings)
-
- if len(ret) == 0 {
- panic("no return value specified for AddConnection")
- }
-
- var r0 gonetworkmanager.Connection
- var r1 error
- if rf, ok := ret.Get(0).(func(gonetworkmanager.ConnectionSettings) (gonetworkmanager.Connection, error)); ok {
- return rf(settings)
- }
- if rf, ok := ret.Get(0).(func(gonetworkmanager.ConnectionSettings) gonetworkmanager.Connection); ok {
- r0 = rf(settings)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.Connection)
- }
- }
-
- if rf, ok := ret.Get(1).(func(gonetworkmanager.ConnectionSettings) error); ok {
- r1 = rf(settings)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockSettings_AddConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddConnection'
-type MockSettings_AddConnection_Call struct {
- *mock.Call
-}
-
-// AddConnection is a helper method to define mock.On call
-// - settings gonetworkmanager.ConnectionSettings
-func (_e *MockSettings_Expecter) AddConnection(settings interface{}) *MockSettings_AddConnection_Call {
- return &MockSettings_AddConnection_Call{Call: _e.mock.On("AddConnection", settings)}
-}
-
-func (_c *MockSettings_AddConnection_Call) Run(run func(settings gonetworkmanager.ConnectionSettings)) *MockSettings_AddConnection_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(gonetworkmanager.ConnectionSettings))
- })
- return _c
-}
-
-func (_c *MockSettings_AddConnection_Call) Return(_a0 gonetworkmanager.Connection, _a1 error) *MockSettings_AddConnection_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockSettings_AddConnection_Call) RunAndReturn(run func(gonetworkmanager.ConnectionSettings) (gonetworkmanager.Connection, error)) *MockSettings_AddConnection_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// AddConnectionUnsaved provides a mock function with given fields: settings
-func (_m *MockSettings) AddConnectionUnsaved(settings gonetworkmanager.ConnectionSettings) (gonetworkmanager.Connection, error) {
- ret := _m.Called(settings)
-
- if len(ret) == 0 {
- panic("no return value specified for AddConnectionUnsaved")
- }
-
- var r0 gonetworkmanager.Connection
- var r1 error
- if rf, ok := ret.Get(0).(func(gonetworkmanager.ConnectionSettings) (gonetworkmanager.Connection, error)); ok {
- return rf(settings)
- }
- if rf, ok := ret.Get(0).(func(gonetworkmanager.ConnectionSettings) gonetworkmanager.Connection); ok {
- r0 = rf(settings)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.Connection)
- }
- }
-
- if rf, ok := ret.Get(1).(func(gonetworkmanager.ConnectionSettings) error); ok {
- r1 = rf(settings)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockSettings_AddConnectionUnsaved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddConnectionUnsaved'
-type MockSettings_AddConnectionUnsaved_Call struct {
- *mock.Call
-}
-
-// AddConnectionUnsaved is a helper method to define mock.On call
-// - settings gonetworkmanager.ConnectionSettings
-func (_e *MockSettings_Expecter) AddConnectionUnsaved(settings interface{}) *MockSettings_AddConnectionUnsaved_Call {
- return &MockSettings_AddConnectionUnsaved_Call{Call: _e.mock.On("AddConnectionUnsaved", settings)}
-}
-
-func (_c *MockSettings_AddConnectionUnsaved_Call) Run(run func(settings gonetworkmanager.ConnectionSettings)) *MockSettings_AddConnectionUnsaved_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(gonetworkmanager.ConnectionSettings))
- })
- return _c
-}
-
-func (_c *MockSettings_AddConnectionUnsaved_Call) Return(_a0 gonetworkmanager.Connection, _a1 error) *MockSettings_AddConnectionUnsaved_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockSettings_AddConnectionUnsaved_Call) RunAndReturn(run func(gonetworkmanager.ConnectionSettings) (gonetworkmanager.Connection, error)) *MockSettings_AddConnectionUnsaved_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetConnectionByUUID provides a mock function with given fields: uuid
-func (_m *MockSettings) GetConnectionByUUID(uuid string) (gonetworkmanager.Connection, error) {
- ret := _m.Called(uuid)
-
- if len(ret) == 0 {
- panic("no return value specified for GetConnectionByUUID")
- }
-
- var r0 gonetworkmanager.Connection
- var r1 error
- if rf, ok := ret.Get(0).(func(string) (gonetworkmanager.Connection, error)); ok {
- return rf(uuid)
- }
- if rf, ok := ret.Get(0).(func(string) gonetworkmanager.Connection); ok {
- r0 = rf(uuid)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(gonetworkmanager.Connection)
- }
- }
-
- if rf, ok := ret.Get(1).(func(string) error); ok {
- r1 = rf(uuid)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockSettings_GetConnectionByUUID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetConnectionByUUID'
-type MockSettings_GetConnectionByUUID_Call struct {
- *mock.Call
-}
-
-// GetConnectionByUUID is a helper method to define mock.On call
-// - uuid string
-func (_e *MockSettings_Expecter) GetConnectionByUUID(uuid interface{}) *MockSettings_GetConnectionByUUID_Call {
- return &MockSettings_GetConnectionByUUID_Call{Call: _e.mock.On("GetConnectionByUUID", uuid)}
-}
-
-func (_c *MockSettings_GetConnectionByUUID_Call) Run(run func(uuid string)) *MockSettings_GetConnectionByUUID_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockSettings_GetConnectionByUUID_Call) Return(_a0 gonetworkmanager.Connection, _a1 error) *MockSettings_GetConnectionByUUID_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockSettings_GetConnectionByUUID_Call) RunAndReturn(run func(string) (gonetworkmanager.Connection, error)) *MockSettings_GetConnectionByUUID_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyCanModify provides a mock function with no fields
-func (_m *MockSettings) GetPropertyCanModify() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyCanModify")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockSettings_GetPropertyCanModify_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyCanModify'
-type MockSettings_GetPropertyCanModify_Call struct {
- *mock.Call
-}
-
-// GetPropertyCanModify is a helper method to define mock.On call
-func (_e *MockSettings_Expecter) GetPropertyCanModify() *MockSettings_GetPropertyCanModify_Call {
- return &MockSettings_GetPropertyCanModify_Call{Call: _e.mock.On("GetPropertyCanModify")}
-}
-
-func (_c *MockSettings_GetPropertyCanModify_Call) Run(run func()) *MockSettings_GetPropertyCanModify_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockSettings_GetPropertyCanModify_Call) Return(_a0 bool, _a1 error) *MockSettings_GetPropertyCanModify_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockSettings_GetPropertyCanModify_Call) RunAndReturn(run func() (bool, error)) *MockSettings_GetPropertyCanModify_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPropertyHostname provides a mock function with no fields
-func (_m *MockSettings) GetPropertyHostname() (string, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPropertyHostname")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func() (string, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockSettings_GetPropertyHostname_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPropertyHostname'
-type MockSettings_GetPropertyHostname_Call struct {
- *mock.Call
-}
-
-// GetPropertyHostname is a helper method to define mock.On call
-func (_e *MockSettings_Expecter) GetPropertyHostname() *MockSettings_GetPropertyHostname_Call {
- return &MockSettings_GetPropertyHostname_Call{Call: _e.mock.On("GetPropertyHostname")}
-}
-
-func (_c *MockSettings_GetPropertyHostname_Call) Run(run func()) *MockSettings_GetPropertyHostname_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockSettings_GetPropertyHostname_Call) Return(_a0 string, _a1 error) *MockSettings_GetPropertyHostname_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockSettings_GetPropertyHostname_Call) RunAndReturn(run func() (string, error)) *MockSettings_GetPropertyHostname_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// ListConnections provides a mock function with no fields
-func (_m *MockSettings) ListConnections() ([]gonetworkmanager.Connection, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for ListConnections")
- }
-
- var r0 []gonetworkmanager.Connection
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]gonetworkmanager.Connection, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []gonetworkmanager.Connection); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]gonetworkmanager.Connection)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockSettings_ListConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListConnections'
-type MockSettings_ListConnections_Call struct {
- *mock.Call
-}
-
-// ListConnections is a helper method to define mock.On call
-func (_e *MockSettings_Expecter) ListConnections() *MockSettings_ListConnections_Call {
- return &MockSettings_ListConnections_Call{Call: _e.mock.On("ListConnections")}
-}
-
-func (_c *MockSettings_ListConnections_Call) Run(run func()) *MockSettings_ListConnections_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockSettings_ListConnections_Call) Return(_a0 []gonetworkmanager.Connection, _a1 error) *MockSettings_ListConnections_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockSettings_ListConnections_Call) RunAndReturn(run func() ([]gonetworkmanager.Connection, error)) *MockSettings_ListConnections_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// ReloadConnections provides a mock function with no fields
-func (_m *MockSettings) ReloadConnections() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for ReloadConnections")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockSettings_ReloadConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReloadConnections'
-type MockSettings_ReloadConnections_Call struct {
- *mock.Call
-}
-
-// ReloadConnections is a helper method to define mock.On call
-func (_e *MockSettings_Expecter) ReloadConnections() *MockSettings_ReloadConnections_Call {
- return &MockSettings_ReloadConnections_Call{Call: _e.mock.On("ReloadConnections")}
-}
-
-func (_c *MockSettings_ReloadConnections_Call) Run(run func()) *MockSettings_ReloadConnections_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockSettings_ReloadConnections_Call) Return(_a0 error) *MockSettings_ReloadConnections_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockSettings_ReloadConnections_Call) RunAndReturn(run func() error) *MockSettings_ReloadConnections_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SaveHostname provides a mock function with given fields: hostname
-func (_m *MockSettings) SaveHostname(hostname string) error {
- ret := _m.Called(hostname)
-
- if len(ret) == 0 {
- panic("no return value specified for SaveHostname")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string) error); ok {
- r0 = rf(hostname)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockSettings_SaveHostname_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveHostname'
-type MockSettings_SaveHostname_Call struct {
- *mock.Call
-}
-
-// SaveHostname is a helper method to define mock.On call
-// - hostname string
-func (_e *MockSettings_Expecter) SaveHostname(hostname interface{}) *MockSettings_SaveHostname_Call {
- return &MockSettings_SaveHostname_Call{Call: _e.mock.On("SaveHostname", hostname)}
-}
-
-func (_c *MockSettings_SaveHostname_Call) Run(run func(hostname string)) *MockSettings_SaveHostname_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockSettings_SaveHostname_Call) Return(_a0 error) *MockSettings_SaveHostname_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockSettings_SaveHostname_Call) RunAndReturn(run func(string) error) *MockSettings_SaveHostname_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// NewMockSettings creates a new instance of MockSettings. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewMockSettings(t interface {
- mock.TestingT
- Cleanup(func())
-}) *MockSettings {
- mock := &MockSettings{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/nix/inputs/dms-cli/internal/mocks/github.com/godbus/dbus/v5/mock_BusObject.go b/nix/inputs/dms-cli/internal/mocks/github.com/godbus/dbus/v5/mock_BusObject.go
deleted file mode 100644
index c0d1a3f..0000000
--- a/nix/inputs/dms-cli/internal/mocks/github.com/godbus/dbus/v5/mock_BusObject.go
+++ /dev/null
@@ -1,649 +0,0 @@
-// Code generated by mockery v2.53.5. DO NOT EDIT.
-
-package dbus
-
-import (
- context "context"
-
- dbus "github.com/godbus/dbus/v5"
- mock "github.com/stretchr/testify/mock"
-)
-
-// MockBusObject is an autogenerated mock type for the BusObject type
-type MockBusObject struct {
- mock.Mock
-}
-
-type MockBusObject_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *MockBusObject) EXPECT() *MockBusObject_Expecter {
- return &MockBusObject_Expecter{mock: &_m.Mock}
-}
-
-// AddMatchSignal provides a mock function with given fields: iface, member, options
-func (_m *MockBusObject) AddMatchSignal(iface string, member string, options ...dbus.MatchOption) *dbus.Call {
- _va := make([]interface{}, len(options))
- for _i := range options {
- _va[_i] = options[_i]
- }
- var _ca []interface{}
- _ca = append(_ca, iface, member)
- _ca = append(_ca, _va...)
- ret := _m.Called(_ca...)
-
- if len(ret) == 0 {
- panic("no return value specified for AddMatchSignal")
- }
-
- var r0 *dbus.Call
- if rf, ok := ret.Get(0).(func(string, string, ...dbus.MatchOption) *dbus.Call); ok {
- r0 = rf(iface, member, options...)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*dbus.Call)
- }
- }
-
- return r0
-}
-
-// MockBusObject_AddMatchSignal_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddMatchSignal'
-type MockBusObject_AddMatchSignal_Call struct {
- *mock.Call
-}
-
-// AddMatchSignal is a helper method to define mock.On call
-// - iface string
-// - member string
-// - options ...dbus.MatchOption
-func (_e *MockBusObject_Expecter) AddMatchSignal(iface interface{}, member interface{}, options ...interface{}) *MockBusObject_AddMatchSignal_Call {
- return &MockBusObject_AddMatchSignal_Call{Call: _e.mock.On("AddMatchSignal",
- append([]interface{}{iface, member}, options...)...)}
-}
-
-func (_c *MockBusObject_AddMatchSignal_Call) Run(run func(iface string, member string, options ...dbus.MatchOption)) *MockBusObject_AddMatchSignal_Call {
- _c.Call.Run(func(args mock.Arguments) {
- variadicArgs := make([]dbus.MatchOption, len(args)-2)
- for i, a := range args[2:] {
- if a != nil {
- variadicArgs[i] = a.(dbus.MatchOption)
- }
- }
- run(args[0].(string), args[1].(string), variadicArgs...)
- })
- return _c
-}
-
-func (_c *MockBusObject_AddMatchSignal_Call) Return(_a0 *dbus.Call) *MockBusObject_AddMatchSignal_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBusObject_AddMatchSignal_Call) RunAndReturn(run func(string, string, ...dbus.MatchOption) *dbus.Call) *MockBusObject_AddMatchSignal_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Call provides a mock function with given fields: method, flags, args
-func (_m *MockBusObject) Call(method string, flags dbus.Flags, args ...interface{}) *dbus.Call {
- var _ca []interface{}
- _ca = append(_ca, method, flags)
- _ca = append(_ca, args...)
- ret := _m.Called(_ca...)
-
- if len(ret) == 0 {
- panic("no return value specified for Call")
- }
-
- var r0 *dbus.Call
- if rf, ok := ret.Get(0).(func(string, dbus.Flags, ...interface{}) *dbus.Call); ok {
- r0 = rf(method, flags, args...)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*dbus.Call)
- }
- }
-
- return r0
-}
-
-// MockBusObject_Call_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Call'
-type MockBusObject_Call_Call struct {
- *mock.Call
-}
-
-// Call is a helper method to define mock.On call
-// - method string
-// - flags dbus.Flags
-// - args ...interface{}
-func (_e *MockBusObject_Expecter) Call(method interface{}, flags interface{}, args ...interface{}) *MockBusObject_Call_Call {
- return &MockBusObject_Call_Call{Call: _e.mock.On("Call",
- append([]interface{}{method, flags}, args...)...)}
-}
-
-func (_c *MockBusObject_Call_Call) Run(run func(method string, flags dbus.Flags, args ...interface{})) *MockBusObject_Call_Call {
- _c.Call.Run(func(args mock.Arguments) {
- variadicArgs := make([]interface{}, len(args)-2)
- for i, a := range args[2:] {
- if a != nil {
- variadicArgs[i] = a.(interface{})
- }
- }
- run(args[0].(string), args[1].(dbus.Flags), variadicArgs...)
- })
- return _c
-}
-
-func (_c *MockBusObject_Call_Call) Return(_a0 *dbus.Call) *MockBusObject_Call_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBusObject_Call_Call) RunAndReturn(run func(string, dbus.Flags, ...interface{}) *dbus.Call) *MockBusObject_Call_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// CallWithContext provides a mock function with given fields: ctx, method, flags, args
-func (_m *MockBusObject) CallWithContext(ctx context.Context, method string, flags dbus.Flags, args ...interface{}) *dbus.Call {
- var _ca []interface{}
- _ca = append(_ca, ctx, method, flags)
- _ca = append(_ca, args...)
- ret := _m.Called(_ca...)
-
- if len(ret) == 0 {
- panic("no return value specified for CallWithContext")
- }
-
- var r0 *dbus.Call
- if rf, ok := ret.Get(0).(func(context.Context, string, dbus.Flags, ...interface{}) *dbus.Call); ok {
- r0 = rf(ctx, method, flags, args...)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*dbus.Call)
- }
- }
-
- return r0
-}
-
-// MockBusObject_CallWithContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CallWithContext'
-type MockBusObject_CallWithContext_Call struct {
- *mock.Call
-}
-
-// CallWithContext is a helper method to define mock.On call
-// - ctx context.Context
-// - method string
-// - flags dbus.Flags
-// - args ...interface{}
-func (_e *MockBusObject_Expecter) CallWithContext(ctx interface{}, method interface{}, flags interface{}, args ...interface{}) *MockBusObject_CallWithContext_Call {
- return &MockBusObject_CallWithContext_Call{Call: _e.mock.On("CallWithContext",
- append([]interface{}{ctx, method, flags}, args...)...)}
-}
-
-func (_c *MockBusObject_CallWithContext_Call) Run(run func(ctx context.Context, method string, flags dbus.Flags, args ...interface{})) *MockBusObject_CallWithContext_Call {
- _c.Call.Run(func(args mock.Arguments) {
- variadicArgs := make([]interface{}, len(args)-3)
- for i, a := range args[3:] {
- if a != nil {
- variadicArgs[i] = a.(interface{})
- }
- }
- run(args[0].(context.Context), args[1].(string), args[2].(dbus.Flags), variadicArgs...)
- })
- return _c
-}
-
-func (_c *MockBusObject_CallWithContext_Call) Return(_a0 *dbus.Call) *MockBusObject_CallWithContext_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBusObject_CallWithContext_Call) RunAndReturn(run func(context.Context, string, dbus.Flags, ...interface{}) *dbus.Call) *MockBusObject_CallWithContext_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Destination provides a mock function with no fields
-func (_m *MockBusObject) Destination() string {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for Destination")
- }
-
- var r0 string
- if rf, ok := ret.Get(0).(func() string); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(string)
- }
-
- return r0
-}
-
-// MockBusObject_Destination_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Destination'
-type MockBusObject_Destination_Call struct {
- *mock.Call
-}
-
-// Destination is a helper method to define mock.On call
-func (_e *MockBusObject_Expecter) Destination() *MockBusObject_Destination_Call {
- return &MockBusObject_Destination_Call{Call: _e.mock.On("Destination")}
-}
-
-func (_c *MockBusObject_Destination_Call) Run(run func()) *MockBusObject_Destination_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBusObject_Destination_Call) Return(_a0 string) *MockBusObject_Destination_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBusObject_Destination_Call) RunAndReturn(run func() string) *MockBusObject_Destination_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetProperty provides a mock function with given fields: p
-func (_m *MockBusObject) GetProperty(p string) (dbus.Variant, error) {
- ret := _m.Called(p)
-
- if len(ret) == 0 {
- panic("no return value specified for GetProperty")
- }
-
- var r0 dbus.Variant
- var r1 error
- if rf, ok := ret.Get(0).(func(string) (dbus.Variant, error)); ok {
- return rf(p)
- }
- if rf, ok := ret.Get(0).(func(string) dbus.Variant); ok {
- r0 = rf(p)
- } else {
- r0 = ret.Get(0).(dbus.Variant)
- }
-
- if rf, ok := ret.Get(1).(func(string) error); ok {
- r1 = rf(p)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockBusObject_GetProperty_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProperty'
-type MockBusObject_GetProperty_Call struct {
- *mock.Call
-}
-
-// GetProperty is a helper method to define mock.On call
-// - p string
-func (_e *MockBusObject_Expecter) GetProperty(p interface{}) *MockBusObject_GetProperty_Call {
- return &MockBusObject_GetProperty_Call{Call: _e.mock.On("GetProperty", p)}
-}
-
-func (_c *MockBusObject_GetProperty_Call) Run(run func(p string)) *MockBusObject_GetProperty_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockBusObject_GetProperty_Call) Return(_a0 dbus.Variant, _a1 error) *MockBusObject_GetProperty_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockBusObject_GetProperty_Call) RunAndReturn(run func(string) (dbus.Variant, error)) *MockBusObject_GetProperty_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Go provides a mock function with given fields: method, flags, ch, args
-func (_m *MockBusObject) Go(method string, flags dbus.Flags, ch chan *dbus.Call, args ...interface{}) *dbus.Call {
- var _ca []interface{}
- _ca = append(_ca, method, flags, ch)
- _ca = append(_ca, args...)
- ret := _m.Called(_ca...)
-
- if len(ret) == 0 {
- panic("no return value specified for Go")
- }
-
- var r0 *dbus.Call
- if rf, ok := ret.Get(0).(func(string, dbus.Flags, chan *dbus.Call, ...interface{}) *dbus.Call); ok {
- r0 = rf(method, flags, ch, args...)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*dbus.Call)
- }
- }
-
- return r0
-}
-
-// MockBusObject_Go_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Go'
-type MockBusObject_Go_Call struct {
- *mock.Call
-}
-
-// Go is a helper method to define mock.On call
-// - method string
-// - flags dbus.Flags
-// - ch chan *dbus.Call
-// - args ...interface{}
-func (_e *MockBusObject_Expecter) Go(method interface{}, flags interface{}, ch interface{}, args ...interface{}) *MockBusObject_Go_Call {
- return &MockBusObject_Go_Call{Call: _e.mock.On("Go",
- append([]interface{}{method, flags, ch}, args...)...)}
-}
-
-func (_c *MockBusObject_Go_Call) Run(run func(method string, flags dbus.Flags, ch chan *dbus.Call, args ...interface{})) *MockBusObject_Go_Call {
- _c.Call.Run(func(args mock.Arguments) {
- variadicArgs := make([]interface{}, len(args)-3)
- for i, a := range args[3:] {
- if a != nil {
- variadicArgs[i] = a.(interface{})
- }
- }
- run(args[0].(string), args[1].(dbus.Flags), args[2].(chan *dbus.Call), variadicArgs...)
- })
- return _c
-}
-
-func (_c *MockBusObject_Go_Call) Return(_a0 *dbus.Call) *MockBusObject_Go_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBusObject_Go_Call) RunAndReturn(run func(string, dbus.Flags, chan *dbus.Call, ...interface{}) *dbus.Call) *MockBusObject_Go_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GoWithContext provides a mock function with given fields: ctx, method, flags, ch, args
-func (_m *MockBusObject) GoWithContext(ctx context.Context, method string, flags dbus.Flags, ch chan *dbus.Call, args ...interface{}) *dbus.Call {
- var _ca []interface{}
- _ca = append(_ca, ctx, method, flags, ch)
- _ca = append(_ca, args...)
- ret := _m.Called(_ca...)
-
- if len(ret) == 0 {
- panic("no return value specified for GoWithContext")
- }
-
- var r0 *dbus.Call
- if rf, ok := ret.Get(0).(func(context.Context, string, dbus.Flags, chan *dbus.Call, ...interface{}) *dbus.Call); ok {
- r0 = rf(ctx, method, flags, ch, args...)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*dbus.Call)
- }
- }
-
- return r0
-}
-
-// MockBusObject_GoWithContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GoWithContext'
-type MockBusObject_GoWithContext_Call struct {
- *mock.Call
-}
-
-// GoWithContext is a helper method to define mock.On call
-// - ctx context.Context
-// - method string
-// - flags dbus.Flags
-// - ch chan *dbus.Call
-// - args ...interface{}
-func (_e *MockBusObject_Expecter) GoWithContext(ctx interface{}, method interface{}, flags interface{}, ch interface{}, args ...interface{}) *MockBusObject_GoWithContext_Call {
- return &MockBusObject_GoWithContext_Call{Call: _e.mock.On("GoWithContext",
- append([]interface{}{ctx, method, flags, ch}, args...)...)}
-}
-
-func (_c *MockBusObject_GoWithContext_Call) Run(run func(ctx context.Context, method string, flags dbus.Flags, ch chan *dbus.Call, args ...interface{})) *MockBusObject_GoWithContext_Call {
- _c.Call.Run(func(args mock.Arguments) {
- variadicArgs := make([]interface{}, len(args)-4)
- for i, a := range args[4:] {
- if a != nil {
- variadicArgs[i] = a.(interface{})
- }
- }
- run(args[0].(context.Context), args[1].(string), args[2].(dbus.Flags), args[3].(chan *dbus.Call), variadicArgs...)
- })
- return _c
-}
-
-func (_c *MockBusObject_GoWithContext_Call) Return(_a0 *dbus.Call) *MockBusObject_GoWithContext_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBusObject_GoWithContext_Call) RunAndReturn(run func(context.Context, string, dbus.Flags, chan *dbus.Call, ...interface{}) *dbus.Call) *MockBusObject_GoWithContext_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Path provides a mock function with no fields
-func (_m *MockBusObject) Path() dbus.ObjectPath {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for Path")
- }
-
- var r0 dbus.ObjectPath
- if rf, ok := ret.Get(0).(func() dbus.ObjectPath); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(dbus.ObjectPath)
- }
-
- return r0
-}
-
-// MockBusObject_Path_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Path'
-type MockBusObject_Path_Call struct {
- *mock.Call
-}
-
-// Path is a helper method to define mock.On call
-func (_e *MockBusObject_Expecter) Path() *MockBusObject_Path_Call {
- return &MockBusObject_Path_Call{Call: _e.mock.On("Path")}
-}
-
-func (_c *MockBusObject_Path_Call) Run(run func()) *MockBusObject_Path_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBusObject_Path_Call) Return(_a0 dbus.ObjectPath) *MockBusObject_Path_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBusObject_Path_Call) RunAndReturn(run func() dbus.ObjectPath) *MockBusObject_Path_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// RemoveMatchSignal provides a mock function with given fields: iface, member, options
-func (_m *MockBusObject) RemoveMatchSignal(iface string, member string, options ...dbus.MatchOption) *dbus.Call {
- _va := make([]interface{}, len(options))
- for _i := range options {
- _va[_i] = options[_i]
- }
- var _ca []interface{}
- _ca = append(_ca, iface, member)
- _ca = append(_ca, _va...)
- ret := _m.Called(_ca...)
-
- if len(ret) == 0 {
- panic("no return value specified for RemoveMatchSignal")
- }
-
- var r0 *dbus.Call
- if rf, ok := ret.Get(0).(func(string, string, ...dbus.MatchOption) *dbus.Call); ok {
- r0 = rf(iface, member, options...)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*dbus.Call)
- }
- }
-
- return r0
-}
-
-// MockBusObject_RemoveMatchSignal_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveMatchSignal'
-type MockBusObject_RemoveMatchSignal_Call struct {
- *mock.Call
-}
-
-// RemoveMatchSignal is a helper method to define mock.On call
-// - iface string
-// - member string
-// - options ...dbus.MatchOption
-func (_e *MockBusObject_Expecter) RemoveMatchSignal(iface interface{}, member interface{}, options ...interface{}) *MockBusObject_RemoveMatchSignal_Call {
- return &MockBusObject_RemoveMatchSignal_Call{Call: _e.mock.On("RemoveMatchSignal",
- append([]interface{}{iface, member}, options...)...)}
-}
-
-func (_c *MockBusObject_RemoveMatchSignal_Call) Run(run func(iface string, member string, options ...dbus.MatchOption)) *MockBusObject_RemoveMatchSignal_Call {
- _c.Call.Run(func(args mock.Arguments) {
- variadicArgs := make([]dbus.MatchOption, len(args)-2)
- for i, a := range args[2:] {
- if a != nil {
- variadicArgs[i] = a.(dbus.MatchOption)
- }
- }
- run(args[0].(string), args[1].(string), variadicArgs...)
- })
- return _c
-}
-
-func (_c *MockBusObject_RemoveMatchSignal_Call) Return(_a0 *dbus.Call) *MockBusObject_RemoveMatchSignal_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBusObject_RemoveMatchSignal_Call) RunAndReturn(run func(string, string, ...dbus.MatchOption) *dbus.Call) *MockBusObject_RemoveMatchSignal_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetProperty provides a mock function with given fields: p, v
-func (_m *MockBusObject) SetProperty(p string, v interface{}) error {
- ret := _m.Called(p, v)
-
- if len(ret) == 0 {
- panic("no return value specified for SetProperty")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string, interface{}) error); ok {
- r0 = rf(p, v)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBusObject_SetProperty_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetProperty'
-type MockBusObject_SetProperty_Call struct {
- *mock.Call
-}
-
-// SetProperty is a helper method to define mock.On call
-// - p string
-// - v interface{}
-func (_e *MockBusObject_Expecter) SetProperty(p interface{}, v interface{}) *MockBusObject_SetProperty_Call {
- return &MockBusObject_SetProperty_Call{Call: _e.mock.On("SetProperty", p, v)}
-}
-
-func (_c *MockBusObject_SetProperty_Call) Run(run func(p string, v interface{})) *MockBusObject_SetProperty_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string), args[1].(interface{}))
- })
- return _c
-}
-
-func (_c *MockBusObject_SetProperty_Call) Return(_a0 error) *MockBusObject_SetProperty_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBusObject_SetProperty_Call) RunAndReturn(run func(string, interface{}) error) *MockBusObject_SetProperty_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// StoreProperty provides a mock function with given fields: p, value
-func (_m *MockBusObject) StoreProperty(p string, value interface{}) error {
- ret := _m.Called(p, value)
-
- if len(ret) == 0 {
- panic("no return value specified for StoreProperty")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string, interface{}) error); ok {
- r0 = rf(p, value)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBusObject_StoreProperty_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StoreProperty'
-type MockBusObject_StoreProperty_Call struct {
- *mock.Call
-}
-
-// StoreProperty is a helper method to define mock.On call
-// - p string
-// - value interface{}
-func (_e *MockBusObject_Expecter) StoreProperty(p interface{}, value interface{}) *MockBusObject_StoreProperty_Call {
- return &MockBusObject_StoreProperty_Call{Call: _e.mock.On("StoreProperty", p, value)}
-}
-
-func (_c *MockBusObject_StoreProperty_Call) Run(run func(p string, value interface{})) *MockBusObject_StoreProperty_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string), args[1].(interface{}))
- })
- return _c
-}
-
-func (_c *MockBusObject_StoreProperty_Call) Return(_a0 error) *MockBusObject_StoreProperty_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBusObject_StoreProperty_Call) RunAndReturn(run func(string, interface{}) error) *MockBusObject_StoreProperty_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// NewMockBusObject creates a new instance of MockBusObject. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewMockBusObject(t interface {
- mock.TestingT
- Cleanup(func())
-}) *MockBusObject {
- mock := &MockBusObject{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/nix/inputs/dms-cli/internal/mocks/internal/plugins/mock_GitClient.go b/nix/inputs/dms-cli/internal/mocks/internal/plugins/mock_GitClient.go
deleted file mode 100644
index d43afed..0000000
--- a/nix/inputs/dms-cli/internal/mocks/internal/plugins/mock_GitClient.go
+++ /dev/null
@@ -1,181 +0,0 @@
-// Code generated by mockery v2.53.5. DO NOT EDIT.
-
-package plugins
-
-import mock "github.com/stretchr/testify/mock"
-
-// MockGitClient is an autogenerated mock type for the GitClient type
-type MockGitClient struct {
- mock.Mock
-}
-
-type MockGitClient_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *MockGitClient) EXPECT() *MockGitClient_Expecter {
- return &MockGitClient_Expecter{mock: &_m.Mock}
-}
-
-// HasUpdates provides a mock function with given fields: path
-func (_m *MockGitClient) HasUpdates(path string) (bool, error) {
- ret := _m.Called(path)
-
- if len(ret) == 0 {
- panic("no return value specified for HasUpdates")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func(string) (bool, error)); ok {
- return rf(path)
- }
- if rf, ok := ret.Get(0).(func(string) bool); ok {
- r0 = rf(path)
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func(string) error); ok {
- r1 = rf(path)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockGitClient_HasUpdates_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasUpdates'
-type MockGitClient_HasUpdates_Call struct {
- *mock.Call
-}
-
-// HasUpdates is a helper method to define mock.On call
-// - path string
-func (_e *MockGitClient_Expecter) HasUpdates(path interface{}) *MockGitClient_HasUpdates_Call {
- return &MockGitClient_HasUpdates_Call{Call: _e.mock.On("HasUpdates", path)}
-}
-
-func (_c *MockGitClient_HasUpdates_Call) Run(run func(path string)) *MockGitClient_HasUpdates_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockGitClient_HasUpdates_Call) Return(_a0 bool, _a1 error) *MockGitClient_HasUpdates_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockGitClient_HasUpdates_Call) RunAndReturn(run func(string) (bool, error)) *MockGitClient_HasUpdates_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// PlainClone provides a mock function with given fields: path, url
-func (_m *MockGitClient) PlainClone(path string, url string) error {
- ret := _m.Called(path, url)
-
- if len(ret) == 0 {
- panic("no return value specified for PlainClone")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string, string) error); ok {
- r0 = rf(path, url)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockGitClient_PlainClone_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PlainClone'
-type MockGitClient_PlainClone_Call struct {
- *mock.Call
-}
-
-// PlainClone is a helper method to define mock.On call
-// - path string
-// - url string
-func (_e *MockGitClient_Expecter) PlainClone(path interface{}, url interface{}) *MockGitClient_PlainClone_Call {
- return &MockGitClient_PlainClone_Call{Call: _e.mock.On("PlainClone", path, url)}
-}
-
-func (_c *MockGitClient_PlainClone_Call) Run(run func(path string, url string)) *MockGitClient_PlainClone_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string), args[1].(string))
- })
- return _c
-}
-
-func (_c *MockGitClient_PlainClone_Call) Return(_a0 error) *MockGitClient_PlainClone_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockGitClient_PlainClone_Call) RunAndReturn(run func(string, string) error) *MockGitClient_PlainClone_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Pull provides a mock function with given fields: path
-func (_m *MockGitClient) Pull(path string) error {
- ret := _m.Called(path)
-
- if len(ret) == 0 {
- panic("no return value specified for Pull")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string) error); ok {
- r0 = rf(path)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockGitClient_Pull_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Pull'
-type MockGitClient_Pull_Call struct {
- *mock.Call
-}
-
-// Pull is a helper method to define mock.On call
-// - path string
-func (_e *MockGitClient_Expecter) Pull(path interface{}) *MockGitClient_Pull_Call {
- return &MockGitClient_Pull_Call{Call: _e.mock.On("Pull", path)}
-}
-
-func (_c *MockGitClient_Pull_Call) Run(run func(path string)) *MockGitClient_Pull_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockGitClient_Pull_Call) Return(_a0 error) *MockGitClient_Pull_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockGitClient_Pull_Call) RunAndReturn(run func(string) error) *MockGitClient_Pull_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// NewMockGitClient creates a new instance of MockGitClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewMockGitClient(t interface {
- mock.TestingT
- Cleanup(func())
-}) *MockGitClient {
- mock := &MockGitClient{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/nix/inputs/dms-cli/internal/mocks/net/mock_Conn.go b/nix/inputs/dms-cli/internal/mocks/net/mock_Conn.go
deleted file mode 100644
index 248a0d8..0000000
--- a/nix/inputs/dms-cli/internal/mocks/net/mock_Conn.go
+++ /dev/null
@@ -1,427 +0,0 @@
-// Code generated by mockery v2.53.5. DO NOT EDIT.
-
-package net
-
-import (
- net "net"
-
- mock "github.com/stretchr/testify/mock"
-
- time "time"
-)
-
-// MockConn is an autogenerated mock type for the Conn type
-type MockConn struct {
- mock.Mock
-}
-
-type MockConn_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *MockConn) EXPECT() *MockConn_Expecter {
- return &MockConn_Expecter{mock: &_m.Mock}
-}
-
-// Close provides a mock function with no fields
-func (_m *MockConn) Close() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for Close")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockConn_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
-type MockConn_Close_Call struct {
- *mock.Call
-}
-
-// Close is a helper method to define mock.On call
-func (_e *MockConn_Expecter) Close() *MockConn_Close_Call {
- return &MockConn_Close_Call{Call: _e.mock.On("Close")}
-}
-
-func (_c *MockConn_Close_Call) Run(run func()) *MockConn_Close_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockConn_Close_Call) Return(_a0 error) *MockConn_Close_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockConn_Close_Call) RunAndReturn(run func() error) *MockConn_Close_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// LocalAddr provides a mock function with no fields
-func (_m *MockConn) LocalAddr() net.Addr {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for LocalAddr")
- }
-
- var r0 net.Addr
- if rf, ok := ret.Get(0).(func() net.Addr); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(net.Addr)
- }
- }
-
- return r0
-}
-
-// MockConn_LocalAddr_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LocalAddr'
-type MockConn_LocalAddr_Call struct {
- *mock.Call
-}
-
-// LocalAddr is a helper method to define mock.On call
-func (_e *MockConn_Expecter) LocalAddr() *MockConn_LocalAddr_Call {
- return &MockConn_LocalAddr_Call{Call: _e.mock.On("LocalAddr")}
-}
-
-func (_c *MockConn_LocalAddr_Call) Run(run func()) *MockConn_LocalAddr_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockConn_LocalAddr_Call) Return(_a0 net.Addr) *MockConn_LocalAddr_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockConn_LocalAddr_Call) RunAndReturn(run func() net.Addr) *MockConn_LocalAddr_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Read provides a mock function with given fields: b
-func (_m *MockConn) Read(b []byte) (int, error) {
- ret := _m.Called(b)
-
- if len(ret) == 0 {
- panic("no return value specified for Read")
- }
-
- var r0 int
- var r1 error
- if rf, ok := ret.Get(0).(func([]byte) (int, error)); ok {
- return rf(b)
- }
- if rf, ok := ret.Get(0).(func([]byte) int); ok {
- r0 = rf(b)
- } else {
- r0 = ret.Get(0).(int)
- }
-
- if rf, ok := ret.Get(1).(func([]byte) error); ok {
- r1 = rf(b)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockConn_Read_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Read'
-type MockConn_Read_Call struct {
- *mock.Call
-}
-
-// Read is a helper method to define mock.On call
-// - b []byte
-func (_e *MockConn_Expecter) Read(b interface{}) *MockConn_Read_Call {
- return &MockConn_Read_Call{Call: _e.mock.On("Read", b)}
-}
-
-func (_c *MockConn_Read_Call) Run(run func(b []byte)) *MockConn_Read_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].([]byte))
- })
- return _c
-}
-
-func (_c *MockConn_Read_Call) Return(n int, err error) *MockConn_Read_Call {
- _c.Call.Return(n, err)
- return _c
-}
-
-func (_c *MockConn_Read_Call) RunAndReturn(run func([]byte) (int, error)) *MockConn_Read_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// RemoteAddr provides a mock function with no fields
-func (_m *MockConn) RemoteAddr() net.Addr {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for RemoteAddr")
- }
-
- var r0 net.Addr
- if rf, ok := ret.Get(0).(func() net.Addr); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(net.Addr)
- }
- }
-
- return r0
-}
-
-// MockConn_RemoteAddr_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoteAddr'
-type MockConn_RemoteAddr_Call struct {
- *mock.Call
-}
-
-// RemoteAddr is a helper method to define mock.On call
-func (_e *MockConn_Expecter) RemoteAddr() *MockConn_RemoteAddr_Call {
- return &MockConn_RemoteAddr_Call{Call: _e.mock.On("RemoteAddr")}
-}
-
-func (_c *MockConn_RemoteAddr_Call) Run(run func()) *MockConn_RemoteAddr_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockConn_RemoteAddr_Call) Return(_a0 net.Addr) *MockConn_RemoteAddr_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockConn_RemoteAddr_Call) RunAndReturn(run func() net.Addr) *MockConn_RemoteAddr_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetDeadline provides a mock function with given fields: t
-func (_m *MockConn) SetDeadline(t time.Time) error {
- ret := _m.Called(t)
-
- if len(ret) == 0 {
- panic("no return value specified for SetDeadline")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(time.Time) error); ok {
- r0 = rf(t)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockConn_SetDeadline_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDeadline'
-type MockConn_SetDeadline_Call struct {
- *mock.Call
-}
-
-// SetDeadline is a helper method to define mock.On call
-// - t time.Time
-func (_e *MockConn_Expecter) SetDeadline(t interface{}) *MockConn_SetDeadline_Call {
- return &MockConn_SetDeadline_Call{Call: _e.mock.On("SetDeadline", t)}
-}
-
-func (_c *MockConn_SetDeadline_Call) Run(run func(t time.Time)) *MockConn_SetDeadline_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(time.Time))
- })
- return _c
-}
-
-func (_c *MockConn_SetDeadline_Call) Return(_a0 error) *MockConn_SetDeadline_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockConn_SetDeadline_Call) RunAndReturn(run func(time.Time) error) *MockConn_SetDeadline_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetReadDeadline provides a mock function with given fields: t
-func (_m *MockConn) SetReadDeadline(t time.Time) error {
- ret := _m.Called(t)
-
- if len(ret) == 0 {
- panic("no return value specified for SetReadDeadline")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(time.Time) error); ok {
- r0 = rf(t)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockConn_SetReadDeadline_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetReadDeadline'
-type MockConn_SetReadDeadline_Call struct {
- *mock.Call
-}
-
-// SetReadDeadline is a helper method to define mock.On call
-// - t time.Time
-func (_e *MockConn_Expecter) SetReadDeadline(t interface{}) *MockConn_SetReadDeadline_Call {
- return &MockConn_SetReadDeadline_Call{Call: _e.mock.On("SetReadDeadline", t)}
-}
-
-func (_c *MockConn_SetReadDeadline_Call) Run(run func(t time.Time)) *MockConn_SetReadDeadline_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(time.Time))
- })
- return _c
-}
-
-func (_c *MockConn_SetReadDeadline_Call) Return(_a0 error) *MockConn_SetReadDeadline_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockConn_SetReadDeadline_Call) RunAndReturn(run func(time.Time) error) *MockConn_SetReadDeadline_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetWriteDeadline provides a mock function with given fields: t
-func (_m *MockConn) SetWriteDeadline(t time.Time) error {
- ret := _m.Called(t)
-
- if len(ret) == 0 {
- panic("no return value specified for SetWriteDeadline")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(time.Time) error); ok {
- r0 = rf(t)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockConn_SetWriteDeadline_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetWriteDeadline'
-type MockConn_SetWriteDeadline_Call struct {
- *mock.Call
-}
-
-// SetWriteDeadline is a helper method to define mock.On call
-// - t time.Time
-func (_e *MockConn_Expecter) SetWriteDeadline(t interface{}) *MockConn_SetWriteDeadline_Call {
- return &MockConn_SetWriteDeadline_Call{Call: _e.mock.On("SetWriteDeadline", t)}
-}
-
-func (_c *MockConn_SetWriteDeadline_Call) Run(run func(t time.Time)) *MockConn_SetWriteDeadline_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(time.Time))
- })
- return _c
-}
-
-func (_c *MockConn_SetWriteDeadline_Call) Return(_a0 error) *MockConn_SetWriteDeadline_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockConn_SetWriteDeadline_Call) RunAndReturn(run func(time.Time) error) *MockConn_SetWriteDeadline_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Write provides a mock function with given fields: b
-func (_m *MockConn) Write(b []byte) (int, error) {
- ret := _m.Called(b)
-
- if len(ret) == 0 {
- panic("no return value specified for Write")
- }
-
- var r0 int
- var r1 error
- if rf, ok := ret.Get(0).(func([]byte) (int, error)); ok {
- return rf(b)
- }
- if rf, ok := ret.Get(0).(func([]byte) int); ok {
- r0 = rf(b)
- } else {
- r0 = ret.Get(0).(int)
- }
-
- if rf, ok := ret.Get(1).(func([]byte) error); ok {
- r1 = rf(b)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockConn_Write_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Write'
-type MockConn_Write_Call struct {
- *mock.Call
-}
-
-// Write is a helper method to define mock.On call
-// - b []byte
-func (_e *MockConn_Expecter) Write(b interface{}) *MockConn_Write_Call {
- return &MockConn_Write_Call{Call: _e.mock.On("Write", b)}
-}
-
-func (_c *MockConn_Write_Call) Run(run func(b []byte)) *MockConn_Write_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].([]byte))
- })
- return _c
-}
-
-func (_c *MockConn_Write_Call) Return(n int, err error) *MockConn_Write_Call {
- _c.Call.Return(n, err)
- return _c
-}
-
-func (_c *MockConn_Write_Call) RunAndReturn(run func([]byte) (int, error)) *MockConn_Write_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// NewMockConn creates a new instance of MockConn. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewMockConn(t interface {
- mock.TestingT
- Cleanup(func())
-}) *MockConn {
- mock := &MockConn{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/nix/inputs/dms-cli/internal/mocks/network/mock_Backend.go b/nix/inputs/dms-cli/internal/mocks/network/mock_Backend.go
deleted file mode 100644
index 8298e24..0000000
--- a/nix/inputs/dms-cli/internal/mocks/network/mock_Backend.go
+++ /dev/null
@@ -1,1371 +0,0 @@
-// Code generated by mockery v2.53.5. DO NOT EDIT.
-
-package mocks_network
-
-import (
- network "github.com/AvengeMedia/danklinux/internal/server/network"
- mock "github.com/stretchr/testify/mock"
-)
-
-// MockBackend is an autogenerated mock type for the Backend type
-type MockBackend struct {
- mock.Mock
-}
-
-type MockBackend_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *MockBackend) EXPECT() *MockBackend_Expecter {
- return &MockBackend_Expecter{mock: &_m.Mock}
-}
-
-// ActivateWiredConnection provides a mock function with given fields: uuid
-func (_m *MockBackend) ActivateWiredConnection(uuid string) error {
- ret := _m.Called(uuid)
-
- if len(ret) == 0 {
- panic("no return value specified for ActivateWiredConnection")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string) error); ok {
- r0 = rf(uuid)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_ActivateWiredConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ActivateWiredConnection'
-type MockBackend_ActivateWiredConnection_Call struct {
- *mock.Call
-}
-
-// ActivateWiredConnection is a helper method to define mock.On call
-// - uuid string
-func (_e *MockBackend_Expecter) ActivateWiredConnection(uuid interface{}) *MockBackend_ActivateWiredConnection_Call {
- return &MockBackend_ActivateWiredConnection_Call{Call: _e.mock.On("ActivateWiredConnection", uuid)}
-}
-
-func (_c *MockBackend_ActivateWiredConnection_Call) Run(run func(uuid string)) *MockBackend_ActivateWiredConnection_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockBackend_ActivateWiredConnection_Call) Return(_a0 error) *MockBackend_ActivateWiredConnection_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_ActivateWiredConnection_Call) RunAndReturn(run func(string) error) *MockBackend_ActivateWiredConnection_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// CancelCredentials provides a mock function with given fields: token
-func (_m *MockBackend) CancelCredentials(token string) error {
- ret := _m.Called(token)
-
- if len(ret) == 0 {
- panic("no return value specified for CancelCredentials")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string) error); ok {
- r0 = rf(token)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_CancelCredentials_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CancelCredentials'
-type MockBackend_CancelCredentials_Call struct {
- *mock.Call
-}
-
-// CancelCredentials is a helper method to define mock.On call
-// - token string
-func (_e *MockBackend_Expecter) CancelCredentials(token interface{}) *MockBackend_CancelCredentials_Call {
- return &MockBackend_CancelCredentials_Call{Call: _e.mock.On("CancelCredentials", token)}
-}
-
-func (_c *MockBackend_CancelCredentials_Call) Run(run func(token string)) *MockBackend_CancelCredentials_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockBackend_CancelCredentials_Call) Return(_a0 error) *MockBackend_CancelCredentials_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_CancelCredentials_Call) RunAndReturn(run func(string) error) *MockBackend_CancelCredentials_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// ClearVPNCredentials provides a mock function with given fields: uuidOrName
-func (_m *MockBackend) ClearVPNCredentials(uuidOrName string) error {
- ret := _m.Called(uuidOrName)
-
- if len(ret) == 0 {
- panic("no return value specified for ClearVPNCredentials")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string) error); ok {
- r0 = rf(uuidOrName)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_ClearVPNCredentials_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClearVPNCredentials'
-type MockBackend_ClearVPNCredentials_Call struct {
- *mock.Call
-}
-
-// ClearVPNCredentials is a helper method to define mock.On call
-// - uuidOrName string
-func (_e *MockBackend_Expecter) ClearVPNCredentials(uuidOrName interface{}) *MockBackend_ClearVPNCredentials_Call {
- return &MockBackend_ClearVPNCredentials_Call{Call: _e.mock.On("ClearVPNCredentials", uuidOrName)}
-}
-
-func (_c *MockBackend_ClearVPNCredentials_Call) Run(run func(uuidOrName string)) *MockBackend_ClearVPNCredentials_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockBackend_ClearVPNCredentials_Call) Return(_a0 error) *MockBackend_ClearVPNCredentials_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_ClearVPNCredentials_Call) RunAndReturn(run func(string) error) *MockBackend_ClearVPNCredentials_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Close provides a mock function with no fields
-func (_m *MockBackend) Close() {
- _m.Called()
-}
-
-// MockBackend_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
-type MockBackend_Close_Call struct {
- *mock.Call
-}
-
-// Close is a helper method to define mock.On call
-func (_e *MockBackend_Expecter) Close() *MockBackend_Close_Call {
- return &MockBackend_Close_Call{Call: _e.mock.On("Close")}
-}
-
-func (_c *MockBackend_Close_Call) Run(run func()) *MockBackend_Close_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBackend_Close_Call) Return() *MockBackend_Close_Call {
- _c.Call.Return()
- return _c
-}
-
-func (_c *MockBackend_Close_Call) RunAndReturn(run func()) *MockBackend_Close_Call {
- _c.Run(run)
- return _c
-}
-
-// ConnectEthernet provides a mock function with no fields
-func (_m *MockBackend) ConnectEthernet() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for ConnectEthernet")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_ConnectEthernet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConnectEthernet'
-type MockBackend_ConnectEthernet_Call struct {
- *mock.Call
-}
-
-// ConnectEthernet is a helper method to define mock.On call
-func (_e *MockBackend_Expecter) ConnectEthernet() *MockBackend_ConnectEthernet_Call {
- return &MockBackend_ConnectEthernet_Call{Call: _e.mock.On("ConnectEthernet")}
-}
-
-func (_c *MockBackend_ConnectEthernet_Call) Run(run func()) *MockBackend_ConnectEthernet_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBackend_ConnectEthernet_Call) Return(_a0 error) *MockBackend_ConnectEthernet_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_ConnectEthernet_Call) RunAndReturn(run func() error) *MockBackend_ConnectEthernet_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// ConnectVPN provides a mock function with given fields: uuidOrName, singleActive
-func (_m *MockBackend) ConnectVPN(uuidOrName string, singleActive bool) error {
- ret := _m.Called(uuidOrName, singleActive)
-
- if len(ret) == 0 {
- panic("no return value specified for ConnectVPN")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string, bool) error); ok {
- r0 = rf(uuidOrName, singleActive)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_ConnectVPN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConnectVPN'
-type MockBackend_ConnectVPN_Call struct {
- *mock.Call
-}
-
-// ConnectVPN is a helper method to define mock.On call
-// - uuidOrName string
-// - singleActive bool
-func (_e *MockBackend_Expecter) ConnectVPN(uuidOrName interface{}, singleActive interface{}) *MockBackend_ConnectVPN_Call {
- return &MockBackend_ConnectVPN_Call{Call: _e.mock.On("ConnectVPN", uuidOrName, singleActive)}
-}
-
-func (_c *MockBackend_ConnectVPN_Call) Run(run func(uuidOrName string, singleActive bool)) *MockBackend_ConnectVPN_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string), args[1].(bool))
- })
- return _c
-}
-
-func (_c *MockBackend_ConnectVPN_Call) Return(_a0 error) *MockBackend_ConnectVPN_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_ConnectVPN_Call) RunAndReturn(run func(string, bool) error) *MockBackend_ConnectVPN_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// ConnectWiFi provides a mock function with given fields: req
-func (_m *MockBackend) ConnectWiFi(req network.ConnectionRequest) error {
- ret := _m.Called(req)
-
- if len(ret) == 0 {
- panic("no return value specified for ConnectWiFi")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(network.ConnectionRequest) error); ok {
- r0 = rf(req)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_ConnectWiFi_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConnectWiFi'
-type MockBackend_ConnectWiFi_Call struct {
- *mock.Call
-}
-
-// ConnectWiFi is a helper method to define mock.On call
-// - req network.ConnectionRequest
-func (_e *MockBackend_Expecter) ConnectWiFi(req interface{}) *MockBackend_ConnectWiFi_Call {
- return &MockBackend_ConnectWiFi_Call{Call: _e.mock.On("ConnectWiFi", req)}
-}
-
-func (_c *MockBackend_ConnectWiFi_Call) Run(run func(req network.ConnectionRequest)) *MockBackend_ConnectWiFi_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(network.ConnectionRequest))
- })
- return _c
-}
-
-func (_c *MockBackend_ConnectWiFi_Call) Return(_a0 error) *MockBackend_ConnectWiFi_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_ConnectWiFi_Call) RunAndReturn(run func(network.ConnectionRequest) error) *MockBackend_ConnectWiFi_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// DisconnectAllVPN provides a mock function with no fields
-func (_m *MockBackend) DisconnectAllVPN() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for DisconnectAllVPN")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_DisconnectAllVPN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisconnectAllVPN'
-type MockBackend_DisconnectAllVPN_Call struct {
- *mock.Call
-}
-
-// DisconnectAllVPN is a helper method to define mock.On call
-func (_e *MockBackend_Expecter) DisconnectAllVPN() *MockBackend_DisconnectAllVPN_Call {
- return &MockBackend_DisconnectAllVPN_Call{Call: _e.mock.On("DisconnectAllVPN")}
-}
-
-func (_c *MockBackend_DisconnectAllVPN_Call) Run(run func()) *MockBackend_DisconnectAllVPN_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBackend_DisconnectAllVPN_Call) Return(_a0 error) *MockBackend_DisconnectAllVPN_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_DisconnectAllVPN_Call) RunAndReturn(run func() error) *MockBackend_DisconnectAllVPN_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// DisconnectEthernet provides a mock function with no fields
-func (_m *MockBackend) DisconnectEthernet() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for DisconnectEthernet")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_DisconnectEthernet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisconnectEthernet'
-type MockBackend_DisconnectEthernet_Call struct {
- *mock.Call
-}
-
-// DisconnectEthernet is a helper method to define mock.On call
-func (_e *MockBackend_Expecter) DisconnectEthernet() *MockBackend_DisconnectEthernet_Call {
- return &MockBackend_DisconnectEthernet_Call{Call: _e.mock.On("DisconnectEthernet")}
-}
-
-func (_c *MockBackend_DisconnectEthernet_Call) Run(run func()) *MockBackend_DisconnectEthernet_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBackend_DisconnectEthernet_Call) Return(_a0 error) *MockBackend_DisconnectEthernet_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_DisconnectEthernet_Call) RunAndReturn(run func() error) *MockBackend_DisconnectEthernet_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// DisconnectVPN provides a mock function with given fields: uuidOrName
-func (_m *MockBackend) DisconnectVPN(uuidOrName string) error {
- ret := _m.Called(uuidOrName)
-
- if len(ret) == 0 {
- panic("no return value specified for DisconnectVPN")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string) error); ok {
- r0 = rf(uuidOrName)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_DisconnectVPN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisconnectVPN'
-type MockBackend_DisconnectVPN_Call struct {
- *mock.Call
-}
-
-// DisconnectVPN is a helper method to define mock.On call
-// - uuidOrName string
-func (_e *MockBackend_Expecter) DisconnectVPN(uuidOrName interface{}) *MockBackend_DisconnectVPN_Call {
- return &MockBackend_DisconnectVPN_Call{Call: _e.mock.On("DisconnectVPN", uuidOrName)}
-}
-
-func (_c *MockBackend_DisconnectVPN_Call) Run(run func(uuidOrName string)) *MockBackend_DisconnectVPN_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockBackend_DisconnectVPN_Call) Return(_a0 error) *MockBackend_DisconnectVPN_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_DisconnectVPN_Call) RunAndReturn(run func(string) error) *MockBackend_DisconnectVPN_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// DisconnectWiFi provides a mock function with no fields
-func (_m *MockBackend) DisconnectWiFi() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for DisconnectWiFi")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_DisconnectWiFi_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisconnectWiFi'
-type MockBackend_DisconnectWiFi_Call struct {
- *mock.Call
-}
-
-// DisconnectWiFi is a helper method to define mock.On call
-func (_e *MockBackend_Expecter) DisconnectWiFi() *MockBackend_DisconnectWiFi_Call {
- return &MockBackend_DisconnectWiFi_Call{Call: _e.mock.On("DisconnectWiFi")}
-}
-
-func (_c *MockBackend_DisconnectWiFi_Call) Run(run func()) *MockBackend_DisconnectWiFi_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBackend_DisconnectWiFi_Call) Return(_a0 error) *MockBackend_DisconnectWiFi_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_DisconnectWiFi_Call) RunAndReturn(run func() error) *MockBackend_DisconnectWiFi_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// ForgetWiFiNetwork provides a mock function with given fields: ssid
-func (_m *MockBackend) ForgetWiFiNetwork(ssid string) error {
- ret := _m.Called(ssid)
-
- if len(ret) == 0 {
- panic("no return value specified for ForgetWiFiNetwork")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string) error); ok {
- r0 = rf(ssid)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_ForgetWiFiNetwork_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ForgetWiFiNetwork'
-type MockBackend_ForgetWiFiNetwork_Call struct {
- *mock.Call
-}
-
-// ForgetWiFiNetwork is a helper method to define mock.On call
-// - ssid string
-func (_e *MockBackend_Expecter) ForgetWiFiNetwork(ssid interface{}) *MockBackend_ForgetWiFiNetwork_Call {
- return &MockBackend_ForgetWiFiNetwork_Call{Call: _e.mock.On("ForgetWiFiNetwork", ssid)}
-}
-
-func (_c *MockBackend_ForgetWiFiNetwork_Call) Run(run func(ssid string)) *MockBackend_ForgetWiFiNetwork_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockBackend_ForgetWiFiNetwork_Call) Return(_a0 error) *MockBackend_ForgetWiFiNetwork_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_ForgetWiFiNetwork_Call) RunAndReturn(run func(string) error) *MockBackend_ForgetWiFiNetwork_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetCurrentState provides a mock function with no fields
-func (_m *MockBackend) GetCurrentState() (*network.BackendState, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetCurrentState")
- }
-
- var r0 *network.BackendState
- var r1 error
- if rf, ok := ret.Get(0).(func() (*network.BackendState, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() *network.BackendState); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*network.BackendState)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockBackend_GetCurrentState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCurrentState'
-type MockBackend_GetCurrentState_Call struct {
- *mock.Call
-}
-
-// GetCurrentState is a helper method to define mock.On call
-func (_e *MockBackend_Expecter) GetCurrentState() *MockBackend_GetCurrentState_Call {
- return &MockBackend_GetCurrentState_Call{Call: _e.mock.On("GetCurrentState")}
-}
-
-func (_c *MockBackend_GetCurrentState_Call) Run(run func()) *MockBackend_GetCurrentState_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBackend_GetCurrentState_Call) Return(_a0 *network.BackendState, _a1 error) *MockBackend_GetCurrentState_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockBackend_GetCurrentState_Call) RunAndReturn(run func() (*network.BackendState, error)) *MockBackend_GetCurrentState_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetPromptBroker provides a mock function with no fields
-func (_m *MockBackend) GetPromptBroker() network.PromptBroker {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetPromptBroker")
- }
-
- var r0 network.PromptBroker
- if rf, ok := ret.Get(0).(func() network.PromptBroker); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(network.PromptBroker)
- }
- }
-
- return r0
-}
-
-// MockBackend_GetPromptBroker_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPromptBroker'
-type MockBackend_GetPromptBroker_Call struct {
- *mock.Call
-}
-
-// GetPromptBroker is a helper method to define mock.On call
-func (_e *MockBackend_Expecter) GetPromptBroker() *MockBackend_GetPromptBroker_Call {
- return &MockBackend_GetPromptBroker_Call{Call: _e.mock.On("GetPromptBroker")}
-}
-
-func (_c *MockBackend_GetPromptBroker_Call) Run(run func()) *MockBackend_GetPromptBroker_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBackend_GetPromptBroker_Call) Return(_a0 network.PromptBroker) *MockBackend_GetPromptBroker_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_GetPromptBroker_Call) RunAndReturn(run func() network.PromptBroker) *MockBackend_GetPromptBroker_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetWiFiEnabled provides a mock function with no fields
-func (_m *MockBackend) GetWiFiEnabled() (bool, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetWiFiEnabled")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func() (bool, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() bool); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockBackend_GetWiFiEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetWiFiEnabled'
-type MockBackend_GetWiFiEnabled_Call struct {
- *mock.Call
-}
-
-// GetWiFiEnabled is a helper method to define mock.On call
-func (_e *MockBackend_Expecter) GetWiFiEnabled() *MockBackend_GetWiFiEnabled_Call {
- return &MockBackend_GetWiFiEnabled_Call{Call: _e.mock.On("GetWiFiEnabled")}
-}
-
-func (_c *MockBackend_GetWiFiEnabled_Call) Run(run func()) *MockBackend_GetWiFiEnabled_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBackend_GetWiFiEnabled_Call) Return(_a0 bool, _a1 error) *MockBackend_GetWiFiEnabled_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockBackend_GetWiFiEnabled_Call) RunAndReturn(run func() (bool, error)) *MockBackend_GetWiFiEnabled_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetWiFiNetworkDetails provides a mock function with given fields: ssid
-func (_m *MockBackend) GetWiFiNetworkDetails(ssid string) (*network.NetworkInfoResponse, error) {
- ret := _m.Called(ssid)
-
- if len(ret) == 0 {
- panic("no return value specified for GetWiFiNetworkDetails")
- }
-
- var r0 *network.NetworkInfoResponse
- var r1 error
- if rf, ok := ret.Get(0).(func(string) (*network.NetworkInfoResponse, error)); ok {
- return rf(ssid)
- }
- if rf, ok := ret.Get(0).(func(string) *network.NetworkInfoResponse); ok {
- r0 = rf(ssid)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*network.NetworkInfoResponse)
- }
- }
-
- if rf, ok := ret.Get(1).(func(string) error); ok {
- r1 = rf(ssid)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockBackend_GetWiFiNetworkDetails_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetWiFiNetworkDetails'
-type MockBackend_GetWiFiNetworkDetails_Call struct {
- *mock.Call
-}
-
-// GetWiFiNetworkDetails is a helper method to define mock.On call
-// - ssid string
-func (_e *MockBackend_Expecter) GetWiFiNetworkDetails(ssid interface{}) *MockBackend_GetWiFiNetworkDetails_Call {
- return &MockBackend_GetWiFiNetworkDetails_Call{Call: _e.mock.On("GetWiFiNetworkDetails", ssid)}
-}
-
-func (_c *MockBackend_GetWiFiNetworkDetails_Call) Run(run func(ssid string)) *MockBackend_GetWiFiNetworkDetails_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockBackend_GetWiFiNetworkDetails_Call) Return(_a0 *network.NetworkInfoResponse, _a1 error) *MockBackend_GetWiFiNetworkDetails_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockBackend_GetWiFiNetworkDetails_Call) RunAndReturn(run func(string) (*network.NetworkInfoResponse, error)) *MockBackend_GetWiFiNetworkDetails_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetWiredConnections provides a mock function with no fields
-func (_m *MockBackend) GetWiredConnections() ([]network.WiredConnection, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for GetWiredConnections")
- }
-
- var r0 []network.WiredConnection
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]network.WiredConnection, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []network.WiredConnection); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]network.WiredConnection)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockBackend_GetWiredConnections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetWiredConnections'
-type MockBackend_GetWiredConnections_Call struct {
- *mock.Call
-}
-
-// GetWiredConnections is a helper method to define mock.On call
-func (_e *MockBackend_Expecter) GetWiredConnections() *MockBackend_GetWiredConnections_Call {
- return &MockBackend_GetWiredConnections_Call{Call: _e.mock.On("GetWiredConnections")}
-}
-
-func (_c *MockBackend_GetWiredConnections_Call) Run(run func()) *MockBackend_GetWiredConnections_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBackend_GetWiredConnections_Call) Return(_a0 []network.WiredConnection, _a1 error) *MockBackend_GetWiredConnections_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockBackend_GetWiredConnections_Call) RunAndReturn(run func() ([]network.WiredConnection, error)) *MockBackend_GetWiredConnections_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// GetWiredNetworkDetails provides a mock function with given fields: uuid
-func (_m *MockBackend) GetWiredNetworkDetails(uuid string) (*network.WiredNetworkInfoResponse, error) {
- ret := _m.Called(uuid)
-
- if len(ret) == 0 {
- panic("no return value specified for GetWiredNetworkDetails")
- }
-
- var r0 *network.WiredNetworkInfoResponse
- var r1 error
- if rf, ok := ret.Get(0).(func(string) (*network.WiredNetworkInfoResponse, error)); ok {
- return rf(uuid)
- }
- if rf, ok := ret.Get(0).(func(string) *network.WiredNetworkInfoResponse); ok {
- r0 = rf(uuid)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*network.WiredNetworkInfoResponse)
- }
- }
-
- if rf, ok := ret.Get(1).(func(string) error); ok {
- r1 = rf(uuid)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockBackend_GetWiredNetworkDetails_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetWiredNetworkDetails'
-type MockBackend_GetWiredNetworkDetails_Call struct {
- *mock.Call
-}
-
-// GetWiredNetworkDetails is a helper method to define mock.On call
-// - uuid string
-func (_e *MockBackend_Expecter) GetWiredNetworkDetails(uuid interface{}) *MockBackend_GetWiredNetworkDetails_Call {
- return &MockBackend_GetWiredNetworkDetails_Call{Call: _e.mock.On("GetWiredNetworkDetails", uuid)}
-}
-
-func (_c *MockBackend_GetWiredNetworkDetails_Call) Run(run func(uuid string)) *MockBackend_GetWiredNetworkDetails_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string))
- })
- return _c
-}
-
-func (_c *MockBackend_GetWiredNetworkDetails_Call) Return(_a0 *network.WiredNetworkInfoResponse, _a1 error) *MockBackend_GetWiredNetworkDetails_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockBackend_GetWiredNetworkDetails_Call) RunAndReturn(run func(string) (*network.WiredNetworkInfoResponse, error)) *MockBackend_GetWiredNetworkDetails_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// Initialize provides a mock function with no fields
-func (_m *MockBackend) Initialize() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for Initialize")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_Initialize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Initialize'
-type MockBackend_Initialize_Call struct {
- *mock.Call
-}
-
-// Initialize is a helper method to define mock.On call
-func (_e *MockBackend_Expecter) Initialize() *MockBackend_Initialize_Call {
- return &MockBackend_Initialize_Call{Call: _e.mock.On("Initialize")}
-}
-
-func (_c *MockBackend_Initialize_Call) Run(run func()) *MockBackend_Initialize_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBackend_Initialize_Call) Return(_a0 error) *MockBackend_Initialize_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_Initialize_Call) RunAndReturn(run func() error) *MockBackend_Initialize_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// ListActiveVPN provides a mock function with no fields
-func (_m *MockBackend) ListActiveVPN() ([]network.VPNActive, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for ListActiveVPN")
- }
-
- var r0 []network.VPNActive
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]network.VPNActive, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []network.VPNActive); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]network.VPNActive)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockBackend_ListActiveVPN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListActiveVPN'
-type MockBackend_ListActiveVPN_Call struct {
- *mock.Call
-}
-
-// ListActiveVPN is a helper method to define mock.On call
-func (_e *MockBackend_Expecter) ListActiveVPN() *MockBackend_ListActiveVPN_Call {
- return &MockBackend_ListActiveVPN_Call{Call: _e.mock.On("ListActiveVPN")}
-}
-
-func (_c *MockBackend_ListActiveVPN_Call) Run(run func()) *MockBackend_ListActiveVPN_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBackend_ListActiveVPN_Call) Return(_a0 []network.VPNActive, _a1 error) *MockBackend_ListActiveVPN_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockBackend_ListActiveVPN_Call) RunAndReturn(run func() ([]network.VPNActive, error)) *MockBackend_ListActiveVPN_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// ListVPNProfiles provides a mock function with no fields
-func (_m *MockBackend) ListVPNProfiles() ([]network.VPNProfile, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for ListVPNProfiles")
- }
-
- var r0 []network.VPNProfile
- var r1 error
- if rf, ok := ret.Get(0).(func() ([]network.VPNProfile, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() []network.VPNProfile); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]network.VPNProfile)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// MockBackend_ListVPNProfiles_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListVPNProfiles'
-type MockBackend_ListVPNProfiles_Call struct {
- *mock.Call
-}
-
-// ListVPNProfiles is a helper method to define mock.On call
-func (_e *MockBackend_Expecter) ListVPNProfiles() *MockBackend_ListVPNProfiles_Call {
- return &MockBackend_ListVPNProfiles_Call{Call: _e.mock.On("ListVPNProfiles")}
-}
-
-func (_c *MockBackend_ListVPNProfiles_Call) Run(run func()) *MockBackend_ListVPNProfiles_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBackend_ListVPNProfiles_Call) Return(_a0 []network.VPNProfile, _a1 error) *MockBackend_ListVPNProfiles_Call {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *MockBackend_ListVPNProfiles_Call) RunAndReturn(run func() ([]network.VPNProfile, error)) *MockBackend_ListVPNProfiles_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// ScanWiFi provides a mock function with no fields
-func (_m *MockBackend) ScanWiFi() error {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for ScanWiFi")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_ScanWiFi_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ScanWiFi'
-type MockBackend_ScanWiFi_Call struct {
- *mock.Call
-}
-
-// ScanWiFi is a helper method to define mock.On call
-func (_e *MockBackend_Expecter) ScanWiFi() *MockBackend_ScanWiFi_Call {
- return &MockBackend_ScanWiFi_Call{Call: _e.mock.On("ScanWiFi")}
-}
-
-func (_c *MockBackend_ScanWiFi_Call) Run(run func()) *MockBackend_ScanWiFi_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBackend_ScanWiFi_Call) Return(_a0 error) *MockBackend_ScanWiFi_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_ScanWiFi_Call) RunAndReturn(run func() error) *MockBackend_ScanWiFi_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetPromptBroker provides a mock function with given fields: broker
-func (_m *MockBackend) SetPromptBroker(broker network.PromptBroker) error {
- ret := _m.Called(broker)
-
- if len(ret) == 0 {
- panic("no return value specified for SetPromptBroker")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(network.PromptBroker) error); ok {
- r0 = rf(broker)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_SetPromptBroker_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPromptBroker'
-type MockBackend_SetPromptBroker_Call struct {
- *mock.Call
-}
-
-// SetPromptBroker is a helper method to define mock.On call
-// - broker network.PromptBroker
-func (_e *MockBackend_Expecter) SetPromptBroker(broker interface{}) *MockBackend_SetPromptBroker_Call {
- return &MockBackend_SetPromptBroker_Call{Call: _e.mock.On("SetPromptBroker", broker)}
-}
-
-func (_c *MockBackend_SetPromptBroker_Call) Run(run func(broker network.PromptBroker)) *MockBackend_SetPromptBroker_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(network.PromptBroker))
- })
- return _c
-}
-
-func (_c *MockBackend_SetPromptBroker_Call) Return(_a0 error) *MockBackend_SetPromptBroker_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_SetPromptBroker_Call) RunAndReturn(run func(network.PromptBroker) error) *MockBackend_SetPromptBroker_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetWiFiAutoconnect provides a mock function with given fields: ssid, autoconnect
-func (_m *MockBackend) SetWiFiAutoconnect(ssid string, autoconnect bool) error {
- ret := _m.Called(ssid, autoconnect)
-
- if len(ret) == 0 {
- panic("no return value specified for SetWiFiAutoconnect")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string, bool) error); ok {
- r0 = rf(ssid, autoconnect)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_SetWiFiAutoconnect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetWiFiAutoconnect'
-type MockBackend_SetWiFiAutoconnect_Call struct {
- *mock.Call
-}
-
-// SetWiFiAutoconnect is a helper method to define mock.On call
-// - ssid string
-// - autoconnect bool
-func (_e *MockBackend_Expecter) SetWiFiAutoconnect(ssid interface{}, autoconnect interface{}) *MockBackend_SetWiFiAutoconnect_Call {
- return &MockBackend_SetWiFiAutoconnect_Call{Call: _e.mock.On("SetWiFiAutoconnect", ssid, autoconnect)}
-}
-
-func (_c *MockBackend_SetWiFiAutoconnect_Call) Run(run func(ssid string, autoconnect bool)) *MockBackend_SetWiFiAutoconnect_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string), args[1].(bool))
- })
- return _c
-}
-
-func (_c *MockBackend_SetWiFiAutoconnect_Call) Return(_a0 error) *MockBackend_SetWiFiAutoconnect_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_SetWiFiAutoconnect_Call) RunAndReturn(run func(string, bool) error) *MockBackend_SetWiFiAutoconnect_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetWiFiEnabled provides a mock function with given fields: enabled
-func (_m *MockBackend) SetWiFiEnabled(enabled bool) error {
- ret := _m.Called(enabled)
-
- if len(ret) == 0 {
- panic("no return value specified for SetWiFiEnabled")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(bool) error); ok {
- r0 = rf(enabled)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_SetWiFiEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetWiFiEnabled'
-type MockBackend_SetWiFiEnabled_Call struct {
- *mock.Call
-}
-
-// SetWiFiEnabled is a helper method to define mock.On call
-// - enabled bool
-func (_e *MockBackend_Expecter) SetWiFiEnabled(enabled interface{}) *MockBackend_SetWiFiEnabled_Call {
- return &MockBackend_SetWiFiEnabled_Call{Call: _e.mock.On("SetWiFiEnabled", enabled)}
-}
-
-func (_c *MockBackend_SetWiFiEnabled_Call) Run(run func(enabled bool)) *MockBackend_SetWiFiEnabled_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(bool))
- })
- return _c
-}
-
-func (_c *MockBackend_SetWiFiEnabled_Call) Return(_a0 error) *MockBackend_SetWiFiEnabled_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_SetWiFiEnabled_Call) RunAndReturn(run func(bool) error) *MockBackend_SetWiFiEnabled_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// StartMonitoring provides a mock function with given fields: onStateChange
-func (_m *MockBackend) StartMonitoring(onStateChange func()) error {
- ret := _m.Called(onStateChange)
-
- if len(ret) == 0 {
- panic("no return value specified for StartMonitoring")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(func()) error); ok {
- r0 = rf(onStateChange)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_StartMonitoring_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StartMonitoring'
-type MockBackend_StartMonitoring_Call struct {
- *mock.Call
-}
-
-// StartMonitoring is a helper method to define mock.On call
-// - onStateChange func()
-func (_e *MockBackend_Expecter) StartMonitoring(onStateChange interface{}) *MockBackend_StartMonitoring_Call {
- return &MockBackend_StartMonitoring_Call{Call: _e.mock.On("StartMonitoring", onStateChange)}
-}
-
-func (_c *MockBackend_StartMonitoring_Call) Run(run func(onStateChange func())) *MockBackend_StartMonitoring_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(func()))
- })
- return _c
-}
-
-func (_c *MockBackend_StartMonitoring_Call) Return(_a0 error) *MockBackend_StartMonitoring_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_StartMonitoring_Call) RunAndReturn(run func(func()) error) *MockBackend_StartMonitoring_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// StopMonitoring provides a mock function with no fields
-func (_m *MockBackend) StopMonitoring() {
- _m.Called()
-}
-
-// MockBackend_StopMonitoring_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StopMonitoring'
-type MockBackend_StopMonitoring_Call struct {
- *mock.Call
-}
-
-// StopMonitoring is a helper method to define mock.On call
-func (_e *MockBackend_Expecter) StopMonitoring() *MockBackend_StopMonitoring_Call {
- return &MockBackend_StopMonitoring_Call{Call: _e.mock.On("StopMonitoring")}
-}
-
-func (_c *MockBackend_StopMonitoring_Call) Run(run func()) *MockBackend_StopMonitoring_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *MockBackend_StopMonitoring_Call) Return() *MockBackend_StopMonitoring_Call {
- _c.Call.Return()
- return _c
-}
-
-func (_c *MockBackend_StopMonitoring_Call) RunAndReturn(run func()) *MockBackend_StopMonitoring_Call {
- _c.Run(run)
- return _c
-}
-
-// SubmitCredentials provides a mock function with given fields: token, secrets, save
-func (_m *MockBackend) SubmitCredentials(token string, secrets map[string]string, save bool) error {
- ret := _m.Called(token, secrets, save)
-
- if len(ret) == 0 {
- panic("no return value specified for SubmitCredentials")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(string, map[string]string, bool) error); ok {
- r0 = rf(token, secrets, save)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// MockBackend_SubmitCredentials_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubmitCredentials'
-type MockBackend_SubmitCredentials_Call struct {
- *mock.Call
-}
-
-// SubmitCredentials is a helper method to define mock.On call
-// - token string
-// - secrets map[string]string
-// - save bool
-func (_e *MockBackend_Expecter) SubmitCredentials(token interface{}, secrets interface{}, save interface{}) *MockBackend_SubmitCredentials_Call {
- return &MockBackend_SubmitCredentials_Call{Call: _e.mock.On("SubmitCredentials", token, secrets, save)}
-}
-
-func (_c *MockBackend_SubmitCredentials_Call) Run(run func(token string, secrets map[string]string, save bool)) *MockBackend_SubmitCredentials_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(string), args[1].(map[string]string), args[2].(bool))
- })
- return _c
-}
-
-func (_c *MockBackend_SubmitCredentials_Call) Return(_a0 error) *MockBackend_SubmitCredentials_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *MockBackend_SubmitCredentials_Call) RunAndReturn(run func(string, map[string]string, bool) error) *MockBackend_SubmitCredentials_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// NewMockBackend creates a new instance of MockBackend. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewMockBackend(t interface {
- mock.TestingT
- Cleanup(func())
-}) *MockBackend {
- mock := &MockBackend{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/nix/inputs/dms-cli/internal/plugins/manager.go b/nix/inputs/dms-cli/internal/plugins/manager.go
deleted file mode 100644
index 0c277eb..0000000
--- a/nix/inputs/dms-cli/internal/plugins/manager.go
+++ /dev/null
@@ -1,430 +0,0 @@
-package plugins
-
-import (
- "crypto/sha256"
- "encoding/hex"
- "encoding/json"
- "fmt"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/spf13/afero"
-)
-
-type Manager struct {
- fs afero.Fs
- pluginsDir string
- gitClient GitClient
-}
-
-func NewManager() (*Manager, error) {
- return NewManagerWithFs(afero.NewOsFs())
-}
-
-func NewManagerWithFs(fs afero.Fs) (*Manager, error) {
- pluginsDir := getPluginsDir()
- return &Manager{
- fs: fs,
- pluginsDir: pluginsDir,
- gitClient: &realGitClient{},
- }, nil
-}
-
-func getPluginsDir() string {
- configHome := os.Getenv("XDG_CONFIG_HOME")
- if configHome == "" {
- homeDir, err := os.UserHomeDir()
- if err != nil {
- return filepath.Join(os.TempDir(), "DankMaterialShell", "plugins")
- }
- configHome = filepath.Join(homeDir, ".config")
- }
- return filepath.Join(configHome, "DankMaterialShell", "plugins")
-}
-
-func (m *Manager) IsInstalled(plugin Plugin) (bool, error) {
- pluginPath := filepath.Join(m.pluginsDir, plugin.ID)
- exists, err := afero.DirExists(m.fs, pluginPath)
- if err != nil {
- return false, err
- }
- if exists {
- return true, nil
- }
-
- systemPluginPath := filepath.Join("/etc/xdg/quickshell/dms-plugins", plugin.ID)
- systemExists, err := afero.DirExists(m.fs, systemPluginPath)
- if err != nil {
- return false, err
- }
- return systemExists, nil
-}
-
-func (m *Manager) Install(plugin Plugin) error {
- pluginPath := filepath.Join(m.pluginsDir, plugin.ID)
-
- exists, err := afero.DirExists(m.fs, pluginPath)
- if err != nil {
- return fmt.Errorf("failed to check if plugin exists: %w", err)
- }
-
- if exists {
- return fmt.Errorf("plugin already installed: %s", plugin.Name)
- }
-
- if err := m.fs.MkdirAll(m.pluginsDir, 0755); err != nil {
- return fmt.Errorf("failed to create plugins directory: %w", err)
- }
-
- reposDir := filepath.Join(m.pluginsDir, ".repos")
- if err := m.fs.MkdirAll(reposDir, 0755); err != nil {
- return fmt.Errorf("failed to create repos directory: %w", err)
- }
-
- if plugin.Path != "" {
- repoName := m.getRepoName(plugin.Repo)
- repoPath := filepath.Join(reposDir, repoName)
-
- repoExists, err := afero.DirExists(m.fs, repoPath)
- if err != nil {
- return fmt.Errorf("failed to check if repo exists: %w", err)
- }
-
- if !repoExists {
- if err := m.gitClient.PlainClone(repoPath, plugin.Repo); err != nil {
- m.fs.RemoveAll(repoPath)
- return fmt.Errorf("failed to clone repository: %w", err)
- }
- } else {
- // Pull latest changes if repo already exists
- if err := m.gitClient.Pull(repoPath); err != nil {
- // If pull fails (e.g., corrupted shallow clone), delete and re-clone
- if err := m.fs.RemoveAll(repoPath); err != nil {
- return fmt.Errorf("failed to remove corrupted repository: %w", err)
- }
-
- if err := m.gitClient.PlainClone(repoPath, plugin.Repo); err != nil {
- return fmt.Errorf("failed to re-clone repository: %w", err)
- }
- }
- }
-
- sourcePath := filepath.Join(repoPath, plugin.Path)
- sourceExists, err := afero.DirExists(m.fs, sourcePath)
- if err != nil {
- return fmt.Errorf("failed to check plugin path: %w", err)
- }
- if !sourceExists {
- return fmt.Errorf("plugin path does not exist in repository: %s", plugin.Path)
- }
-
- if err := m.createSymlink(sourcePath, pluginPath); err != nil {
- return fmt.Errorf("failed to create symlink: %w", err)
- }
-
- metaPath := pluginPath + ".meta"
- metaContent := fmt.Sprintf("repo=%s\npath=%s\nrepodir=%s", plugin.Repo, plugin.Path, repoName)
- if err := afero.WriteFile(m.fs, metaPath, []byte(metaContent), 0644); err != nil {
- return fmt.Errorf("failed to write metadata: %w", err)
- }
- } else {
- if err := m.gitClient.PlainClone(pluginPath, plugin.Repo); err != nil {
- m.fs.RemoveAll(pluginPath)
- return fmt.Errorf("failed to clone plugin: %w", err)
- }
- }
-
- return nil
-}
-
-func (m *Manager) getRepoName(repoURL string) string {
- hash := sha256.Sum256([]byte(repoURL))
- return hex.EncodeToString(hash[:])[:16]
-}
-
-func (m *Manager) createSymlink(source, dest string) error {
- if symlinkFs, ok := m.fs.(afero.Symlinker); ok {
- return symlinkFs.SymlinkIfPossible(source, dest)
- }
- return os.Symlink(source, dest)
-}
-
-func (m *Manager) Update(plugin Plugin) error {
- pluginPath := filepath.Join(m.pluginsDir, plugin.ID)
-
- exists, err := afero.DirExists(m.fs, pluginPath)
- if err != nil {
- return fmt.Errorf("failed to check if plugin exists: %w", err)
- }
-
- if !exists {
- systemPluginPath := filepath.Join("/etc/xdg/quickshell/dms-plugins", plugin.ID)
- systemExists, err := afero.DirExists(m.fs, systemPluginPath)
- if err != nil {
- return fmt.Errorf("failed to check if plugin exists: %w", err)
- }
- if systemExists {
- return fmt.Errorf("cannot update system plugin: %s", plugin.Name)
- }
- return fmt.Errorf("plugin not installed: %s", plugin.Name)
- }
-
- metaPath := pluginPath + ".meta"
- metaExists, err := afero.Exists(m.fs, metaPath)
- if err != nil {
- return fmt.Errorf("failed to check metadata: %w", err)
- }
-
- if metaExists {
- reposDir := filepath.Join(m.pluginsDir, ".repos")
- repoName := m.getRepoName(plugin.Repo)
- repoPath := filepath.Join(reposDir, repoName)
-
- // Try to pull, if it fails (e.g., shallow clone corruption), delete and re-clone
- if err := m.gitClient.Pull(repoPath); err != nil {
- // Repository is likely corrupted or has issues, delete and re-clone
- if err := m.fs.RemoveAll(repoPath); err != nil {
- return fmt.Errorf("failed to remove corrupted repository: %w", err)
- }
-
- if err := m.gitClient.PlainClone(repoPath, plugin.Repo); err != nil {
- return fmt.Errorf("failed to re-clone repository: %w", err)
- }
- }
- } else {
- // Try to pull, if it fails, delete and re-clone
- if err := m.gitClient.Pull(pluginPath); err != nil {
- if err := m.fs.RemoveAll(pluginPath); err != nil {
- return fmt.Errorf("failed to remove corrupted plugin: %w", err)
- }
-
- if err := m.gitClient.PlainClone(pluginPath, plugin.Repo); err != nil {
- return fmt.Errorf("failed to re-clone plugin: %w", err)
- }
- }
- }
-
- return nil
-}
-
-func (m *Manager) Uninstall(plugin Plugin) error {
- pluginPath := filepath.Join(m.pluginsDir, plugin.ID)
-
- exists, err := afero.DirExists(m.fs, pluginPath)
- if err != nil {
- return fmt.Errorf("failed to check if plugin exists: %w", err)
- }
-
- if !exists {
- systemPluginPath := filepath.Join("/etc/xdg/quickshell/dms-plugins", plugin.ID)
- systemExists, err := afero.DirExists(m.fs, systemPluginPath)
- if err != nil {
- return fmt.Errorf("failed to check if plugin exists: %w", err)
- }
- if systemExists {
- return fmt.Errorf("cannot uninstall system plugin: %s", plugin.Name)
- }
- return fmt.Errorf("plugin not installed: %s", plugin.Name)
- }
-
- metaPath := pluginPath + ".meta"
- metaExists, err := afero.Exists(m.fs, metaPath)
- if err != nil {
- return fmt.Errorf("failed to check metadata: %w", err)
- }
-
- if metaExists {
- reposDir := filepath.Join(m.pluginsDir, ".repos")
- repoName := m.getRepoName(plugin.Repo)
- repoPath := filepath.Join(reposDir, repoName)
-
- shouldCleanup, err := m.shouldCleanupRepo(repoPath, plugin.Repo, plugin.ID)
- if err != nil {
- return fmt.Errorf("failed to check repo cleanup: %w", err)
- }
-
- if err := m.fs.Remove(pluginPath); err != nil {
- return fmt.Errorf("failed to remove symlink: %w", err)
- }
-
- if err := m.fs.Remove(metaPath); err != nil {
- return fmt.Errorf("failed to remove metadata: %w", err)
- }
-
- if shouldCleanup {
- if err := m.fs.RemoveAll(repoPath); err != nil {
- return fmt.Errorf("failed to cleanup repository: %w", err)
- }
- }
- } else {
- if err := m.fs.RemoveAll(pluginPath); err != nil {
- return fmt.Errorf("failed to remove plugin: %w", err)
- }
- }
-
- return nil
-}
-
-func (m *Manager) shouldCleanupRepo(repoPath, repoURL, excludePlugin string) (bool, error) {
- installed, err := m.ListInstalled()
- if err != nil {
- return false, err
- }
-
- registry, err := NewRegistry()
- if err != nil {
- return false, err
- }
-
- allPlugins, err := registry.List()
- if err != nil {
- return false, err
- }
-
- for _, id := range installed {
- if id == excludePlugin {
- continue
- }
-
- for _, p := range allPlugins {
- if p.ID == id && p.Repo == repoURL && p.Path != "" {
- return false, nil
- }
- }
- }
-
- return true, nil
-}
-
-func (m *Manager) ListInstalled() ([]string, error) {
- installedMap := make(map[string]bool)
-
- exists, err := afero.DirExists(m.fs, m.pluginsDir)
- if err != nil {
- return nil, err
- }
-
- if exists {
- entries, err := afero.ReadDir(m.fs, m.pluginsDir)
- if err != nil {
- return nil, fmt.Errorf("failed to read plugins directory: %w", err)
- }
-
- for _, entry := range entries {
- name := entry.Name()
- if name == ".repos" || strings.HasSuffix(name, ".meta") {
- continue
- }
-
- fullPath := filepath.Join(m.pluginsDir, name)
- isPlugin := false
-
- if entry.IsDir() {
- isPlugin = true
- } else if entry.Mode()&os.ModeSymlink != 0 {
- isPlugin = true
- } else {
- info, err := m.fs.Stat(fullPath)
- if err == nil && info.IsDir() {
- isPlugin = true
- }
- }
-
- if isPlugin {
- // Read plugin.json to get the actual plugin ID
- pluginID := m.getPluginID(fullPath)
- if pluginID != "" {
- installedMap[pluginID] = true
- }
- }
- }
- }
-
- systemPluginsDir := "/etc/xdg/quickshell/dms-plugins"
- systemExists, err := afero.DirExists(m.fs, systemPluginsDir)
- if err == nil && systemExists {
- entries, err := afero.ReadDir(m.fs, systemPluginsDir)
- if err == nil {
- for _, entry := range entries {
- if entry.IsDir() {
- fullPath := filepath.Join(systemPluginsDir, entry.Name())
- // Read plugin.json to get the actual plugin ID
- pluginID := m.getPluginID(fullPath)
- if pluginID != "" {
- installedMap[pluginID] = true
- }
- }
- }
- }
- }
-
- var installed []string
- for name := range installedMap {
- installed = append(installed, name)
- }
-
- return installed, nil
-}
-
-// getPluginID reads the plugin.json file and returns the plugin ID
-func (m *Manager) getPluginID(pluginPath string) string {
- manifestPath := filepath.Join(pluginPath, "plugin.json")
- data, err := afero.ReadFile(m.fs, manifestPath)
- if err != nil {
- return ""
- }
-
- var manifest struct {
- ID string `json:"id"`
- }
- if err := json.Unmarshal(data, &manifest); err != nil {
- return ""
- }
-
- return manifest.ID
-}
-
-func (m *Manager) GetPluginsDir() string {
- return m.pluginsDir
-}
-
-func (m *Manager) HasUpdates(pluginID string, plugin Plugin) (bool, error) {
- pluginPath := filepath.Join(m.pluginsDir, pluginID)
-
- exists, err := afero.DirExists(m.fs, pluginPath)
- if err != nil {
- return false, fmt.Errorf("failed to check if plugin exists: %w", err)
- }
-
- if !exists {
- systemPluginPath := filepath.Join("/etc/xdg/quickshell/dms-plugins", pluginID)
- systemExists, err := afero.DirExists(m.fs, systemPluginPath)
- if err != nil {
- return false, fmt.Errorf("failed to check system plugin: %w", err)
- }
- if systemExists {
- return false, nil
- }
- return false, fmt.Errorf("plugin not installed: %s", pluginID)
- }
-
- // Check if there's a .meta file (plugin installed from a monorepo)
- metaPath := pluginPath + ".meta"
- metaExists, err := afero.Exists(m.fs, metaPath)
- if err != nil {
- return false, fmt.Errorf("failed to check metadata: %w", err)
- }
-
- if metaExists {
- // Plugin is from a monorepo, check the repo directory
- reposDir := filepath.Join(m.pluginsDir, ".repos")
- repoName := m.getRepoName(plugin.Repo)
- repoPath := filepath.Join(reposDir, repoName)
-
- return m.gitClient.HasUpdates(repoPath)
- }
-
- // Plugin is a standalone repo
- return m.gitClient.HasUpdates(pluginPath)
-}
diff --git a/nix/inputs/dms-cli/internal/plugins/manager_test.go b/nix/inputs/dms-cli/internal/plugins/manager_test.go
deleted file mode 100644
index 5dd9d01..0000000
--- a/nix/inputs/dms-cli/internal/plugins/manager_test.go
+++ /dev/null
@@ -1,247 +0,0 @@
-package plugins
-
-import (
- "os"
- "path/filepath"
- "testing"
-
- "github.com/spf13/afero"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func setupTestManager(t *testing.T) (*Manager, afero.Fs, string) {
- fs := afero.NewMemMapFs()
- pluginsDir := "/test-plugins"
- manager := &Manager{
- fs: fs,
- pluginsDir: pluginsDir,
- gitClient: &mockGitClient{},
- }
- return manager, fs, pluginsDir
-}
-
-func TestNewManager(t *testing.T) {
- manager, err := NewManager()
- assert.NoError(t, err)
- assert.NotNil(t, manager)
- assert.NotEmpty(t, manager.pluginsDir)
-}
-
-func TestGetPluginsDir(t *testing.T) {
- t.Run("uses XDG_CONFIG_HOME when set", func(t *testing.T) {
- oldConfig := os.Getenv("XDG_CONFIG_HOME")
- defer func() {
- if oldConfig != "" {
- os.Setenv("XDG_CONFIG_HOME", oldConfig)
- } else {
- os.Unsetenv("XDG_CONFIG_HOME")
- }
- }()
-
- os.Setenv("XDG_CONFIG_HOME", "/tmp/test-config")
- dir := getPluginsDir()
- assert.Equal(t, "/tmp/test-config/DankMaterialShell/plugins", dir)
- })
-
- t.Run("falls back to home directory", func(t *testing.T) {
- oldConfig := os.Getenv("XDG_CONFIG_HOME")
- defer func() {
- if oldConfig != "" {
- os.Setenv("XDG_CONFIG_HOME", oldConfig)
- } else {
- os.Unsetenv("XDG_CONFIG_HOME")
- }
- }()
-
- os.Unsetenv("XDG_CONFIG_HOME")
- dir := getPluginsDir()
- assert.Contains(t, dir, ".config/DankMaterialShell/plugins")
- })
-}
-
-func TestIsInstalled(t *testing.T) {
- t.Run("returns true when plugin is installed", func(t *testing.T) {
- manager, fs, pluginsDir := setupTestManager(t)
-
- plugin := Plugin{ID: "test-plugin", Name: "TestPlugin"}
- pluginPath := filepath.Join(pluginsDir, plugin.ID)
- err := fs.MkdirAll(pluginPath, 0755)
- require.NoError(t, err)
-
- installed, err := manager.IsInstalled(plugin)
- assert.NoError(t, err)
- assert.True(t, installed)
- })
-
- t.Run("returns false when plugin is not installed", func(t *testing.T) {
- manager, _, _ := setupTestManager(t)
-
- plugin := Plugin{ID: "non-existent", Name: "NonExistent"}
- installed, err := manager.IsInstalled(plugin)
- assert.NoError(t, err)
- assert.False(t, installed)
- })
-}
-
-func TestInstall(t *testing.T) {
- t.Run("installs plugin successfully", func(t *testing.T) {
- manager, fs, pluginsDir := setupTestManager(t)
-
- plugin := Plugin{
- ID: "test-plugin",
- Name: "TestPlugin",
- Repo: "https://github.com/test/plugin",
- }
-
- cloneCalled := false
- mockGit := &mockGitClient{
- cloneFunc: func(path string, url string) error {
- cloneCalled = true
- assert.Equal(t, filepath.Join(pluginsDir, plugin.ID), path)
- assert.Equal(t, plugin.Repo, url)
- return fs.MkdirAll(path, 0755)
- },
- }
- manager.gitClient = mockGit
-
- err := manager.Install(plugin)
- assert.NoError(t, err)
- assert.True(t, cloneCalled)
-
- exists, _ := afero.DirExists(fs, filepath.Join(pluginsDir, plugin.ID))
- assert.True(t, exists)
- })
-
- t.Run("returns error when plugin already installed", func(t *testing.T) {
- manager, fs, pluginsDir := setupTestManager(t)
-
- plugin := Plugin{ID: "test-plugin", Name: "TestPlugin"}
- pluginPath := filepath.Join(pluginsDir, plugin.ID)
- err := fs.MkdirAll(pluginPath, 0755)
- require.NoError(t, err)
-
- err = manager.Install(plugin)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "already installed")
- })
-
- t.Run("installs monorepo plugin with symlink", func(t *testing.T) {
- t.Skip("Skipping symlink test as MemMapFs doesn't support symlinks")
- })
-}
-
-func TestManagerUpdate(t *testing.T) {
- t.Run("updates plugin successfully", func(t *testing.T) {
- manager, fs, pluginsDir := setupTestManager(t)
-
- plugin := Plugin{ID: "test-plugin", Name: "TestPlugin"}
- pluginPath := filepath.Join(pluginsDir, plugin.ID)
- err := fs.MkdirAll(pluginPath, 0755)
- require.NoError(t, err)
-
- pullCalled := false
- mockGit := &mockGitClient{
- pullFunc: func(path string) error {
- pullCalled = true
- assert.Equal(t, pluginPath, path)
- return nil
- },
- }
- manager.gitClient = mockGit
-
- err = manager.Update(plugin)
- assert.NoError(t, err)
- assert.True(t, pullCalled)
- })
-
- t.Run("returns error when plugin not installed", func(t *testing.T) {
- manager, _, _ := setupTestManager(t)
-
- plugin := Plugin{ID: "non-existent", Name: "NonExistent"}
- err := manager.Update(plugin)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not installed")
- })
-}
-
-func TestUninstall(t *testing.T) {
- t.Run("uninstalls plugin successfully", func(t *testing.T) {
- manager, fs, pluginsDir := setupTestManager(t)
-
- plugin := Plugin{ID: "test-plugin", Name: "TestPlugin"}
- pluginPath := filepath.Join(pluginsDir, plugin.ID)
- err := fs.MkdirAll(pluginPath, 0755)
- require.NoError(t, err)
-
- err = manager.Uninstall(plugin)
- assert.NoError(t, err)
-
- exists, _ := afero.DirExists(fs, pluginPath)
- assert.False(t, exists)
- })
-
- t.Run("returns error when plugin not installed", func(t *testing.T) {
- manager, _, _ := setupTestManager(t)
-
- plugin := Plugin{ID: "non-existent", Name: "NonExistent"}
- err := manager.Uninstall(plugin)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not installed")
- })
-}
-
-func TestListInstalled(t *testing.T) {
- t.Run("lists installed plugins", func(t *testing.T) {
- manager, fs, pluginsDir := setupTestManager(t)
-
- err := fs.MkdirAll(filepath.Join(pluginsDir, "Plugin1"), 0755)
- require.NoError(t, err)
- err = afero.WriteFile(fs, filepath.Join(pluginsDir, "Plugin1", "plugin.json"), []byte(`{"id":"Plugin1"}`), 0644)
- require.NoError(t, err)
-
- err = fs.MkdirAll(filepath.Join(pluginsDir, "Plugin2"), 0755)
- require.NoError(t, err)
- err = afero.WriteFile(fs, filepath.Join(pluginsDir, "Plugin2", "plugin.json"), []byte(`{"id":"Plugin2"}`), 0644)
- require.NoError(t, err)
-
- installed, err := manager.ListInstalled()
- assert.NoError(t, err)
- assert.Len(t, installed, 2)
- assert.Contains(t, installed, "Plugin1")
- assert.Contains(t, installed, "Plugin2")
- })
-
- t.Run("returns empty list when no plugins installed", func(t *testing.T) {
- manager, _, _ := setupTestManager(t)
-
- installed, err := manager.ListInstalled()
- assert.NoError(t, err)
- assert.Empty(t, installed)
- })
-
- t.Run("ignores files and .repos directory", func(t *testing.T) {
- manager, fs, pluginsDir := setupTestManager(t)
-
- err := fs.MkdirAll(pluginsDir, 0755)
- require.NoError(t, err)
- err = fs.MkdirAll(filepath.Join(pluginsDir, "Plugin1"), 0755)
- require.NoError(t, err)
- err = afero.WriteFile(fs, filepath.Join(pluginsDir, "Plugin1", "plugin.json"), []byte(`{"id":"Plugin1"}`), 0644)
- require.NoError(t, err)
- err = fs.MkdirAll(filepath.Join(pluginsDir, ".repos"), 0755)
- require.NoError(t, err)
- err = afero.WriteFile(fs, filepath.Join(pluginsDir, "README.md"), []byte("test"), 0644)
- require.NoError(t, err)
-
- installed, err := manager.ListInstalled()
- assert.NoError(t, err)
- assert.Len(t, installed, 1)
- assert.Equal(t, "Plugin1", installed[0])
- })
-}
-
-func TestManagerGetPluginsDir(t *testing.T) {
- manager, _, pluginsDir := setupTestManager(t)
- assert.Equal(t, pluginsDir, manager.GetPluginsDir())
-}
diff --git a/nix/inputs/dms-cli/internal/plugins/registry.go b/nix/inputs/dms-cli/internal/plugins/registry.go
deleted file mode 100644
index f2e626d..0000000
--- a/nix/inputs/dms-cli/internal/plugins/registry.go
+++ /dev/null
@@ -1,256 +0,0 @@
-package plugins
-
-import (
- "encoding/json"
- "fmt"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/go-git/go-git/v6"
- "github.com/spf13/afero"
-)
-
-const registryRepo = "https://github.com/AvengeMedia/dms-plugin-registry.git"
-
-type Plugin struct {
- ID string `json:"id"`
- Name string `json:"name"`
- Capabilities []string `json:"capabilities"`
- Category string `json:"category"`
- Repo string `json:"repo"`
- Path string `json:"path,omitempty"`
- Author string `json:"author"`
- Description string `json:"description"`
- Dependencies []string `json:"dependencies,omitempty"`
- Compositors []string `json:"compositors"`
- Distro []string `json:"distro"`
- Screenshot string `json:"screenshot,omitempty"`
-}
-
-type GitClient interface {
- PlainClone(path string, url string) error
- Pull(path string) error
- HasUpdates(path string) (bool, error)
-}
-
-type realGitClient struct{}
-
-func (g *realGitClient) PlainClone(path string, url string) error {
- _, err := git.PlainClone(path, &git.CloneOptions{
- URL: url,
- Progress: os.Stdout,
- })
- return err
-}
-
-func (g *realGitClient) Pull(path string) error {
- repo, err := git.PlainOpen(path)
- if err != nil {
- return err
- }
-
- worktree, err := repo.Worktree()
- if err != nil {
- return err
- }
-
- err = worktree.Pull(&git.PullOptions{})
- if err != nil && err.Error() != "already up-to-date" {
- return err
- }
-
- return nil
-}
-
-func (g *realGitClient) HasUpdates(path string) (bool, error) {
- repo, err := git.PlainOpen(path)
- if err != nil {
- return false, err
- }
-
- // Fetch remote changes
- err = repo.Fetch(&git.FetchOptions{})
- if err != nil && err.Error() != "already up-to-date" {
- // If fetch fails, we can't determine if there are updates
- // Return false and the error
- return false, err
- }
-
- // Get the HEAD reference
- head, err := repo.Head()
- if err != nil {
- return false, err
- }
-
- // Get the remote HEAD reference (typically origin/HEAD or origin/main or origin/master)
- remote, err := repo.Remote("origin")
- if err != nil {
- return false, err
- }
-
- refs, err := remote.List(&git.ListOptions{})
- if err != nil {
- return false, err
- }
-
- // Find the default branch remote ref
- var remoteHead string
- for _, ref := range refs {
- if ref.Name().IsBranch() {
- // Try common branch names
- if ref.Name().Short() == "main" || ref.Name().Short() == "master" {
- remoteHead = ref.Hash().String()
- break
- }
- }
- }
-
- // If we couldn't find a remote HEAD, assume no updates
- if remoteHead == "" {
- return false, nil
- }
-
- // Compare local HEAD with remote HEAD
- return head.Hash().String() != remoteHead, nil
-}
-
-type Registry struct {
- fs afero.Fs
- cacheDir string
- plugins []Plugin
- git GitClient
-}
-
-func NewRegistry() (*Registry, error) {
- return NewRegistryWithFs(afero.NewOsFs())
-}
-
-func NewRegistryWithFs(fs afero.Fs) (*Registry, error) {
- cacheDir := getCacheDir()
- return &Registry{
- fs: fs,
- cacheDir: cacheDir,
- git: &realGitClient{},
- }, nil
-}
-
-func getCacheDir() string {
- return filepath.Join(os.TempDir(), "dankdots-plugin-registry")
-}
-
-func (r *Registry) Update() error {
- exists, err := afero.DirExists(r.fs, r.cacheDir)
- if err != nil {
- return fmt.Errorf("failed to check cache directory: %w", err)
- }
-
- if !exists {
- if err := r.fs.MkdirAll(filepath.Dir(r.cacheDir), 0755); err != nil {
- return fmt.Errorf("failed to create cache directory: %w", err)
- }
-
- if err := r.git.PlainClone(r.cacheDir, registryRepo); err != nil {
- return fmt.Errorf("failed to clone registry: %w", err)
- }
- } else {
- // Try to pull, if it fails (e.g., shallow clone corruption), delete and re-clone
- if err := r.git.Pull(r.cacheDir); err != nil {
- // Repository is likely corrupted or has issues, delete and re-clone
- if err := r.fs.RemoveAll(r.cacheDir); err != nil {
- return fmt.Errorf("failed to remove corrupted registry: %w", err)
- }
-
- if err := r.fs.MkdirAll(filepath.Dir(r.cacheDir), 0755); err != nil {
- return fmt.Errorf("failed to create cache directory: %w", err)
- }
-
- if err := r.git.PlainClone(r.cacheDir, registryRepo); err != nil {
- return fmt.Errorf("failed to re-clone registry: %w", err)
- }
- }
- }
-
- return r.loadPlugins()
-}
-
-func (r *Registry) loadPlugins() error {
- pluginsDir := filepath.Join(r.cacheDir, "plugins")
-
- entries, err := afero.ReadDir(r.fs, pluginsDir)
- if err != nil {
- return fmt.Errorf("failed to read plugins directory: %w", err)
- }
-
- r.plugins = []Plugin{}
-
- for _, entry := range entries {
- if entry.IsDir() || filepath.Ext(entry.Name()) != ".json" {
- continue
- }
-
- data, err := afero.ReadFile(r.fs, filepath.Join(pluginsDir, entry.Name()))
- if err != nil {
- continue
- }
-
- var plugin Plugin
- if err := json.Unmarshal(data, &plugin); err != nil {
- continue
- }
-
- if plugin.ID == "" {
- plugin.ID = strings.TrimSuffix(entry.Name(), ".json")
- }
-
- r.plugins = append(r.plugins, plugin)
- }
-
- return nil
-}
-
-func (r *Registry) List() ([]Plugin, error) {
- if len(r.plugins) == 0 {
- if err := r.Update(); err != nil {
- return nil, err
- }
- }
-
- return SortByFirstParty(r.plugins), nil
-}
-
-func (r *Registry) Search(query string) ([]Plugin, error) {
- allPlugins, err := r.List()
- if err != nil {
- return nil, err
- }
-
- if query == "" {
- return allPlugins, nil
- }
-
- return SortByFirstParty(FuzzySearch(query, allPlugins)), nil
-}
-
-func (r *Registry) Get(idOrName string) (*Plugin, error) {
- plugins, err := r.List()
- if err != nil {
- return nil, err
- }
-
- // First, try to find by ID (preferred method)
- for _, p := range plugins {
- if p.ID == idOrName {
- return &p, nil
- }
- }
-
- // Fallback to name for backward compatibility
- for _, p := range plugins {
- if p.Name == idOrName {
- return &p, nil
- }
- }
-
- return nil, fmt.Errorf("plugin not found: %s", idOrName)
-}
diff --git a/nix/inputs/dms-cli/internal/plugins/registry_test.go b/nix/inputs/dms-cli/internal/plugins/registry_test.go
deleted file mode 100644
index 0abcacb..0000000
--- a/nix/inputs/dms-cli/internal/plugins/registry_test.go
+++ /dev/null
@@ -1,326 +0,0 @@
-package plugins
-
-import (
- "encoding/json"
- "path/filepath"
- "testing"
-
- "github.com/spf13/afero"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-type mockGitClient struct {
- cloneFunc func(path string, url string) error
- pullFunc func(path string) error
- hasUpdatesFunc func(path string) (bool, error)
-}
-
-func (m *mockGitClient) PlainClone(path string, url string) error {
- if m.cloneFunc != nil {
- return m.cloneFunc(path, url)
- }
- return nil
-}
-
-func (m *mockGitClient) Pull(path string) error {
- if m.pullFunc != nil {
- return m.pullFunc(path)
- }
- return nil
-}
-
-func (m *mockGitClient) HasUpdates(path string) (bool, error) {
- if m.hasUpdatesFunc != nil {
- return m.hasUpdatesFunc(path)
- }
- return false, nil
-}
-
-func TestNewRegistry(t *testing.T) {
- registry, err := NewRegistry()
- assert.NoError(t, err)
- assert.NotNil(t, registry)
- assert.NotEmpty(t, registry.cacheDir)
-}
-
-func TestGetCacheDir(t *testing.T) {
- cacheDir := getCacheDir()
- assert.Contains(t, cacheDir, "/tmp/dankdots-plugin-registry")
-}
-
-func setupTestRegistry(t *testing.T) (*Registry, afero.Fs, string) {
- fs := afero.NewMemMapFs()
- tmpDir := "/test-cache"
- registry := &Registry{
- fs: fs,
- cacheDir: tmpDir,
- plugins: []Plugin{},
- git: &mockGitClient{},
- }
- return registry, fs, tmpDir
-}
-
-func createTestPlugin(t *testing.T, fs afero.Fs, dir string, filename string, plugin Plugin) {
- pluginsDir := filepath.Join(dir, "plugins")
- err := fs.MkdirAll(pluginsDir, 0755)
- require.NoError(t, err)
-
- data, err := json.Marshal(plugin)
- require.NoError(t, err)
-
- err = afero.WriteFile(fs, filepath.Join(pluginsDir, filename), data, 0644)
- require.NoError(t, err)
-}
-
-func TestLoadPlugins(t *testing.T) {
- t.Run("loads valid plugin files", func(t *testing.T) {
- registry, fs, tmpDir := setupTestRegistry(t)
-
- plugin1 := Plugin{
- Name: "TestPlugin1",
- Capabilities: []string{"dankbar-widget"},
- Category: "monitoring",
- Repo: "https://github.com/test/plugin1",
- Author: "Test Author",
- Description: "Test plugin 1",
- Compositors: []string{"niri"},
- Distro: []string{"any"},
- }
-
- plugin2 := Plugin{
- Name: "TestPlugin2",
- Capabilities: []string{"system-tray"},
- Category: "utilities",
- Repo: "https://github.com/test/plugin2",
- Author: "Another Author",
- Description: "Test plugin 2",
- Dependencies: []string{"dep1", "dep2"},
- Compositors: []string{"hyprland", "niri"},
- Distro: []string{"arch"},
- Screenshot: "https://example.com/screenshot.png",
- }
-
- createTestPlugin(t, fs, tmpDir, "plugin1.json", plugin1)
- createTestPlugin(t, fs, tmpDir, "plugin2.json", plugin2)
-
- err := registry.loadPlugins()
- assert.NoError(t, err)
- assert.Len(t, registry.plugins, 2)
-
- assert.Equal(t, "TestPlugin1", registry.plugins[0].Name)
- assert.Equal(t, "TestPlugin2", registry.plugins[1].Name)
- assert.Equal(t, []string{"dankbar-widget"}, registry.plugins[0].Capabilities)
- assert.Equal(t, []string{"dep1", "dep2"}, registry.plugins[1].Dependencies)
- })
-
- t.Run("skips non-json files", func(t *testing.T) {
- registry, fs, tmpDir := setupTestRegistry(t)
-
- pluginsDir := filepath.Join(tmpDir, "plugins")
- err := fs.MkdirAll(pluginsDir, 0755)
- require.NoError(t, err)
-
- err = afero.WriteFile(fs, filepath.Join(pluginsDir, "README.md"), []byte("# Test"), 0644)
- require.NoError(t, err)
-
- plugin := Plugin{
- Name: "ValidPlugin",
- Capabilities: []string{"test"},
- Category: "test",
- Repo: "https://github.com/test/test",
- Author: "Test",
- Description: "Test",
- Compositors: []string{"niri"},
- Distro: []string{"any"},
- }
- createTestPlugin(t, fs, tmpDir, "valid.json", plugin)
-
- err = registry.loadPlugins()
- assert.NoError(t, err)
- assert.Len(t, registry.plugins, 1)
- assert.Equal(t, "ValidPlugin", registry.plugins[0].Name)
- })
-
- t.Run("skips directories", func(t *testing.T) {
- registry, fs, tmpDir := setupTestRegistry(t)
-
- pluginsDir := filepath.Join(tmpDir, "plugins")
- err := fs.MkdirAll(filepath.Join(pluginsDir, "subdir"), 0755)
- require.NoError(t, err)
-
- plugin := Plugin{
- Name: "ValidPlugin",
- Capabilities: []string{"test"},
- Category: "test",
- Repo: "https://github.com/test/test",
- Author: "Test",
- Description: "Test",
- Compositors: []string{"niri"},
- Distro: []string{"any"},
- }
- createTestPlugin(t, fs, tmpDir, "valid.json", plugin)
-
- err = registry.loadPlugins()
- assert.NoError(t, err)
- assert.Len(t, registry.plugins, 1)
- })
-
- t.Run("skips invalid json files", func(t *testing.T) {
- registry, fs, tmpDir := setupTestRegistry(t)
-
- pluginsDir := filepath.Join(tmpDir, "plugins")
- err := fs.MkdirAll(pluginsDir, 0755)
- require.NoError(t, err)
-
- err = afero.WriteFile(fs, filepath.Join(pluginsDir, "invalid.json"), []byte("{invalid json}"), 0644)
- require.NoError(t, err)
-
- plugin := Plugin{
- Name: "ValidPlugin",
- Capabilities: []string{"test"},
- Category: "test",
- Repo: "https://github.com/test/test",
- Author: "Test",
- Description: "Test",
- Compositors: []string{"niri"},
- Distro: []string{"any"},
- }
- createTestPlugin(t, fs, tmpDir, "valid.json", plugin)
-
- err = registry.loadPlugins()
- assert.NoError(t, err)
- assert.Len(t, registry.plugins, 1)
- assert.Equal(t, "ValidPlugin", registry.plugins[0].Name)
- })
-
- t.Run("returns error when plugins directory missing", func(t *testing.T) {
- registry, _, _ := setupTestRegistry(t)
-
- err := registry.loadPlugins()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "failed to read plugins directory")
- })
-}
-
-func TestList(t *testing.T) {
- t.Run("returns cached plugins if available", func(t *testing.T) {
- registry, _, _ := setupTestRegistry(t)
-
- plugin := Plugin{
- Name: "CachedPlugin",
- Capabilities: []string{"test"},
- Category: "test",
- Repo: "https://github.com/test/test",
- Author: "Test",
- Description: "Test",
- Compositors: []string{"niri"},
- Distro: []string{"any"},
- }
-
- registry.plugins = []Plugin{plugin}
-
- plugins, err := registry.List()
- assert.NoError(t, err)
- assert.Len(t, plugins, 1)
- assert.Equal(t, "CachedPlugin", plugins[0].Name)
- })
-
- t.Run("updates and loads plugins when cache is empty", func(t *testing.T) {
- registry, fs, _ := setupTestRegistry(t)
-
- plugin := Plugin{
- Name: "NewPlugin",
- Capabilities: []string{"test"},
- Category: "test",
- Repo: "https://github.com/test/test",
- Author: "Test",
- Description: "Test",
- Compositors: []string{"niri"},
- Distro: []string{"any"},
- }
-
- mockGit := &mockGitClient{
- cloneFunc: func(path string, url string) error {
- createTestPlugin(t, fs, path, "plugin.json", plugin)
- return nil
- },
- }
- registry.git = mockGit
-
- plugins, err := registry.List()
- assert.NoError(t, err)
- assert.Len(t, plugins, 1)
- assert.Equal(t, "NewPlugin", plugins[0].Name)
- })
-}
-
-func TestUpdate(t *testing.T) {
- t.Run("clones repository when cache doesn't exist", func(t *testing.T) {
- registry, fs, tmpDir := setupTestRegistry(t)
-
- plugin := Plugin{
- Name: "RepoPlugin",
- Capabilities: []string{"test"},
- Category: "test",
- Repo: "https://github.com/test/test",
- Author: "Test",
- Description: "Test",
- Compositors: []string{"niri"},
- Distro: []string{"any"},
- }
-
- cloneCalled := false
- mockGit := &mockGitClient{
- cloneFunc: func(path string, url string) error {
- cloneCalled = true
- assert.Equal(t, registryRepo, url)
- assert.Equal(t, tmpDir, path)
- createTestPlugin(t, fs, path, "plugin.json", plugin)
- return nil
- },
- }
- registry.git = mockGit
-
- err := registry.Update()
- assert.NoError(t, err)
- assert.True(t, cloneCalled)
- assert.Len(t, registry.plugins, 1)
- assert.Equal(t, "RepoPlugin", registry.plugins[0].Name)
- })
-
- t.Run("pulls updates when cache exists", func(t *testing.T) {
- registry, fs, tmpDir := setupTestRegistry(t)
-
- plugin := Plugin{
- Name: "UpdatedPlugin",
- Capabilities: []string{"test"},
- Category: "test",
- Repo: "https://github.com/test/test",
- Author: "Test",
- Description: "Test",
- Compositors: []string{"niri"},
- Distro: []string{"any"},
- }
-
- err := fs.MkdirAll(tmpDir, 0755)
- require.NoError(t, err)
-
- pullCalled := false
- mockGit := &mockGitClient{
- pullFunc: func(path string) error {
- pullCalled = true
- assert.Equal(t, tmpDir, path)
- createTestPlugin(t, fs, path, "plugin.json", plugin)
- return nil
- },
- }
- registry.git = mockGit
-
- err = registry.Update()
- assert.NoError(t, err)
- assert.True(t, pullCalled)
- assert.Len(t, registry.plugins, 1)
- assert.Equal(t, "UpdatedPlugin", registry.plugins[0].Name)
- })
-}
diff --git a/nix/inputs/dms-cli/internal/plugins/search.go b/nix/inputs/dms-cli/internal/plugins/search.go
deleted file mode 100644
index 0505180..0000000
--- a/nix/inputs/dms-cli/internal/plugins/search.go
+++ /dev/null
@@ -1,105 +0,0 @@
-package plugins
-
-import (
- "sort"
- "strings"
-)
-
-func FuzzySearch(query string, plugins []Plugin) []Plugin {
- if query == "" {
- return plugins
- }
-
- queryLower := strings.ToLower(query)
- var results []Plugin
-
- for _, plugin := range plugins {
- if fuzzyMatch(queryLower, strings.ToLower(plugin.Name)) ||
- fuzzyMatch(queryLower, strings.ToLower(plugin.Category)) ||
- fuzzyMatch(queryLower, strings.ToLower(plugin.Description)) ||
- fuzzyMatch(queryLower, strings.ToLower(plugin.Author)) {
- results = append(results, plugin)
- }
- }
-
- return results
-}
-
-func fuzzyMatch(query, text string) bool {
- queryIdx := 0
- for _, char := range text {
- if queryIdx < len(query) && char == rune(query[queryIdx]) {
- queryIdx++
- }
- }
- return queryIdx == len(query)
-}
-
-func FilterByCategory(category string, plugins []Plugin) []Plugin {
- if category == "" {
- return plugins
- }
-
- var results []Plugin
- categoryLower := strings.ToLower(category)
-
- for _, plugin := range plugins {
- if strings.ToLower(plugin.Category) == categoryLower {
- results = append(results, plugin)
- }
- }
-
- return results
-}
-
-func FilterByCompositor(compositor string, plugins []Plugin) []Plugin {
- if compositor == "" {
- return plugins
- }
-
- var results []Plugin
- compositorLower := strings.ToLower(compositor)
-
- for _, plugin := range plugins {
- for _, comp := range plugin.Compositors {
- if strings.ToLower(comp) == compositorLower {
- results = append(results, plugin)
- break
- }
- }
- }
-
- return results
-}
-
-func FilterByCapability(capability string, plugins []Plugin) []Plugin {
- if capability == "" {
- return plugins
- }
-
- var results []Plugin
- capabilityLower := strings.ToLower(capability)
-
- for _, plugin := range plugins {
- for _, cap := range plugin.Capabilities {
- if strings.ToLower(cap) == capabilityLower {
- results = append(results, plugin)
- break
- }
- }
- }
-
- return results
-}
-
-func SortByFirstParty(plugins []Plugin) []Plugin {
- sort.SliceStable(plugins, func(i, j int) bool {
- isFirstPartyI := strings.HasPrefix(plugins[i].Repo, "https://github.com/AvengeMedia")
- isFirstPartyJ := strings.HasPrefix(plugins[j].Repo, "https://github.com/AvengeMedia")
- if isFirstPartyI != isFirstPartyJ {
- return isFirstPartyI
- }
- return false
- })
- return plugins
-}
diff --git a/nix/inputs/dms-cli/internal/proto/dwl_ipc/dwl_ipc.go b/nix/inputs/dms-cli/internal/proto/dwl_ipc/dwl_ipc.go
deleted file mode 100644
index 65b590d..0000000
--- a/nix/inputs/dms-cli/internal/proto/dwl_ipc/dwl_ipc.go
+++ /dev/null
@@ -1,491 +0,0 @@
-// Generated by go-wayland-scanner
-// https://github.com/yaslama/go-wayland/cmd/go-wayland-scanner
-// XML file : internal/proto/xml/dwl-ipc-unstable-v2.xml
-//
-// dwl_ipc_unstable_v2 Protocol Copyright:
-
-package dwl_ipc
-
-import "github.com/yaslama/go-wayland/wayland/client"
-
-// ZdwlIpcManagerV2InterfaceName is the name of the interface as it appears in the [client.Registry].
-// It can be used to match the [client.RegistryGlobalEvent.Interface] in the
-// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies.
-const ZdwlIpcManagerV2InterfaceName = "zdwl_ipc_manager_v2"
-
-// ZdwlIpcManagerV2 : manage dwl state
-//
-// This interface is exposed as a global in wl_registry.
-//
-// Clients can use this interface to get a dwl_ipc_output.
-// After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events.
-// The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client.
-type ZdwlIpcManagerV2 struct {
- client.BaseProxy
- tagsHandler ZdwlIpcManagerV2TagsHandlerFunc
- layoutHandler ZdwlIpcManagerV2LayoutHandlerFunc
-}
-
-// NewZdwlIpcManagerV2 : manage dwl state
-//
-// This interface is exposed as a global in wl_registry.
-//
-// Clients can use this interface to get a dwl_ipc_output.
-// After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events.
-// The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client.
-func NewZdwlIpcManagerV2(ctx *client.Context) *ZdwlIpcManagerV2 {
- zdwlIpcManagerV2 := &ZdwlIpcManagerV2{}
- ctx.Register(zdwlIpcManagerV2)
- return zdwlIpcManagerV2
-}
-
-// Release : release dwl_ipc_manager
-//
-// Indicates that the client will not the dwl_ipc_manager object anymore.
-// Objects created through this instance are not affected.
-func (i *ZdwlIpcManagerV2) Release() error {
- defer i.Context().Unregister(i)
- const opcode = 0
- const _reqBufLen = 8
- var _reqBuf [_reqBufLen]byte
- l := 0
- client.PutUint32(_reqBuf[l:4], i.ID())
- l += 4
- client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
- l += 4
- err := i.Context().WriteMsg(_reqBuf[:], nil)
- return err
-}
-
-// GetOutput : get a dwl_ipc_outout for a wl_output
-//
-// Get a dwl_ipc_outout for the specified wl_output.
-func (i *ZdwlIpcManagerV2) GetOutput(output *client.Output) (*ZdwlIpcOutputV2, error) {
- id := NewZdwlIpcOutputV2(i.Context())
- const opcode = 1
- const _reqBufLen = 8 + 4 + 4
- var _reqBuf [_reqBufLen]byte
- l := 0
- client.PutUint32(_reqBuf[l:4], i.ID())
- l += 4
- client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
- l += 4
- client.PutUint32(_reqBuf[l:l+4], id.ID())
- l += 4
- client.PutUint32(_reqBuf[l:l+4], output.ID())
- l += 4
- err := i.Context().WriteMsg(_reqBuf[:], nil)
- return id, err
-}
-
-// ZdwlIpcManagerV2TagsEvent : Announces tag amount
-//
-// This event is sent after binding.
-// A roundtrip after binding guarantees the client recieved all tags.
-type ZdwlIpcManagerV2TagsEvent struct {
- Amount uint32
-}
-type ZdwlIpcManagerV2TagsHandlerFunc func(ZdwlIpcManagerV2TagsEvent)
-
-// SetTagsHandler : sets handler for ZdwlIpcManagerV2TagsEvent
-func (i *ZdwlIpcManagerV2) SetTagsHandler(f ZdwlIpcManagerV2TagsHandlerFunc) {
- i.tagsHandler = f
-}
-
-// ZdwlIpcManagerV2LayoutEvent : Announces a layout
-//
-// This event is sent after binding.
-// A roundtrip after binding guarantees the client recieved all layouts.
-type ZdwlIpcManagerV2LayoutEvent struct {
- Name string
-}
-type ZdwlIpcManagerV2LayoutHandlerFunc func(ZdwlIpcManagerV2LayoutEvent)
-
-// SetLayoutHandler : sets handler for ZdwlIpcManagerV2LayoutEvent
-func (i *ZdwlIpcManagerV2) SetLayoutHandler(f ZdwlIpcManagerV2LayoutHandlerFunc) {
- i.layoutHandler = f
-}
-
-func (i *ZdwlIpcManagerV2) Dispatch(opcode uint32, fd int, data []byte) {
- switch opcode {
- case 0:
- if i.tagsHandler == nil {
- return
- }
- var e ZdwlIpcManagerV2TagsEvent
- l := 0
- e.Amount = client.Uint32(data[l : l+4])
- l += 4
-
- i.tagsHandler(e)
- case 1:
- if i.layoutHandler == nil {
- return
- }
- var e ZdwlIpcManagerV2LayoutEvent
- l := 0
- nameLen := client.PaddedLen(int(client.Uint32(data[l : l+4])))
- l += 4
- e.Name = client.String(data[l : l+nameLen])
- l += nameLen
-
- i.layoutHandler(e)
- }
-}
-
-// ZdwlIpcOutputV2InterfaceName is the name of the interface as it appears in the [client.Registry].
-// It can be used to match the [client.RegistryGlobalEvent.Interface] in the
-// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies.
-const ZdwlIpcOutputV2InterfaceName = "zdwl_ipc_output_v2"
-
-// ZdwlIpcOutputV2 : control dwl output
-//
-// Observe and control a dwl output.
-//
-// Events are double-buffered:
-// Clients should cache events and redraw when a dwl_ipc_output.frame event is sent.
-//
-// Request are not double-buffered:
-// The compositor will update immediately upon request.
-type ZdwlIpcOutputV2 struct {
- client.BaseProxy
- toggleVisibilityHandler ZdwlIpcOutputV2ToggleVisibilityHandlerFunc
- activeHandler ZdwlIpcOutputV2ActiveHandlerFunc
- tagHandler ZdwlIpcOutputV2TagHandlerFunc
- layoutHandler ZdwlIpcOutputV2LayoutHandlerFunc
- titleHandler ZdwlIpcOutputV2TitleHandlerFunc
- appidHandler ZdwlIpcOutputV2AppidHandlerFunc
- layoutSymbolHandler ZdwlIpcOutputV2LayoutSymbolHandlerFunc
- frameHandler ZdwlIpcOutputV2FrameHandlerFunc
-}
-
-// NewZdwlIpcOutputV2 : control dwl output
-//
-// Observe and control a dwl output.
-//
-// Events are double-buffered:
-// Clients should cache events and redraw when a dwl_ipc_output.frame event is sent.
-//
-// Request are not double-buffered:
-// The compositor will update immediately upon request.
-func NewZdwlIpcOutputV2(ctx *client.Context) *ZdwlIpcOutputV2 {
- zdwlIpcOutputV2 := &ZdwlIpcOutputV2{}
- ctx.Register(zdwlIpcOutputV2)
- return zdwlIpcOutputV2
-}
-
-// Release : release dwl_ipc_outout
-//
-// Indicates to that the client no longer needs this dwl_ipc_output.
-func (i *ZdwlIpcOutputV2) Release() error {
- defer i.Context().Unregister(i)
- const opcode = 0
- const _reqBufLen = 8
- var _reqBuf [_reqBufLen]byte
- l := 0
- client.PutUint32(_reqBuf[l:4], i.ID())
- l += 4
- client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
- l += 4
- err := i.Context().WriteMsg(_reqBuf[:], nil)
- return err
-}
-
-// SetTags : Set the active tags of this output
-//
-// tagmask: bitmask of the tags that should be set.
-// toggleTagset: toggle the selected tagset, zero for invalid, nonzero for valid.
-func (i *ZdwlIpcOutputV2) SetTags(tagmask, toggleTagset uint32) error {
- const opcode = 1
- const _reqBufLen = 8 + 4 + 4
- var _reqBuf [_reqBufLen]byte
- l := 0
- client.PutUint32(_reqBuf[l:4], i.ID())
- l += 4
- client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
- l += 4
- client.PutUint32(_reqBuf[l:l+4], uint32(tagmask))
- l += 4
- client.PutUint32(_reqBuf[l:l+4], uint32(toggleTagset))
- l += 4
- err := i.Context().WriteMsg(_reqBuf[:], nil)
- return err
-}
-
-// SetClientTags : Set the tags of the focused client.
-//
-// The tags are updated as follows:
-// new_tags = (current_tags AND and_tags) XOR xor_tags
-func (i *ZdwlIpcOutputV2) SetClientTags(andTags, xorTags uint32) error {
- const opcode = 2
- const _reqBufLen = 8 + 4 + 4
- var _reqBuf [_reqBufLen]byte
- l := 0
- client.PutUint32(_reqBuf[l:4], i.ID())
- l += 4
- client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
- l += 4
- client.PutUint32(_reqBuf[l:l+4], uint32(andTags))
- l += 4
- client.PutUint32(_reqBuf[l:l+4], uint32(xorTags))
- l += 4
- err := i.Context().WriteMsg(_reqBuf[:], nil)
- return err
-}
-
-// SetLayout : Set the layout of this output
-//
-// index: index of a layout recieved by dwl_ipc_manager.layout
-func (i *ZdwlIpcOutputV2) SetLayout(index uint32) error {
- const opcode = 3
- const _reqBufLen = 8 + 4
- var _reqBuf [_reqBufLen]byte
- l := 0
- client.PutUint32(_reqBuf[l:4], i.ID())
- l += 4
- client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
- l += 4
- client.PutUint32(_reqBuf[l:l+4], uint32(index))
- l += 4
- err := i.Context().WriteMsg(_reqBuf[:], nil)
- return err
-}
-
-type ZdwlIpcOutputV2TagState uint32
-
-// ZdwlIpcOutputV2TagState :
-const (
- // ZdwlIpcOutputV2TagStateNone : no state
- ZdwlIpcOutputV2TagStateNone ZdwlIpcOutputV2TagState = 0
- // ZdwlIpcOutputV2TagStateActive : tag is active
- ZdwlIpcOutputV2TagStateActive ZdwlIpcOutputV2TagState = 1
- // ZdwlIpcOutputV2TagStateUrgent : tag has at least one urgent client
- ZdwlIpcOutputV2TagStateUrgent ZdwlIpcOutputV2TagState = 2
-)
-
-func (e ZdwlIpcOutputV2TagState) Name() string {
- switch e {
- case ZdwlIpcOutputV2TagStateNone:
- return "none"
- case ZdwlIpcOutputV2TagStateActive:
- return "active"
- case ZdwlIpcOutputV2TagStateUrgent:
- return "urgent"
- default:
- return ""
- }
-}
-
-func (e ZdwlIpcOutputV2TagState) Value() string {
- switch e {
- case ZdwlIpcOutputV2TagStateNone:
- return "0"
- case ZdwlIpcOutputV2TagStateActive:
- return "1"
- case ZdwlIpcOutputV2TagStateUrgent:
- return "2"
- default:
- return ""
- }
-}
-
-func (e ZdwlIpcOutputV2TagState) String() string {
- return e.Name() + "=" + e.Value()
-}
-
-// ZdwlIpcOutputV2ToggleVisibilityEvent : Toggle client visibilty
-//
-// Indicates the client should hide or show themselves.
-// If the client is visible then hide, if hidden then show.
-type ZdwlIpcOutputV2ToggleVisibilityEvent struct{}
-type ZdwlIpcOutputV2ToggleVisibilityHandlerFunc func(ZdwlIpcOutputV2ToggleVisibilityEvent)
-
-// SetToggleVisibilityHandler : sets handler for ZdwlIpcOutputV2ToggleVisibilityEvent
-func (i *ZdwlIpcOutputV2) SetToggleVisibilityHandler(f ZdwlIpcOutputV2ToggleVisibilityHandlerFunc) {
- i.toggleVisibilityHandler = f
-}
-
-// ZdwlIpcOutputV2ActiveEvent : Update the selected output.
-//
-// Indicates if the output is active. Zero is invalid, nonzero is valid.
-type ZdwlIpcOutputV2ActiveEvent struct {
- Active uint32
-}
-type ZdwlIpcOutputV2ActiveHandlerFunc func(ZdwlIpcOutputV2ActiveEvent)
-
-// SetActiveHandler : sets handler for ZdwlIpcOutputV2ActiveEvent
-func (i *ZdwlIpcOutputV2) SetActiveHandler(f ZdwlIpcOutputV2ActiveHandlerFunc) {
- i.activeHandler = f
-}
-
-// ZdwlIpcOutputV2TagEvent : Update the state of a tag.
-//
-// Indicates that a tag has been updated.
-type ZdwlIpcOutputV2TagEvent struct {
- Tag uint32
- State uint32
- Clients uint32
- Focused uint32
-}
-type ZdwlIpcOutputV2TagHandlerFunc func(ZdwlIpcOutputV2TagEvent)
-
-// SetTagHandler : sets handler for ZdwlIpcOutputV2TagEvent
-func (i *ZdwlIpcOutputV2) SetTagHandler(f ZdwlIpcOutputV2TagHandlerFunc) {
- i.tagHandler = f
-}
-
-// ZdwlIpcOutputV2LayoutEvent : Update the layout.
-//
-// Indicates a new layout is selected.
-type ZdwlIpcOutputV2LayoutEvent struct {
- Layout uint32
-}
-type ZdwlIpcOutputV2LayoutHandlerFunc func(ZdwlIpcOutputV2LayoutEvent)
-
-// SetLayoutHandler : sets handler for ZdwlIpcOutputV2LayoutEvent
-func (i *ZdwlIpcOutputV2) SetLayoutHandler(f ZdwlIpcOutputV2LayoutHandlerFunc) {
- i.layoutHandler = f
-}
-
-// ZdwlIpcOutputV2TitleEvent : Update the title.
-//
-// Indicates the title has changed.
-type ZdwlIpcOutputV2TitleEvent struct {
- Title string
-}
-type ZdwlIpcOutputV2TitleHandlerFunc func(ZdwlIpcOutputV2TitleEvent)
-
-// SetTitleHandler : sets handler for ZdwlIpcOutputV2TitleEvent
-func (i *ZdwlIpcOutputV2) SetTitleHandler(f ZdwlIpcOutputV2TitleHandlerFunc) {
- i.titleHandler = f
-}
-
-// ZdwlIpcOutputV2AppidEvent : Update the appid.
-//
-// Indicates the appid has changed.
-type ZdwlIpcOutputV2AppidEvent struct {
- Appid string
-}
-type ZdwlIpcOutputV2AppidHandlerFunc func(ZdwlIpcOutputV2AppidEvent)
-
-// SetAppidHandler : sets handler for ZdwlIpcOutputV2AppidEvent
-func (i *ZdwlIpcOutputV2) SetAppidHandler(f ZdwlIpcOutputV2AppidHandlerFunc) {
- i.appidHandler = f
-}
-
-// ZdwlIpcOutputV2LayoutSymbolEvent : Update the current layout symbol
-//
-// Indicates the layout has changed. Since layout symbols are dynamic.
-// As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying.
-// You can ignore the zdwl_ipc_output.layout event.
-type ZdwlIpcOutputV2LayoutSymbolEvent struct {
- Layout string
-}
-type ZdwlIpcOutputV2LayoutSymbolHandlerFunc func(ZdwlIpcOutputV2LayoutSymbolEvent)
-
-// SetLayoutSymbolHandler : sets handler for ZdwlIpcOutputV2LayoutSymbolEvent
-func (i *ZdwlIpcOutputV2) SetLayoutSymbolHandler(f ZdwlIpcOutputV2LayoutSymbolHandlerFunc) {
- i.layoutSymbolHandler = f
-}
-
-// ZdwlIpcOutputV2FrameEvent : The update sequence is done.
-//
-// Indicates that a sequence of status updates have finished and the client should redraw.
-type ZdwlIpcOutputV2FrameEvent struct{}
-type ZdwlIpcOutputV2FrameHandlerFunc func(ZdwlIpcOutputV2FrameEvent)
-
-// SetFrameHandler : sets handler for ZdwlIpcOutputV2FrameEvent
-func (i *ZdwlIpcOutputV2) SetFrameHandler(f ZdwlIpcOutputV2FrameHandlerFunc) {
- i.frameHandler = f
-}
-
-func (i *ZdwlIpcOutputV2) Dispatch(opcode uint32, fd int, data []byte) {
- switch opcode {
- case 0:
- if i.toggleVisibilityHandler == nil {
- return
- }
- var e ZdwlIpcOutputV2ToggleVisibilityEvent
-
- i.toggleVisibilityHandler(e)
- case 1:
- if i.activeHandler == nil {
- return
- }
- var e ZdwlIpcOutputV2ActiveEvent
- l := 0
- e.Active = client.Uint32(data[l : l+4])
- l += 4
-
- i.activeHandler(e)
- case 2:
- if i.tagHandler == nil {
- return
- }
- var e ZdwlIpcOutputV2TagEvent
- l := 0
- e.Tag = client.Uint32(data[l : l+4])
- l += 4
- e.State = client.Uint32(data[l : l+4])
- l += 4
- e.Clients = client.Uint32(data[l : l+4])
- l += 4
- e.Focused = client.Uint32(data[l : l+4])
- l += 4
-
- i.tagHandler(e)
- case 3:
- if i.layoutHandler == nil {
- return
- }
- var e ZdwlIpcOutputV2LayoutEvent
- l := 0
- e.Layout = client.Uint32(data[l : l+4])
- l += 4
-
- i.layoutHandler(e)
- case 4:
- if i.titleHandler == nil {
- return
- }
- var e ZdwlIpcOutputV2TitleEvent
- l := 0
- titleLen := client.PaddedLen(int(client.Uint32(data[l : l+4])))
- l += 4
- e.Title = client.String(data[l : l+titleLen])
- l += titleLen
-
- i.titleHandler(e)
- case 5:
- if i.appidHandler == nil {
- return
- }
- var e ZdwlIpcOutputV2AppidEvent
- l := 0
- appidLen := client.PaddedLen(int(client.Uint32(data[l : l+4])))
- l += 4
- e.Appid = client.String(data[l : l+appidLen])
- l += appidLen
-
- i.appidHandler(e)
- case 6:
- if i.layoutSymbolHandler == nil {
- return
- }
- var e ZdwlIpcOutputV2LayoutSymbolEvent
- l := 0
- layoutLen := client.PaddedLen(int(client.Uint32(data[l : l+4])))
- l += 4
- e.Layout = client.String(data[l : l+layoutLen])
- l += layoutLen
-
- i.layoutSymbolHandler(e)
- case 7:
- if i.frameHandler == nil {
- return
- }
- var e ZdwlIpcOutputV2FrameEvent
-
- i.frameHandler(e)
- }
-}
diff --git a/nix/inputs/dms-cli/internal/proto/wlr_gamma_control/gamma_control.go b/nix/inputs/dms-cli/internal/proto/wlr_gamma_control/gamma_control.go
deleted file mode 100644
index 63e1b6a..0000000
--- a/nix/inputs/dms-cli/internal/proto/wlr_gamma_control/gamma_control.go
+++ /dev/null
@@ -1,268 +0,0 @@
-// Generated by go-wayland-scanner
-// https://github.com/yaslama/go-wayland/cmd/go-wayland-scanner
-// XML file : wayland-protocols/wlr-gamma-control-unstable-v1.xml
-//
-// wlr_gamma_control_unstable_v1 Protocol Copyright:
-//
-// Copyright © 2015 Giulio camuffo
-// Copyright © 2018 Simon Ser
-//
-// Permission to use, copy, modify, distribute, and sell this
-// software and its documentation for any purpose is hereby granted
-// without fee, provided that the above copyright notice appear in
-// all copies and that both that copyright notice and this permission
-// notice appear in supporting documentation, and that the name of
-// the copyright holders not be used in advertising or publicity
-// pertaining to distribution of the software without specific,
-// written prior permission. The copyright holders make no
-// representations about the suitability of this software for any
-// purpose. It is provided "as is" without express or implied
-// warranty.
-//
-// THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
-// SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-// FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
-// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
-// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
-// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
-// THIS SOFTWARE.
-
-package wlr_gamma_control
-
-import (
- "github.com/yaslama/go-wayland/wayland/client"
- "golang.org/x/sys/unix"
-)
-
-// ZwlrGammaControlManagerV1InterfaceName is the name of the interface as it appears in the [client.Registry].
-// It can be used to match the [client.RegistryGlobalEvent.Interface] in the
-// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies.
-const ZwlrGammaControlManagerV1InterfaceName = "zwlr_gamma_control_manager_v1"
-
-// ZwlrGammaControlManagerV1 : manager to create per-output gamma controls
-//
-// This interface is a manager that allows creating per-output gamma
-// controls.
-type ZwlrGammaControlManagerV1 struct {
- client.BaseProxy
-}
-
-// NewZwlrGammaControlManagerV1 : manager to create per-output gamma controls
-//
-// This interface is a manager that allows creating per-output gamma
-// controls.
-func NewZwlrGammaControlManagerV1(ctx *client.Context) *ZwlrGammaControlManagerV1 {
- zwlrGammaControlManagerV1 := &ZwlrGammaControlManagerV1{}
- ctx.Register(zwlrGammaControlManagerV1)
- return zwlrGammaControlManagerV1
-}
-
-// GetGammaControl : get a gamma control for an output
-//
-// Create a gamma control that can be used to adjust gamma tables for the
-// provided output.
-func (i *ZwlrGammaControlManagerV1) GetGammaControl(output *client.Output) (*ZwlrGammaControlV1, error) {
- id := NewZwlrGammaControlV1(i.Context())
- const opcode = 0
- const _reqBufLen = 8 + 4 + 4
- var _reqBuf [_reqBufLen]byte
- l := 0
- client.PutUint32(_reqBuf[l:4], i.ID())
- l += 4
- client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
- l += 4
- client.PutUint32(_reqBuf[l:l+4], id.ID())
- l += 4
- client.PutUint32(_reqBuf[l:l+4], output.ID())
- l += 4
- err := i.Context().WriteMsg(_reqBuf[:], nil)
- return id, err
-}
-
-// Destroy : destroy the manager
-//
-// All objects created by the manager will still remain valid, until their
-// appropriate destroy request has been called.
-func (i *ZwlrGammaControlManagerV1) Destroy() error {
- defer i.Context().Unregister(i)
- const opcode = 1
- const _reqBufLen = 8
- var _reqBuf [_reqBufLen]byte
- l := 0
- client.PutUint32(_reqBuf[l:4], i.ID())
- l += 4
- client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
- l += 4
- err := i.Context().WriteMsg(_reqBuf[:], nil)
- return err
-}
-
-// ZwlrGammaControlV1InterfaceName is the name of the interface as it appears in the [client.Registry].
-// It can be used to match the [client.RegistryGlobalEvent.Interface] in the
-// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies.
-const ZwlrGammaControlV1InterfaceName = "zwlr_gamma_control_v1"
-
-// ZwlrGammaControlV1 : adjust gamma tables for an output
-//
-// This interface allows a client to adjust gamma tables for a particular
-// output.
-//
-// The client will receive the gamma size, and will then be able to set gamma
-// tables. At any time the compositor can send a failed event indicating that
-// this object is no longer valid.
-//
-// There can only be at most one gamma control object per output, which
-// has exclusive access to this particular output. When the gamma control
-// object is destroyed, the gamma table is restored to its original value.
-type ZwlrGammaControlV1 struct {
- client.BaseProxy
- gammaSizeHandler ZwlrGammaControlV1GammaSizeHandlerFunc
- failedHandler ZwlrGammaControlV1FailedHandlerFunc
-}
-
-// NewZwlrGammaControlV1 : adjust gamma tables for an output
-//
-// This interface allows a client to adjust gamma tables for a particular
-// output.
-//
-// The client will receive the gamma size, and will then be able to set gamma
-// tables. At any time the compositor can send a failed event indicating that
-// this object is no longer valid.
-//
-// There can only be at most one gamma control object per output, which
-// has exclusive access to this particular output. When the gamma control
-// object is destroyed, the gamma table is restored to its original value.
-func NewZwlrGammaControlV1(ctx *client.Context) *ZwlrGammaControlV1 {
- zwlrGammaControlV1 := &ZwlrGammaControlV1{}
- ctx.Register(zwlrGammaControlV1)
- return zwlrGammaControlV1
-}
-
-// SetGamma : set the gamma table
-//
-// Set the gamma table. The file descriptor can be memory-mapped to provide
-// the raw gamma table, which contains successive gamma ramps for the red,
-// green and blue channels. Each gamma ramp is an array of 16-byte unsigned
-// integers which has the same length as the gamma size.
-//
-// The file descriptor data must have the same length as three times the
-// gamma size.
-//
-// fd: gamma table file descriptor
-func (i *ZwlrGammaControlV1) SetGamma(fd int) error {
- const opcode = 0
- const _reqBufLen = 8
- var _reqBuf [_reqBufLen]byte
- l := 0
- client.PutUint32(_reqBuf[l:4], i.ID())
- l += 4
- client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
- l += 4
- oob := unix.UnixRights(int(fd))
- err := i.Context().WriteMsg(_reqBuf[:], oob)
- return err
-}
-
-// Destroy : destroy this control
-//
-// Destroys the gamma control object. If the object is still valid, this
-// restores the original gamma tables.
-func (i *ZwlrGammaControlV1) Destroy() error {
- defer i.Context().Unregister(i)
- const opcode = 1
- const _reqBufLen = 8
- var _reqBuf [_reqBufLen]byte
- l := 0
- client.PutUint32(_reqBuf[l:4], i.ID())
- l += 4
- client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
- l += 4
- err := i.Context().WriteMsg(_reqBuf[:], nil)
- return err
-}
-
-type ZwlrGammaControlV1Error uint32
-
-// ZwlrGammaControlV1Error :
-const (
- // ZwlrGammaControlV1ErrorInvalidGamma : invalid gamma tables
- ZwlrGammaControlV1ErrorInvalidGamma ZwlrGammaControlV1Error = 1
-)
-
-func (e ZwlrGammaControlV1Error) Name() string {
- switch e {
- case ZwlrGammaControlV1ErrorInvalidGamma:
- return "invalid_gamma"
- default:
- return ""
- }
-}
-
-func (e ZwlrGammaControlV1Error) Value() string {
- switch e {
- case ZwlrGammaControlV1ErrorInvalidGamma:
- return "1"
- default:
- return ""
- }
-}
-
-func (e ZwlrGammaControlV1Error) String() string {
- return e.Name() + "=" + e.Value()
-}
-
-// ZwlrGammaControlV1GammaSizeEvent : size of gamma ramps
-//
-// Advertise the size of each gamma ramp.
-//
-// This event is sent immediately when the gamma control object is created.
-type ZwlrGammaControlV1GammaSizeEvent struct {
- Size uint32
-}
-type ZwlrGammaControlV1GammaSizeHandlerFunc func(ZwlrGammaControlV1GammaSizeEvent)
-
-// SetGammaSizeHandler : sets handler for ZwlrGammaControlV1GammaSizeEvent
-func (i *ZwlrGammaControlV1) SetGammaSizeHandler(f ZwlrGammaControlV1GammaSizeHandlerFunc) {
- i.gammaSizeHandler = f
-}
-
-// ZwlrGammaControlV1FailedEvent : object no longer valid
-//
-// This event indicates that the gamma control is no longer valid. This
-// can happen for a number of reasons, including:
-// - The output doesn't support gamma tables
-// - Setting the gamma tables failed
-// - Another client already has exclusive gamma control for this output
-// - The compositor has transferred gamma control to another client
-//
-// Upon receiving this event, the client should destroy this object.
-type ZwlrGammaControlV1FailedEvent struct{}
-type ZwlrGammaControlV1FailedHandlerFunc func(ZwlrGammaControlV1FailedEvent)
-
-// SetFailedHandler : sets handler for ZwlrGammaControlV1FailedEvent
-func (i *ZwlrGammaControlV1) SetFailedHandler(f ZwlrGammaControlV1FailedHandlerFunc) {
- i.failedHandler = f
-}
-
-func (i *ZwlrGammaControlV1) Dispatch(opcode uint32, fd int, data []byte) {
- switch opcode {
- case 0:
- if i.gammaSizeHandler == nil {
- return
- }
- var e ZwlrGammaControlV1GammaSizeEvent
- l := 0
- e.Size = client.Uint32(data[l : l+4])
- l += 4
-
- i.gammaSizeHandler(e)
- case 1:
- if i.failedHandler == nil {
- return
- }
- var e ZwlrGammaControlV1FailedEvent
-
- i.failedHandler(e)
- }
-}
diff --git a/nix/inputs/dms-cli/internal/proto/xml/dwl-ipc-unstable-v2.xml b/nix/inputs/dms-cli/internal/proto/xml/dwl-ipc-unstable-v2.xml
deleted file mode 100644
index 74a212f..0000000
--- a/nix/inputs/dms-cli/internal/proto/xml/dwl-ipc-unstable-v2.xml
+++ /dev/null
@@ -1,166 +0,0 @@
-
-
-
-
- This protocol allows clients to update and get updates from dwl.
-
- Warning! The protocol described in this file is experimental and
- backward incompatible changes may be made. Backward compatible
- changes may be added together with the corresponding interface
- version bump.
- Backward incompatible changes are done by bumping the version
- number in the protocol and interface names and resetting the
- interface version. Once the protocol is to be declared stable,
- the 'z' prefix and the version number in the protocol and
- interface names are removed and the interface version number is
- reset.
-
-
-
-
- This interface is exposed as a global in wl_registry.
-
- Clients can use this interface to get a dwl_ipc_output.
- After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events.
- The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client.
-
-
-
-
- Indicates that the client will not the dwl_ipc_manager object anymore.
- Objects created through this instance are not affected.
-
-
-
-
-
- Get a dwl_ipc_outout for the specified wl_output.
-
-
-
-
-
-
-
- This event is sent after binding.
- A roundtrip after binding guarantees the client recieved all tags.
-
-
-
-
-
-
- This event is sent after binding.
- A roundtrip after binding guarantees the client recieved all layouts.
-
-
-
-
-
-
-
- Observe and control a dwl output.
-
- Events are double-buffered:
- Clients should cache events and redraw when a dwl_ipc_output.frame event is sent.
-
- Request are not double-buffered:
- The compositor will update immediately upon request.
-
-
-
-
-
-
-
-
-
-
- Indicates to that the client no longer needs this dwl_ipc_output.
-
-
-
-
-
- Indicates the client should hide or show themselves.
- If the client is visible then hide, if hidden then show.
-
-
-
-
-
- Indicates if the output is active. Zero is invalid, nonzero is valid.
-
-
-
-
-
-
- Indicates that a tag has been updated.
-
-
-
-
-
-
-
-
-
- Indicates a new layout is selected.
-
-
-
-
-
-
- Indicates the title has changed.
-
-
-
-
-
-
- Indicates the appid has changed.
-
-
-
-
-
-
- Indicates the layout has changed. Since layout symbols are dynamic.
- As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying.
- You can ignore the zdwl_ipc_output.layout event.
-
-
-
-
-
-
- Indicates that a sequence of status updates have finished and the client should redraw.
-
-
-
-
-
-
-
-
-
-
-
- The tags are updated as follows:
- new_tags = (current_tags AND and_tags) XOR xor_tags
-
-
-
-
-
-
-
-
-
-
-
diff --git a/nix/inputs/dms-cli/internal/proto/xml/wlr-gamma-control-unstable-v1.xml b/nix/inputs/dms-cli/internal/proto/xml/wlr-gamma-control-unstable-v1.xml
deleted file mode 100644
index 16e0be8..0000000
--- a/nix/inputs/dms-cli/internal/proto/xml/wlr-gamma-control-unstable-v1.xml
+++ /dev/null
@@ -1,126 +0,0 @@
-
-
-
- Copyright © 2015 Giulio camuffo
- Copyright © 2018 Simon Ser
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, provided that the above copyright notice appear in
- all copies and that both that copyright notice and this permission
- notice appear in supporting documentation, and that the name of
- the copyright holders not be used in advertising or publicity
- pertaining to distribution of the software without specific,
- written prior permission. The copyright holders make no
- representations about the suitability of this software for any
- purpose. It is provided "as is" without express or implied
- warranty.
-
- THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
- SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
- AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
- THIS SOFTWARE.
-
-
-
- This protocol allows a privileged client to set the gamma tables for
- outputs.
-
- Warning! The protocol described in this file is experimental and
- backward incompatible changes may be made. Backward compatible changes
- may be added together with the corresponding interface version bump.
- Backward incompatible changes are done by bumping the version number in
- the protocol and interface names and resetting the interface version.
- Once the protocol is to be declared stable, the 'z' prefix and the
- version number in the protocol and interface names are removed and the
- interface version number is reset.
-
-
-
-
- This interface is a manager that allows creating per-output gamma
- controls.
-
-
-
-
- Create a gamma control that can be used to adjust gamma tables for the
- provided output.
-
-
-
-
-
-
-
- All objects created by the manager will still remain valid, until their
- appropriate destroy request has been called.
-
-
-
-
-
-
- This interface allows a client to adjust gamma tables for a particular
- output.
-
- The client will receive the gamma size, and will then be able to set gamma
- tables. At any time the compositor can send a failed event indicating that
- this object is no longer valid.
-
- There can only be at most one gamma control object per output, which
- has exclusive access to this particular output. When the gamma control
- object is destroyed, the gamma table is restored to its original value.
-
-
-
-
- Advertise the size of each gamma ramp.
-
- This event is sent immediately when the gamma control object is created.
-
-
-
-
-
-
-
-
-
-
- Set the gamma table. The file descriptor can be memory-mapped to provide
- the raw gamma table, which contains successive gamma ramps for the red,
- green and blue channels. Each gamma ramp is an array of 16-byte unsigned
- integers which has the same length as the gamma size.
-
- The file descriptor data must have the same length as three times the
- gamma size.
-
-
-
-
-
-
- This event indicates that the gamma control is no longer valid. This
- can happen for a number of reasons, including:
- - The output doesn't support gamma tables
- - Setting the gamma tables failed
- - Another client already has exclusive gamma control for this output
- - The compositor has transferred gamma control to another client
-
- Upon receiving this event, the client should destroy this object.
-
-
-
-
-
- Destroys the gamma control object. If the object is still valid, this
- restores the original gamma tables.
-
-
-
-
diff --git a/nix/inputs/dms-cli/internal/server/bluez/agent.go b/nix/inputs/dms-cli/internal/server/bluez/agent.go
deleted file mode 100644
index 591e820..0000000
--- a/nix/inputs/dms-cli/internal/server/bluez/agent.go
+++ /dev/null
@@ -1,341 +0,0 @@
-package bluez
-
-import (
- "context"
- "errors"
- "fmt"
- "strconv"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/errdefs"
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/godbus/dbus/v5"
-)
-
-const (
- bluezService = "org.bluez"
- agentManagerPath = "/org/bluez"
- agentManagerIface = "org.bluez.AgentManager1"
- agent1Iface = "org.bluez.Agent1"
- device1Iface = "org.bluez.Device1"
- agentPath = "/com/danklinux/bluez/agent"
- agentCapability = "KeyboardDisplay"
-)
-
-const introspectXML = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`
-
-type BluezAgent struct {
- conn *dbus.Conn
- broker PromptBroker
-}
-
-func NewBluezAgent(broker PromptBroker) (*BluezAgent, error) {
- conn, err := dbus.ConnectSystemBus()
- if err != nil {
- return nil, fmt.Errorf("system bus connection failed: %w", err)
- }
-
- agent := &BluezAgent{
- conn: conn,
- broker: broker,
- }
-
- if err := conn.Export(agent, dbus.ObjectPath(agentPath), agent1Iface); err != nil {
- conn.Close()
- return nil, fmt.Errorf("agent export failed: %w", err)
- }
-
- if err := conn.Export(agent, dbus.ObjectPath(agentPath), "org.freedesktop.DBus.Introspectable"); err != nil {
- conn.Close()
- return nil, fmt.Errorf("introspection export failed: %w", err)
- }
-
- mgr := conn.Object(bluezService, dbus.ObjectPath(agentManagerPath))
- if err := mgr.Call(agentManagerIface+".RegisterAgent", 0, dbus.ObjectPath(agentPath), agentCapability).Err; err != nil {
- conn.Close()
- return nil, fmt.Errorf("agent registration failed: %w", err)
- }
-
- if err := mgr.Call(agentManagerIface+".RequestDefaultAgent", 0, dbus.ObjectPath(agentPath)).Err; err != nil {
- log.Debugf("[BluezAgent] not default agent: %v", err)
- }
-
- log.Infof("[BluezAgent] registered at %s with capability %s", agentPath, agentCapability)
- return agent, nil
-}
-
-func (a *BluezAgent) Close() {
- if a.conn == nil {
- return
- }
- mgr := a.conn.Object(bluezService, dbus.ObjectPath(agentManagerPath))
- mgr.Call(agentManagerIface+".UnregisterAgent", 0, dbus.ObjectPath(agentPath))
- a.conn.Close()
-}
-
-func (a *BluezAgent) Release() *dbus.Error {
- log.Infof("[BluezAgent] Release called")
- return nil
-}
-
-func (a *BluezAgent) RequestPinCode(device dbus.ObjectPath) (string, *dbus.Error) {
- log.Infof("[BluezAgent] RequestPinCode: device=%s", device)
-
- secrets, err := a.promptFor(device, "pin", []string{"pin"}, nil)
- if err != nil {
- log.Warnf("[BluezAgent] RequestPinCode failed: %v", err)
- return "", a.errorFrom(err)
- }
-
- pin := secrets["pin"]
- log.Infof("[BluezAgent] RequestPinCode returning PIN (len=%d)", len(pin))
- return pin, nil
-}
-
-func (a *BluezAgent) RequestPasskey(device dbus.ObjectPath) (uint32, *dbus.Error) {
- log.Infof("[BluezAgent] RequestPasskey: device=%s", device)
-
- secrets, err := a.promptFor(device, "passkey", []string{"passkey"}, nil)
- if err != nil {
- log.Warnf("[BluezAgent] RequestPasskey failed: %v", err)
- return 0, a.errorFrom(err)
- }
-
- passkey, err := strconv.ParseUint(secrets["passkey"], 10, 32)
- if err != nil {
- log.Warnf("[BluezAgent] invalid passkey format: %v", err)
- return 0, dbus.MakeFailedError(fmt.Errorf("invalid passkey: %w", err))
- }
-
- log.Infof("[BluezAgent] RequestPasskey returning: %d", passkey)
- return uint32(passkey), nil
-}
-
-func (a *BluezAgent) DisplayPinCode(device dbus.ObjectPath, pincode string) *dbus.Error {
- log.Infof("[BluezAgent] DisplayPinCode: device=%s, pin=%s", device, pincode)
-
- _, err := a.promptFor(device, "display-pin", []string{}, &pincode)
- if err != nil {
- log.Warnf("[BluezAgent] DisplayPinCode acknowledgment failed: %v", err)
- }
-
- return nil
-}
-
-func (a *BluezAgent) DisplayPasskey(device dbus.ObjectPath, passkey uint32, entered uint16) *dbus.Error {
- log.Infof("[BluezAgent] DisplayPasskey: device=%s, passkey=%06d, entered=%d", device, passkey, entered)
-
- if entered == 0 {
- pk := passkey
- _, err := a.promptFor(device, "display-passkey", []string{}, nil)
- if err != nil {
- log.Warnf("[BluezAgent] DisplayPasskey acknowledgment failed: %v", err)
- }
- _ = pk
- }
-
- return nil
-}
-
-func (a *BluezAgent) RequestConfirmation(device dbus.ObjectPath, passkey uint32) *dbus.Error {
- log.Infof("[BluezAgent] RequestConfirmation: device=%s, passkey=%06d", device, passkey)
-
- secrets, err := a.promptFor(device, "confirm", []string{"decision"}, nil)
- if err != nil {
- log.Warnf("[BluezAgent] RequestConfirmation failed: %v", err)
- return a.errorFrom(err)
- }
-
- if secrets["decision"] != "yes" && secrets["decision"] != "accept" {
- log.Debugf("[BluezAgent] RequestConfirmation rejected by user")
- return dbus.NewError("org.bluez.Error.Rejected", nil)
- }
-
- log.Infof("[BluezAgent] RequestConfirmation accepted")
- return nil
-}
-
-func (a *BluezAgent) RequestAuthorization(device dbus.ObjectPath) *dbus.Error {
- log.Infof("[BluezAgent] RequestAuthorization: device=%s", device)
-
- secrets, err := a.promptFor(device, "authorize", []string{"decision"}, nil)
- if err != nil {
- log.Warnf("[BluezAgent] RequestAuthorization failed: %v", err)
- return a.errorFrom(err)
- }
-
- if secrets["decision"] != "yes" && secrets["decision"] != "accept" {
- log.Debugf("[BluezAgent] RequestAuthorization rejected by user")
- return dbus.NewError("org.bluez.Error.Rejected", nil)
- }
-
- log.Infof("[BluezAgent] RequestAuthorization accepted")
- return nil
-}
-
-func (a *BluezAgent) AuthorizeService(device dbus.ObjectPath, uuid string) *dbus.Error {
- log.Infof("[BluezAgent] AuthorizeService: device=%s, uuid=%s", device, uuid)
-
- secrets, err := a.promptFor(device, "authorize-service:"+uuid, []string{"decision"}, nil)
- if err != nil {
- log.Warnf("[BluezAgent] AuthorizeService failed: %v", err)
- return a.errorFrom(err)
- }
-
- if secrets["decision"] != "yes" && secrets["decision"] != "accept" {
- log.Debugf("[BluezAgent] AuthorizeService rejected by user")
- return dbus.NewError("org.bluez.Error.Rejected", nil)
- }
-
- log.Infof("[BluezAgent] AuthorizeService accepted")
- return nil
-}
-
-func (a *BluezAgent) Cancel() *dbus.Error {
- log.Infof("[BluezAgent] Cancel called")
- return nil
-}
-
-func (a *BluezAgent) Introspect() (string, *dbus.Error) {
- return introspectXML, nil
-}
-
-func (a *BluezAgent) promptFor(device dbus.ObjectPath, requestType string, fields []string, displayValue *string) (map[string]string, error) {
- if a.broker == nil {
- return nil, fmt.Errorf("broker not initialized")
- }
-
- deviceName, deviceAddr := a.getDeviceInfo(device)
- hints := []string{}
- if displayValue != nil {
- hints = append(hints, *displayValue)
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
- defer cancel()
-
- var passkey *uint32
- if requestType == "confirm" || requestType == "display-passkey" {
- if displayValue != nil {
- if pk, err := strconv.ParseUint(*displayValue, 10, 32); err == nil {
- pk32 := uint32(pk)
- passkey = &pk32
- }
- }
- }
-
- token, err := a.broker.Ask(ctx, PromptRequest{
- DevicePath: string(device),
- DeviceName: deviceName,
- DeviceAddr: deviceAddr,
- RequestType: requestType,
- Fields: fields,
- Hints: hints,
- Passkey: passkey,
- })
- if err != nil {
- return nil, fmt.Errorf("prompt creation failed: %w", err)
- }
-
- log.Infof("[BluezAgent] waiting for user response (token=%s)", token)
- reply, err := a.broker.Wait(ctx, token)
- if err != nil {
- if errors.Is(err, errdefs.ErrSecretPromptTimeout) {
- return nil, err
- }
- if reply.Cancel || errors.Is(err, errdefs.ErrSecretPromptCancelled) {
- return nil, errdefs.ErrSecretPromptCancelled
- }
- return nil, err
- }
-
- if !reply.Accept && len(fields) > 0 {
- return nil, errdefs.ErrSecretPromptCancelled
- }
-
- return reply.Secrets, nil
-}
-
-func (a *BluezAgent) getDeviceInfo(device dbus.ObjectPath) (string, string) {
- obj := a.conn.Object(bluezService, device)
-
- var name, alias, addr string
-
- nameVar, err := obj.GetProperty(device1Iface + ".Name")
- if err == nil {
- if n, ok := nameVar.Value().(string); ok {
- name = n
- }
- }
-
- aliasVar, err := obj.GetProperty(device1Iface + ".Alias")
- if err == nil {
- if a, ok := aliasVar.Value().(string); ok {
- alias = a
- }
- }
-
- addrVar, err := obj.GetProperty(device1Iface + ".Address")
- if err == nil {
- if a, ok := addrVar.Value().(string); ok {
- addr = a
- }
- }
-
- if alias != "" {
- return alias, addr
- }
- if name != "" {
- return name, addr
- }
- return addr, addr
-}
-
-func (a *BluezAgent) errorFrom(err error) *dbus.Error {
- if errors.Is(err, errdefs.ErrSecretPromptTimeout) {
- return dbus.NewError("org.bluez.Error.Canceled", nil)
- }
- if errors.Is(err, errdefs.ErrSecretPromptCancelled) {
- return dbus.NewError("org.bluez.Error.Canceled", nil)
- }
- return dbus.MakeFailedError(err)
-}
diff --git a/nix/inputs/dms-cli/internal/server/bluez/broker.go b/nix/inputs/dms-cli/internal/server/bluez/broker.go
deleted file mode 100644
index f817707..0000000
--- a/nix/inputs/dms-cli/internal/server/bluez/broker.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package bluez
-
-import (
- "context"
- "crypto/rand"
- "encoding/hex"
-)
-
-type PromptBroker interface {
- Ask(ctx context.Context, req PromptRequest) (token string, err error)
- Wait(ctx context.Context, token string) (PromptReply, error)
- Resolve(token string, reply PromptReply) error
-}
-
-func generateToken() (string, error) {
- bytes := make([]byte, 16)
- if _, err := rand.Read(bytes); err != nil {
- return "", err
- }
- return hex.EncodeToString(bytes), nil
-}
diff --git a/nix/inputs/dms-cli/internal/server/bluez/broker_test.go b/nix/inputs/dms-cli/internal/server/bluez/broker_test.go
deleted file mode 100644
index 9eebe61..0000000
--- a/nix/inputs/dms-cli/internal/server/bluez/broker_test.go
+++ /dev/null
@@ -1,220 +0,0 @@
-package bluez
-
-import (
- "context"
- "testing"
- "time"
-)
-
-func TestSubscriptionBrokerAskWait(t *testing.T) {
- promptReceived := false
- broker := NewSubscriptionBroker(func(p PairingPrompt) {
- promptReceived = true
- if p.Token == "" {
- t.Error("expected token to be non-empty")
- }
- if p.DeviceName != "TestDevice" {
- t.Errorf("expected DeviceName=TestDevice, got %s", p.DeviceName)
- }
- })
-
- ctx := context.Background()
- req := PromptRequest{
- DevicePath: "/org/bluez/test",
- DeviceName: "TestDevice",
- DeviceAddr: "AA:BB:CC:DD:EE:FF",
- RequestType: "pin",
- Fields: []string{"pin"},
- }
-
- token, err := broker.Ask(ctx, req)
- if err != nil {
- t.Fatalf("Ask failed: %v", err)
- }
-
- if token == "" {
- t.Fatal("expected non-empty token")
- }
-
- if !promptReceived {
- t.Fatal("expected prompt broadcast to be called")
- }
-
- go func() {
- time.Sleep(50 * time.Millisecond)
- broker.Resolve(token, PromptReply{
- Secrets: map[string]string{"pin": "1234"},
- Accept: true,
- })
- }()
-
- reply, err := broker.Wait(ctx, token)
- if err != nil {
- t.Fatalf("Wait failed: %v", err)
- }
-
- if reply.Secrets["pin"] != "1234" {
- t.Errorf("expected pin=1234, got %s", reply.Secrets["pin"])
- }
-
- if !reply.Accept {
- t.Error("expected Accept=true")
- }
-}
-
-func TestSubscriptionBrokerTimeout(t *testing.T) {
- broker := NewSubscriptionBroker(nil)
-
- ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
- defer cancel()
-
- req := PromptRequest{
- DevicePath: "/org/bluez/test",
- DeviceName: "TestDevice",
- RequestType: "passkey",
- Fields: []string{"passkey"},
- }
-
- token, err := broker.Ask(ctx, req)
- if err != nil {
- t.Fatalf("Ask failed: %v", err)
- }
-
- _, err = broker.Wait(ctx, token)
- if err == nil {
- t.Fatal("expected timeout error")
- }
-}
-
-func TestSubscriptionBrokerCancel(t *testing.T) {
- broker := NewSubscriptionBroker(nil)
-
- ctx := context.Background()
- req := PromptRequest{
- DevicePath: "/org/bluez/test",
- DeviceName: "TestDevice",
- RequestType: "confirm",
- Fields: []string{"decision"},
- }
-
- token, err := broker.Ask(ctx, req)
- if err != nil {
- t.Fatalf("Ask failed: %v", err)
- }
-
- go func() {
- time.Sleep(50 * time.Millisecond)
- broker.Resolve(token, PromptReply{
- Cancel: true,
- })
- }()
-
- _, err = broker.Wait(ctx, token)
- if err == nil {
- t.Fatal("expected cancelled error")
- }
-}
-
-func TestSubscriptionBrokerUnknownToken(t *testing.T) {
- broker := NewSubscriptionBroker(nil)
-
- ctx := context.Background()
- _, err := broker.Wait(ctx, "invalid-token")
- if err == nil {
- t.Fatal("expected error for unknown token")
- }
-}
-
-func TestGenerateToken(t *testing.T) {
- token1, err := generateToken()
- if err != nil {
- t.Fatalf("generateToken failed: %v", err)
- }
-
- token2, err := generateToken()
- if err != nil {
- t.Fatalf("generateToken failed: %v", err)
- }
-
- if token1 == token2 {
- t.Error("expected unique tokens")
- }
-
- if len(token1) != 32 {
- t.Errorf("expected token length 32, got %d", len(token1))
- }
-}
-
-func TestSubscriptionBrokerResolveUnknownToken(t *testing.T) {
- broker := NewSubscriptionBroker(nil)
-
- err := broker.Resolve("unknown-token", PromptReply{
- Secrets: map[string]string{"test": "value"},
- })
- if err == nil {
- t.Fatal("expected error for unknown token")
- }
-}
-
-func TestSubscriptionBrokerMultipleRequests(t *testing.T) {
- broker := NewSubscriptionBroker(nil)
- ctx := context.Background()
-
- req1 := PromptRequest{
- DevicePath: "/org/bluez/test1",
- DeviceName: "Device1",
- RequestType: "pin",
- Fields: []string{"pin"},
- }
-
- req2 := PromptRequest{
- DevicePath: "/org/bluez/test2",
- DeviceName: "Device2",
- RequestType: "passkey",
- Fields: []string{"passkey"},
- }
-
- token1, err := broker.Ask(ctx, req1)
- if err != nil {
- t.Fatalf("Ask1 failed: %v", err)
- }
-
- token2, err := broker.Ask(ctx, req2)
- if err != nil {
- t.Fatalf("Ask2 failed: %v", err)
- }
-
- if token1 == token2 {
- t.Error("expected different tokens")
- }
-
- go func() {
- time.Sleep(50 * time.Millisecond)
- broker.Resolve(token1, PromptReply{
- Secrets: map[string]string{"pin": "1234"},
- Accept: true,
- })
- broker.Resolve(token2, PromptReply{
- Secrets: map[string]string{"passkey": "567890"},
- Accept: true,
- })
- }()
-
- reply1, err := broker.Wait(ctx, token1)
- if err != nil {
- t.Fatalf("Wait1 failed: %v", err)
- }
-
- reply2, err := broker.Wait(ctx, token2)
- if err != nil {
- t.Fatalf("Wait2 failed: %v", err)
- }
-
- if reply1.Secrets["pin"] != "1234" {
- t.Errorf("expected pin=1234, got %s", reply1.Secrets["pin"])
- }
-
- if reply2.Secrets["passkey"] != "567890" {
- t.Errorf("expected passkey=567890, got %s", reply2.Secrets["passkey"])
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/bluez/handlers.go b/nix/inputs/dms-cli/internal/server/bluez/handlers.go
deleted file mode 100644
index 4421a79..0000000
--- a/nix/inputs/dms-cli/internal/server/bluez/handlers.go
+++ /dev/null
@@ -1,260 +0,0 @@
-package bluez
-
-import (
- "encoding/json"
- "fmt"
- "net"
-
- "github.com/AvengeMedia/danklinux/internal/server/models"
-)
-
-type Request struct {
- ID int `json:"id,omitempty"`
- Method string `json:"method"`
- Params map[string]interface{} `json:"params,omitempty"`
-}
-
-type SuccessResult struct {
- Success bool `json:"success"`
- Message string `json:"message"`
-}
-
-type BluetoothEvent struct {
- Type string `json:"type"`
- Data BluetoothState `json:"data"`
-}
-
-func HandleRequest(conn net.Conn, req Request, manager *Manager) {
- switch req.Method {
- case "bluetooth.getState":
- handleGetState(conn, req, manager)
- case "bluetooth.startDiscovery":
- handleStartDiscovery(conn, req, manager)
- case "bluetooth.stopDiscovery":
- handleStopDiscovery(conn, req, manager)
- case "bluetooth.setPowered":
- handleSetPowered(conn, req, manager)
- case "bluetooth.pair":
- handlePairDevice(conn, req, manager)
- case "bluetooth.connect":
- handleConnectDevice(conn, req, manager)
- case "bluetooth.disconnect":
- handleDisconnectDevice(conn, req, manager)
- case "bluetooth.remove":
- handleRemoveDevice(conn, req, manager)
- case "bluetooth.trust":
- handleTrustDevice(conn, req, manager)
- case "bluetooth.untrust":
- handleUntrustDevice(conn, req, manager)
- case "bluetooth.subscribe":
- handleSubscribe(conn, req, manager)
- case "bluetooth.pairing.submit":
- handlePairingSubmit(conn, req, manager)
- case "bluetooth.pairing.cancel":
- handlePairingCancel(conn, req, manager)
- default:
- models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method))
- }
-}
-
-func handleGetState(conn net.Conn, req Request, manager *Manager) {
- state := manager.GetState()
- models.Respond(conn, req.ID, state)
-}
-
-func handleStartDiscovery(conn net.Conn, req Request, manager *Manager) {
- if err := manager.StartDiscovery(); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "discovery started"})
-}
-
-func handleStopDiscovery(conn net.Conn, req Request, manager *Manager) {
- if err := manager.StopDiscovery(); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "discovery stopped"})
-}
-
-func handleSetPowered(conn net.Conn, req Request, manager *Manager) {
- powered, ok := req.Params["powered"].(bool)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'powered' parameter")
- return
- }
-
- if err := manager.SetPowered(powered); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "powered state updated"})
-}
-
-func handlePairDevice(conn net.Conn, req Request, manager *Manager) {
- devicePath, ok := req.Params["device"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'device' parameter")
- return
- }
-
- if err := manager.PairDevice(devicePath); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "pairing initiated"})
-}
-
-func handleConnectDevice(conn net.Conn, req Request, manager *Manager) {
- devicePath, ok := req.Params["device"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'device' parameter")
- return
- }
-
- if err := manager.ConnectDevice(devicePath); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "connecting"})
-}
-
-func handleDisconnectDevice(conn net.Conn, req Request, manager *Manager) {
- devicePath, ok := req.Params["device"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'device' parameter")
- return
- }
-
- if err := manager.DisconnectDevice(devicePath); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "disconnected"})
-}
-
-func handleRemoveDevice(conn net.Conn, req Request, manager *Manager) {
- devicePath, ok := req.Params["device"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'device' parameter")
- return
- }
-
- if err := manager.RemoveDevice(devicePath); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "device removed"})
-}
-
-func handleTrustDevice(conn net.Conn, req Request, manager *Manager) {
- devicePath, ok := req.Params["device"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'device' parameter")
- return
- }
-
- if err := manager.TrustDevice(devicePath, true); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "device trusted"})
-}
-
-func handleUntrustDevice(conn net.Conn, req Request, manager *Manager) {
- devicePath, ok := req.Params["device"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'device' parameter")
- return
- }
-
- if err := manager.TrustDevice(devicePath, false); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "device untrusted"})
-}
-
-func handlePairingSubmit(conn net.Conn, req Request, manager *Manager) {
- token, ok := req.Params["token"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'token' parameter")
- return
- }
-
- secretsRaw, ok := req.Params["secrets"].(map[string]interface{})
- secrets := make(map[string]string)
- if ok {
- for k, v := range secretsRaw {
- if str, ok := v.(string); ok {
- secrets[k] = str
- }
- }
- }
-
- accept := false
- if acceptParam, ok := req.Params["accept"].(bool); ok {
- accept = acceptParam
- }
-
- if err := manager.SubmitPairing(token, secrets, accept); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "pairing response submitted"})
-}
-
-func handlePairingCancel(conn net.Conn, req Request, manager *Manager) {
- token, ok := req.Params["token"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'token' parameter")
- return
- }
-
- if err := manager.CancelPairing(token); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "pairing cancelled"})
-}
-
-func handleSubscribe(conn net.Conn, req Request, manager *Manager) {
- clientID := fmt.Sprintf("client-%p", conn)
- stateChan := manager.Subscribe(clientID)
- defer manager.Unsubscribe(clientID)
-
- initialState := manager.GetState()
- event := BluetoothEvent{
- Type: "state_changed",
- Data: initialState,
- }
-
- if err := json.NewEncoder(conn).Encode(models.Response[BluetoothEvent]{
- ID: req.ID,
- Result: &event,
- }); err != nil {
- return
- }
-
- for state := range stateChan {
- event := BluetoothEvent{
- Type: "state_changed",
- Data: state,
- }
- if err := json.NewEncoder(conn).Encode(models.Response[BluetoothEvent]{
- Result: &event,
- }); err != nil {
- return
- }
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/bluez/handlers_test.go b/nix/inputs/dms-cli/internal/server/bluez/handlers_test.go
deleted file mode 100644
index 1846eb0..0000000
--- a/nix/inputs/dms-cli/internal/server/bluez/handlers_test.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package bluez
-
-import (
- "context"
- "testing"
- "time"
-)
-
-func TestBrokerIntegration(t *testing.T) {
- broker := NewSubscriptionBroker(nil)
- ctx := context.Background()
-
- req := PromptRequest{
- DevicePath: "/org/bluez/test",
- DeviceName: "TestDevice",
- RequestType: "pin",
- Fields: []string{"pin"},
- }
-
- token, err := broker.Ask(ctx, req)
- if err != nil {
- t.Fatalf("Ask failed: %v", err)
- }
-
- go func() {
- time.Sleep(50 * time.Millisecond)
- broker.Resolve(token, PromptReply{
- Secrets: map[string]string{"pin": "1234"},
- Accept: true,
- })
- }()
-
- reply, err := broker.Wait(ctx, token)
- if err != nil {
- t.Fatalf("Wait failed: %v", err)
- }
-
- if reply.Secrets["pin"] != "1234" {
- t.Errorf("expected pin=1234, got %s", reply.Secrets["pin"])
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/bluez/manager.go b/nix/inputs/dms-cli/internal/server/bluez/manager.go
deleted file mode 100644
index 309c492..0000000
--- a/nix/inputs/dms-cli/internal/server/bluez/manager.go
+++ /dev/null
@@ -1,668 +0,0 @@
-package bluez
-
-import (
- "fmt"
- "strings"
- "sync"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/godbus/dbus/v5"
-)
-
-const (
- adapter1Iface = "org.bluez.Adapter1"
- objectMgrIface = "org.freedesktop.DBus.ObjectManager"
- propertiesIface = "org.freedesktop.DBus.Properties"
-)
-
-func NewManager() (*Manager, error) {
- conn, err := dbus.ConnectSystemBus()
- if err != nil {
- return nil, fmt.Errorf("system bus connection failed: %w", err)
- }
-
- m := &Manager{
- state: &BluetoothState{
- Powered: false,
- Discovering: false,
- Devices: []Device{},
- PairedDevices: []Device{},
- ConnectedDevices: []Device{},
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan BluetoothState),
- subMutex: sync.RWMutex{},
- stopChan: make(chan struct{}),
- dbusConn: conn,
- signals: make(chan *dbus.Signal, 256),
- pairingSubscribers: make(map[string]chan PairingPrompt),
- pairingSubMutex: sync.RWMutex{},
- dirty: make(chan struct{}, 1),
- pendingPairings: make(map[string]bool),
- eventQueue: make(chan func(), 32),
- }
-
- broker := NewSubscriptionBroker(m.broadcastPairingPrompt)
- m.promptBroker = broker
-
- adapter, err := m.findAdapter()
- if err != nil {
- conn.Close()
- return nil, fmt.Errorf("no bluetooth adapter found: %w", err)
- }
- m.adapterPath = adapter
-
- if err := m.initialize(); err != nil {
- conn.Close()
- return nil, err
- }
-
- if err := m.startAgent(); err != nil {
- conn.Close()
- return nil, fmt.Errorf("agent start failed: %w", err)
- }
-
- if err := m.startSignalPump(); err != nil {
- m.Close()
- return nil, err
- }
-
- m.notifierWg.Add(1)
- go m.notifier()
-
- m.eventWg.Add(1)
- go m.eventWorker()
-
- return m, nil
-}
-
-func (m *Manager) findAdapter() (dbus.ObjectPath, error) {
- obj := m.dbusConn.Object(bluezService, dbus.ObjectPath("/"))
- var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant
-
- if err := obj.Call(objectMgrIface+".GetManagedObjects", 0).Store(&objects); err != nil {
- return "", err
- }
-
- for path, interfaces := range objects {
- if _, ok := interfaces[adapter1Iface]; ok {
- log.Infof("[BluezManager] found adapter: %s", path)
- return path, nil
- }
- }
-
- return "", fmt.Errorf("no adapter found")
-}
-
-func (m *Manager) initialize() error {
- if err := m.updateAdapterState(); err != nil {
- return err
- }
-
- if err := m.updateDevices(); err != nil {
- return err
- }
-
- return nil
-}
-
-func (m *Manager) updateAdapterState() error {
- obj := m.dbusConn.Object(bluezService, m.adapterPath)
-
- poweredVar, err := obj.GetProperty(adapter1Iface + ".Powered")
- if err != nil {
- return err
- }
- powered, _ := poweredVar.Value().(bool)
-
- discoveringVar, err := obj.GetProperty(adapter1Iface + ".Discovering")
- if err != nil {
- return err
- }
- discovering, _ := discoveringVar.Value().(bool)
-
- m.stateMutex.Lock()
- m.state.Powered = powered
- m.state.Discovering = discovering
- m.stateMutex.Unlock()
-
- return nil
-}
-
-func (m *Manager) updateDevices() error {
- obj := m.dbusConn.Object(bluezService, dbus.ObjectPath("/"))
- var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant
-
- if err := obj.Call(objectMgrIface+".GetManagedObjects", 0).Store(&objects); err != nil {
- return err
- }
-
- devices := []Device{}
- paired := []Device{}
- connected := []Device{}
-
- for path, interfaces := range objects {
- devProps, ok := interfaces[device1Iface]
- if !ok {
- continue
- }
-
- if !strings.HasPrefix(string(path), string(m.adapterPath)+"/") {
- continue
- }
-
- dev := m.deviceFromProps(string(path), devProps)
- devices = append(devices, dev)
-
- if dev.Paired {
- paired = append(paired, dev)
- }
- if dev.Connected {
- connected = append(connected, dev)
- }
- }
-
- m.stateMutex.Lock()
- m.state.Devices = devices
- m.state.PairedDevices = paired
- m.state.ConnectedDevices = connected
- m.stateMutex.Unlock()
-
- return nil
-}
-
-func (m *Manager) deviceFromProps(path string, props map[string]dbus.Variant) Device {
- dev := Device{Path: path}
-
- if v, ok := props["Address"]; ok {
- if addr, ok := v.Value().(string); ok {
- dev.Address = addr
- }
- }
- if v, ok := props["Name"]; ok {
- if name, ok := v.Value().(string); ok {
- dev.Name = name
- }
- }
- if v, ok := props["Alias"]; ok {
- if alias, ok := v.Value().(string); ok {
- dev.Alias = alias
- }
- }
- if v, ok := props["Paired"]; ok {
- if paired, ok := v.Value().(bool); ok {
- dev.Paired = paired
- }
- }
- if v, ok := props["Trusted"]; ok {
- if trusted, ok := v.Value().(bool); ok {
- dev.Trusted = trusted
- }
- }
- if v, ok := props["Blocked"]; ok {
- if blocked, ok := v.Value().(bool); ok {
- dev.Blocked = blocked
- }
- }
- if v, ok := props["Connected"]; ok {
- if connected, ok := v.Value().(bool); ok {
- dev.Connected = connected
- }
- }
- if v, ok := props["Class"]; ok {
- if class, ok := v.Value().(uint32); ok {
- dev.Class = class
- }
- }
- if v, ok := props["Icon"]; ok {
- if icon, ok := v.Value().(string); ok {
- dev.Icon = icon
- }
- }
- if v, ok := props["RSSI"]; ok {
- if rssi, ok := v.Value().(int16); ok {
- dev.RSSI = rssi
- }
- }
- if v, ok := props["LegacyPairing"]; ok {
- if legacy, ok := v.Value().(bool); ok {
- dev.LegacyPairing = legacy
- }
- }
-
- return dev
-}
-
-func (m *Manager) startAgent() error {
- if m.promptBroker == nil {
- return fmt.Errorf("prompt broker not initialized")
- }
-
- agent, err := NewBluezAgent(m.promptBroker)
- if err != nil {
- return err
- }
-
- m.agent = agent
- return nil
-}
-
-func (m *Manager) startSignalPump() error {
- m.dbusConn.Signal(m.signals)
-
- if err := m.dbusConn.AddMatchSignal(
- dbus.WithMatchInterface(propertiesIface),
- dbus.WithMatchMember("PropertiesChanged"),
- ); err != nil {
- return err
- }
-
- if err := m.dbusConn.AddMatchSignal(
- dbus.WithMatchInterface(objectMgrIface),
- dbus.WithMatchMember("InterfacesAdded"),
- ); err != nil {
- return err
- }
-
- if err := m.dbusConn.AddMatchSignal(
- dbus.WithMatchInterface(objectMgrIface),
- dbus.WithMatchMember("InterfacesRemoved"),
- ); err != nil {
- return err
- }
-
- m.sigWG.Add(1)
- go func() {
- defer m.sigWG.Done()
- for {
- select {
- case <-m.stopChan:
- return
- case sig, ok := <-m.signals:
- if !ok {
- return
- }
- if sig == nil {
- continue
- }
- m.handleSignal(sig)
- }
- }
- }()
-
- return nil
-}
-
-func (m *Manager) handleSignal(sig *dbus.Signal) {
- switch sig.Name {
- case propertiesIface + ".PropertiesChanged":
- if len(sig.Body) < 2 {
- return
- }
-
- iface, ok := sig.Body[0].(string)
- if !ok {
- return
- }
-
- changed, ok := sig.Body[1].(map[string]dbus.Variant)
- if !ok {
- return
- }
-
- switch iface {
- case adapter1Iface:
- if strings.HasPrefix(string(sig.Path), string(m.adapterPath)) {
- m.handleAdapterPropertiesChanged(changed)
- }
- case device1Iface:
- m.handleDevicePropertiesChanged(sig.Path, changed)
- }
-
- case objectMgrIface + ".InterfacesAdded":
- m.notifySubscribers()
-
- case objectMgrIface + ".InterfacesRemoved":
- m.notifySubscribers()
- }
-}
-
-func (m *Manager) handleAdapterPropertiesChanged(changed map[string]dbus.Variant) {
- m.stateMutex.Lock()
- dirty := false
-
- if v, ok := changed["Powered"]; ok {
- if powered, ok := v.Value().(bool); ok {
- m.state.Powered = powered
- dirty = true
- }
- }
- if v, ok := changed["Discovering"]; ok {
- if discovering, ok := v.Value().(bool); ok {
- m.state.Discovering = discovering
- dirty = true
- }
- }
-
- m.stateMutex.Unlock()
-
- if dirty {
- m.notifySubscribers()
- }
-}
-
-func (m *Manager) handleDevicePropertiesChanged(path dbus.ObjectPath, changed map[string]dbus.Variant) {
- pairedVar, hasPaired := changed["Paired"]
- _, hasConnected := changed["Connected"]
- _, hasTrusted := changed["Trusted"]
-
- if hasPaired {
- if paired, ok := pairedVar.Value().(bool); ok && paired {
- devicePath := string(path)
- m.pendingPairingsMux.Lock()
- wasPending := m.pendingPairings[devicePath]
- if wasPending {
- delete(m.pendingPairings, devicePath)
- }
- m.pendingPairingsMux.Unlock()
-
- if wasPending {
- select {
- case m.eventQueue <- func() {
- time.Sleep(300 * time.Millisecond)
- log.Infof("[Bluetooth] Auto-connecting newly paired device: %s", devicePath)
- if err := m.ConnectDevice(devicePath); err != nil {
- log.Warnf("[Bluetooth] Auto-connect failed: %v", err)
- }
- }:
- default:
- }
- }
- }
- }
-
- if hasPaired || hasConnected || hasTrusted {
- select {
- case m.eventQueue <- func() {
- time.Sleep(100 * time.Millisecond)
- m.updateDevices()
- m.notifySubscribers()
- }:
- default:
- }
- }
-}
-
-func (m *Manager) eventWorker() {
- defer m.eventWg.Done()
- for {
- select {
- case <-m.stopChan:
- return
- case event := <-m.eventQueue:
- event()
- }
- }
-}
-
-func (m *Manager) notifier() {
- defer m.notifierWg.Done()
- const minGap = 200 * time.Millisecond
- timer := time.NewTimer(minGap)
- timer.Stop()
- var pending bool
-
- for {
- select {
- case <-m.stopChan:
- timer.Stop()
- return
- case <-m.dirty:
- if pending {
- continue
- }
- pending = true
- timer.Reset(minGap)
- case <-timer.C:
- if !pending {
- continue
- }
- m.updateDevices()
-
- m.subMutex.RLock()
- if len(m.subscribers) == 0 {
- m.subMutex.RUnlock()
- pending = false
- continue
- }
-
- currentState := m.snapshotState()
-
- if m.lastNotifiedState != nil && !stateChanged(m.lastNotifiedState, ¤tState) {
- m.subMutex.RUnlock()
- pending = false
- continue
- }
-
- for _, ch := range m.subscribers {
- select {
- case ch <- currentState:
- default:
- }
- }
- m.subMutex.RUnlock()
-
- stateCopy := currentState
- m.lastNotifiedState = &stateCopy
- pending = false
- }
- }
-}
-
-func (m *Manager) notifySubscribers() {
- select {
- case m.dirty <- struct{}{}:
- default:
- }
-}
-
-func (m *Manager) GetState() BluetoothState {
- return m.snapshotState()
-}
-
-func (m *Manager) snapshotState() BluetoothState {
- m.stateMutex.RLock()
- defer m.stateMutex.RUnlock()
-
- s := *m.state
- s.Devices = append([]Device(nil), m.state.Devices...)
- s.PairedDevices = append([]Device(nil), m.state.PairedDevices...)
- s.ConnectedDevices = append([]Device(nil), m.state.ConnectedDevices...)
- return s
-}
-
-func (m *Manager) Subscribe(id string) chan BluetoothState {
- ch := make(chan BluetoothState, 64)
- m.subMutex.Lock()
- m.subscribers[id] = ch
- m.subMutex.Unlock()
- return ch
-}
-
-func (m *Manager) Unsubscribe(id string) {
- m.subMutex.Lock()
- if ch, ok := m.subscribers[id]; ok {
- close(ch)
- delete(m.subscribers, id)
- }
- m.subMutex.Unlock()
-}
-
-func (m *Manager) SubscribePairing(id string) chan PairingPrompt {
- ch := make(chan PairingPrompt, 16)
- m.pairingSubMutex.Lock()
- m.pairingSubscribers[id] = ch
- m.pairingSubMutex.Unlock()
- return ch
-}
-
-func (m *Manager) UnsubscribePairing(id string) {
- m.pairingSubMutex.Lock()
- if ch, ok := m.pairingSubscribers[id]; ok {
- close(ch)
- delete(m.pairingSubscribers, id)
- }
- m.pairingSubMutex.Unlock()
-}
-
-func (m *Manager) broadcastPairingPrompt(prompt PairingPrompt) {
- m.pairingSubMutex.RLock()
- defer m.pairingSubMutex.RUnlock()
-
- for _, ch := range m.pairingSubscribers {
- select {
- case ch <- prompt:
- default:
- }
- }
-}
-
-func (m *Manager) SubmitPairing(token string, secrets map[string]string, accept bool) error {
- if m.promptBroker == nil {
- return fmt.Errorf("prompt broker not initialized")
- }
-
- return m.promptBroker.Resolve(token, PromptReply{
- Secrets: secrets,
- Accept: accept,
- Cancel: false,
- })
-}
-
-func (m *Manager) CancelPairing(token string) error {
- if m.promptBroker == nil {
- return fmt.Errorf("prompt broker not initialized")
- }
-
- return m.promptBroker.Resolve(token, PromptReply{
- Cancel: true,
- })
-}
-
-func (m *Manager) StartDiscovery() error {
- obj := m.dbusConn.Object(bluezService, m.adapterPath)
- return obj.Call(adapter1Iface+".StartDiscovery", 0).Err
-}
-
-func (m *Manager) StopDiscovery() error {
- obj := m.dbusConn.Object(bluezService, m.adapterPath)
- return obj.Call(adapter1Iface+".StopDiscovery", 0).Err
-}
-
-func (m *Manager) SetPowered(powered bool) error {
- obj := m.dbusConn.Object(bluezService, m.adapterPath)
- return obj.Call(propertiesIface+".Set", 0, adapter1Iface, "Powered", dbus.MakeVariant(powered)).Err
-}
-
-func (m *Manager) PairDevice(devicePath string) error {
- m.pendingPairingsMux.Lock()
- m.pendingPairings[devicePath] = true
- m.pendingPairingsMux.Unlock()
-
- obj := m.dbusConn.Object(bluezService, dbus.ObjectPath(devicePath))
- err := obj.Call(device1Iface+".Pair", 0).Err
-
- if err != nil {
- m.pendingPairingsMux.Lock()
- delete(m.pendingPairings, devicePath)
- m.pendingPairingsMux.Unlock()
- }
-
- return err
-}
-
-func (m *Manager) ConnectDevice(devicePath string) error {
- obj := m.dbusConn.Object(bluezService, dbus.ObjectPath(devicePath))
- return obj.Call(device1Iface+".Connect", 0).Err
-}
-
-func (m *Manager) DisconnectDevice(devicePath string) error {
- obj := m.dbusConn.Object(bluezService, dbus.ObjectPath(devicePath))
- return obj.Call(device1Iface+".Disconnect", 0).Err
-}
-
-func (m *Manager) RemoveDevice(devicePath string) error {
- obj := m.dbusConn.Object(bluezService, m.adapterPath)
- return obj.Call(adapter1Iface+".RemoveDevice", 0, dbus.ObjectPath(devicePath)).Err
-}
-
-func (m *Manager) TrustDevice(devicePath string, trusted bool) error {
- obj := m.dbusConn.Object(bluezService, dbus.ObjectPath(devicePath))
- return obj.Call(propertiesIface+".Set", 0, device1Iface, "Trusted", dbus.MakeVariant(trusted)).Err
-}
-
-func (m *Manager) Close() {
- close(m.stopChan)
- m.notifierWg.Wait()
- m.eventWg.Wait()
-
- m.sigWG.Wait()
-
- if m.signals != nil {
- m.dbusConn.RemoveSignal(m.signals)
- close(m.signals)
- }
-
- if m.agent != nil {
- m.agent.Close()
- }
-
- m.subMutex.Lock()
- for _, ch := range m.subscribers {
- close(ch)
- }
- m.subscribers = make(map[string]chan BluetoothState)
- m.subMutex.Unlock()
-
- m.pairingSubMutex.Lock()
- for _, ch := range m.pairingSubscribers {
- close(ch)
- }
- m.pairingSubscribers = make(map[string]chan PairingPrompt)
- m.pairingSubMutex.Unlock()
-
- if m.dbusConn != nil {
- m.dbusConn.Close()
- }
-}
-
-func stateChanged(old, new *BluetoothState) bool {
- if old.Powered != new.Powered {
- return true
- }
- if old.Discovering != new.Discovering {
- return true
- }
- if len(old.Devices) != len(new.Devices) {
- return true
- }
- if len(old.PairedDevices) != len(new.PairedDevices) {
- return true
- }
- if len(old.ConnectedDevices) != len(new.ConnectedDevices) {
- return true
- }
- for i := range old.Devices {
- if old.Devices[i].Path != new.Devices[i].Path {
- return true
- }
- if old.Devices[i].Paired != new.Devices[i].Paired {
- return true
- }
- if old.Devices[i].Connected != new.Devices[i].Connected {
- return true
- }
- }
- return false
-}
diff --git a/nix/inputs/dms-cli/internal/server/bluez/subscription_broker.go b/nix/inputs/dms-cli/internal/server/bluez/subscription_broker.go
deleted file mode 100644
index e466866..0000000
--- a/nix/inputs/dms-cli/internal/server/bluez/subscription_broker.go
+++ /dev/null
@@ -1,99 +0,0 @@
-package bluez
-
-import (
- "context"
- "fmt"
- "sync"
-
- "github.com/AvengeMedia/danklinux/internal/errdefs"
-)
-
-type SubscriptionBroker struct {
- mu sync.RWMutex
- pending map[string]chan PromptReply
- requests map[string]PromptRequest
- broadcastPrompt func(PairingPrompt)
-}
-
-func NewSubscriptionBroker(broadcastPrompt func(PairingPrompt)) PromptBroker {
- return &SubscriptionBroker{
- pending: make(map[string]chan PromptReply),
- requests: make(map[string]PromptRequest),
- broadcastPrompt: broadcastPrompt,
- }
-}
-
-func (b *SubscriptionBroker) Ask(ctx context.Context, req PromptRequest) (string, error) {
- token, err := generateToken()
- if err != nil {
- return "", err
- }
-
- replyChan := make(chan PromptReply, 1)
- b.mu.Lock()
- b.pending[token] = replyChan
- b.requests[token] = req
- b.mu.Unlock()
-
- if b.broadcastPrompt != nil {
- prompt := PairingPrompt{
- Token: token,
- DevicePath: req.DevicePath,
- DeviceName: req.DeviceName,
- DeviceAddr: req.DeviceAddr,
- RequestType: req.RequestType,
- Fields: req.Fields,
- Hints: req.Hints,
- Passkey: req.Passkey,
- }
- b.broadcastPrompt(prompt)
- }
-
- return token, nil
-}
-
-func (b *SubscriptionBroker) Wait(ctx context.Context, token string) (PromptReply, error) {
- b.mu.RLock()
- replyChan, exists := b.pending[token]
- b.mu.RUnlock()
-
- if !exists {
- return PromptReply{}, fmt.Errorf("unknown token: %s", token)
- }
-
- select {
- case <-ctx.Done():
- b.cleanup(token)
- return PromptReply{}, errdefs.ErrSecretPromptTimeout
- case reply := <-replyChan:
- b.cleanup(token)
- if reply.Cancel {
- return reply, errdefs.ErrSecretPromptCancelled
- }
- return reply, nil
- }
-}
-
-func (b *SubscriptionBroker) Resolve(token string, reply PromptReply) error {
- b.mu.RLock()
- replyChan, exists := b.pending[token]
- b.mu.RUnlock()
-
- if !exists {
- return fmt.Errorf("unknown or expired token: %s", token)
- }
-
- select {
- case replyChan <- reply:
- return nil
- default:
- return fmt.Errorf("failed to deliver reply for token: %s", token)
- }
-}
-
-func (b *SubscriptionBroker) cleanup(token string) {
- b.mu.Lock()
- delete(b.pending, token)
- delete(b.requests, token)
- b.mu.Unlock()
-}
diff --git a/nix/inputs/dms-cli/internal/server/bluez/types.go b/nix/inputs/dms-cli/internal/server/bluez/types.go
deleted file mode 100644
index 6375587..0000000
--- a/nix/inputs/dms-cli/internal/server/bluez/types.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package bluez
-
-import (
- "sync"
-
- "github.com/godbus/dbus/v5"
-)
-
-type BluetoothState struct {
- Powered bool `json:"powered"`
- Discovering bool `json:"discovering"`
- Devices []Device `json:"devices"`
- PairedDevices []Device `json:"pairedDevices"`
- ConnectedDevices []Device `json:"connectedDevices"`
-}
-
-type Device struct {
- Path string `json:"path"`
- Address string `json:"address"`
- Name string `json:"name"`
- Alias string `json:"alias"`
- Paired bool `json:"paired"`
- Trusted bool `json:"trusted"`
- Blocked bool `json:"blocked"`
- Connected bool `json:"connected"`
- Class uint32 `json:"class"`
- Icon string `json:"icon"`
- RSSI int16 `json:"rssi"`
- LegacyPairing bool `json:"legacyPairing"`
-}
-
-type PromptRequest struct {
- DevicePath string `json:"devicePath"`
- DeviceName string `json:"deviceName"`
- DeviceAddr string `json:"deviceAddr"`
- RequestType string `json:"requestType"`
- Fields []string `json:"fields"`
- Hints []string `json:"hints"`
- Passkey *uint32 `json:"passkey,omitempty"`
-}
-
-type PromptReply struct {
- Secrets map[string]string `json:"secrets"`
- Accept bool `json:"accept"`
- Cancel bool `json:"cancel"`
-}
-
-type PairingPrompt struct {
- Token string `json:"token"`
- DevicePath string `json:"devicePath"`
- DeviceName string `json:"deviceName"`
- DeviceAddr string `json:"deviceAddr"`
- RequestType string `json:"requestType"`
- Fields []string `json:"fields"`
- Hints []string `json:"hints"`
- Passkey *uint32 `json:"passkey,omitempty"`
-}
-
-type Manager struct {
- state *BluetoothState
- stateMutex sync.RWMutex
- subscribers map[string]chan BluetoothState
- subMutex sync.RWMutex
- stopChan chan struct{}
- dbusConn *dbus.Conn
- signals chan *dbus.Signal
- sigWG sync.WaitGroup
- agent *BluezAgent
- promptBroker PromptBroker
- pairingSubscribers map[string]chan PairingPrompt
- pairingSubMutex sync.RWMutex
- dirty chan struct{}
- notifierWg sync.WaitGroup
- lastNotifiedState *BluetoothState
- adapterPath dbus.ObjectPath
- pendingPairings map[string]bool
- pendingPairingsMux sync.Mutex
- eventQueue chan func()
- eventWg sync.WaitGroup
-}
diff --git a/nix/inputs/dms-cli/internal/server/bluez/types_test.go b/nix/inputs/dms-cli/internal/server/bluez/types_test.go
deleted file mode 100644
index ab5b857..0000000
--- a/nix/inputs/dms-cli/internal/server/bluez/types_test.go
+++ /dev/null
@@ -1,210 +0,0 @@
-package bluez
-
-import (
- "encoding/json"
- "testing"
-)
-
-func TestBluetoothStateJSON(t *testing.T) {
- state := BluetoothState{
- Powered: true,
- Discovering: false,
- Devices: []Device{
- {
- Path: "/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF",
- Address: "AA:BB:CC:DD:EE:FF",
- Name: "TestDevice",
- Alias: "My Device",
- Paired: true,
- Trusted: false,
- Connected: true,
- Class: 0x240418,
- Icon: "audio-headset",
- RSSI: -50,
- },
- },
- PairedDevices: []Device{
- {
- Path: "/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF",
- Address: "AA:BB:CC:DD:EE:FF",
- Paired: true,
- },
- },
- ConnectedDevices: []Device{
- {
- Path: "/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF",
- Address: "AA:BB:CC:DD:EE:FF",
- Connected: true,
- },
- },
- }
-
- data, err := json.Marshal(state)
- if err != nil {
- t.Fatalf("failed to marshal state: %v", err)
- }
-
- var decoded BluetoothState
- if err := json.Unmarshal(data, &decoded); err != nil {
- t.Fatalf("failed to unmarshal state: %v", err)
- }
-
- if decoded.Powered != state.Powered {
- t.Errorf("expected Powered=%v, got %v", state.Powered, decoded.Powered)
- }
-
- if len(decoded.Devices) != 1 {
- t.Fatalf("expected 1 device, got %d", len(decoded.Devices))
- }
-
- if decoded.Devices[0].Address != "AA:BB:CC:DD:EE:FF" {
- t.Errorf("expected address AA:BB:CC:DD:EE:FF, got %s", decoded.Devices[0].Address)
- }
-}
-
-func TestDeviceJSON(t *testing.T) {
- device := Device{
- Path: "/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF",
- Address: "AA:BB:CC:DD:EE:FF",
- Name: "TestDevice",
- Alias: "My Device",
- Paired: true,
- Trusted: true,
- Blocked: false,
- Connected: true,
- Class: 0x240418,
- Icon: "audio-headset",
- RSSI: -50,
- LegacyPairing: false,
- }
-
- data, err := json.Marshal(device)
- if err != nil {
- t.Fatalf("failed to marshal device: %v", err)
- }
-
- var decoded Device
- if err := json.Unmarshal(data, &decoded); err != nil {
- t.Fatalf("failed to unmarshal device: %v", err)
- }
-
- if decoded.Address != device.Address {
- t.Errorf("expected Address=%s, got %s", device.Address, decoded.Address)
- }
-
- if decoded.Name != device.Name {
- t.Errorf("expected Name=%s, got %s", device.Name, decoded.Name)
- }
-
- if decoded.Paired != device.Paired {
- t.Errorf("expected Paired=%v, got %v", device.Paired, decoded.Paired)
- }
-
- if decoded.RSSI != device.RSSI {
- t.Errorf("expected RSSI=%d, got %d", device.RSSI, decoded.RSSI)
- }
-}
-
-func TestPairingPromptJSON(t *testing.T) {
- passkey := uint32(123456)
- prompt := PairingPrompt{
- Token: "test-token",
- DevicePath: "/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF",
- DeviceName: "TestDevice",
- DeviceAddr: "AA:BB:CC:DD:EE:FF",
- RequestType: "confirm",
- Fields: []string{"decision"},
- Hints: []string{},
- Passkey: &passkey,
- }
-
- data, err := json.Marshal(prompt)
- if err != nil {
- t.Fatalf("failed to marshal prompt: %v", err)
- }
-
- var decoded PairingPrompt
- if err := json.Unmarshal(data, &decoded); err != nil {
- t.Fatalf("failed to unmarshal prompt: %v", err)
- }
-
- if decoded.Token != prompt.Token {
- t.Errorf("expected Token=%s, got %s", prompt.Token, decoded.Token)
- }
-
- if decoded.DeviceName != prompt.DeviceName {
- t.Errorf("expected DeviceName=%s, got %s", prompt.DeviceName, decoded.DeviceName)
- }
-
- if decoded.Passkey == nil {
- t.Fatal("expected non-nil Passkey")
- }
-
- if *decoded.Passkey != *prompt.Passkey {
- t.Errorf("expected Passkey=%d, got %d", *prompt.Passkey, *decoded.Passkey)
- }
-}
-
-func TestPromptReplyJSON(t *testing.T) {
- reply := PromptReply{
- Secrets: map[string]string{
- "pin": "1234",
- "passkey": "567890",
- },
- Accept: true,
- Cancel: false,
- }
-
- data, err := json.Marshal(reply)
- if err != nil {
- t.Fatalf("failed to marshal reply: %v", err)
- }
-
- var decoded PromptReply
- if err := json.Unmarshal(data, &decoded); err != nil {
- t.Fatalf("failed to unmarshal reply: %v", err)
- }
-
- if decoded.Secrets["pin"] != reply.Secrets["pin"] {
- t.Errorf("expected pin=%s, got %s", reply.Secrets["pin"], decoded.Secrets["pin"])
- }
-
- if decoded.Accept != reply.Accept {
- t.Errorf("expected Accept=%v, got %v", reply.Accept, decoded.Accept)
- }
-}
-
-func TestPromptRequestJSON(t *testing.T) {
- passkey := uint32(123456)
- req := PromptRequest{
- DevicePath: "/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF",
- DeviceName: "TestDevice",
- DeviceAddr: "AA:BB:CC:DD:EE:FF",
- RequestType: "confirm",
- Fields: []string{"decision"},
- Hints: []string{"hint1", "hint2"},
- Passkey: &passkey,
- }
-
- data, err := json.Marshal(req)
- if err != nil {
- t.Fatalf("failed to marshal request: %v", err)
- }
-
- var decoded PromptRequest
- if err := json.Unmarshal(data, &decoded); err != nil {
- t.Fatalf("failed to unmarshal request: %v", err)
- }
-
- if decoded.DevicePath != req.DevicePath {
- t.Errorf("expected DevicePath=%s, got %s", req.DevicePath, decoded.DevicePath)
- }
-
- if decoded.RequestType != req.RequestType {
- t.Errorf("expected RequestType=%s, got %s", req.RequestType, decoded.RequestType)
- }
-
- if len(decoded.Fields) != len(req.Fields) {
- t.Errorf("expected %d fields, got %d", len(req.Fields), len(decoded.Fields))
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/brightness/ddc.go b/nix/inputs/dms-cli/internal/server/brightness/ddc.go
deleted file mode 100644
index 726d107..0000000
--- a/nix/inputs/dms-cli/internal/server/brightness/ddc.go
+++ /dev/null
@@ -1,485 +0,0 @@
-package brightness
-
-import (
- "encoding/binary"
- "fmt"
- "math"
- "os"
- "path/filepath"
- "strings"
- "syscall"
- "time"
- "unsafe"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "golang.org/x/sys/unix"
-)
-
-const (
- I2C_SLAVE = 0x0703
- DDCCI_ADDR = 0x37
- DDCCI_VCP_GET = 0x01
- DDCCI_VCP_SET = 0x03
- VCP_BRIGHTNESS = 0x10
- DDC_SOURCE_ADDR = 0x51
-)
-
-func NewDDCBackend() (*DDCBackend, error) {
- b := &DDCBackend{
- devices: make(map[string]*ddcDevice),
- scanInterval: 30 * time.Second,
- debounceTimers: make(map[string]*time.Timer),
- debouncePending: make(map[string]ddcPendingSet),
- }
-
- if err := b.scanI2CDevices(); err != nil {
- return nil, err
- }
-
- return b, nil
-}
-
-func (b *DDCBackend) scanI2CDevices() error {
- b.scanMutex.Lock()
- lastScan := b.lastScan
- b.scanMutex.Unlock()
-
- if time.Since(lastScan) < b.scanInterval {
- return nil
- }
-
- b.scanMutex.Lock()
- defer b.scanMutex.Unlock()
-
- if time.Since(b.lastScan) < b.scanInterval {
- return nil
- }
-
- b.devicesMutex.Lock()
- defer b.devicesMutex.Unlock()
-
- b.devices = make(map[string]*ddcDevice)
-
- for i := 0; i < 32; i++ {
- busPath := fmt.Sprintf("/dev/i2c-%d", i)
- if _, err := os.Stat(busPath); os.IsNotExist(err) {
- continue
- }
-
- // Skip SMBus, GPU internal buses (e.g. AMDGPU SMU) to prevent GPU hangs
- if isIgnorableI2CBus(i) {
- log.Debugf("Skipping ignorable i2c-%d", i)
- continue
- }
-
- dev, err := b.probeDDCDevice(i)
- if err != nil || dev == nil {
- continue
- }
-
- id := fmt.Sprintf("ddc:i2c-%d", i)
- dev.id = id
- b.devices[id] = dev
- log.Debugf("found DDC device on i2c-%d", i)
- }
-
- b.lastScan = time.Now()
-
- return nil
-}
-
-func (b *DDCBackend) probeDDCDevice(bus int) (*ddcDevice, error) {
- busPath := fmt.Sprintf("/dev/i2c-%d", bus)
-
- fd, err := syscall.Open(busPath, syscall.O_RDWR, 0)
- if err != nil {
- return nil, err
- }
- defer syscall.Close(fd)
-
- if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), I2C_SLAVE, uintptr(DDCCI_ADDR)); errno != 0 {
- return nil, errno
- }
-
- dummy := make([]byte, 32)
- syscall.Read(fd, dummy)
-
- writebuf := []byte{0x00}
- n, err := syscall.Write(fd, writebuf)
- if err == nil && n == len(writebuf) {
- name := b.getDDCName(bus)
- dev := &ddcDevice{
- bus: bus,
- addr: DDCCI_ADDR,
- name: name,
- }
- b.readInitialBrightness(fd, dev)
- return dev, nil
- }
-
- readbuf := make([]byte, 4)
- n, err = syscall.Read(fd, readbuf)
- if err != nil || n == 0 {
- return nil, fmt.Errorf("x37 unresponsive")
- }
-
- name := b.getDDCName(bus)
-
- dev := &ddcDevice{
- bus: bus,
- addr: DDCCI_ADDR,
- name: name,
- }
- b.readInitialBrightness(fd, dev)
- return dev, nil
-}
-
-func (b *DDCBackend) getDDCName(bus int) string {
- sysfsPath := fmt.Sprintf("/sys/class/i2c-adapter/i2c-%d/name", bus)
- data, err := os.ReadFile(sysfsPath)
- if err != nil {
- return fmt.Sprintf("I2C-%d", bus)
- }
-
- name := strings.TrimSpace(string(data))
- if name == "" {
- name = fmt.Sprintf("I2C-%d", bus)
- }
-
- return name
-}
-
-func (b *DDCBackend) readInitialBrightness(fd int, dev *ddcDevice) {
- cap, err := b.getVCPFeature(fd, VCP_BRIGHTNESS)
- if err != nil {
- log.Debugf("failed to read initial brightness for %s: %v", dev.name, err)
- return
- }
-
- dev.max = cap.max
- dev.lastBrightness = cap.current
- log.Debugf("initialized %s with brightness %d/%d", dev.name, cap.current, cap.max)
-}
-
-func (b *DDCBackend) GetDevices() ([]Device, error) {
- if err := b.scanI2CDevices(); err != nil {
- log.Debugf("DDC scan error: %v", err)
- }
-
- b.devicesMutex.Lock()
- defer b.devicesMutex.Unlock()
-
- devices := make([]Device, 0, len(b.devices))
-
- for id, dev := range b.devices {
- devices = append(devices, Device{
- Class: ClassDDC,
- ID: id,
- Name: dev.name,
- Current: dev.lastBrightness,
- Max: dev.max,
- CurrentPercent: dev.lastBrightness,
- Backend: "ddc",
- })
- }
-
- return devices, nil
-}
-
-func (b *DDCBackend) SetBrightness(id string, value int, exponential bool, callback func()) error {
- return b.SetBrightnessWithExponent(id, value, exponential, 1.2, callback)
-}
-
-func (b *DDCBackend) SetBrightnessWithExponent(id string, value int, exponential bool, exponent float64, callback func()) error {
- b.devicesMutex.RLock()
- _, ok := b.devices[id]
- b.devicesMutex.RUnlock()
-
- if !ok {
- return fmt.Errorf("device not found: %s", id)
- }
-
- if value < 0 || value > 100 {
- return fmt.Errorf("value out of range: %d", value)
- }
-
- b.debounceMutex.Lock()
- defer b.debounceMutex.Unlock()
-
- b.debouncePending[id] = ddcPendingSet{
- percent: value,
- callback: callback,
- }
-
- if timer, exists := b.debounceTimers[id]; exists {
- timer.Reset(200 * time.Millisecond)
- } else {
- b.debounceTimers[id] = time.AfterFunc(200*time.Millisecond, func() {
- b.debounceMutex.Lock()
- pending, exists := b.debouncePending[id]
- if exists {
- delete(b.debouncePending, id)
- }
- b.debounceMutex.Unlock()
-
- if !exists {
- return
- }
-
- err := b.setBrightnessImmediateWithExponent(id, pending.percent, exponential, exponent)
- if err != nil {
- log.Debugf("Failed to set brightness for %s: %v", id, err)
- }
-
- if pending.callback != nil {
- pending.callback()
- }
- })
- }
-
- return nil
-}
-
-func (b *DDCBackend) setBrightnessImmediate(id string, value int, exponential bool) error {
- return b.setBrightnessImmediateWithExponent(id, value, exponential, 1.2)
-}
-
-func (b *DDCBackend) setBrightnessImmediateWithExponent(id string, value int, exponential bool, exponent float64) error {
- b.devicesMutex.RLock()
- dev, ok := b.devices[id]
- b.devicesMutex.RUnlock()
-
- if !ok {
- return fmt.Errorf("device not found: %s", id)
- }
-
- busPath := fmt.Sprintf("/dev/i2c-%d", dev.bus)
-
- fd, err := syscall.Open(busPath, syscall.O_RDWR, 0)
- if err != nil {
- return fmt.Errorf("open i2c device: %w", err)
- }
- defer syscall.Close(fd)
-
- if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), I2C_SLAVE, uintptr(dev.addr)); errno != 0 {
- return fmt.Errorf("set i2c slave addr: %w", errno)
- }
-
- max := dev.max
- if max == 0 {
- cap, err := b.getVCPFeature(fd, VCP_BRIGHTNESS)
- if err != nil {
- return fmt.Errorf("get current capability: %w", err)
- }
- max = cap.max
- b.devicesMutex.Lock()
- dev.max = max
- b.devicesMutex.Unlock()
- }
-
- if err := b.setVCPFeature(fd, VCP_BRIGHTNESS, value); err != nil {
- return fmt.Errorf("set vcp feature: %w", err)
- }
-
- log.Debugf("set %s to %d/%d", id, value, max)
-
- b.devicesMutex.Lock()
- dev.max = max
- dev.lastBrightness = value
- b.devicesMutex.Unlock()
-
- return nil
-}
-
-func (b *DDCBackend) getVCPFeature(fd int, vcp byte) (*ddcCapability, error) {
- for flushTry := 0; flushTry < 3; flushTry++ {
- dummy := make([]byte, 32)
- n, _ := syscall.Read(fd, dummy)
- if n == 0 {
- break
- }
- time.Sleep(20 * time.Millisecond)
- }
-
- data := []byte{
- DDCCI_VCP_GET,
- vcp,
- }
-
- payload := []byte{
- DDC_SOURCE_ADDR,
- byte(len(data)) | 0x80,
- }
- payload = append(payload, data...)
- payload = append(payload, ddcciChecksum(payload))
-
- n, err := syscall.Write(fd, payload)
- if err != nil || n != len(payload) {
- return nil, fmt.Errorf("write i2c: %w", err)
- }
-
- time.Sleep(50 * time.Millisecond)
-
- pollFds := []unix.PollFd{
- {
- Fd: int32(fd),
- Events: unix.POLLIN,
- },
- }
-
- pollTimeout := 200
- pollResult, err := unix.Poll(pollFds, pollTimeout)
- if err != nil {
- return nil, fmt.Errorf("poll i2c: %w", err)
- }
- if pollResult == 0 {
- return nil, fmt.Errorf("poll timeout after %dms", pollTimeout)
- }
- if pollFds[0].Revents&unix.POLLIN == 0 {
- return nil, fmt.Errorf("poll returned but POLLIN not set")
- }
-
- response := make([]byte, 12)
- n, err = syscall.Read(fd, response)
- if err != nil || n < 8 {
- return nil, fmt.Errorf("read i2c: %w", err)
- }
-
- if response[0] != 0x6E || response[2] != 0x02 {
- return nil, fmt.Errorf("invalid ddc response")
- }
-
- resultCode := response[3]
- if resultCode != 0x00 {
- return nil, fmt.Errorf("vcp feature not supported")
- }
-
- responseVCP := response[4]
- if responseVCP != vcp {
- return nil, fmt.Errorf("vcp mismatch: wanted 0x%02x, got 0x%02x", vcp, responseVCP)
- }
-
- maxHigh := response[6]
- maxLow := response[7]
- currentHigh := response[8]
- currentLow := response[9]
-
- max := int(binary.BigEndian.Uint16([]byte{maxHigh, maxLow}))
- current := int(binary.BigEndian.Uint16([]byte{currentHigh, currentLow}))
-
- return &ddcCapability{
- vcp: vcp,
- max: max,
- current: current,
- }, nil
-}
-
-func ddcciChecksum(payload []byte) byte {
- sum := byte(0x6E)
- for _, b := range payload {
- sum ^= b
- }
- return sum
-}
-
-func (b *DDCBackend) setVCPFeature(fd int, vcp byte, value int) error {
- data := []byte{
- DDCCI_VCP_SET,
- vcp,
- byte(value >> 8),
- byte(value & 0xFF),
- }
-
- payload := []byte{
- DDC_SOURCE_ADDR,
- byte(len(data)) | 0x80,
- }
- payload = append(payload, data...)
- payload = append(payload, ddcciChecksum(payload))
-
- if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), I2C_SLAVE, uintptr(DDCCI_ADDR)); errno != 0 {
- return fmt.Errorf("set i2c slave for write: %w", errno)
- }
-
- n, err := syscall.Write(fd, payload)
- if err != nil || n != len(payload) {
- return fmt.Errorf("write i2c: wrote %d/%d: %w", n, len(payload), err)
- }
-
- time.Sleep(50 * time.Millisecond)
-
- return nil
-}
-
-func (b *DDCBackend) percentToValue(percent int, max int, exponential bool) int {
- const minValue = 1
-
- if percent == 0 {
- return minValue
- }
-
- usableRange := max - minValue
- var value int
-
- if exponential {
- const exponent = 2.0
- normalizedPercent := float64(percent) / 100.0
- hardwarePercent := math.Pow(normalizedPercent, 1.0/exponent)
- value = minValue + int(math.Round(hardwarePercent*float64(usableRange)))
- } else {
- value = minValue + ((percent - 1) * usableRange / 99)
- }
-
- if value < minValue {
- value = minValue
- }
- if value > max {
- value = max
- }
-
- return value
-}
-
-func (b *DDCBackend) valueToPercent(value int, max int, exponential bool) int {
- const minValue = 1
-
- if max == 0 {
- return 0
- }
-
- if value <= minValue {
- return 1
- }
-
- usableRange := max - minValue
- if usableRange == 0 {
- return 100
- }
-
- var percent int
-
- if exponential {
- const exponent = 2.0
- linearPercent := 1 + ((value - minValue) * 99 / usableRange)
- normalizedLinear := float64(linearPercent) / 100.0
- expPercent := math.Pow(normalizedLinear, exponent)
- percent = int(math.Round(expPercent * 100.0))
- } else {
- percent = 1 + ((value - minValue) * 99 / usableRange)
- }
-
- if percent > 100 {
- percent = 100
- }
- if percent < 1 {
- percent = 1
- }
-
- return percent
-}
-
-func (b *DDCBackend) Close() {
-}
-
-var _ = unsafe.Sizeof(0)
-var _ = filepath.Join
diff --git a/nix/inputs/dms-cli/internal/server/brightness/ddc_filter.go b/nix/inputs/dms-cli/internal/server/brightness/ddc_filter.go
deleted file mode 100644
index 32f3dd2..0000000
--- a/nix/inputs/dms-cli/internal/server/brightness/ddc_filter.go
+++ /dev/null
@@ -1,135 +0,0 @@
-package brightness
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "strconv"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/log"
-)
-
-// isIgnorableI2CBus checks if an I2C bus should be skipped during DDC probing.
-// Based on ddcutil's sysfs_is_ignorable_i2c_device() (sysfs_base.c:1441)
-func isIgnorableI2CBus(busno int) bool {
- name := getI2CDeviceSysfsName(busno)
- driver := getI2CSysfsDriver(busno)
-
- if name != "" && isIgnorableI2CDeviceName(name, driver) {
- log.Debugf("i2c-%d: ignoring '%s' (driver: %s)", busno, name, driver)
- return true
- }
-
- // Only probe display adapters (0x03xxxx) and docking stations (0x0axxxx)
- class := getI2CDeviceSysfsClass(busno)
- if class != 0 {
- classHigh := class & 0xFFFF0000
- ignorable := (classHigh != 0x030000 && classHigh != 0x0A0000)
- if ignorable {
- log.Debugf("i2c-%d: ignoring class 0x%08x", busno, class)
- }
- return ignorable
- }
-
- return false
-}
-
-// Based on ddcutil's ignorable_i2c_device_sysfs_name() (sysfs_base.c:1408)
-func isIgnorableI2CDeviceName(name, driver string) bool {
- ignorablePrefixes := []string{
- "SMBus",
- "Synopsys DesignWare",
- "soc:i2cdsi",
- "smu",
- "mac-io",
- "u4",
- "AMDGPU SMU", // AMD Navi2+ - probing hangs GPU
- }
-
- for _, prefix := range ignorablePrefixes {
- if strings.HasPrefix(name, prefix) {
- return true
- }
- }
-
- // nouveau driver: only nvkm-* buses are valid
- if driver == "nouveau" && !strings.HasPrefix(name, "nvkm-") {
- return true
- }
-
- return false
-}
-
-// Based on ddcutil's get_i2c_device_sysfs_name() (sysfs_base.c:1175)
-func getI2CDeviceSysfsName(busno int) string {
- path := fmt.Sprintf("/sys/bus/i2c/devices/i2c-%d/name", busno)
- data, err := os.ReadFile(path)
- if err != nil {
- return ""
- }
- return strings.TrimSpace(string(data))
-}
-
-// Based on ddcutil's get_i2c_device_sysfs_class() (sysfs_base.c:1380)
-func getI2CDeviceSysfsClass(busno int) uint32 {
- classPath := fmt.Sprintf("/sys/bus/i2c/devices/i2c-%d/device/class", busno)
- data, err := os.ReadFile(classPath)
- if err != nil {
- classPath = fmt.Sprintf("/sys/bus/i2c/devices/i2c-%d/device/device/device/class", busno)
- data, err = os.ReadFile(classPath)
- if err != nil {
- return 0
- }
- }
-
- classStr := strings.TrimSpace(string(data))
- classStr = strings.TrimPrefix(classStr, "0x")
-
- class, err := strconv.ParseUint(classStr, 16, 32)
- if err != nil {
- return 0
- }
-
- return uint32(class)
-}
-
-// Based on ddcutil's get_i2c_sysfs_driver_by_busno() (sysfs_base.c:1284)
-func getI2CSysfsDriver(busno int) string {
- devicePath := fmt.Sprintf("/sys/bus/i2c/devices/i2c-%d", busno)
- adapterPath, err := findI2CAdapter(devicePath)
- if err != nil {
- return ""
- }
-
- driverLink := filepath.Join(adapterPath, "driver")
- target, err := os.Readlink(driverLink)
- if err != nil {
- return ""
- }
-
- return filepath.Base(target)
-}
-
-func findI2CAdapter(devicePath string) (string, error) {
- currentPath := devicePath
-
- for depth := 0; depth < 10; depth++ {
- if _, err := os.Stat(filepath.Join(currentPath, "name")); err == nil {
- return currentPath, nil
- }
-
- deviceLink := filepath.Join(currentPath, "device")
- target, err := os.Readlink(deviceLink)
- if err != nil {
- break
- }
-
- if !filepath.IsAbs(target) {
- target = filepath.Join(filepath.Dir(currentPath), target)
- }
- currentPath = filepath.Clean(target)
- }
-
- return "", fmt.Errorf("could not find adapter for %s", devicePath)
-}
diff --git a/nix/inputs/dms-cli/internal/server/brightness/ddc_filter_test.go b/nix/inputs/dms-cli/internal/server/brightness/ddc_filter_test.go
deleted file mode 100644
index 5f365c6..0000000
--- a/nix/inputs/dms-cli/internal/server/brightness/ddc_filter_test.go
+++ /dev/null
@@ -1,123 +0,0 @@
-package brightness
-
-import (
- "testing"
-)
-
-func TestIsIgnorableI2CDeviceName(t *testing.T) {
- tests := []struct {
- name string
- deviceName string
- driver string
- want bool
- }{
- {
- name: "AMDGPU SMU should be ignored",
- deviceName: "AMDGPU SMU",
- driver: "amdgpu",
- want: true,
- },
- {
- name: "SMBus should be ignored",
- deviceName: "SMBus I801 adapter",
- driver: "",
- want: true,
- },
- {
- name: "Synopsys DesignWare should be ignored",
- deviceName: "Synopsys DesignWare I2C adapter",
- driver: "",
- want: true,
- },
- {
- name: "smu prefix should be ignored (Mac G5)",
- deviceName: "smu-i2c-controller",
- driver: "",
- want: true,
- },
- {
- name: "Regular NVIDIA DDC should not be ignored",
- deviceName: "NVIDIA i2c adapter 1",
- driver: "nvidia",
- want: false,
- },
- {
- name: "nouveau nvkm bus should not be ignored",
- deviceName: "nvkm-0000:01:00.0-bus-0000",
- driver: "nouveau",
- want: false,
- },
- {
- name: "nouveau non-nvkm bus should be ignored",
- deviceName: "nouveau-other-bus",
- driver: "nouveau",
- want: true,
- },
- {
- name: "Regular AMD display adapter should not be ignored",
- deviceName: "AMDGPU DM i2c hw bus 0",
- driver: "amdgpu",
- want: false,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := isIgnorableI2CDeviceName(tt.deviceName, tt.driver)
- if got != tt.want {
- t.Errorf("isIgnorableI2CDeviceName(%q, %q) = %v, want %v",
- tt.deviceName, tt.driver, got, tt.want)
- }
- })
- }
-}
-
-func TestClassFiltering(t *testing.T) {
- tests := []struct {
- name string
- class uint32
- want bool
- }{
- {
- name: "Display adapter class should not be ignored",
- class: 0x030000,
- want: false,
- },
- {
- name: "Docking station class should not be ignored",
- class: 0x0a0000,
- want: false,
- },
- {
- name: "Display adapter with subclass should not be ignored",
- class: 0x030001,
- want: false,
- },
- {
- name: "SMBus class should be ignored",
- class: 0x0c0500,
- want: true,
- },
- {
- name: "Bridge class should be ignored",
- class: 0x060400,
- want: true,
- },
- {
- name: "Generic system peripheral should be ignored",
- class: 0x088000,
- want: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- // Test the class filtering logic directly
- classHigh := tt.class & 0xFFFF0000
- ignorable := (classHigh != 0x030000 && classHigh != 0x0A0000)
- if ignorable != tt.want {
- t.Errorf("class 0x%08x: ignorable = %v, want %v", tt.class, ignorable, tt.want)
- }
- })
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/brightness/ddc_test.go b/nix/inputs/dms-cli/internal/server/brightness/ddc_test.go
deleted file mode 100644
index 7f85510..0000000
--- a/nix/inputs/dms-cli/internal/server/brightness/ddc_test.go
+++ /dev/null
@@ -1,135 +0,0 @@
-package brightness
-
-import (
- "testing"
-)
-
-func TestDDCBackend_PercentConversions(t *testing.T) {
- tests := []struct {
- name string
- max int
- percent int
- wantValue int
- }{
- {
- name: "0% should map to minValue=1",
- max: 100,
- percent: 0,
- wantValue: 1,
- },
- {
- name: "1% should be 1",
- max: 100,
- percent: 1,
- wantValue: 1,
- },
- {
- name: "50% should be ~50",
- max: 100,
- percent: 50,
- wantValue: 50,
- },
- {
- name: "100% should be max",
- max: 100,
- percent: 100,
- wantValue: 100,
- },
- }
-
- b := &DDCBackend{}
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := b.percentToValue(tt.percent, tt.max, false)
- diff := got - tt.wantValue
- if diff < 0 {
- diff = -diff
- }
- if diff > 1 {
- t.Errorf("percentToValue() = %v, want %v (±1)", got, tt.wantValue)
- }
- })
- }
-}
-
-func TestDDCBackend_ValueToPercent(t *testing.T) {
- tests := []struct {
- name string
- max int
- value int
- wantPercent int
- tolerance int
- }{
- {
- name: "zero value should be 1%",
- max: 100,
- value: 0,
- wantPercent: 1,
- tolerance: 0,
- },
- {
- name: "min value should be 1%",
- max: 100,
- value: 1,
- wantPercent: 1,
- tolerance: 0,
- },
- {
- name: "mid value should be ~50%",
- max: 100,
- value: 50,
- wantPercent: 50,
- tolerance: 2,
- },
- {
- name: "max value should be 100%",
- max: 100,
- value: 100,
- wantPercent: 100,
- tolerance: 0,
- },
- }
-
- b := &DDCBackend{}
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := b.valueToPercent(tt.value, tt.max, false)
- diff := got - tt.wantPercent
- if diff < 0 {
- diff = -diff
- }
- if diff > tt.tolerance {
- t.Errorf("valueToPercent() = %v, want %v (±%d)", got, tt.wantPercent, tt.tolerance)
- }
- })
- }
-}
-
-func TestDDCBackend_RoundTrip(t *testing.T) {
- b := &DDCBackend{}
-
- tests := []struct {
- name string
- max int
- percent int
- }{
- {"1%", 100, 1},
- {"25%", 100, 25},
- {"50%", 100, 50},
- {"75%", 100, 75},
- {"100%", 100, 100},
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- value := b.percentToValue(tt.percent, tt.max, false)
- gotPercent := b.valueToPercent(value, tt.max, false)
-
- if diff := tt.percent - gotPercent; diff < -1 || diff > 1 {
- t.Errorf("round trip failed: wanted %d%%, got %d%% (value=%d)", tt.percent, gotPercent, value)
- }
- })
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/brightness/handlers.go b/nix/inputs/dms-cli/internal/server/brightness/handlers.go
deleted file mode 100644
index 7a1e35d..0000000
--- a/nix/inputs/dms-cli/internal/server/brightness/handlers.go
+++ /dev/null
@@ -1,163 +0,0 @@
-package brightness
-
-import (
- "encoding/json"
- "net"
-
- "github.com/AvengeMedia/danklinux/internal/server/models"
-)
-
-func HandleRequest(conn net.Conn, req Request, m *Manager) {
- switch req.Method {
- case "brightness.getState":
- handleGetState(conn, req, m)
- case "brightness.setBrightness":
- handleSetBrightness(conn, req, m)
- case "brightness.increment":
- handleIncrement(conn, req, m)
- case "brightness.decrement":
- handleDecrement(conn, req, m)
- case "brightness.rescan":
- handleRescan(conn, req, m)
- case "brightness.subscribe":
- handleSubscribe(conn, req, m)
- default:
- models.RespondError(conn, req.ID.(int), "unknown method: "+req.Method)
- }
-}
-
-func handleGetState(conn net.Conn, req Request, m *Manager) {
- state := m.GetState()
- models.Respond(conn, req.ID.(int), state)
-}
-
-func handleSetBrightness(conn net.Conn, req Request, m *Manager) {
- var params SetBrightnessParams
-
- device, ok := req.Params["device"].(string)
- if !ok {
- models.RespondError(conn, req.ID.(int), "missing or invalid device parameter")
- return
- }
- params.Device = device
-
- percentFloat, ok := req.Params["percent"].(float64)
- if !ok {
- models.RespondError(conn, req.ID.(int), "missing or invalid percent parameter")
- return
- }
- params.Percent = int(percentFloat)
-
- if exponential, ok := req.Params["exponential"].(bool); ok {
- params.Exponential = exponential
- }
-
- exponent := 1.2
- if exponentFloat, ok := req.Params["exponent"].(float64); ok {
- params.Exponent = exponentFloat
- exponent = exponentFloat
- }
-
- if err := m.SetBrightnessWithExponent(params.Device, params.Percent, params.Exponential, exponent); err != nil {
- models.RespondError(conn, req.ID.(int), err.Error())
- return
- }
-
- state := m.GetState()
- models.Respond(conn, req.ID.(int), state)
-}
-
-func handleIncrement(conn net.Conn, req Request, m *Manager) {
- device, ok := req.Params["device"].(string)
- if !ok {
- models.RespondError(conn, req.ID.(int), "missing or invalid device parameter")
- return
- }
-
- step := 10
- if stepFloat, ok := req.Params["step"].(float64); ok {
- step = int(stepFloat)
- }
-
- exponential := false
- if expBool, ok := req.Params["exponential"].(bool); ok {
- exponential = expBool
- }
-
- exponent := 1.2
- if exponentFloat, ok := req.Params["exponent"].(float64); ok {
- exponent = exponentFloat
- }
-
- if err := m.IncrementBrightnessWithExponent(device, step, exponential, exponent); err != nil {
- models.RespondError(conn, req.ID.(int), err.Error())
- return
- }
-
- state := m.GetState()
- models.Respond(conn, req.ID.(int), state)
-}
-
-func handleDecrement(conn net.Conn, req Request, m *Manager) {
- device, ok := req.Params["device"].(string)
- if !ok {
- models.RespondError(conn, req.ID.(int), "missing or invalid device parameter")
- return
- }
-
- step := 10
- if stepFloat, ok := req.Params["step"].(float64); ok {
- step = int(stepFloat)
- }
-
- exponential := false
- if expBool, ok := req.Params["exponential"].(bool); ok {
- exponential = expBool
- }
-
- exponent := 1.2
- if exponentFloat, ok := req.Params["exponent"].(float64); ok {
- exponent = exponentFloat
- }
-
- if err := m.IncrementBrightnessWithExponent(device, -step, exponential, exponent); err != nil {
- models.RespondError(conn, req.ID.(int), err.Error())
- return
- }
-
- state := m.GetState()
- models.Respond(conn, req.ID.(int), state)
-}
-
-func handleRescan(conn net.Conn, req Request, m *Manager) {
- m.Rescan()
- state := m.GetState()
- models.Respond(conn, req.ID.(int), state)
-}
-
-func handleSubscribe(conn net.Conn, req Request, m *Manager) {
- clientID := "brightness-subscriber"
- if idStr, ok := req.ID.(string); ok && idStr != "" {
- clientID = idStr
- }
-
- ch := m.Subscribe(clientID)
- defer m.Unsubscribe(clientID)
-
- initialState := m.GetState()
- if err := json.NewEncoder(conn).Encode(models.Response[State]{
- ID: req.ID.(int),
- Result: &initialState,
- }); err != nil {
- return
- }
-
- for state := range ch {
- if err := json.NewEncoder(conn).Encode(models.Response[State]{
- ID: req.ID.(int),
- Result: &state,
- }); err != nil {
- return
- }
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/brightness/logind.go b/nix/inputs/dms-cli/internal/server/brightness/logind.go
deleted file mode 100644
index 57c6b39..0000000
--- a/nix/inputs/dms-cli/internal/server/brightness/logind.go
+++ /dev/null
@@ -1,67 +0,0 @@
-package brightness
-
-import (
- "fmt"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/godbus/dbus/v5"
-)
-
-type DBusConn interface {
- Object(dest string, path dbus.ObjectPath) dbus.BusObject
- Close() error
-}
-
-type LogindBackend struct {
- conn DBusConn
- connOnce bool
-}
-
-func NewLogindBackend() (*LogindBackend, error) {
- conn, err := dbus.ConnectSystemBus()
- if err != nil {
- return nil, fmt.Errorf("connect to system bus: %w", err)
- }
-
- obj := conn.Object("org.freedesktop.login1", "/org/freedesktop/login1/session/auto")
- call := obj.Call("org.freedesktop.DBus.Peer.Ping", 0)
- if call.Err != nil {
- conn.Close()
- return nil, fmt.Errorf("logind not available: %w", call.Err)
- }
-
- conn.Close()
-
- return &LogindBackend{}, nil
-}
-
-func NewLogindBackendWithConn(conn DBusConn) *LogindBackend {
- return &LogindBackend{
- conn: conn,
- }
-}
-
-func (b *LogindBackend) SetBrightness(subsystem, name string, brightness uint32) error {
- if b.conn == nil {
- conn, err := dbus.ConnectSystemBus()
- if err != nil {
- return fmt.Errorf("connect to system bus: %w", err)
- }
- b.conn = conn
- }
-
- obj := b.conn.Object("org.freedesktop.login1", "/org/freedesktop/login1/session/auto")
- call := obj.Call("org.freedesktop.login1.Session.SetBrightness", 0, subsystem, name, brightness)
- if call.Err != nil {
- return fmt.Errorf("dbus call failed: %w", call.Err)
- }
-
- log.Debugf("logind: set %s/%s to %d", subsystem, name, brightness)
- return nil
-}
-
-func (b *LogindBackend) Close() {
- if b.conn != nil {
- b.conn.Close()
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/brightness/logind_test.go b/nix/inputs/dms-cli/internal/server/brightness/logind_test.go
deleted file mode 100644
index 74ecb9d..0000000
--- a/nix/inputs/dms-cli/internal/server/brightness/logind_test.go
+++ /dev/null
@@ -1,95 +0,0 @@
-package brightness
-
-import (
- "errors"
- "testing"
-
- mocks_brightness "github.com/AvengeMedia/danklinux/internal/mocks/brightness"
- mock_dbus "github.com/AvengeMedia/danklinux/internal/mocks/github.com/godbus/dbus/v5"
- "github.com/godbus/dbus/v5"
- "github.com/stretchr/testify/mock"
-)
-
-func TestLogindBackend_SetBrightness_Success(t *testing.T) {
- mockConn := mocks_brightness.NewMockDBusConn(t)
- mockObj := mock_dbus.NewMockBusObject(t)
-
- backend := NewLogindBackendWithConn(mockConn)
-
- mockConn.EXPECT().
- Object("org.freedesktop.login1", dbus.ObjectPath("/org/freedesktop/login1/session/auto")).
- Return(mockObj).
- Once()
-
- mockObj.EXPECT().
- Call("org.freedesktop.login1.Session.SetBrightness", dbus.Flags(0), "backlight", "nvidia_0", uint32(75)).
- Return(&dbus.Call{Err: nil}).
- Once()
-
- err := backend.SetBrightness("backlight", "nvidia_0", 75)
- if err != nil {
- t.Errorf("SetBrightness() error = %v, want nil", err)
- }
-}
-
-func TestLogindBackend_SetBrightness_DBusError(t *testing.T) {
- mockConn := mocks_brightness.NewMockDBusConn(t)
- mockObj := mock_dbus.NewMockBusObject(t)
-
- backend := NewLogindBackendWithConn(mockConn)
-
- mockConn.EXPECT().
- Object("org.freedesktop.login1", dbus.ObjectPath("/org/freedesktop/login1/session/auto")).
- Return(mockObj).
- Once()
-
- dbusErr := errors.New("permission denied")
- mockObj.EXPECT().
- Call("org.freedesktop.login1.Session.SetBrightness", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
- Return(&dbus.Call{Err: dbusErr}).
- Once()
-
- err := backend.SetBrightness("backlight", "test_device", 50)
- if err == nil {
- t.Error("SetBrightness() error = nil, want error")
- }
-}
-
-func TestLogindBackend_SetBrightness_LEDDevice(t *testing.T) {
- mockConn := mocks_brightness.NewMockDBusConn(t)
- mockObj := mock_dbus.NewMockBusObject(t)
-
- backend := NewLogindBackendWithConn(mockConn)
-
- mockConn.EXPECT().
- Object("org.freedesktop.login1", dbus.ObjectPath("/org/freedesktop/login1/session/auto")).
- Return(mockObj).
- Once()
-
- mockObj.EXPECT().
- Call("org.freedesktop.login1.Session.SetBrightness", dbus.Flags(0), "leds", "test_led", uint32(128)).
- Return(&dbus.Call{Err: nil}).
- Once()
-
- err := backend.SetBrightness("leds", "test_led", 128)
- if err != nil {
- t.Errorf("SetBrightness() error = %v, want nil", err)
- }
-}
-
-func TestLogindBackend_Close(t *testing.T) {
- mockConn := mocks_brightness.NewMockDBusConn(t)
- backend := NewLogindBackendWithConn(mockConn)
-
- mockConn.EXPECT().
- Close().
- Return(nil).
- Once()
-
- backend.Close()
-}
-
-func TestLogindBackend_Close_NilConn(t *testing.T) {
- backend := &LogindBackend{conn: nil}
- backend.Close()
-}
diff --git a/nix/inputs/dms-cli/internal/server/brightness/manager.go b/nix/inputs/dms-cli/internal/server/brightness/manager.go
deleted file mode 100644
index 96351fc..0000000
--- a/nix/inputs/dms-cli/internal/server/brightness/manager.go
+++ /dev/null
@@ -1,383 +0,0 @@
-package brightness
-
-import (
- "fmt"
- "sort"
- "strings"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/log"
-)
-
-func NewManager() (*Manager, error) {
- return NewManagerWithOptions(false)
-}
-
-func NewManagerWithOptions(exponential bool) (*Manager, error) {
- m := &Manager{
- subscribers: make(map[string]chan State),
- updateSubscribers: make(map[string]chan DeviceUpdate),
- stopChan: make(chan struct{}),
- exponential: exponential,
- }
-
- go m.initLogind()
- go m.initSysfs()
- go m.initDDC()
-
- return m, nil
-}
-
-func (m *Manager) initLogind() {
- log.Debug("Initializing logind backend...")
- logind, err := NewLogindBackend()
- if err != nil {
- log.Infof("Logind backend not available: %v", err)
- log.Info("Will use direct sysfs access for brightness control")
- return
- }
-
- m.logindBackend = logind
- m.logindReady = true
- log.Info("Logind backend initialized - will use for brightness control")
-}
-
-func (m *Manager) initSysfs() {
- log.Debug("Initializing sysfs backend...")
- sysfs, err := NewSysfsBackend()
- if err != nil {
- log.Warnf("Failed to initialize sysfs backend: %v", err)
- return
- }
-
- devices, err := sysfs.GetDevices()
- if err != nil {
- log.Warnf("Failed to get initial sysfs devices: %v", err)
- m.sysfsBackend = sysfs
- m.sysfsReady = true
- m.updateState()
- return
- }
-
- log.Infof("Sysfs backend initialized with %d devices", len(devices))
- for _, d := range devices {
- log.Debugf(" - %s: %s (%d%%)", d.ID, d.Name, d.CurrentPercent)
- }
-
- m.sysfsBackend = sysfs
- m.sysfsReady = true
- m.updateState()
-}
-
-func (m *Manager) initDDC() {
- ddc, err := NewDDCBackend()
- if err != nil {
- log.Debugf("Failed to initialize DDC backend: %v", err)
- return
- }
-
- m.ddcBackend = ddc
- m.ddcReady = true
- log.Info("DDC backend initialized")
-
- m.updateState()
-}
-
-func (m *Manager) Rescan() {
- log.Debug("Rescanning brightness devices...")
- m.updateState()
-}
-
-func sortDevices(devices []Device) {
- sort.Slice(devices, func(i, j int) bool {
- classOrder := map[DeviceClass]int{
- ClassBacklight: 0,
- ClassDDC: 1,
- ClassLED: 2,
- }
-
- orderI := classOrder[devices[i].Class]
- orderJ := classOrder[devices[j].Class]
-
- if orderI != orderJ {
- return orderI < orderJ
- }
-
- return devices[i].Name < devices[j].Name
- })
-}
-
-func stateChanged(old, new State) bool {
- if len(old.Devices) != len(new.Devices) {
- return true
- }
-
- oldMap := make(map[string]Device)
- for _, d := range old.Devices {
- oldMap[d.ID] = d
- }
-
- for _, newDev := range new.Devices {
- oldDev, exists := oldMap[newDev.ID]
- if !exists {
- return true
- }
- if oldDev.Current != newDev.Current || oldDev.Max != newDev.Max {
- return true
- }
- }
-
- return false
-}
-
-func (m *Manager) updateState() {
- allDevices := make([]Device, 0)
-
- if m.sysfsReady && m.sysfsBackend != nil {
- devices, err := m.sysfsBackend.GetDevices()
- if err != nil {
- log.Debugf("Failed to get sysfs devices: %v", err)
- }
- if err == nil {
- allDevices = append(allDevices, devices...)
- }
- }
-
- if m.ddcReady && m.ddcBackend != nil {
- devices, err := m.ddcBackend.GetDevices()
- if err != nil {
- log.Debugf("Failed to get DDC devices: %v", err)
- }
- if err == nil {
- allDevices = append(allDevices, devices...)
- }
- }
-
- sortDevices(allDevices)
-
- m.stateMutex.Lock()
- oldState := m.state
- newState := State{Devices: allDevices}
-
- if !stateChanged(oldState, newState) {
- m.stateMutex.Unlock()
- return
- }
-
- m.state = newState
- m.stateMutex.Unlock()
- log.Debugf("State changed, notifying subscribers")
- m.NotifySubscribers()
-}
-
-func (m *Manager) SetBrightness(deviceID string, percent int) error {
- return m.SetBrightnessWithMode(deviceID, percent, m.exponential)
-}
-
-func (m *Manager) SetBrightnessWithMode(deviceID string, percent int, exponential bool) error {
- return m.SetBrightnessWithExponent(deviceID, percent, exponential, 1.2)
-}
-
-func (m *Manager) SetBrightnessWithExponent(deviceID string, percent int, exponential bool, exponent float64) error {
- if percent < 0 || percent > 100 {
- return fmt.Errorf("percent out of range: %d", percent)
- }
-
- log.Debugf("SetBrightness: %s to %d%%", deviceID, percent)
-
- m.stateMutex.Lock()
- currentState := m.state
- var found bool
- var deviceClass DeviceClass
- var deviceIndex int
-
- log.Debugf("Current state has %d devices", len(currentState.Devices))
-
- for i, dev := range currentState.Devices {
- if dev.ID == deviceID {
- found = true
- deviceClass = dev.Class
- deviceIndex = i
- break
- }
- }
-
- if !found {
- m.stateMutex.Unlock()
- log.Debugf("Device not found in state: %s", deviceID)
- return fmt.Errorf("device not found: %s", deviceID)
- }
-
- newDevices := make([]Device, len(currentState.Devices))
- copy(newDevices, currentState.Devices)
- newDevices[deviceIndex].CurrentPercent = percent
- m.state = State{Devices: newDevices}
- m.stateMutex.Unlock()
-
- var err error
- if deviceClass == ClassDDC {
- log.Debugf("Calling DDC backend for %s", deviceID)
- err = m.ddcBackend.SetBrightnessWithExponent(deviceID, percent, exponential, exponent, func() {
- m.updateState()
- m.debouncedBroadcast(deviceID)
- })
- } else if m.logindReady && m.logindBackend != nil {
- log.Debugf("Calling logind backend for %s", deviceID)
- err = m.setViaSysfsWithLogindWithExponent(deviceID, percent, exponential, exponent)
- } else {
- log.Debugf("Calling sysfs backend for %s", deviceID)
- err = m.sysfsBackend.SetBrightnessWithExponent(deviceID, percent, exponential, exponent)
- }
-
- if err != nil {
- m.updateState()
- return fmt.Errorf("failed to set brightness: %w", err)
- }
-
- if deviceClass != ClassDDC {
- log.Debugf("Queueing broadcast for %s", deviceID)
- m.debouncedBroadcast(deviceID)
- }
- return nil
-}
-
-func (m *Manager) IncrementBrightness(deviceID string, step int) error {
- return m.IncrementBrightnessWithMode(deviceID, step, m.exponential)
-}
-
-func (m *Manager) IncrementBrightnessWithMode(deviceID string, step int, exponential bool) error {
- return m.IncrementBrightnessWithExponent(deviceID, step, exponential, 1.2)
-}
-
-func (m *Manager) IncrementBrightnessWithExponent(deviceID string, step int, exponential bool, exponent float64) error {
- m.stateMutex.RLock()
- currentState := m.state
- m.stateMutex.RUnlock()
-
- var currentPercent int
- var found bool
-
- for _, dev := range currentState.Devices {
- if dev.ID == deviceID {
- currentPercent = dev.CurrentPercent
- found = true
- break
- }
- }
-
- if !found {
- return fmt.Errorf("device not found: %s", deviceID)
- }
-
- newPercent := currentPercent + step
- if newPercent > 100 {
- newPercent = 100
- }
- if newPercent < 0 {
- newPercent = 0
- }
-
- return m.SetBrightnessWithExponent(deviceID, newPercent, exponential, exponent)
-}
-
-func (m *Manager) DecrementBrightness(deviceID string, step int) error {
- return m.IncrementBrightness(deviceID, -step)
-}
-
-func (m *Manager) setViaSysfsWithLogind(deviceID string, percent int, exponential bool) error {
- return m.setViaSysfsWithLogindWithExponent(deviceID, percent, exponential, 1.2)
-}
-
-func (m *Manager) setViaSysfsWithLogindWithExponent(deviceID string, percent int, exponential bool, exponent float64) error {
- parts := strings.SplitN(deviceID, ":", 2)
- if len(parts) != 2 {
- return fmt.Errorf("invalid device id: %s", deviceID)
- }
-
- subsystem := parts[0]
- name := parts[1]
-
- dev, err := m.sysfsBackend.GetDevice(deviceID)
- if err != nil {
- return err
- }
-
- value := m.sysfsBackend.PercentToValueWithExponent(percent, dev, exponential, exponent)
-
- if m.logindBackend == nil {
- return m.sysfsBackend.SetBrightnessWithExponent(deviceID, percent, exponential, exponent)
- }
-
- err = m.logindBackend.SetBrightness(subsystem, name, uint32(value))
- if err != nil {
- log.Debugf("logind SetBrightness failed, falling back to direct sysfs: %v", err)
- return m.sysfsBackend.SetBrightnessWithExponent(deviceID, percent, exponential, exponent)
- }
-
- log.Debugf("set %s to %d%% (%d/%d) via logind", deviceID, percent, value, dev.maxBrightness)
- return nil
-}
-
-func (m *Manager) debouncedBroadcast(deviceID string) {
- m.broadcastMutex.Lock()
- defer m.broadcastMutex.Unlock()
-
- m.broadcastPending = true
- m.pendingDeviceID = deviceID
-
- if m.broadcastTimer == nil {
- m.broadcastTimer = time.AfterFunc(150*time.Millisecond, func() {
- m.broadcastMutex.Lock()
- pending := m.broadcastPending
- deviceID := m.pendingDeviceID
- m.broadcastPending = false
- m.pendingDeviceID = ""
- m.broadcastMutex.Unlock()
-
- if !pending || deviceID == "" {
- return
- }
-
- m.broadcastDeviceUpdate(deviceID)
- })
- } else {
- m.broadcastTimer.Reset(150 * time.Millisecond)
- }
-}
-
-func (m *Manager) broadcastDeviceUpdate(deviceID string) {
- m.stateMutex.RLock()
- var targetDevice *Device
- for _, dev := range m.state.Devices {
- if dev.ID == deviceID {
- devCopy := dev
- targetDevice = &devCopy
- break
- }
- }
- m.stateMutex.RUnlock()
-
- if targetDevice == nil {
- log.Debugf("Device not found for broadcast: %s", deviceID)
- return
- }
-
- update := DeviceUpdate{Device: *targetDevice}
-
- m.subMutex.RLock()
- defer m.subMutex.RUnlock()
-
- if len(m.updateSubscribers) == 0 {
- log.Debugf("No update subscribers for device: %s", deviceID)
- return
- }
-
- log.Debugf("Broadcasting device update: %s at %d%%", deviceID, targetDevice.CurrentPercent)
-
- for _, ch := range m.updateSubscribers {
- select {
- case ch <- update:
- default:
- }
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/brightness/manager_test.go b/nix/inputs/dms-cli/internal/server/brightness/manager_test.go
deleted file mode 100644
index a8ae0f8..0000000
--- a/nix/inputs/dms-cli/internal/server/brightness/manager_test.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package brightness
-
-import (
- "testing"
-)
-
-// Manager tests can be added here as needed
-func TestManager_Placeholder(t *testing.T) {
- // Placeholder test to keep the test file valid
- t.Skip("No tests implemented yet")
-}
diff --git a/nix/inputs/dms-cli/internal/server/brightness/sysfs.go b/nix/inputs/dms-cli/internal/server/brightness/sysfs.go
deleted file mode 100644
index 21a04da..0000000
--- a/nix/inputs/dms-cli/internal/server/brightness/sysfs.go
+++ /dev/null
@@ -1,272 +0,0 @@
-package brightness
-
-import (
- "fmt"
- "math"
- "os"
- "path/filepath"
- "strconv"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/log"
-)
-
-func NewSysfsBackend() (*SysfsBackend, error) {
- b := &SysfsBackend{
- basePath: "/sys/class",
- classes: []string{"backlight", "leds"},
- deviceCache: make(map[string]*sysfsDevice),
- }
-
- if err := b.scanDevices(); err != nil {
- return nil, err
- }
-
- return b, nil
-}
-
-func (b *SysfsBackend) scanDevices() error {
- b.deviceCacheMutex.Lock()
- defer b.deviceCacheMutex.Unlock()
-
- for _, class := range b.classes {
- classPath := filepath.Join(b.basePath, class)
- entries, err := os.ReadDir(classPath)
- if err != nil {
- if os.IsNotExist(err) {
- continue
- }
- return fmt.Errorf("read %s: %w", classPath, err)
- }
-
- for _, entry := range entries {
- devicePath := filepath.Join(classPath, entry.Name())
-
- stat, err := os.Stat(devicePath)
- if err != nil || !stat.IsDir() {
- continue
- }
- maxPath := filepath.Join(devicePath, "max_brightness")
-
- maxData, err := os.ReadFile(maxPath)
- if err != nil {
- log.Debugf("skip %s/%s: no max_brightness", class, entry.Name())
- continue
- }
-
- maxBrightness, err := strconv.Atoi(strings.TrimSpace(string(maxData)))
- if err != nil || maxBrightness <= 0 {
- log.Debugf("skip %s/%s: invalid max_brightness", class, entry.Name())
- continue
- }
-
- deviceClass := ClassBacklight
- minValue := 1
- if class == "leds" {
- deviceClass = ClassLED
- minValue = 0
- }
-
- deviceID := fmt.Sprintf("%s:%s", class, entry.Name())
- b.deviceCache[deviceID] = &sysfsDevice{
- class: deviceClass,
- id: deviceID,
- name: entry.Name(),
- maxBrightness: maxBrightness,
- minValue: minValue,
- }
-
- log.Debugf("found %s device: %s (max=%d)", class, entry.Name(), maxBrightness)
- }
- }
-
- return nil
-}
-
-func shouldSuppressDevice(name string) bool {
- if strings.HasSuffix(name, "::lan") {
- return true
- }
-
- keyboardLEDs := []string{
- "::scrolllock",
- "::capslock",
- "::numlock",
- "::kana",
- "::compose",
- }
-
- for _, suffix := range keyboardLEDs {
- if strings.HasSuffix(name, suffix) {
- return true
- }
- }
-
- return false
-}
-
-func (b *SysfsBackend) GetDevices() ([]Device, error) {
- b.deviceCacheMutex.RLock()
- defer b.deviceCacheMutex.RUnlock()
-
- devices := make([]Device, 0, len(b.deviceCache))
-
- for _, dev := range b.deviceCache {
- if shouldSuppressDevice(dev.name) {
- continue
- }
-
- parts := strings.SplitN(dev.id, ":", 2)
- if len(parts) != 2 {
- continue
- }
-
- class := parts[0]
- name := parts[1]
-
- devicePath := filepath.Join(b.basePath, class, name)
- brightnessPath := filepath.Join(devicePath, "brightness")
-
- brightnessData, err := os.ReadFile(brightnessPath)
- if err != nil {
- log.Debugf("failed to read brightness for %s: %v", dev.id, err)
- continue
- }
-
- current, err := strconv.Atoi(strings.TrimSpace(string(brightnessData)))
- if err != nil {
- log.Debugf("failed to parse brightness for %s: %v", dev.id, err)
- continue
- }
-
- percent := b.ValueToPercent(current, dev, false)
-
- devices = append(devices, Device{
- Class: dev.class,
- ID: dev.id,
- Name: dev.name,
- Current: current,
- Max: dev.maxBrightness,
- CurrentPercent: percent,
- Backend: "sysfs",
- })
- }
-
- return devices, nil
-}
-
-func (b *SysfsBackend) GetDevice(id string) (*sysfsDevice, error) {
- b.deviceCacheMutex.RLock()
- defer b.deviceCacheMutex.RUnlock()
-
- dev, ok := b.deviceCache[id]
- if !ok {
- return nil, fmt.Errorf("device not found: %s", id)
- }
-
- return dev, nil
-}
-
-func (b *SysfsBackend) SetBrightness(id string, percent int, exponential bool) error {
- return b.SetBrightnessWithExponent(id, percent, exponential, 1.2)
-}
-
-func (b *SysfsBackend) SetBrightnessWithExponent(id string, percent int, exponential bool, exponent float64) error {
- dev, err := b.GetDevice(id)
- if err != nil {
- return err
- }
-
- if percent < 0 || percent > 100 {
- return fmt.Errorf("percent out of range: %d", percent)
- }
-
- value := b.PercentToValueWithExponent(percent, dev, exponential, exponent)
-
- parts := strings.SplitN(id, ":", 2)
- if len(parts) != 2 {
- return fmt.Errorf("invalid device id: %s", id)
- }
-
- class := parts[0]
- name := parts[1]
-
- devicePath := filepath.Join(b.basePath, class, name)
- brightnessPath := filepath.Join(devicePath, "brightness")
-
- data := []byte(fmt.Sprintf("%d", value))
- if err := os.WriteFile(brightnessPath, data, 0644); err != nil {
- return fmt.Errorf("write brightness: %w", err)
- }
-
- log.Debugf("set %s to %d%% (%d/%d) via direct sysfs", id, percent, value, dev.maxBrightness)
-
- return nil
-}
-
-func (b *SysfsBackend) PercentToValue(percent int, dev *sysfsDevice, exponential bool) int {
- return b.PercentToValueWithExponent(percent, dev, exponential, 1.2)
-}
-
-func (b *SysfsBackend) PercentToValueWithExponent(percent int, dev *sysfsDevice, exponential bool, exponent float64) int {
- if percent == 0 {
- return dev.minValue
- }
-
- usableRange := dev.maxBrightness - dev.minValue
- var value int
-
- if exponential {
- normalizedPercent := float64(percent) / 100.0
- hardwarePercent := math.Pow(normalizedPercent, exponent)
- value = dev.minValue + int(math.Round(hardwarePercent*float64(usableRange)))
- } else {
- value = dev.minValue + ((percent - 1) * usableRange / 99)
- }
-
- if value < dev.minValue {
- value = dev.minValue
- }
- if value > dev.maxBrightness {
- value = dev.maxBrightness
- }
-
- return value
-}
-
-func (b *SysfsBackend) ValueToPercent(value int, dev *sysfsDevice, exponential bool) int {
- return b.ValueToPercentWithExponent(value, dev, exponential, 1.2)
-}
-
-func (b *SysfsBackend) ValueToPercentWithExponent(value int, dev *sysfsDevice, exponential bool, exponent float64) int {
- if value <= dev.minValue {
- if dev.minValue == 0 && value == 0 {
- return 0
- }
- return 1
- }
-
- usableRange := dev.maxBrightness - dev.minValue
- if usableRange == 0 {
- return 100
- }
-
- var percent int
-
- if exponential {
- hardwarePercent := float64(value-dev.minValue) / float64(usableRange)
- normalizedPercent := math.Pow(hardwarePercent, 1.0/exponent)
- percent = int(math.Round(normalizedPercent * 100.0))
- } else {
- percent = 1 + ((value - dev.minValue) * 99 / usableRange)
- }
-
- if percent > 100 {
- percent = 100
- }
- if percent < 1 {
- percent = 1
- }
-
- return percent
-}
diff --git a/nix/inputs/dms-cli/internal/server/brightness/sysfs_logind_test.go b/nix/inputs/dms-cli/internal/server/brightness/sysfs_logind_test.go
deleted file mode 100644
index 58dd40e..0000000
--- a/nix/inputs/dms-cli/internal/server/brightness/sysfs_logind_test.go
+++ /dev/null
@@ -1,290 +0,0 @@
-package brightness
-
-import (
- "os"
- "path/filepath"
- "testing"
-
- mocks_brightness "github.com/AvengeMedia/danklinux/internal/mocks/brightness"
- mock_dbus "github.com/AvengeMedia/danklinux/internal/mocks/github.com/godbus/dbus/v5"
- "github.com/godbus/dbus/v5"
- "github.com/stretchr/testify/mock"
-)
-
-func TestManager_SetBrightness_LogindSuccess(t *testing.T) {
- tmpDir := t.TempDir()
-
- backlightDir := filepath.Join(tmpDir, "backlight", "test_backlight")
- if err := os.MkdirAll(backlightDir, 0755); err != nil {
- t.Fatal(err)
- }
- if err := os.WriteFile(filepath.Join(backlightDir, "max_brightness"), []byte("100\n"), 0644); err != nil {
- t.Fatal(err)
- }
- if err := os.WriteFile(filepath.Join(backlightDir, "brightness"), []byte("50\n"), 0644); err != nil {
- t.Fatal(err)
- }
-
- mockConn := mocks_brightness.NewMockDBusConn(t)
- mockObj := mock_dbus.NewMockBusObject(t)
-
- mockLogind := NewLogindBackendWithConn(mockConn)
-
- sysfs := &SysfsBackend{
- basePath: tmpDir,
- classes: []string{"backlight"},
- deviceCache: make(map[string]*sysfsDevice),
- }
-
- if err := sysfs.scanDevices(); err != nil {
- t.Fatal(err)
- }
-
- m := &Manager{
- logindBackend: mockLogind,
- sysfsBackend: sysfs,
- logindReady: true,
- sysfsReady: true,
- subscribers: make(map[string]chan State),
- updateSubscribers: make(map[string]chan DeviceUpdate),
- stopChan: make(chan struct{}),
- }
-
- m.state = State{
- Devices: []Device{
- {
- Class: ClassBacklight,
- ID: "backlight:test_backlight",
- Name: "test_backlight",
- Current: 50,
- Max: 100,
- CurrentPercent: 50,
- Backend: "sysfs",
- },
- },
- }
-
- mockConn.EXPECT().
- Object("org.freedesktop.login1", dbus.ObjectPath("/org/freedesktop/login1/session/auto")).
- Return(mockObj).
- Once()
-
- mockObj.EXPECT().
- Call("org.freedesktop.login1.Session.SetBrightness", mock.Anything, "backlight", "test_backlight", uint32(75)).
- Return(&dbus.Call{Err: nil}).
- Once()
-
- err := m.SetBrightness("backlight:test_backlight", 75)
- if err != nil {
- t.Errorf("SetBrightness() with logind error = %v, want nil", err)
- }
-
- data, _ := os.ReadFile(filepath.Join(backlightDir, "brightness"))
- if string(data) == "75\n" {
- t.Error("Direct sysfs write occurred when logind should have been used")
- }
-}
-
-func TestManager_SetBrightness_LogindFailsFallbackToSysfs(t *testing.T) {
- tmpDir := t.TempDir()
-
- backlightDir := filepath.Join(tmpDir, "backlight", "test_backlight")
- if err := os.MkdirAll(backlightDir, 0755); err != nil {
- t.Fatal(err)
- }
- if err := os.WriteFile(filepath.Join(backlightDir, "max_brightness"), []byte("100\n"), 0644); err != nil {
- t.Fatal(err)
- }
- if err := os.WriteFile(filepath.Join(backlightDir, "brightness"), []byte("50\n"), 0644); err != nil {
- t.Fatal(err)
- }
-
- mockConn := mocks_brightness.NewMockDBusConn(t)
- mockObj := mock_dbus.NewMockBusObject(t)
-
- mockLogind := NewLogindBackendWithConn(mockConn)
-
- sysfs := &SysfsBackend{
- basePath: tmpDir,
- classes: []string{"backlight"},
- deviceCache: make(map[string]*sysfsDevice),
- }
-
- if err := sysfs.scanDevices(); err != nil {
- t.Fatal(err)
- }
-
- m := &Manager{
- logindBackend: mockLogind,
- sysfsBackend: sysfs,
- logindReady: true,
- sysfsReady: true,
- subscribers: make(map[string]chan State),
- updateSubscribers: make(map[string]chan DeviceUpdate),
- stopChan: make(chan struct{}),
- }
-
- m.state = State{
- Devices: []Device{
- {
- Class: ClassBacklight,
- ID: "backlight:test_backlight",
- Name: "test_backlight",
- Current: 50,
- Max: 100,
- CurrentPercent: 50,
- Backend: "sysfs",
- },
- },
- }
-
- mockConn.EXPECT().
- Object("org.freedesktop.login1", dbus.ObjectPath("/org/freedesktop/login1/session/auto")).
- Return(mockObj).
- Once()
-
- mockObj.EXPECT().
- Call("org.freedesktop.login1.Session.SetBrightness", mock.Anything, "backlight", "test_backlight", mock.Anything).
- Return(&dbus.Call{Err: dbus.ErrMsgNoObject}).
- Once()
-
- err := m.SetBrightness("backlight:test_backlight", 75)
- if err != nil {
- t.Errorf("SetBrightness() with fallback error = %v, want nil", err)
- }
-
- data, _ := os.ReadFile(filepath.Join(backlightDir, "brightness"))
- brightness := string(data)
- if brightness != "75" {
- t.Errorf("Fallback sysfs write did not occur, got brightness = %q, want %q", brightness, "75")
- }
-}
-
-func TestManager_SetBrightness_NoLogind(t *testing.T) {
- tmpDir := t.TempDir()
-
- backlightDir := filepath.Join(tmpDir, "backlight", "test_backlight")
- if err := os.MkdirAll(backlightDir, 0755); err != nil {
- t.Fatal(err)
- }
- if err := os.WriteFile(filepath.Join(backlightDir, "max_brightness"), []byte("100\n"), 0644); err != nil {
- t.Fatal(err)
- }
- if err := os.WriteFile(filepath.Join(backlightDir, "brightness"), []byte("50\n"), 0644); err != nil {
- t.Fatal(err)
- }
-
- sysfs := &SysfsBackend{
- basePath: tmpDir,
- classes: []string{"backlight"},
- deviceCache: make(map[string]*sysfsDevice),
- }
-
- if err := sysfs.scanDevices(); err != nil {
- t.Fatal(err)
- }
-
- m := &Manager{
- logindBackend: nil,
- sysfsBackend: sysfs,
- logindReady: false,
- sysfsReady: true,
- subscribers: make(map[string]chan State),
- updateSubscribers: make(map[string]chan DeviceUpdate),
- stopChan: make(chan struct{}),
- }
-
- m.state = State{
- Devices: []Device{
- {
- Class: ClassBacklight,
- ID: "backlight:test_backlight",
- Name: "test_backlight",
- Current: 50,
- Max: 100,
- CurrentPercent: 50,
- Backend: "sysfs",
- },
- },
- }
-
- err := m.SetBrightness("backlight:test_backlight", 75)
- if err != nil {
- t.Errorf("SetBrightness() without logind error = %v, want nil", err)
- }
-
- data, _ := os.ReadFile(filepath.Join(backlightDir, "brightness"))
- brightness := string(data)
- if brightness != "75" {
- t.Errorf("Direct sysfs write = %q, want %q", brightness, "75")
- }
-}
-
-func TestManager_SetBrightness_LEDWithLogind(t *testing.T) {
- tmpDir := t.TempDir()
-
- ledsDir := filepath.Join(tmpDir, "leds", "test_led")
- if err := os.MkdirAll(ledsDir, 0755); err != nil {
- t.Fatal(err)
- }
- if err := os.WriteFile(filepath.Join(ledsDir, "max_brightness"), []byte("255\n"), 0644); err != nil {
- t.Fatal(err)
- }
- if err := os.WriteFile(filepath.Join(ledsDir, "brightness"), []byte("128\n"), 0644); err != nil {
- t.Fatal(err)
- }
-
- mockConn := mocks_brightness.NewMockDBusConn(t)
- mockObj := mock_dbus.NewMockBusObject(t)
-
- mockLogind := NewLogindBackendWithConn(mockConn)
-
- sysfs := &SysfsBackend{
- basePath: tmpDir,
- classes: []string{"leds"},
- deviceCache: make(map[string]*sysfsDevice),
- }
-
- if err := sysfs.scanDevices(); err != nil {
- t.Fatal(err)
- }
-
- m := &Manager{
- logindBackend: mockLogind,
- sysfsBackend: sysfs,
- logindReady: true,
- sysfsReady: true,
- subscribers: make(map[string]chan State),
- updateSubscribers: make(map[string]chan DeviceUpdate),
- stopChan: make(chan struct{}),
- }
-
- m.state = State{
- Devices: []Device{
- {
- Class: ClassLED,
- ID: "leds:test_led",
- Name: "test_led",
- Current: 128,
- Max: 255,
- CurrentPercent: 50,
- Backend: "sysfs",
- },
- },
- }
-
- mockConn.EXPECT().
- Object("org.freedesktop.login1", dbus.ObjectPath("/org/freedesktop/login1/session/auto")).
- Return(mockObj).
- Once()
-
- mockObj.EXPECT().
- Call("org.freedesktop.login1.Session.SetBrightness", mock.Anything, "leds", "test_led", uint32(0)).
- Return(&dbus.Call{Err: nil}).
- Once()
-
- err := m.SetBrightness("leds:test_led", 0)
- if err != nil {
- t.Errorf("SetBrightness() LED with logind error = %v, want nil", err)
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/brightness/sysfs_test.go b/nix/inputs/dms-cli/internal/server/brightness/sysfs_test.go
deleted file mode 100644
index b31db63..0000000
--- a/nix/inputs/dms-cli/internal/server/brightness/sysfs_test.go
+++ /dev/null
@@ -1,185 +0,0 @@
-package brightness
-
-import (
- "os"
- "path/filepath"
- "testing"
-)
-
-func TestSysfsBackend_PercentConversions(t *testing.T) {
- tests := []struct {
- name string
- device *sysfsDevice
- percent int
- wantValue int
- tolerance int
- }{
- {
- name: "backlight 0% should be minValue=1",
- device: &sysfsDevice{maxBrightness: 100, minValue: 1, class: ClassBacklight},
- percent: 0,
- wantValue: 1,
- tolerance: 0,
- },
- {
- name: "backlight 1% should be minValue=1",
- device: &sysfsDevice{maxBrightness: 100, minValue: 1, class: ClassBacklight},
- percent: 1,
- wantValue: 1,
- tolerance: 0,
- },
- {
- name: "backlight 50% should be ~50",
- device: &sysfsDevice{maxBrightness: 100, minValue: 1, class: ClassBacklight},
- percent: 50,
- wantValue: 50,
- tolerance: 1,
- },
- {
- name: "backlight 100% should be max",
- device: &sysfsDevice{maxBrightness: 100, minValue: 1, class: ClassBacklight},
- percent: 100,
- wantValue: 100,
- tolerance: 0,
- },
- {
- name: "led 0% should be 0",
- device: &sysfsDevice{maxBrightness: 255, minValue: 0, class: ClassLED},
- percent: 0,
- wantValue: 0,
- tolerance: 0,
- },
- {
- name: "led 1% should be ~2-3",
- device: &sysfsDevice{maxBrightness: 255, minValue: 0, class: ClassLED},
- percent: 1,
- wantValue: 2,
- tolerance: 3,
- },
- {
- name: "led 50% should be ~127",
- device: &sysfsDevice{maxBrightness: 255, minValue: 0, class: ClassLED},
- percent: 50,
- wantValue: 127,
- tolerance: 2,
- },
- {
- name: "led 100% should be max",
- device: &sysfsDevice{maxBrightness: 255, minValue: 0, class: ClassLED},
- percent: 100,
- wantValue: 255,
- tolerance: 0,
- },
- }
-
- b := &SysfsBackend{}
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := b.PercentToValue(tt.percent, tt.device, false)
- diff := got - tt.wantValue
- if diff < 0 {
- diff = -diff
- }
- if diff > tt.tolerance {
- t.Errorf("percentToValue() = %v, want %v (±%d)", got, tt.wantValue, tt.tolerance)
- }
-
- gotPercent := b.ValueToPercent(got, tt.device, false)
- if tt.percent > 1 && gotPercent == 0 {
- t.Errorf("valueToPercent() returned 0 for non-zero input (percent=%d, got value=%d)", tt.percent, got)
- }
- })
- }
-}
-
-func TestSysfsBackend_ValueToPercent(t *testing.T) {
- tests := []struct {
- name string
- device *sysfsDevice
- value int
- wantPercent int
- }{
- {
- name: "backlight min value",
- device: &sysfsDevice{maxBrightness: 100, minValue: 1, class: ClassBacklight},
- value: 1,
- wantPercent: 1,
- },
- {
- name: "backlight max value",
- device: &sysfsDevice{maxBrightness: 100, minValue: 1, class: ClassBacklight},
- value: 100,
- wantPercent: 100,
- },
- {
- name: "led zero",
- device: &sysfsDevice{maxBrightness: 255, minValue: 0, class: ClassLED},
- value: 0,
- wantPercent: 0,
- },
- }
-
- b := &SysfsBackend{}
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := b.ValueToPercent(tt.value, tt.device, false)
- if got != tt.wantPercent {
- t.Errorf("valueToPercent() = %v, want %v", got, tt.wantPercent)
- }
- })
- }
-}
-
-func TestSysfsBackend_ScanDevices(t *testing.T) {
- tmpDir := t.TempDir()
-
- backlightDir := filepath.Join(tmpDir, "backlight", "test_backlight")
- if err := os.MkdirAll(backlightDir, 0755); err != nil {
- t.Fatal(err)
- }
-
- if err := os.WriteFile(filepath.Join(backlightDir, "max_brightness"), []byte("100\n"), 0644); err != nil {
- t.Fatal(err)
- }
- if err := os.WriteFile(filepath.Join(backlightDir, "brightness"), []byte("50\n"), 0644); err != nil {
- t.Fatal(err)
- }
-
- ledsDir := filepath.Join(tmpDir, "leds", "test_led")
- if err := os.MkdirAll(ledsDir, 0755); err != nil {
- t.Fatal(err)
- }
-
- if err := os.WriteFile(filepath.Join(ledsDir, "max_brightness"), []byte("255\n"), 0644); err != nil {
- t.Fatal(err)
- }
- if err := os.WriteFile(filepath.Join(ledsDir, "brightness"), []byte("128\n"), 0644); err != nil {
- t.Fatal(err)
- }
-
- b := &SysfsBackend{
- basePath: tmpDir,
- classes: []string{"backlight", "leds"},
- deviceCache: make(map[string]*sysfsDevice),
- }
-
- if err := b.scanDevices(); err != nil {
- t.Fatalf("scanDevices() error = %v", err)
- }
-
- if len(b.deviceCache) != 2 {
- t.Errorf("expected 2 devices, got %d", len(b.deviceCache))
- }
-
- backlightID := "backlight:test_backlight"
- if _, ok := b.deviceCache[backlightID]; !ok {
- t.Errorf("backlight device not found")
- }
-
- ledID := "leds:test_led"
- if _, ok := b.deviceCache[ledID]; !ok {
- t.Errorf("LED device not found")
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/brightness/types.go b/nix/inputs/dms-cli/internal/server/brightness/types.go
deleted file mode 100644
index a1e83b9..0000000
--- a/nix/inputs/dms-cli/internal/server/brightness/types.go
+++ /dev/null
@@ -1,199 +0,0 @@
-package brightness
-
-import (
- "sync"
- "time"
-)
-
-type DeviceClass string
-
-const (
- ClassBacklight DeviceClass = "backlight"
- ClassLED DeviceClass = "leds"
- ClassDDC DeviceClass = "ddc"
-)
-
-type Device struct {
- Class DeviceClass `json:"class"`
- ID string `json:"id"`
- Name string `json:"name"`
- Current int `json:"current"`
- Max int `json:"max"`
- CurrentPercent int `json:"currentPercent"`
- Backend string `json:"backend"`
-}
-
-type State struct {
- Devices []Device `json:"devices"`
-}
-
-type DeviceUpdate struct {
- Device Device `json:"device"`
-}
-
-type Request struct {
- ID interface{} `json:"id"`
- Method string `json:"method"`
- Params map[string]interface{} `json:"params"`
-}
-
-type Manager struct {
- logindBackend *LogindBackend
- sysfsBackend *SysfsBackend
- ddcBackend *DDCBackend
-
- logindReady bool
- sysfsReady bool
- ddcReady bool
-
- exponential bool
-
- stateMutex sync.RWMutex
- state State
-
- subscribers map[string]chan State
- updateSubscribers map[string]chan DeviceUpdate
- subMutex sync.RWMutex
-
- broadcastMutex sync.Mutex
- broadcastTimer *time.Timer
- broadcastPending bool
- pendingDeviceID string
-
- stopChan chan struct{}
-}
-
-type SysfsBackend struct {
- basePath string
- classes []string
-
- deviceCache map[string]*sysfsDevice
- deviceCacheMutex sync.RWMutex
-}
-
-type sysfsDevice struct {
- class DeviceClass
- id string
- name string
- maxBrightness int
- minValue int
-}
-
-type DDCBackend struct {
- devices map[string]*ddcDevice
- devicesMutex sync.RWMutex
-
- scanMutex sync.Mutex
- lastScan time.Time
- scanInterval time.Duration
-
- debounceMutex sync.Mutex
- debounceTimers map[string]*time.Timer
- debouncePending map[string]ddcPendingSet
-}
-
-type ddcPendingSet struct {
- percent int
- callback func()
-}
-
-type ddcDevice struct {
- bus int
- addr int
- id string
- name string
- max int
- lastBrightness int
-}
-
-type ddcCapability struct {
- vcp byte
- max int
- current int
-}
-
-type SetBrightnessParams struct {
- Device string `json:"device"`
- Percent int `json:"percent"`
- Exponential bool `json:"exponential,omitempty"`
- Exponent float64 `json:"exponent,omitempty"`
-}
-
-func (m *Manager) Subscribe(id string) chan State {
- ch := make(chan State, 16)
- m.subMutex.Lock()
- m.subscribers[id] = ch
- m.subMutex.Unlock()
- return ch
-}
-
-func (m *Manager) Unsubscribe(id string) {
- m.subMutex.Lock()
- if ch, ok := m.subscribers[id]; ok {
- close(ch)
- delete(m.subscribers, id)
- }
- m.subMutex.Unlock()
-}
-
-func (m *Manager) SubscribeUpdates(id string) chan DeviceUpdate {
- ch := make(chan DeviceUpdate, 16)
- m.subMutex.Lock()
- m.updateSubscribers[id] = ch
- m.subMutex.Unlock()
- return ch
-}
-
-func (m *Manager) UnsubscribeUpdates(id string) {
- m.subMutex.Lock()
- if ch, ok := m.updateSubscribers[id]; ok {
- close(ch)
- delete(m.updateSubscribers, id)
- }
- m.subMutex.Unlock()
-}
-
-func (m *Manager) NotifySubscribers() {
- m.stateMutex.RLock()
- state := m.state
- m.stateMutex.RUnlock()
-
- m.subMutex.RLock()
- defer m.subMutex.RUnlock()
-
- for _, ch := range m.subscribers {
- select {
- case ch <- state:
- default:
- }
- }
-}
-
-func (m *Manager) GetState() State {
- m.stateMutex.RLock()
- defer m.stateMutex.RUnlock()
- return m.state
-}
-
-func (m *Manager) Close() {
- close(m.stopChan)
-
- m.subMutex.Lock()
- for _, ch := range m.subscribers {
- close(ch)
- }
- m.subscribers = make(map[string]chan State)
- for _, ch := range m.updateSubscribers {
- close(ch)
- }
- m.updateSubscribers = make(map[string]chan DeviceUpdate)
- m.subMutex.Unlock()
-
- if m.logindBackend != nil {
- m.logindBackend.Close()
- }
-
- if m.ddcBackend != nil {
- m.ddcBackend.Close()
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/cups/actions.go b/nix/inputs/dms-cli/internal/server/cups/actions.go
deleted file mode 100644
index 4ba7457..0000000
--- a/nix/inputs/dms-cli/internal/server/cups/actions.go
+++ /dev/null
@@ -1,107 +0,0 @@
-package cups
-
-import (
- "strings"
- "time"
-
- "github.com/AvengeMedia/danklinux/pkg/ipp"
-)
-
-func (m *Manager) GetPrinters() ([]Printer, error) {
- attributes := []string{
- ipp.AttributePrinterName,
- ipp.AttributePrinterUriSupported,
- ipp.AttributePrinterState,
- ipp.AttributePrinterStateReasons,
- ipp.AttributePrinterLocation,
- ipp.AttributePrinterInfo,
- ipp.AttributePrinterMakeAndModel,
- ipp.AttributePrinterIsAcceptingJobs,
- }
-
- printerAttrs, err := m.client.GetPrinters(attributes)
- if err != nil {
- return nil, err
- }
-
- printers := make([]Printer, 0, len(printerAttrs))
- for _, attrs := range printerAttrs {
- printer := Printer{
- Name: getStringAttr(attrs, ipp.AttributePrinterName),
- URI: getStringAttr(attrs, ipp.AttributePrinterUriSupported),
- State: parsePrinterState(attrs),
- StateReason: getStringAttr(attrs, ipp.AttributePrinterStateReasons),
- Location: getStringAttr(attrs, ipp.AttributePrinterLocation),
- Info: getStringAttr(attrs, ipp.AttributePrinterInfo),
- MakeModel: getStringAttr(attrs, ipp.AttributePrinterMakeAndModel),
- Accepting: getBoolAttr(attrs, ipp.AttributePrinterIsAcceptingJobs),
- }
-
- if printer.Name != "" {
- printers = append(printers, printer)
- }
- }
-
- return printers, nil
-}
-
-func (m *Manager) GetJobs(printerName string, whichJobs string) ([]Job, error) {
- attributes := []string{
- ipp.AttributeJobID,
- ipp.AttributeJobName,
- ipp.AttributeJobState,
- ipp.AttributeJobPrinterURI,
- ipp.AttributeJobOriginatingUserName,
- ipp.AttributeJobKilobyteOctets,
- "time-at-creation",
- }
-
- jobAttrs, err := m.client.GetJobs(printerName, "", whichJobs, false, 0, 0, attributes)
- if err != nil {
- return nil, err
- }
-
- jobs := make([]Job, 0, len(jobAttrs))
- for _, attrs := range jobAttrs {
- job := Job{
- ID: getIntAttr(attrs, ipp.AttributeJobID),
- Name: getStringAttr(attrs, ipp.AttributeJobName),
- State: parseJobState(attrs),
- User: getStringAttr(attrs, ipp.AttributeJobOriginatingUserName),
- Size: getIntAttr(attrs, ipp.AttributeJobKilobyteOctets) * 1024,
- }
-
- if uri := getStringAttr(attrs, ipp.AttributeJobPrinterURI); uri != "" {
- parts := strings.Split(uri, "/")
- if len(parts) > 0 {
- job.Printer = parts[len(parts)-1]
- }
- }
-
- if ts := getIntAttr(attrs, "time-at-creation"); ts > 0 {
- job.TimeCreated = time.Unix(int64(ts), 0)
- }
-
- if job.ID != 0 {
- jobs = append(jobs, job)
- }
- }
-
- return jobs, nil
-}
-
-func (m *Manager) CancelJob(jobID int) error {
- return m.client.CancelJob(jobID, false)
-}
-
-func (m *Manager) PausePrinter(printerName string) error {
- return m.client.PausePrinter(printerName)
-}
-
-func (m *Manager) ResumePrinter(printerName string) error {
- return m.client.ResumePrinter(printerName)
-}
-
-func (m *Manager) PurgeJobs(printerName string) error {
- return m.client.CancelAllJob(printerName, true)
-}
diff --git a/nix/inputs/dms-cli/internal/server/cups/actions_test.go b/nix/inputs/dms-cli/internal/server/cups/actions_test.go
deleted file mode 100644
index 9ff548c..0000000
--- a/nix/inputs/dms-cli/internal/server/cups/actions_test.go
+++ /dev/null
@@ -1,285 +0,0 @@
-package cups
-
-import (
- "errors"
- "testing"
- "time"
-
- mocks_cups "github.com/AvengeMedia/danklinux/internal/mocks/cups"
- "github.com/AvengeMedia/danklinux/pkg/ipp"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
-)
-
-func TestManager_GetPrinters(t *testing.T) {
- tests := []struct {
- name string
- mockRet map[string]ipp.Attributes
- mockErr error
- want int
- wantErr bool
- }{
- {
- name: "success",
- mockRet: map[string]ipp.Attributes{
- "printer1": {
- ipp.AttributePrinterName: []ipp.Attribute{{Value: "printer1"}},
- ipp.AttributePrinterUriSupported: []ipp.Attribute{{Value: "ipp://localhost/printers/printer1"}},
- ipp.AttributePrinterState: []ipp.Attribute{{Value: 3}},
- ipp.AttributePrinterStateReasons: []ipp.Attribute{{Value: "none"}},
- ipp.AttributePrinterLocation: []ipp.Attribute{{Value: "Office"}},
- ipp.AttributePrinterInfo: []ipp.Attribute{{Value: "Test Printer"}},
- ipp.AttributePrinterMakeAndModel: []ipp.Attribute{{Value: "Generic"}},
- ipp.AttributePrinterIsAcceptingJobs: []ipp.Attribute{{Value: true}},
- },
- },
- mockErr: nil,
- want: 1,
- wantErr: false,
- },
- {
- name: "error",
- mockRet: nil,
- mockErr: errors.New("test error"),
- want: 0,
- wantErr: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(tt.mockRet, tt.mockErr)
-
- m := &Manager{
- client: mockClient,
- }
-
- got, err := m.GetPrinters()
- if tt.wantErr {
- assert.Error(t, err)
- } else {
- assert.NoError(t, err)
- assert.Equal(t, tt.want, len(got))
- if len(got) > 0 {
- assert.Equal(t, "printer1", got[0].Name)
- assert.Equal(t, "idle", got[0].State)
- assert.Equal(t, "Office", got[0].Location)
- assert.True(t, got[0].Accepting)
- }
- }
- })
- }
-}
-
-func TestManager_GetJobs(t *testing.T) {
- tests := []struct {
- name string
- mockRet map[int]ipp.Attributes
- mockErr error
- want int
- wantErr bool
- }{
- {
- name: "success",
- mockRet: map[int]ipp.Attributes{
- 1: {
- ipp.AttributeJobID: []ipp.Attribute{{Value: 1}},
- ipp.AttributeJobName: []ipp.Attribute{{Value: "test-job"}},
- ipp.AttributeJobState: []ipp.Attribute{{Value: 5}},
- ipp.AttributeJobPrinterURI: []ipp.Attribute{{Value: "ipp://localhost/printers/printer1"}},
- ipp.AttributeJobOriginatingUserName: []ipp.Attribute{{Value: "testuser"}},
- ipp.AttributeJobKilobyteOctets: []ipp.Attribute{{Value: 10}},
- "time-at-creation": []ipp.Attribute{{Value: 1609459200}},
- },
- },
- mockErr: nil,
- want: 1,
- wantErr: false,
- },
- {
- name: "error",
- mockRet: nil,
- mockErr: errors.New("test error"),
- want: 0,
- wantErr: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetJobs("printer1", "", "not-completed", false, 0, 0, mock.Anything).
- Return(tt.mockRet, tt.mockErr)
-
- m := &Manager{
- client: mockClient,
- }
-
- got, err := m.GetJobs("printer1", "not-completed")
- if tt.wantErr {
- assert.Error(t, err)
- } else {
- assert.NoError(t, err)
- assert.Equal(t, tt.want, len(got))
- if len(got) > 0 {
- assert.Equal(t, 1, got[0].ID)
- assert.Equal(t, "test-job", got[0].Name)
- assert.Equal(t, "processing", got[0].State)
- assert.Equal(t, "testuser", got[0].User)
- assert.Equal(t, "printer1", got[0].Printer)
- assert.Equal(t, 10240, got[0].Size)
- assert.Equal(t, time.Unix(1609459200, 0), got[0].TimeCreated)
- }
- }
- })
- }
-}
-
-func TestManager_CancelJob(t *testing.T) {
- tests := []struct {
- name string
- mockErr error
- wantErr bool
- }{
- {
- name: "success",
- mockErr: nil,
- wantErr: false,
- },
- {
- name: "error",
- mockErr: errors.New("test error"),
- wantErr: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().CancelJob(1, false).Return(tt.mockErr)
-
- m := &Manager{
- client: mockClient,
- }
-
- err := m.CancelJob(1)
- if tt.wantErr {
- assert.Error(t, err)
- } else {
- assert.NoError(t, err)
- }
- })
- }
-}
-
-func TestManager_PausePrinter(t *testing.T) {
- tests := []struct {
- name string
- mockErr error
- wantErr bool
- }{
- {
- name: "success",
- mockErr: nil,
- wantErr: false,
- },
- {
- name: "error",
- mockErr: errors.New("test error"),
- wantErr: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().PausePrinter("printer1").Return(tt.mockErr)
-
- m := &Manager{
- client: mockClient,
- }
-
- err := m.PausePrinter("printer1")
- if tt.wantErr {
- assert.Error(t, err)
- } else {
- assert.NoError(t, err)
- }
- })
- }
-}
-
-func TestManager_ResumePrinter(t *testing.T) {
- tests := []struct {
- name string
- mockErr error
- wantErr bool
- }{
- {
- name: "success",
- mockErr: nil,
- wantErr: false,
- },
- {
- name: "error",
- mockErr: errors.New("test error"),
- wantErr: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().ResumePrinter("printer1").Return(tt.mockErr)
-
- m := &Manager{
- client: mockClient,
- }
-
- err := m.ResumePrinter("printer1")
- if tt.wantErr {
- assert.Error(t, err)
- } else {
- assert.NoError(t, err)
- }
- })
- }
-}
-
-func TestManager_PurgeJobs(t *testing.T) {
- tests := []struct {
- name string
- mockErr error
- wantErr bool
- }{
- {
- name: "success",
- mockErr: nil,
- wantErr: false,
- },
- {
- name: "error",
- mockErr: errors.New("test error"),
- wantErr: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().CancelAllJob("printer1", true).Return(tt.mockErr)
-
- m := &Manager{
- client: mockClient,
- }
-
- err := m.PurgeJobs("printer1")
- if tt.wantErr {
- assert.Error(t, err)
- } else {
- assert.NoError(t, err)
- }
- })
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/cups/handlers.go b/nix/inputs/dms-cli/internal/server/cups/handlers.go
deleted file mode 100644
index ff5c2e7..0000000
--- a/nix/inputs/dms-cli/internal/server/cups/handlers.go
+++ /dev/null
@@ -1,160 +0,0 @@
-package cups
-
-import (
- "encoding/json"
- "fmt"
- "net"
-
- "github.com/AvengeMedia/danklinux/internal/server/models"
-)
-
-type Request struct {
- ID int `json:"id,omitempty"`
- Method string `json:"method"`
- Params map[string]interface{} `json:"params,omitempty"`
-}
-
-type SuccessResult struct {
- Success bool `json:"success"`
- Message string `json:"message"`
-}
-
-type CUPSEvent struct {
- Type string `json:"type"`
- Data CUPSState `json:"data"`
-}
-
-func HandleRequest(conn net.Conn, req Request, manager *Manager) {
- switch req.Method {
- case "cups.subscribe":
- handleSubscribe(conn, req, manager)
- case "cups.getPrinters":
- handleGetPrinters(conn, req, manager)
- case "cups.getJobs":
- handleGetJobs(conn, req, manager)
- case "cups.pausePrinter":
- handlePausePrinter(conn, req, manager)
- case "cups.resumePrinter":
- handleResumePrinter(conn, req, manager)
- case "cups.cancelJob":
- handleCancelJob(conn, req, manager)
- case "cups.purgeJobs":
- handlePurgeJobs(conn, req, manager)
- default:
- models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method))
- }
-}
-
-func handleGetPrinters(conn net.Conn, req Request, manager *Manager) {
- printers, err := manager.GetPrinters()
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, printers)
-}
-
-func handleGetJobs(conn net.Conn, req Request, manager *Manager) {
- printerName, ok := req.Params["printerName"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'printerName' parameter")
- return
- }
-
- jobs, err := manager.GetJobs(printerName, "not-completed")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, jobs)
-}
-
-func handlePausePrinter(conn net.Conn, req Request, manager *Manager) {
- printerName, ok := req.Params["printerName"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'printerName' parameter")
- return
- }
-
- if err := manager.PausePrinter(printerName); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "paused"})
-}
-
-func handleResumePrinter(conn net.Conn, req Request, manager *Manager) {
- printerName, ok := req.Params["printerName"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'printerName' parameter")
- return
- }
-
- if err := manager.ResumePrinter(printerName); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "resumed"})
-}
-
-func handleCancelJob(conn net.Conn, req Request, manager *Manager) {
- jobIDFloat, ok := req.Params["jobID"].(float64)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'jobid' parameter")
- return
- }
- jobID := int(jobIDFloat)
-
- if err := manager.CancelJob(jobID); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "job canceled"})
-}
-
-func handlePurgeJobs(conn net.Conn, req Request, manager *Manager) {
- printerName, ok := req.Params["printerName"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'printerName' parameter")
- return
- }
-
- if err := manager.PurgeJobs(printerName); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "jobs canceled"})
-}
-
-func handleSubscribe(conn net.Conn, req Request, manager *Manager) {
- clientID := fmt.Sprintf("client-%p", conn)
- stateChan := manager.Subscribe(clientID)
- defer manager.Unsubscribe(clientID)
-
- initialState := manager.GetState()
- event := CUPSEvent{
- Type: "state_changed",
- Data: initialState,
- }
-
- if err := json.NewEncoder(conn).Encode(models.Response[CUPSEvent]{
- ID: req.ID,
- Result: &event,
- }); err != nil {
- return
- }
-
- for state := range stateChan {
- event := CUPSEvent{
- Type: "state_changed",
- Data: state,
- }
- if err := json.NewEncoder(conn).Encode(models.Response[CUPSEvent]{
- Result: &event,
- }); err != nil {
- return
- }
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/cups/handlers_test.go b/nix/inputs/dms-cli/internal/server/cups/handlers_test.go
deleted file mode 100644
index 655d385..0000000
--- a/nix/inputs/dms-cli/internal/server/cups/handlers_test.go
+++ /dev/null
@@ -1,279 +0,0 @@
-package cups
-
-import (
- "bytes"
- "encoding/json"
- "errors"
- "net"
- "testing"
- "time"
-
- mocks_cups "github.com/AvengeMedia/danklinux/internal/mocks/cups"
- "github.com/AvengeMedia/danklinux/internal/server/models"
- "github.com/AvengeMedia/danklinux/pkg/ipp"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
-)
-
-type mockConn struct {
- *bytes.Buffer
-}
-
-func (m *mockConn) Close() error { return nil }
-func (m *mockConn) LocalAddr() net.Addr { return nil }
-func (m *mockConn) RemoteAddr() net.Addr { return nil }
-func (m *mockConn) SetDeadline(t time.Time) error { return nil }
-func (m *mockConn) SetReadDeadline(t time.Time) error { return nil }
-func (m *mockConn) SetWriteDeadline(t time.Time) error { return nil }
-
-func TestHandleGetPrinters(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{
- "printer1": {
- ipp.AttributePrinterName: []ipp.Attribute{{Value: "printer1"}},
- ipp.AttributePrinterState: []ipp.Attribute{{Value: 3}},
- ipp.AttributePrinterUriSupported: []ipp.Attribute{{Value: "ipp://localhost/printers/printer1"}},
- },
- }, nil)
-
- m := &Manager{
- client: mockClient,
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := Request{
- ID: 1,
- Method: "cups.getPrinters",
- }
-
- handleGetPrinters(conn, req, m)
-
- var resp models.Response[[]Printer]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.Equal(t, 1, len(*resp.Result))
-}
-
-func TestHandleGetPrinters_Error(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(nil, errors.New("test error"))
-
- m := &Manager{
- client: mockClient,
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := Request{
- ID: 1,
- Method: "cups.getPrinters",
- }
-
- handleGetPrinters(conn, req, m)
-
- var resp models.Response[interface{}]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.Nil(t, resp.Result)
- assert.NotNil(t, resp.Error)
-}
-
-func TestHandleGetJobs(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetJobs("printer1", "", "not-completed", false, 0, 0, mock.Anything).
- Return(map[int]ipp.Attributes{
- 1: {
- ipp.AttributeJobID: []ipp.Attribute{{Value: 1}},
- ipp.AttributeJobName: []ipp.Attribute{{Value: "job1"}},
- ipp.AttributeJobState: []ipp.Attribute{{Value: 5}},
- },
- }, nil)
-
- m := &Manager{
- client: mockClient,
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := Request{
- ID: 1,
- Method: "cups.getJobs",
- Params: map[string]interface{}{
- "printerName": "printer1",
- },
- }
-
- handleGetJobs(conn, req, m)
-
- var resp models.Response[[]Job]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.Equal(t, 1, len(*resp.Result))
-}
-
-func TestHandleGetJobs_MissingParam(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
-
- m := &Manager{
- client: mockClient,
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := Request{
- ID: 1,
- Method: "cups.getJobs",
- Params: map[string]interface{}{},
- }
-
- handleGetJobs(conn, req, m)
-
- var resp models.Response[interface{}]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.Nil(t, resp.Result)
- assert.NotNil(t, resp.Error)
-}
-
-func TestHandlePausePrinter(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().PausePrinter("printer1").Return(nil)
-
- m := &Manager{
- client: mockClient,
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := Request{
- ID: 1,
- Method: "cups.pausePrinter",
- Params: map[string]interface{}{
- "printerName": "printer1",
- },
- }
-
- handlePausePrinter(conn, req, m)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleResumePrinter(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().ResumePrinter("printer1").Return(nil)
-
- m := &Manager{
- client: mockClient,
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := Request{
- ID: 1,
- Method: "cups.resumePrinter",
- Params: map[string]interface{}{
- "printerName": "printer1",
- },
- }
-
- handleResumePrinter(conn, req, m)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleCancelJob(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().CancelJob(1, false).Return(nil)
-
- m := &Manager{
- client: mockClient,
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := Request{
- ID: 1,
- Method: "cups.cancelJob",
- Params: map[string]interface{}{
- "jobID": float64(1),
- },
- }
-
- handleCancelJob(conn, req, m)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandlePurgeJobs(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().CancelAllJob("printer1", true).Return(nil)
-
- m := &Manager{
- client: mockClient,
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := Request{
- ID: 1,
- Method: "cups.purgeJobs",
- Params: map[string]interface{}{
- "printerName": "printer1",
- },
- }
-
- handlePurgeJobs(conn, req, m)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleRequest_UnknownMethod(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
-
- m := &Manager{
- client: mockClient,
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := Request{
- ID: 1,
- Method: "cups.unknownMethod",
- }
-
- HandleRequest(conn, req, m)
-
- var resp models.Response[interface{}]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.Nil(t, resp.Result)
- assert.NotNil(t, resp.Error)
-}
diff --git a/nix/inputs/dms-cli/internal/server/cups/manager.go b/nix/inputs/dms-cli/internal/server/cups/manager.go
deleted file mode 100644
index b7cae27..0000000
--- a/nix/inputs/dms-cli/internal/server/cups/manager.go
+++ /dev/null
@@ -1,340 +0,0 @@
-package cups
-
-import (
- "fmt"
- "os"
- "strconv"
- "sync"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/AvengeMedia/danklinux/pkg/ipp"
-)
-
-func NewManager() (*Manager, error) {
- host := os.Getenv("DMS_IPP_HOST")
- if host == "" {
- host = "localhost"
- }
-
- portStr := os.Getenv("DMS_IPP_PORT")
- port := 631
- if portStr != "" {
- if p, err := strconv.Atoi(portStr); err == nil {
- port = p
- }
- }
-
- username := os.Getenv("DMS_IPP_USERNAME")
- password := os.Getenv("DMS_IPP_PASSWORD")
-
- client := ipp.NewCUPSClient(host, port, username, password, false)
- baseURL := fmt.Sprintf("http://%s:%d", host, port)
-
- m := &Manager{
- state: &CUPSState{
- Printers: make(map[string]*Printer),
- },
- client: client,
- baseURL: baseURL,
- stateMutex: sync.RWMutex{},
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- subscribers: make(map[string]chan CUPSState),
- subMutex: sync.RWMutex{},
- }
-
- if err := m.updateState(); err != nil {
- return nil, err
- }
-
- if isLocalCUPS(host) {
- m.subscription = NewDBusSubscriptionManager(client, baseURL)
- log.Infof("[CUPS] Using D-Bus notifications for local CUPS")
- } else {
- m.subscription = NewSubscriptionManager(client, baseURL)
- log.Infof("[CUPS] Using IPPGET notifications for remote CUPS")
- }
-
- m.notifierWg.Add(1)
- go m.notifier()
-
- return m, nil
-}
-
-func isLocalCUPS(host string) bool {
- switch host {
- case "localhost", "127.0.0.1", "::1", "":
- return true
- }
- return false
-}
-
-func (m *Manager) eventHandler() {
- defer m.eventWG.Done()
-
- if m.subscription == nil {
- return
- }
-
- for {
- select {
- case <-m.stopChan:
- return
- case event, ok := <-m.subscription.Events():
- if !ok {
- return
- }
- log.Debugf("[CUPS] Received event: %s (printer: %s, job: %d)",
- event.EventName, event.PrinterName, event.JobID)
-
- if err := m.updateState(); err != nil {
- log.Warnf("[CUPS] Failed to update state after event: %v", err)
- } else {
- m.notifySubscribers()
- }
- }
- }
-}
-
-func (m *Manager) updateState() error {
- printers, err := m.GetPrinters()
- if err != nil {
- return err
- }
-
- printerMap := make(map[string]*Printer, len(printers))
- for _, printer := range printers {
- jobs, err := m.GetJobs(printer.Name, "not-completed")
- if err != nil {
- return err
- }
-
- printer.Jobs = jobs
- printerMap[printer.Name] = &printer
- }
-
- m.stateMutex.Lock()
- m.state.Printers = printerMap
- m.stateMutex.Unlock()
-
- return nil
-}
-
-func (m *Manager) notifier() {
- defer m.notifierWg.Done()
- const minGap = 100 * time.Millisecond
- timer := time.NewTimer(minGap)
- timer.Stop()
- var pending bool
- for {
- select {
- case <-m.stopChan:
- timer.Stop()
- return
- case <-m.dirty:
- if pending {
- continue
- }
- pending = true
- timer.Reset(minGap)
- case <-timer.C:
- if !pending {
- continue
- }
- m.subMutex.RLock()
- if len(m.subscribers) == 0 {
- m.subMutex.RUnlock()
- pending = false
- continue
- }
-
- currentState := m.snapshotState()
-
- if m.lastNotifiedState != nil && !stateChanged(m.lastNotifiedState, ¤tState) {
- m.subMutex.RUnlock()
- pending = false
- continue
- }
-
- for _, ch := range m.subscribers {
- select {
- case ch <- currentState:
- default:
- }
- }
- m.subMutex.RUnlock()
-
- stateCopy := currentState
- m.lastNotifiedState = &stateCopy
- pending = false
- }
- }
-}
-
-func (m *Manager) notifySubscribers() {
- select {
- case m.dirty <- struct{}{}:
- default:
- }
-}
-
-func (m *Manager) GetState() CUPSState {
- return m.snapshotState()
-}
-
-func (m *Manager) snapshotState() CUPSState {
- m.stateMutex.RLock()
- defer m.stateMutex.RUnlock()
-
- s := CUPSState{
- Printers: make(map[string]*Printer, len(m.state.Printers)),
- }
- for name, printer := range m.state.Printers {
- printerCopy := *printer
- s.Printers[name] = &printerCopy
- }
- return s
-}
-
-func (m *Manager) Subscribe(id string) chan CUPSState {
- ch := make(chan CUPSState, 64)
- m.subMutex.Lock()
- wasEmpty := len(m.subscribers) == 0
- m.subscribers[id] = ch
- m.subMutex.Unlock()
-
- if wasEmpty && m.subscription != nil {
- if err := m.subscription.Start(); err != nil {
- log.Warnf("[CUPS] Failed to start subscription manager: %v", err)
- } else {
- m.eventWG.Add(1)
- go m.eventHandler()
- }
- }
-
- return ch
-}
-
-func (m *Manager) Unsubscribe(id string) {
- m.subMutex.Lock()
- if ch, ok := m.subscribers[id]; ok {
- close(ch)
- delete(m.subscribers, id)
- }
- isEmpty := len(m.subscribers) == 0
- m.subMutex.Unlock()
-
- if isEmpty && m.subscription != nil {
- m.subscription.Stop()
- m.eventWG.Wait()
- }
-}
-
-func (m *Manager) Close() {
- close(m.stopChan)
-
- if m.subscription != nil {
- m.subscription.Stop()
- }
-
- m.eventWG.Wait()
- m.notifierWg.Wait()
-
- m.subMutex.Lock()
- for _, ch := range m.subscribers {
- close(ch)
- }
- m.subscribers = make(map[string]chan CUPSState)
- m.subMutex.Unlock()
-}
-
-func stateChanged(old, new *CUPSState) bool {
- if len(old.Printers) != len(new.Printers) {
- return true
- }
- for name, oldPrinter := range old.Printers {
- newPrinter, exists := new.Printers[name]
- if !exists {
- return true
- }
- if oldPrinter.State != newPrinter.State ||
- oldPrinter.StateReason != newPrinter.StateReason ||
- len(oldPrinter.Jobs) != len(newPrinter.Jobs) {
- return true
- }
- }
- return false
-}
-
-func parsePrinterState(attrs ipp.Attributes) string {
- if stateAttr, ok := attrs[ipp.AttributePrinterState]; ok && len(stateAttr) > 0 {
- if state, ok := stateAttr[0].Value.(int); ok {
- switch state {
- case 3:
- return "idle"
- case 4:
- return "processing"
- case 5:
- return "stopped"
- default:
- return fmt.Sprintf("%d", state)
- }
- }
- }
- return "unknown"
-}
-
-func parseJobState(attrs ipp.Attributes) string {
- if stateAttr, ok := attrs[ipp.AttributeJobState]; ok && len(stateAttr) > 0 {
- if state, ok := stateAttr[0].Value.(int); ok {
- switch state {
- case 3:
- return "pending"
- case 4:
- return "pending-held"
- case 5:
- return "processing"
- case 6:
- return "processing-stopped"
- case 7:
- return "canceled"
- case 8:
- return "aborted"
- case 9:
- return "completed"
- default:
- return fmt.Sprintf("%d", state)
- }
- }
- }
- return "unknown"
-}
-
-func getStringAttr(attrs ipp.Attributes, key string) string {
- if attr, ok := attrs[key]; ok && len(attr) > 0 {
- if val, ok := attr[0].Value.(string); ok {
- return val
- }
- return fmt.Sprintf("%v", attr[0].Value)
- }
- return ""
-}
-
-func getIntAttr(attrs ipp.Attributes, key string) int {
- if attr, ok := attrs[key]; ok && len(attr) > 0 {
- if val, ok := attr[0].Value.(int); ok {
- return val
- }
- }
- return 0
-}
-
-func getBoolAttr(attrs ipp.Attributes, key string) bool {
- if attr, ok := attrs[key]; ok && len(attr) > 0 {
- if val, ok := attr[0].Value.(bool); ok {
- return val
- }
- }
- return false
-}
diff --git a/nix/inputs/dms-cli/internal/server/cups/manager_test.go b/nix/inputs/dms-cli/internal/server/cups/manager_test.go
deleted file mode 100644
index 53541e1..0000000
--- a/nix/inputs/dms-cli/internal/server/cups/manager_test.go
+++ /dev/null
@@ -1,351 +0,0 @@
-package cups
-
-import (
- "testing"
-
- mocks_cups "github.com/AvengeMedia/danklinux/internal/mocks/cups"
- "github.com/AvengeMedia/danklinux/pkg/ipp"
- "github.com/stretchr/testify/assert"
-)
-
-func TestNewManager(t *testing.T) {
- m := &Manager{
- state: &CUPSState{
- Printers: make(map[string]*Printer),
- },
- client: nil,
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- subscribers: make(map[string]chan CUPSState),
- }
-
- assert.NotNil(t, m)
- assert.NotNil(t, m.state)
-}
-
-func TestManager_GetState(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
-
- m := &Manager{
- state: &CUPSState{
- Printers: map[string]*Printer{
- "test-printer": {
- Name: "test-printer",
- State: "idle",
- },
- },
- },
- client: mockClient,
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- subscribers: make(map[string]chan CUPSState),
- }
-
- state := m.GetState()
- assert.Equal(t, 1, len(state.Printers))
- assert.Equal(t, "test-printer", state.Printers["test-printer"].Name)
-}
-
-func TestManager_Subscribe(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
-
- m := &Manager{
- state: &CUPSState{
- Printers: make(map[string]*Printer),
- },
- client: mockClient,
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- subscribers: make(map[string]chan CUPSState),
- }
-
- ch := m.Subscribe("test-client")
- assert.NotNil(t, ch)
- assert.Equal(t, 1, len(m.subscribers))
-
- m.Unsubscribe("test-client")
- assert.Equal(t, 0, len(m.subscribers))
-}
-
-func TestManager_Close(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
-
- m := &Manager{
- state: &CUPSState{
- Printers: make(map[string]*Printer),
- },
- client: mockClient,
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- subscribers: make(map[string]chan CUPSState),
- }
-
- m.eventWG.Add(1)
- go func() {
- defer m.eventWG.Done()
- <-m.stopChan
- }()
-
- m.notifierWg.Add(1)
- go func() {
- defer m.notifierWg.Done()
- <-m.stopChan
- }()
-
- m.Close()
- assert.Equal(t, 0, len(m.subscribers))
-}
-
-func TestStateChanged(t *testing.T) {
- tests := []struct {
- name string
- oldState *CUPSState
- newState *CUPSState
- want bool
- }{
- {
- name: "no change",
- oldState: &CUPSState{
- Printers: map[string]*Printer{
- "p1": {Name: "p1", State: "idle"},
- },
- },
- newState: &CUPSState{
- Printers: map[string]*Printer{
- "p1": {Name: "p1", State: "idle"},
- },
- },
- want: false,
- },
- {
- name: "state changed",
- oldState: &CUPSState{
- Printers: map[string]*Printer{
- "p1": {Name: "p1", State: "idle"},
- },
- },
- newState: &CUPSState{
- Printers: map[string]*Printer{
- "p1": {Name: "p1", State: "processing"},
- },
- },
- want: true,
- },
- {
- name: "printer added",
- oldState: &CUPSState{
- Printers: map[string]*Printer{},
- },
- newState: &CUPSState{
- Printers: map[string]*Printer{
- "p1": {Name: "p1", State: "idle"},
- },
- },
- want: true,
- },
- {
- name: "printer removed",
- oldState: &CUPSState{
- Printers: map[string]*Printer{
- "p1": {Name: "p1", State: "idle"},
- },
- },
- newState: &CUPSState{
- Printers: map[string]*Printer{},
- },
- want: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := stateChanged(tt.oldState, tt.newState)
- assert.Equal(t, tt.want, got)
- })
- }
-}
-
-func TestParsePrinterState(t *testing.T) {
- tests := []struct {
- name string
- attrs ipp.Attributes
- want string
- }{
- {
- name: "idle",
- attrs: ipp.Attributes{
- ipp.AttributePrinterState: []ipp.Attribute{{Value: 3}},
- },
- want: "idle",
- },
- {
- name: "processing",
- attrs: ipp.Attributes{
- ipp.AttributePrinterState: []ipp.Attribute{{Value: 4}},
- },
- want: "processing",
- },
- {
- name: "stopped",
- attrs: ipp.Attributes{
- ipp.AttributePrinterState: []ipp.Attribute{{Value: 5}},
- },
- want: "stopped",
- },
- {
- name: "unknown",
- attrs: ipp.Attributes{},
- want: "unknown",
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := parsePrinterState(tt.attrs)
- assert.Equal(t, tt.want, got)
- })
- }
-}
-
-func TestParseJobState(t *testing.T) {
- tests := []struct {
- name string
- attrs ipp.Attributes
- want string
- }{
- {
- name: "pending",
- attrs: ipp.Attributes{
- ipp.AttributeJobState: []ipp.Attribute{{Value: 3}},
- },
- want: "pending",
- },
- {
- name: "processing",
- attrs: ipp.Attributes{
- ipp.AttributeJobState: []ipp.Attribute{{Value: 5}},
- },
- want: "processing",
- },
- {
- name: "completed",
- attrs: ipp.Attributes{
- ipp.AttributeJobState: []ipp.Attribute{{Value: 9}},
- },
- want: "completed",
- },
- {
- name: "unknown",
- attrs: ipp.Attributes{},
- want: "unknown",
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := parseJobState(tt.attrs)
- assert.Equal(t, tt.want, got)
- })
- }
-}
-
-func TestGetStringAttr(t *testing.T) {
- tests := []struct {
- name string
- attrs ipp.Attributes
- key string
- want string
- }{
- {
- name: "string value",
- attrs: ipp.Attributes{
- "test-key": []ipp.Attribute{{Value: "test-value"}},
- },
- key: "test-key",
- want: "test-value",
- },
- {
- name: "missing key",
- attrs: ipp.Attributes{},
- key: "missing",
- want: "",
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := getStringAttr(tt.attrs, tt.key)
- assert.Equal(t, tt.want, got)
- })
- }
-}
-
-func TestGetIntAttr(t *testing.T) {
- tests := []struct {
- name string
- attrs ipp.Attributes
- key string
- want int
- }{
- {
- name: "int value",
- attrs: ipp.Attributes{
- "test-key": []ipp.Attribute{{Value: 42}},
- },
- key: "test-key",
- want: 42,
- },
- {
- name: "missing key",
- attrs: ipp.Attributes{},
- key: "missing",
- want: 0,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := getIntAttr(tt.attrs, tt.key)
- assert.Equal(t, tt.want, got)
- })
- }
-}
-
-func TestGetBoolAttr(t *testing.T) {
- tests := []struct {
- name string
- attrs ipp.Attributes
- key string
- want bool
- }{
- {
- name: "true value",
- attrs: ipp.Attributes{
- "test-key": []ipp.Attribute{{Value: true}},
- },
- key: "test-key",
- want: true,
- },
- {
- name: "false value",
- attrs: ipp.Attributes{
- "test-key": []ipp.Attribute{{Value: false}},
- },
- key: "test-key",
- want: false,
- },
- {
- name: "missing key",
- attrs: ipp.Attributes{},
- key: "missing",
- want: false,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := getBoolAttr(tt.attrs, tt.key)
- assert.Equal(t, tt.want, got)
- })
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/cups/subscription.go b/nix/inputs/dms-cli/internal/server/cups/subscription.go
deleted file mode 100644
index 9b35f5f..0000000
--- a/nix/inputs/dms-cli/internal/server/cups/subscription.go
+++ /dev/null
@@ -1,245 +0,0 @@
-package cups
-
-import (
- "fmt"
- "sync"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/AvengeMedia/danklinux/pkg/ipp"
-)
-
-type SubscriptionManager struct {
- client CUPSClientInterface
- subscriptionID int
- sequenceNumber int
- eventChan chan SubscriptionEvent
- stopChan chan struct{}
- wg sync.WaitGroup
- baseURL string
- running bool
- mu sync.Mutex
-}
-
-func NewSubscriptionManager(client CUPSClientInterface, baseURL string) *SubscriptionManager {
- return &SubscriptionManager{
- client: client,
- eventChan: make(chan SubscriptionEvent, 100),
- stopChan: make(chan struct{}),
- baseURL: baseURL,
- }
-}
-
-func (sm *SubscriptionManager) Start() error {
- sm.mu.Lock()
- if sm.running {
- sm.mu.Unlock()
- return fmt.Errorf("subscription manager already running")
- }
- sm.running = true
- sm.mu.Unlock()
-
- subID, err := sm.createSubscription()
- if err != nil {
- sm.mu.Lock()
- sm.running = false
- sm.mu.Unlock()
- return fmt.Errorf("failed to create subscription: %w", err)
- }
-
- sm.subscriptionID = subID
- log.Infof("[CUPS] Created IPP subscription with ID %d", subID)
-
- sm.wg.Add(1)
- go sm.notificationLoop()
-
- return nil
-}
-
-func (sm *SubscriptionManager) createSubscription() (int, error) {
- req := ipp.NewRequest(ipp.OperationCreatePrinterSubscriptions, 1)
- req.OperationAttributes[ipp.AttributePrinterURI] = fmt.Sprintf("%s/", sm.baseURL)
- req.OperationAttributes[ipp.AttributeRequestingUserName] = "dms"
-
- // Subscription attributes go in SubscriptionAttributes (subscription-attributes-tag in IPP)
- req.SubscriptionAttributes = map[string]interface{}{
- "notify-events": []string{
- "printer-state-changed",
- "printer-added",
- "printer-deleted",
- "job-created",
- "job-completed",
- "job-state-changed",
- },
- "notify-pull-method": "ippget",
- "notify-lease-duration": 0,
- }
-
- // Send to root IPP endpoint
- resp, err := sm.client.SendRequest(fmt.Sprintf("%s/", sm.baseURL), req, nil)
- if err != nil {
- return 0, fmt.Errorf("SendRequest failed: %w", err)
- }
-
- // Check for IPP errors
- if err := resp.CheckForErrors(); err != nil {
- return 0, fmt.Errorf("IPP error: %w", err)
- }
-
- // Subscription ID comes back in SubscriptionAttributes
- if len(resp.SubscriptionAttributes) > 0 {
- if idAttr, ok := resp.SubscriptionAttributes[0]["notify-subscription-id"]; ok && len(idAttr) > 0 {
- if val, ok := idAttr[0].Value.(int); ok {
- return val, nil
- }
- }
- }
-
- return 0, fmt.Errorf("no subscription ID returned")
-}
-
-func (sm *SubscriptionManager) notificationLoop() {
- defer sm.wg.Done()
-
- backoff := 1 * time.Second
-
- for {
- select {
- case <-sm.stopChan:
- return
- default:
- }
-
- gotAny, err := sm.fetchNotificationsWithWait()
- if err != nil {
- log.Warnf("[CUPS] Error fetching notifications: %v", err)
- jitter := time.Duration(50+(time.Now().UnixNano()%200)) * time.Millisecond
- sleepTime := backoff + jitter
- if sleepTime > 30*time.Second {
- sleepTime = 30 * time.Second
- }
- select {
- case <-sm.stopChan:
- return
- case <-time.After(sleepTime):
- }
- if backoff < 30*time.Second {
- backoff *= 2
- }
- continue
- }
-
- backoff = 1 * time.Second
-
- if gotAny {
- continue
- }
-
- select {
- case <-sm.stopChan:
- return
- case <-time.After(2 * time.Second):
- }
- }
-}
-
-func (sm *SubscriptionManager) fetchNotificationsWithWait() (bool, error) {
- req := ipp.NewRequest(ipp.OperationGetNotifications, 1)
- req.OperationAttributes[ipp.AttributePrinterURI] = fmt.Sprintf("%s/", sm.baseURL)
- req.OperationAttributes[ipp.AttributeRequestingUserName] = "dms"
- req.OperationAttributes["notify-subscription-ids"] = sm.subscriptionID
- if sm.sequenceNumber > 0 {
- req.OperationAttributes["notify-sequence-numbers"] = sm.sequenceNumber
- }
-
- resp, err := sm.client.SendRequest(fmt.Sprintf("%s/", sm.baseURL), req, nil)
- if err != nil {
- return false, err
- }
-
- gotAny := false
- for _, eventGroup := range resp.SubscriptionAttributes {
- if seqAttr, ok := eventGroup["notify-sequence-number"]; ok && len(seqAttr) > 0 {
- if seqNum, ok := seqAttr[0].Value.(int); ok {
- sm.sequenceNumber = seqNum + 1
- }
- }
-
- event := sm.parseEvent(eventGroup)
- gotAny = true
- select {
- case sm.eventChan <- event:
- case <-sm.stopChan:
- return gotAny, nil
- default:
- log.Warn("[CUPS] Event channel full, dropping event")
- }
- }
-
- return gotAny, nil
-}
-
-func (sm *SubscriptionManager) parseEvent(attrs ipp.Attributes) SubscriptionEvent {
- event := SubscriptionEvent{
- SubscribedAt: time.Now(),
- }
-
- if attr, ok := attrs["notify-subscribed-event"]; ok && len(attr) > 0 {
- if val, ok := attr[0].Value.(string); ok {
- event.EventName = val
- }
- }
-
- if attr, ok := attrs["printer-name"]; ok && len(attr) > 0 {
- if val, ok := attr[0].Value.(string); ok {
- event.PrinterName = val
- }
- }
-
- if attr, ok := attrs["notify-job-id"]; ok && len(attr) > 0 {
- if val, ok := attr[0].Value.(int); ok {
- event.JobID = val
- }
- }
-
- return event
-}
-
-func (sm *SubscriptionManager) Events() <-chan SubscriptionEvent {
- return sm.eventChan
-}
-
-func (sm *SubscriptionManager) Stop() {
- sm.mu.Lock()
- if !sm.running {
- sm.mu.Unlock()
- return
- }
- sm.running = false
- sm.mu.Unlock()
-
- close(sm.stopChan)
- sm.wg.Wait()
-
- if sm.subscriptionID != 0 {
- sm.cancelSubscription()
- sm.subscriptionID = 0
- sm.sequenceNumber = 0
- }
-
- sm.stopChan = make(chan struct{})
-}
-
-func (sm *SubscriptionManager) cancelSubscription() {
- req := ipp.NewRequest(ipp.OperationCancelSubscription, 1)
- req.OperationAttributes[ipp.AttributePrinterURI] = fmt.Sprintf("%s/", sm.baseURL)
- req.OperationAttributes[ipp.AttributeRequestingUserName] = "dms"
- req.OperationAttributes["notify-subscription-id"] = sm.subscriptionID
-
- _, err := sm.client.SendRequest(fmt.Sprintf("%s/", sm.baseURL), req, nil)
- if err != nil {
- log.Warnf("[CUPS] Failed to cancel subscription %d: %v", sm.subscriptionID, err)
- } else {
- log.Infof("[CUPS] Cancelled subscription %d", sm.subscriptionID)
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/cups/subscription_dbus.go b/nix/inputs/dms-cli/internal/server/cups/subscription_dbus.go
deleted file mode 100644
index e438318..0000000
--- a/nix/inputs/dms-cli/internal/server/cups/subscription_dbus.go
+++ /dev/null
@@ -1,295 +0,0 @@
-package cups
-
-import (
- "fmt"
- "strings"
- "sync"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/AvengeMedia/danklinux/pkg/ipp"
- "github.com/godbus/dbus/v5"
-)
-
-type DBusSubscriptionManager struct {
- client CUPSClientInterface
- subscriptionID int
- eventChan chan SubscriptionEvent
- stopChan chan struct{}
- wg sync.WaitGroup
- baseURL string
- running bool
- mu sync.Mutex
- conn *dbus.Conn
-}
-
-func NewDBusSubscriptionManager(client CUPSClientInterface, baseURL string) *DBusSubscriptionManager {
- return &DBusSubscriptionManager{
- client: client,
- eventChan: make(chan SubscriptionEvent, 100),
- stopChan: make(chan struct{}),
- baseURL: baseURL,
- }
-}
-
-func (sm *DBusSubscriptionManager) Start() error {
- sm.mu.Lock()
- if sm.running {
- sm.mu.Unlock()
- return fmt.Errorf("subscription manager already running")
- }
- sm.running = true
- sm.mu.Unlock()
-
- conn, err := dbus.ConnectSystemBus()
- if err != nil {
- sm.mu.Lock()
- sm.running = false
- sm.mu.Unlock()
- return fmt.Errorf("connect to system bus: %w", err)
- }
- sm.conn = conn
-
- subID, err := sm.createDBusSubscription()
- if err != nil {
- sm.conn.Close()
- sm.mu.Lock()
- sm.running = false
- sm.mu.Unlock()
- return fmt.Errorf("failed to create D-Bus subscription: %w", err)
- }
-
- sm.subscriptionID = subID
- log.Infof("[CUPS] Created D-Bus subscription with ID %d", subID)
-
- if err := sm.conn.AddMatchSignal(
- dbus.WithMatchInterface("org.cups.cupsd.Notifier"),
- ); err != nil {
- sm.cancelSubscription()
- sm.conn.Close()
- sm.mu.Lock()
- sm.running = false
- sm.mu.Unlock()
- return fmt.Errorf("failed to add D-Bus match: %w", err)
- }
-
- sm.wg.Add(1)
- go sm.dbusListenerLoop()
-
- return nil
-}
-
-func (sm *DBusSubscriptionManager) createDBusSubscription() (int, error) {
- req := ipp.NewRequest(ipp.OperationCreatePrinterSubscriptions, 2)
- req.OperationAttributes[ipp.AttributePrinterURI] = fmt.Sprintf("%s/", sm.baseURL)
- req.OperationAttributes[ipp.AttributeRequestingUserName] = "dms"
-
- req.SubscriptionAttributes = map[string]interface{}{
- "notify-events": []string{
- "printer-state-changed",
- "printer-added",
- "printer-deleted",
- "job-created",
- "job-completed",
- "job-state-changed",
- },
- "notify-recipient-uri": "dbus:/",
- "notify-lease-duration": 86400,
- }
-
- resp, err := sm.client.SendRequest(fmt.Sprintf("%s/", sm.baseURL), req, nil)
- if err != nil {
- return 0, fmt.Errorf("SendRequest failed: %w", err)
- }
-
- if err := resp.CheckForErrors(); err != nil {
- return 0, fmt.Errorf("IPP error: %w", err)
- }
-
- if len(resp.SubscriptionAttributes) > 0 {
- if idAttr, ok := resp.SubscriptionAttributes[0]["notify-subscription-id"]; ok && len(idAttr) > 0 {
- if val, ok := idAttr[0].Value.(int); ok {
- return val, nil
- }
- }
- }
-
- return 0, fmt.Errorf("no subscription ID returned")
-}
-
-func (sm *DBusSubscriptionManager) dbusListenerLoop() {
- defer sm.wg.Done()
-
- signalChan := make(chan *dbus.Signal, 10)
- sm.conn.Signal(signalChan)
- defer sm.conn.RemoveSignal(signalChan)
-
- for {
- select {
- case <-sm.stopChan:
- return
- case sig := <-signalChan:
- if sig == nil {
- continue
- }
-
- event := sm.parseDBusSignal(sig)
- if event.EventName == "" {
- continue
- }
-
- select {
- case sm.eventChan <- event:
- case <-sm.stopChan:
- return
- default:
- log.Warn("[CUPS] Event channel full, dropping event")
- }
- }
- }
-}
-
-func (sm *DBusSubscriptionManager) parseDBusSignal(sig *dbus.Signal) SubscriptionEvent {
- event := SubscriptionEvent{}
-
- switch sig.Name {
- case "org.cups.cupsd.Notifier.JobStateChanged":
- if len(sig.Body) >= 6 {
- if text, ok := sig.Body[0].(string); ok {
- event.EventName = "job-state-changed"
- parts := strings.Split(text, " ")
- if len(parts) >= 2 {
- event.PrinterName = parts[0]
- }
- }
- if printerURI, ok := sig.Body[1].(string); ok && event.PrinterName == "" {
- if idx := strings.LastIndex(printerURI, "/"); idx != -1 {
- event.PrinterName = printerURI[idx+1:]
- }
- }
- if jobID, ok := sig.Body[3].(uint32); ok {
- event.JobID = int(jobID)
- }
- }
-
- case "org.cups.cupsd.Notifier.JobCreated":
- if len(sig.Body) >= 6 {
- if text, ok := sig.Body[0].(string); ok {
- event.EventName = "job-created"
- parts := strings.Split(text, " ")
- if len(parts) >= 2 {
- event.PrinterName = parts[0]
- }
- }
- if printerURI, ok := sig.Body[1].(string); ok && event.PrinterName == "" {
- if idx := strings.LastIndex(printerURI, "/"); idx != -1 {
- event.PrinterName = printerURI[idx+1:]
- }
- }
- if jobID, ok := sig.Body[3].(uint32); ok {
- event.JobID = int(jobID)
- }
- }
-
- case "org.cups.cupsd.Notifier.JobCompleted":
- if len(sig.Body) >= 6 {
- if text, ok := sig.Body[0].(string); ok {
- event.EventName = "job-completed"
- parts := strings.Split(text, " ")
- if len(parts) >= 2 {
- event.PrinterName = parts[0]
- }
- }
- if printerURI, ok := sig.Body[1].(string); ok && event.PrinterName == "" {
- if idx := strings.LastIndex(printerURI, "/"); idx != -1 {
- event.PrinterName = printerURI[idx+1:]
- }
- }
- if jobID, ok := sig.Body[3].(uint32); ok {
- event.JobID = int(jobID)
- }
- }
-
- case "org.cups.cupsd.Notifier.PrinterStateChanged":
- if len(sig.Body) >= 6 {
- if text, ok := sig.Body[0].(string); ok {
- event.EventName = "printer-state-changed"
- parts := strings.Split(text, " ")
- if len(parts) >= 2 {
- event.PrinterName = parts[0]
- }
- }
- if printerURI, ok := sig.Body[1].(string); ok && event.PrinterName == "" {
- if idx := strings.LastIndex(printerURI, "/"); idx != -1 {
- event.PrinterName = printerURI[idx+1:]
- }
- }
- }
-
- case "org.cups.cupsd.Notifier.PrinterAdded":
- if len(sig.Body) >= 6 {
- if text, ok := sig.Body[0].(string); ok {
- event.EventName = "printer-added"
- parts := strings.Split(text, " ")
- if len(parts) >= 2 {
- event.PrinterName = parts[0]
- }
- }
- }
-
- case "org.cups.cupsd.Notifier.PrinterDeleted":
- if len(sig.Body) >= 6 {
- if text, ok := sig.Body[0].(string); ok {
- event.EventName = "printer-deleted"
- parts := strings.Split(text, " ")
- if len(parts) >= 2 {
- event.PrinterName = parts[0]
- }
- }
- }
- }
-
- return event
-}
-
-func (sm *DBusSubscriptionManager) Events() <-chan SubscriptionEvent {
- return sm.eventChan
-}
-
-func (sm *DBusSubscriptionManager) Stop() {
- sm.mu.Lock()
- if !sm.running {
- sm.mu.Unlock()
- return
- }
- sm.running = false
- sm.mu.Unlock()
-
- close(sm.stopChan)
- sm.wg.Wait()
-
- if sm.subscriptionID != 0 {
- sm.cancelSubscription()
- sm.subscriptionID = 0
- }
-
- if sm.conn != nil {
- sm.conn.Close()
- sm.conn = nil
- }
-
- sm.stopChan = make(chan struct{})
-}
-
-func (sm *DBusSubscriptionManager) cancelSubscription() {
- req := ipp.NewRequest(ipp.OperationCancelSubscription, 1)
- req.OperationAttributes[ipp.AttributePrinterURI] = fmt.Sprintf("%s/", sm.baseURL)
- req.OperationAttributes[ipp.AttributeRequestingUserName] = "dms"
- req.OperationAttributes["notify-subscription-id"] = sm.subscriptionID
-
- _, err := sm.client.SendRequest(fmt.Sprintf("%s/", sm.baseURL), req, nil)
- if err != nil {
- log.Warnf("[CUPS] Failed to cancel subscription %d: %v", sm.subscriptionID, err)
- } else {
- log.Infof("[CUPS] Cancelled subscription %d", sm.subscriptionID)
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/cups/types.go b/nix/inputs/dms-cli/internal/server/cups/types.go
deleted file mode 100644
index 9151331..0000000
--- a/nix/inputs/dms-cli/internal/server/cups/types.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package cups
-
-import (
- "io"
- "sync"
- "time"
-
- "github.com/AvengeMedia/danklinux/pkg/ipp"
-)
-
-type CUPSState struct {
- Printers map[string]*Printer `json:"printers"`
-}
-
-type Printer struct {
- Name string `json:"name"`
- URI string `json:"uri"`
- State string `json:"state"`
- StateReason string `json:"stateReason"`
- Location string `json:"location"`
- Info string `json:"info"`
- MakeModel string `json:"makeModel"`
- Accepting bool `json:"accepting"`
- Jobs []Job `json:"jobs"`
-}
-
-type Job struct {
- ID int `json:"id"`
- Name string `json:"name"`
- State string `json:"state"`
- Printer string `json:"printer"`
- User string `json:"user"`
- Size int `json:"size"`
- TimeCreated time.Time `json:"timeCreated"`
-}
-
-type Manager struct {
- state *CUPSState
- client CUPSClientInterface
- subscription SubscriptionManagerInterface
- stateMutex sync.RWMutex
- subscribers map[string]chan CUPSState
- subMutex sync.RWMutex
- stopChan chan struct{}
- eventWG sync.WaitGroup
- dirty chan struct{}
- notifierWg sync.WaitGroup
- lastNotifiedState *CUPSState
- baseURL string
-}
-
-type SubscriptionManagerInterface interface {
- Start() error
- Stop()
- Events() <-chan SubscriptionEvent
-}
-
-type CUPSClientInterface interface {
- GetPrinters(attributes []string) (map[string]ipp.Attributes, error)
- GetJobs(printer, class string, whichJobs string, myJobs bool, firstJobId, limit int, attributes []string) (map[int]ipp.Attributes, error)
- CancelJob(jobID int, purge bool) error
- PausePrinter(printer string) error
- ResumePrinter(printer string) error
- CancelAllJob(printer string, purge bool) error
- SendRequest(url string, req *ipp.Request, additionalResponseData io.Writer) (*ipp.Response, error)
-}
-
-type SubscriptionEvent struct {
- EventName string
- PrinterName string
- JobID int
- SubscribedAt time.Time
-}
diff --git a/nix/inputs/dms-cli/internal/server/dwl/handlers.go b/nix/inputs/dms-cli/internal/server/dwl/handlers.go
deleted file mode 100644
index 5bac463..0000000
--- a/nix/inputs/dms-cli/internal/server/dwl/handlers.go
+++ /dev/null
@@ -1,144 +0,0 @@
-package dwl
-
-import (
- "encoding/json"
- "fmt"
- "net"
-
- "github.com/AvengeMedia/danklinux/internal/server/models"
-)
-
-type Request struct {
- ID int `json:"id,omitempty"`
- Method string `json:"method"`
- Params map[string]interface{} `json:"params,omitempty"`
-}
-
-type SuccessResult struct {
- Success bool `json:"success"`
- Message string `json:"message"`
-}
-
-func HandleRequest(conn net.Conn, req Request, manager *Manager) {
- if manager == nil {
- models.RespondError(conn, req.ID, "dwl manager not initialized")
- return
- }
-
- switch req.Method {
- case "dwl.getState":
- handleGetState(conn, req, manager)
- case "dwl.setTags":
- handleSetTags(conn, req, manager)
- case "dwl.setClientTags":
- handleSetClientTags(conn, req, manager)
- case "dwl.setLayout":
- handleSetLayout(conn, req, manager)
- case "dwl.subscribe":
- handleSubscribe(conn, req, manager)
- default:
- models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method))
- }
-}
-
-func handleGetState(conn net.Conn, req Request, manager *Manager) {
- state := manager.GetState()
- models.Respond(conn, req.ID, state)
-}
-
-func handleSetTags(conn net.Conn, req Request, manager *Manager) {
- output, ok := req.Params["output"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'output' parameter")
- return
- }
-
- tagmask, ok := req.Params["tagmask"].(float64)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'tagmask' parameter")
- return
- }
-
- toggleTagset, ok := req.Params["toggleTagset"].(float64)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'toggleTagset' parameter")
- return
- }
-
- if err := manager.SetTags(output, uint32(tagmask), uint32(toggleTagset)); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "tags set"})
-}
-
-func handleSetClientTags(conn net.Conn, req Request, manager *Manager) {
- output, ok := req.Params["output"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'output' parameter")
- return
- }
-
- andTags, ok := req.Params["andTags"].(float64)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'andTags' parameter")
- return
- }
-
- xorTags, ok := req.Params["xorTags"].(float64)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'xorTags' parameter")
- return
- }
-
- if err := manager.SetClientTags(output, uint32(andTags), uint32(xorTags)); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "client tags set"})
-}
-
-func handleSetLayout(conn net.Conn, req Request, manager *Manager) {
- output, ok := req.Params["output"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'output' parameter")
- return
- }
-
- index, ok := req.Params["index"].(float64)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'index' parameter")
- return
- }
-
- if err := manager.SetLayout(output, uint32(index)); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "layout set"})
-}
-
-func handleSubscribe(conn net.Conn, req Request, manager *Manager) {
- clientID := fmt.Sprintf("client-%p", conn)
- stateChan := manager.Subscribe(clientID)
- defer manager.Unsubscribe(clientID)
-
- initialState := manager.GetState()
- if err := json.NewEncoder(conn).Encode(models.Response[State]{
- ID: req.ID,
- Result: &initialState,
- }); err != nil {
- return
- }
-
- for state := range stateChan {
- if err := json.NewEncoder(conn).Encode(models.Response[State]{
- Result: &state,
- }); err != nil {
- return
- }
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/dwl/manager.go b/nix/inputs/dms-cli/internal/server/dwl/manager.go
deleted file mode 100644
index 4bdf6e7..0000000
--- a/nix/inputs/dms-cli/internal/server/dwl/manager.go
+++ /dev/null
@@ -1,539 +0,0 @@
-package dwl
-
-import (
- "fmt"
- "time"
-
- wlclient "github.com/yaslama/go-wayland/wayland/client"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/AvengeMedia/danklinux/internal/proto/dwl_ipc"
-)
-
-func NewManager(display *wlclient.Display) (*Manager, error) {
- m := &Manager{
- display: display,
- outputs: make(map[uint32]*outputState),
- cmdq: make(chan cmd, 128),
- outputSetupReq: make(chan uint32, 16),
- stopChan: make(chan struct{}),
- subscribers: make(map[string]chan State),
- dirty: make(chan struct{}, 1),
- layouts: make([]string, 0),
- }
-
- if err := m.setupRegistry(); err != nil {
- return nil, err
- }
-
- m.updateState()
-
- m.notifierWg.Add(1)
- go m.notifier()
-
- m.wg.Add(1)
- go m.waylandActor()
-
- return m, nil
-}
-
-func (m *Manager) post(fn func()) {
- select {
- case m.cmdq <- cmd{fn: fn}:
- default:
- log.Warn("DWL actor command queue full, dropping command")
- }
-}
-
-func (m *Manager) waylandActor() {
- defer m.wg.Done()
-
- for {
- select {
- case <-m.stopChan:
- return
- case c := <-m.cmdq:
- c.fn()
- case outputID := <-m.outputSetupReq:
- m.outputsMutex.RLock()
- out, exists := m.outputs[outputID]
- m.outputsMutex.RUnlock()
-
- if !exists {
- log.Warnf("DWL: Output %d no longer exists, skipping setup", outputID)
- continue
- }
-
- if out.ipcOutput != nil {
- continue
- }
-
- mgr, ok := m.manager.(*dwl_ipc.ZdwlIpcManagerV2)
- if !ok || mgr == nil {
- log.Errorf("DWL: Manager not available for output %d setup", outputID)
- continue
- }
-
- log.Infof("DWL: Setting up ipcOutput for dynamically added output %d", outputID)
- if err := m.setupOutput(mgr, out.output); err != nil {
- log.Errorf("DWL: Failed to setup output %d: %v", outputID, err)
- } else {
- m.updateState()
- }
- }
- }
-}
-
-func (m *Manager) setupRegistry() error {
- log.Info("DWL: starting registry setup")
- ctx := m.display.Context()
-
- registry, err := m.display.GetRegistry()
- if err != nil {
- return fmt.Errorf("failed to get registry: %w", err)
- }
- m.registry = registry
-
- outputs := make([]*wlclient.Output, 0)
- outputRegNames := make(map[uint32]uint32)
- var dwlMgr *dwl_ipc.ZdwlIpcManagerV2
-
- registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) {
- switch e.Interface {
- case dwl_ipc.ZdwlIpcManagerV2InterfaceName:
- log.Infof("DWL: found %s", dwl_ipc.ZdwlIpcManagerV2InterfaceName)
- manager := dwl_ipc.NewZdwlIpcManagerV2(ctx)
- version := e.Version
- if version > 1 {
- version = 1
- }
- if err := registry.Bind(e.Name, e.Interface, version, manager); err == nil {
- dwlMgr = manager
- log.Info("DWL: manager bound successfully")
- } else {
- log.Errorf("DWL: failed to bind manager: %v", err)
- }
- case "wl_output":
- log.Debugf("DWL: found wl_output (name=%d)", e.Name)
- output := wlclient.NewOutput(ctx)
-
- outState := &outputState{
- registryName: e.Name,
- output: output,
- tags: make([]TagState, 0),
- }
-
- output.SetNameHandler(func(ev wlclient.OutputNameEvent) {
- log.Debugf("DWL: Output name: %s (registry=%d)", ev.Name, e.Name)
- outState.name = ev.Name
- })
-
- output.SetDescriptionHandler(func(ev wlclient.OutputDescriptionEvent) {
- log.Debugf("DWL: Output description: %s", ev.Description)
- })
-
- version := e.Version
- if version > 4 {
- version = 4
- }
- if err := registry.Bind(e.Name, e.Interface, version, output); err == nil {
- outputID := output.ID()
- outState.id = outputID
- log.Infof("DWL: Bound wl_output id=%d registry_name=%d", outputID, e.Name)
- outputs = append(outputs, output)
- outputRegNames[outputID] = e.Name
-
- m.outputsMutex.Lock()
- m.outputs[outputID] = outState
- m.outputsMutex.Unlock()
-
- if m.manager != nil {
- select {
- case m.outputSetupReq <- outputID:
- log.Debugf("DWL: Queued setup for output %d", outputID)
- default:
- log.Warnf("DWL: Setup queue full, output %d will not be initialized", outputID)
- }
- }
- } else {
- log.Errorf("DWL: Failed to bind wl_output: %v", err)
- }
- }
- })
-
- registry.SetGlobalRemoveHandler(func(e wlclient.RegistryGlobalRemoveEvent) {
- m.post(func() {
- m.outputsMutex.Lock()
- var outToRelease *outputState
- for id, out := range m.outputs {
- if out.registryName == e.Name {
- log.Infof("DWL: Output %d removed", id)
- outToRelease = out
- delete(m.outputs, id)
- break
- }
- }
- m.outputsMutex.Unlock()
-
- if outToRelease != nil {
- if ipcOut, ok := outToRelease.ipcOutput.(*dwl_ipc.ZdwlIpcOutputV2); ok && ipcOut != nil {
- m.wlMutex.Lock()
- ipcOut.Release()
- m.wlMutex.Unlock()
- log.Debugf("DWL: Released ipcOutput for removed output %d", outToRelease.id)
- }
- m.updateState()
- }
- })
- })
-
- if err := m.display.Roundtrip(); err != nil {
- return fmt.Errorf("first roundtrip failed: %w", err)
- }
- if err := m.display.Roundtrip(); err != nil {
- return fmt.Errorf("second roundtrip failed: %w", err)
- }
-
- if dwlMgr == nil {
- log.Info("DWL: manager not found in registry")
- return fmt.Errorf("dwl_ipc_manager_v2 not available")
- }
-
- dwlMgr.SetTagsHandler(func(e dwl_ipc.ZdwlIpcManagerV2TagsEvent) {
- log.Infof("DWL: Tags count: %d", e.Amount)
- m.tagCount = e.Amount
- m.updateState()
- })
-
- dwlMgr.SetLayoutHandler(func(e dwl_ipc.ZdwlIpcManagerV2LayoutEvent) {
- log.Infof("DWL: Layout: %s", e.Name)
- m.layouts = append(m.layouts, e.Name)
- m.updateState()
- })
-
- m.manager = dwlMgr
-
- for _, output := range outputs {
- if err := m.setupOutput(dwlMgr, output); err != nil {
- log.Warnf("DWL: Failed to setup output %d: %v", output.ID(), err)
- }
- }
-
- if err := m.display.Roundtrip(); err != nil {
- return fmt.Errorf("final roundtrip failed: %w", err)
- }
-
- log.Info("DWL: registry setup complete")
- return nil
-}
-
-func (m *Manager) setupOutput(manager *dwl_ipc.ZdwlIpcManagerV2, output *wlclient.Output) error {
- m.wlMutex.Lock()
- ipcOutput, err := manager.GetOutput(output)
- m.wlMutex.Unlock()
- if err != nil {
- return fmt.Errorf("failed to get dwl output: %w", err)
- }
-
- m.outputsMutex.Lock()
- outState, exists := m.outputs[output.ID()]
- if !exists {
- m.outputsMutex.Unlock()
- return fmt.Errorf("output state not found for id %d", output.ID())
- }
- outState.ipcOutput = ipcOutput
- m.outputsMutex.Unlock()
-
- ipcOutput.SetActiveHandler(func(e dwl_ipc.ZdwlIpcOutputV2ActiveEvent) {
- outState.active = e.Active
- })
-
- ipcOutput.SetTagHandler(func(e dwl_ipc.ZdwlIpcOutputV2TagEvent) {
- updated := false
- for i, tag := range outState.tags {
- if tag.Tag == e.Tag {
- outState.tags[i] = TagState{
- Tag: e.Tag,
- State: e.State,
- Clients: e.Clients,
- Focused: e.Focused,
- }
- updated = true
- break
- }
- }
-
- if !updated {
- outState.tags = append(outState.tags, TagState{
- Tag: e.Tag,
- State: e.State,
- Clients: e.Clients,
- Focused: e.Focused,
- })
- }
-
- m.updateState()
- })
-
- ipcOutput.SetLayoutHandler(func(e dwl_ipc.ZdwlIpcOutputV2LayoutEvent) {
- outState.layout = e.Layout
- })
-
- ipcOutput.SetTitleHandler(func(e dwl_ipc.ZdwlIpcOutputV2TitleEvent) {
- outState.title = e.Title
- })
-
- ipcOutput.SetAppidHandler(func(e dwl_ipc.ZdwlIpcOutputV2AppidEvent) {
- outState.appID = e.Appid
- })
-
- ipcOutput.SetLayoutSymbolHandler(func(e dwl_ipc.ZdwlIpcOutputV2LayoutSymbolEvent) {
- outState.layoutSymbol = e.Layout
- })
-
- ipcOutput.SetFrameHandler(func(e dwl_ipc.ZdwlIpcOutputV2FrameEvent) {
- m.updateState()
- })
-
- return nil
-}
-
-func (m *Manager) updateState() {
- m.outputsMutex.RLock()
- outputs := make(map[string]*OutputState)
- activeOutput := ""
-
- for _, out := range m.outputs {
- name := out.name
- if name == "" {
- name = fmt.Sprintf("output-%d", out.id)
- }
-
- tagsCopy := make([]TagState, len(out.tags))
- copy(tagsCopy, out.tags)
-
- outputs[name] = &OutputState{
- Name: name,
- Active: out.active,
- Tags: tagsCopy,
- Layout: out.layout,
- LayoutSymbol: out.layoutSymbol,
- Title: out.title,
- AppID: out.appID,
- }
-
- if out.active != 0 {
- activeOutput = name
- }
- }
- m.outputsMutex.RUnlock()
-
- newState := State{
- Outputs: outputs,
- TagCount: m.tagCount,
- Layouts: m.layouts,
- ActiveOutput: activeOutput,
- }
-
- m.stateMutex.Lock()
- m.state = &newState
- m.stateMutex.Unlock()
-
- m.notifySubscribers()
-}
-
-func (m *Manager) notifier() {
- defer m.notifierWg.Done()
- const minGap = 100 * time.Millisecond
- timer := time.NewTimer(minGap)
- timer.Stop()
- var pending bool
-
- for {
- select {
- case <-m.stopChan:
- timer.Stop()
- return
- case <-m.dirty:
- if pending {
- continue
- }
- pending = true
- timer.Reset(minGap)
- case <-timer.C:
- if !pending {
- continue
- }
- m.subMutex.RLock()
- subCount := len(m.subscribers)
- m.subMutex.RUnlock()
-
- if subCount == 0 {
- pending = false
- continue
- }
-
- currentState := m.GetState()
-
- if m.lastNotified != nil && !stateChanged(m.lastNotified, ¤tState) {
- pending = false
- continue
- }
-
- m.subMutex.RLock()
- for _, ch := range m.subscribers {
- select {
- case ch <- currentState:
- default:
- log.Warn("DWL: subscriber channel full, dropping update")
- }
- }
- m.subMutex.RUnlock()
-
- stateCopy := currentState
- m.lastNotified = &stateCopy
- pending = false
- }
- }
-}
-
-func (m *Manager) ensureOutputSetup(out *outputState) error {
- if out.ipcOutput != nil {
- return nil
- }
-
- return fmt.Errorf("output not yet initialized - setup in progress, retry in a moment")
-}
-
-func (m *Manager) SetTags(outputName string, tagmask uint32, toggleTagset uint32) error {
- m.outputsMutex.RLock()
-
- availableOutputs := make([]string, 0, len(m.outputs))
- var targetOut *outputState
- for _, out := range m.outputs {
- name := out.name
- if name == "" {
- name = fmt.Sprintf("output-%d", out.id)
- }
- availableOutputs = append(availableOutputs, name)
- if name == outputName {
- targetOut = out
- break
- }
- }
- m.outputsMutex.RUnlock()
-
- if targetOut == nil {
- return fmt.Errorf("output not found: %s (available: %v)", outputName, availableOutputs)
- }
-
- if err := m.ensureOutputSetup(targetOut); err != nil {
- return fmt.Errorf("failed to setup output %s: %w", outputName, err)
- }
-
- ipcOut, ok := targetOut.ipcOutput.(*dwl_ipc.ZdwlIpcOutputV2)
- if !ok {
- return fmt.Errorf("output %s has invalid ipcOutput type", outputName)
- }
-
- m.wlMutex.Lock()
- err := ipcOut.SetTags(tagmask, toggleTagset)
- m.wlMutex.Unlock()
- return err
-}
-
-func (m *Manager) SetClientTags(outputName string, andTags uint32, xorTags uint32) error {
- m.outputsMutex.RLock()
-
- var targetOut *outputState
- for _, out := range m.outputs {
- name := out.name
- if name == "" {
- name = fmt.Sprintf("output-%d", out.id)
- }
- if name == outputName {
- targetOut = out
- break
- }
- }
- m.outputsMutex.RUnlock()
-
- if targetOut == nil {
- return fmt.Errorf("output not found: %s", outputName)
- }
-
- if err := m.ensureOutputSetup(targetOut); err != nil {
- return fmt.Errorf("failed to setup output %s: %w", outputName, err)
- }
-
- ipcOut, ok := targetOut.ipcOutput.(*dwl_ipc.ZdwlIpcOutputV2)
- if !ok {
- return fmt.Errorf("output %s has invalid ipcOutput type", outputName)
- }
-
- m.wlMutex.Lock()
- err := ipcOut.SetClientTags(andTags, xorTags)
- m.wlMutex.Unlock()
- return err
-}
-
-func (m *Manager) SetLayout(outputName string, index uint32) error {
- m.outputsMutex.RLock()
-
- var targetOut *outputState
- for _, out := range m.outputs {
- name := out.name
- if name == "" {
- name = fmt.Sprintf("output-%d", out.id)
- }
- if name == outputName {
- targetOut = out
- break
- }
- }
- m.outputsMutex.RUnlock()
-
- if targetOut == nil {
- return fmt.Errorf("output not found: %s", outputName)
- }
-
- if err := m.ensureOutputSetup(targetOut); err != nil {
- return fmt.Errorf("failed to setup output %s: %w", outputName, err)
- }
-
- ipcOut, ok := targetOut.ipcOutput.(*dwl_ipc.ZdwlIpcOutputV2)
- if !ok {
- return fmt.Errorf("output %s has invalid ipcOutput type", outputName)
- }
-
- m.wlMutex.Lock()
- err := ipcOut.SetLayout(index)
- m.wlMutex.Unlock()
- return err
-}
-
-func (m *Manager) Close() {
- close(m.stopChan)
- m.wg.Wait()
- m.notifierWg.Wait()
-
- m.subMutex.Lock()
- for _, ch := range m.subscribers {
- close(ch)
- }
- m.subscribers = make(map[string]chan State)
- m.subMutex.Unlock()
-
- m.outputsMutex.Lock()
- for _, out := range m.outputs {
- if ipcOut, ok := out.ipcOutput.(*dwl_ipc.ZdwlIpcOutputV2); ok {
- ipcOut.Release()
- }
- }
- m.outputs = make(map[uint32]*outputState)
- m.outputsMutex.Unlock()
-
- if mgr, ok := m.manager.(*dwl_ipc.ZdwlIpcManagerV2); ok {
- mgr.Release()
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/dwl/types.go b/nix/inputs/dms-cli/internal/server/dwl/types.go
deleted file mode 100644
index a974df5..0000000
--- a/nix/inputs/dms-cli/internal/server/dwl/types.go
+++ /dev/null
@@ -1,169 +0,0 @@
-package dwl
-
-import (
- "sync"
-
- wlclient "github.com/yaslama/go-wayland/wayland/client"
-)
-
-type TagState struct {
- Tag uint32 `json:"tag"`
- State uint32 `json:"state"`
- Clients uint32 `json:"clients"`
- Focused uint32 `json:"focused"`
-}
-
-type OutputState struct {
- Name string `json:"name"`
- Active uint32 `json:"active"`
- Tags []TagState `json:"tags"`
- Layout uint32 `json:"layout"`
- LayoutSymbol string `json:"layoutSymbol"`
- Title string `json:"title"`
- AppID string `json:"appId"`
-}
-
-type State struct {
- Outputs map[string]*OutputState `json:"outputs"`
- TagCount uint32 `json:"tagCount"`
- Layouts []string `json:"layouts"`
- ActiveOutput string `json:"activeOutput"`
-}
-
-type cmd struct {
- fn func()
-}
-
-type Manager struct {
- display *wlclient.Display
- registry *wlclient.Registry
- manager interface{}
-
- outputs map[uint32]*outputState
- outputsMutex sync.RWMutex
-
- tagCount uint32
- layouts []string
-
- wlMutex sync.Mutex
- cmdq chan cmd
- outputSetupReq chan uint32
- stopChan chan struct{}
- wg sync.WaitGroup
-
- subscribers map[string]chan State
- subMutex sync.RWMutex
- dirty chan struct{}
- notifierWg sync.WaitGroup
- lastNotified *State
-
- stateMutex sync.RWMutex
- state *State
-}
-
-type outputState struct {
- id uint32
- registryName uint32
- output *wlclient.Output
- ipcOutput interface{}
- name string
- active uint32
- tags []TagState
- layout uint32
- layoutSymbol string
- title string
- appID string
-}
-
-func (m *Manager) GetState() State {
- m.stateMutex.RLock()
- defer m.stateMutex.RUnlock()
- if m.state == nil {
- return State{
- Outputs: make(map[string]*OutputState),
- Layouts: []string{},
- TagCount: 0,
- }
- }
- stateCopy := *m.state
- return stateCopy
-}
-
-func (m *Manager) Subscribe(id string) chan State {
- ch := make(chan State, 64)
- m.subMutex.Lock()
- m.subscribers[id] = ch
- m.subMutex.Unlock()
- return ch
-}
-
-func (m *Manager) Unsubscribe(id string) {
- m.subMutex.Lock()
- if ch, ok := m.subscribers[id]; ok {
- close(ch)
- delete(m.subscribers, id)
- }
- m.subMutex.Unlock()
-}
-
-func (m *Manager) notifySubscribers() {
- select {
- case m.dirty <- struct{}{}:
- default:
- }
-}
-
-func stateChanged(old, new *State) bool {
- if old == nil || new == nil {
- return true
- }
- if old.TagCount != new.TagCount {
- return true
- }
- if len(old.Layouts) != len(new.Layouts) {
- return true
- }
- if old.ActiveOutput != new.ActiveOutput {
- return true
- }
- if len(old.Outputs) != len(new.Outputs) {
- return true
- }
-
- for name, newOut := range new.Outputs {
- oldOut, exists := old.Outputs[name]
- if !exists {
- return true
- }
- if oldOut.Active != newOut.Active {
- return true
- }
- if oldOut.Layout != newOut.Layout {
- return true
- }
- if oldOut.LayoutSymbol != newOut.LayoutSymbol {
- return true
- }
- if oldOut.Title != newOut.Title {
- return true
- }
- if oldOut.AppID != newOut.AppID {
- return true
- }
- if len(oldOut.Tags) != len(newOut.Tags) {
- return true
- }
- for i, newTag := range newOut.Tags {
- if i >= len(oldOut.Tags) {
- return true
- }
- oldTag := oldOut.Tags[i]
- if oldTag.Tag != newTag.Tag || oldTag.State != newTag.State ||
- oldTag.Clients != newTag.Clients || oldTag.Focused != newTag.Focused {
- return true
- }
- }
- }
-
- return false
-}
diff --git a/nix/inputs/dms-cli/internal/server/freedesktop/actions.go b/nix/inputs/dms-cli/internal/server/freedesktop/actions.go
deleted file mode 100644
index c187e2e..0000000
--- a/nix/inputs/dms-cli/internal/server/freedesktop/actions.go
+++ /dev/null
@@ -1,128 +0,0 @@
-package freedesktop
-
-import (
- "context"
- "fmt"
- "os/exec"
- "time"
-
- "github.com/godbus/dbus/v5"
-)
-
-func (m *Manager) SetIconFile(iconPath string) error {
- if !m.state.Accounts.Available || m.accountsObj == nil {
- return fmt.Errorf("accounts service not available")
- }
-
- err := m.accountsObj.Call(dbusAccountsUserInterface+".SetIconFile", 0, iconPath).Err
- if err != nil {
- return fmt.Errorf("failed to set icon file: %w", err)
- }
-
- m.updateAccountsState()
- return nil
-}
-
-func (m *Manager) SetRealName(name string) error {
- if !m.state.Accounts.Available || m.accountsObj == nil {
- return fmt.Errorf("accounts service not available")
- }
-
- err := m.accountsObj.Call(dbusAccountsUserInterface+".SetRealName", 0, name).Err
- if err != nil {
- return fmt.Errorf("failed to set real name: %w", err)
- }
-
- m.updateAccountsState()
- return nil
-}
-
-func (m *Manager) SetEmail(email string) error {
- if !m.state.Accounts.Available || m.accountsObj == nil {
- return fmt.Errorf("accounts service not available")
- }
-
- err := m.accountsObj.Call(dbusAccountsUserInterface+".SetEmail", 0, email).Err
- if err != nil {
- return fmt.Errorf("failed to set email: %w", err)
- }
-
- m.updateAccountsState()
- return nil
-}
-
-func (m *Manager) SetLanguage(language string) error {
- if !m.state.Accounts.Available || m.accountsObj == nil {
- return fmt.Errorf("accounts service not available")
- }
-
- err := m.accountsObj.Call(dbusAccountsUserInterface+".SetLanguage", 0, language).Err
- if err != nil {
- return fmt.Errorf("failed to set language: %w", err)
- }
-
- m.updateAccountsState()
- return nil
-}
-
-func (m *Manager) SetLocation(location string) error {
- if !m.state.Accounts.Available || m.accountsObj == nil {
- return fmt.Errorf("accounts service not available")
- }
-
- err := m.accountsObj.Call(dbusAccountsUserInterface+".SetLocation", 0, location).Err
- if err != nil {
- return fmt.Errorf("failed to set location: %w", err)
- }
-
- m.updateAccountsState()
- return nil
-}
-
-func (m *Manager) GetUserIconFile(username string) (string, error) {
- if m.systemConn == nil {
- return "", fmt.Errorf("accounts service not available")
- }
-
- accountsManager := m.systemConn.Object(dbusAccountsDest, dbus.ObjectPath(dbusAccountsPath))
-
- var userPath dbus.ObjectPath
- err := accountsManager.Call(dbusAccountsInterface+".FindUserByName", 0, username).Store(&userPath)
- if err != nil {
- return "", fmt.Errorf("user not found: %w", err)
- }
-
- userObj := m.systemConn.Object(dbusAccountsDest, userPath)
- variant, err := userObj.GetProperty(dbusAccountsUserInterface + ".IconFile")
- if err != nil {
- return "", err
- }
-
- var iconFile string
- if err := variant.Store(&iconFile); err != nil {
- return "", err
- }
-
- return iconFile, nil
-}
-
-func (m *Manager) SetIconTheme(iconTheme string) error {
- ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
- defer cancel()
-
- check := exec.CommandContext(ctx, "gsettings", "writable", "org.gnome.desktop.interface", "icon-theme")
- if err := check.Run(); err == nil {
- cmd := exec.CommandContext(ctx, "gsettings", "set", "org.gnome.desktop.interface", "icon-theme", iconTheme)
- if err := cmd.Run(); err != nil {
- return fmt.Errorf("gsettings set failed: %w", err)
- }
- return nil
- }
-
- checkDconf := exec.CommandContext(ctx, "dconf", "write", "/org/gnome/desktop/interface/icon-theme", fmt.Sprintf("'%s'", iconTheme))
- if err := checkDconf.Run(); err != nil {
- return fmt.Errorf("both gsettings and dconf unavailable or failed: %w", err)
- }
-
- return nil
-}
diff --git a/nix/inputs/dms-cli/internal/server/freedesktop/actions_test.go b/nix/inputs/dms-cli/internal/server/freedesktop/actions_test.go
deleted file mode 100644
index e2c21e8..0000000
--- a/nix/inputs/dms-cli/internal/server/freedesktop/actions_test.go
+++ /dev/null
@@ -1,145 +0,0 @@
-package freedesktop
-
-import (
- "sync"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestManager_SetIconFile(t *testing.T) {
- t.Run("accounts not available", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: false,
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- err := manager.SetIconFile("/path/to/icon.png")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "accounts service not available")
- })
-}
-
-func TestManager_SetRealName(t *testing.T) {
- t.Run("accounts not available", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: false,
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- err := manager.SetRealName("New Name")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "accounts service not available")
- })
-}
-
-func TestManager_SetEmail(t *testing.T) {
- t.Run("accounts not available", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: false,
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- err := manager.SetEmail("test@example.com")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "accounts service not available")
- })
-}
-
-func TestManager_SetLanguage(t *testing.T) {
- t.Run("accounts not available", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: false,
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- err := manager.SetLanguage("en_US.UTF-8")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "accounts service not available")
- })
-}
-
-func TestManager_SetLocation(t *testing.T) {
- t.Run("accounts not available", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: false,
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- err := manager.SetLocation("Test Location")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "accounts service not available")
- })
-}
-
-func TestManager_GetUserIconFile(t *testing.T) {
- t.Run("accounts not available", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: false,
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- iconFile, err := manager.GetUserIconFile("testuser")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "accounts service not available")
- assert.Empty(t, iconFile)
- })
-}
-
-func TestManager_UpdateAccountsState(t *testing.T) {
- t.Run("accounts not available", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: false,
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- err := manager.updateAccountsState()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "accounts service not available")
- })
-}
-
-func TestManager_UpdateSettingsState(t *testing.T) {
- t.Run("settings not available", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Settings: SettingsState{
- Available: false,
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- err := manager.updateSettingsState()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "settings portal not available")
- })
-}
diff --git a/nix/inputs/dms-cli/internal/server/freedesktop/constants.go b/nix/inputs/dms-cli/internal/server/freedesktop/constants.go
deleted file mode 100644
index e777ee2..0000000
--- a/nix/inputs/dms-cli/internal/server/freedesktop/constants.go
+++ /dev/null
@@ -1,14 +0,0 @@
-package freedesktop
-
-const (
- dbusAccountsDest = "org.freedesktop.Accounts"
- dbusAccountsPath = "/org/freedesktop/Accounts"
- dbusAccountsInterface = "org.freedesktop.Accounts"
- dbusAccountsUserInterface = "org.freedesktop.Accounts.User"
-
- dbusPortalDest = "org.freedesktop.portal.Desktop"
- dbusPortalPath = "/org/freedesktop/portal/desktop"
- dbusPortalSettingsInterface = "org.freedesktop.portal.Settings"
-
- dbusPropsInterface = "org.freedesktop.DBus.Properties"
-)
diff --git a/nix/inputs/dms-cli/internal/server/freedesktop/handlers.go b/nix/inputs/dms-cli/internal/server/freedesktop/handlers.go
deleted file mode 100644
index b6a54c8..0000000
--- a/nix/inputs/dms-cli/internal/server/freedesktop/handlers.go
+++ /dev/null
@@ -1,166 +0,0 @@
-package freedesktop
-
-import (
- "fmt"
- "net"
-
- "github.com/AvengeMedia/danklinux/internal/server/models"
-)
-
-type Request struct {
- ID int `json:"id,omitempty"`
- Method string `json:"method"`
- Params map[string]interface{} `json:"params,omitempty"`
-}
-
-type SuccessResult struct {
- Success bool `json:"success"`
- Message string `json:"message"`
- Value string `json:"value,omitempty"`
-}
-
-func HandleRequest(conn net.Conn, req Request, manager *Manager) {
- switch req.Method {
- case "freedesktop.getState":
- handleGetState(conn, req, manager)
- case "freedesktop.accounts.setIconFile":
- handleSetIconFile(conn, req, manager)
- case "freedesktop.accounts.setRealName":
- handleSetRealName(conn, req, manager)
- case "freedesktop.accounts.setEmail":
- handleSetEmail(conn, req, manager)
- case "freedesktop.accounts.setLanguage":
- handleSetLanguage(conn, req, manager)
- case "freedesktop.accounts.setLocation":
- handleSetLocation(conn, req, manager)
- case "freedesktop.accounts.getUserIconFile":
- handleGetUserIconFile(conn, req, manager)
- case "freedesktop.settings.getColorScheme":
- handleGetColorScheme(conn, req, manager)
- case "freedesktop.settings.setIconTheme":
- handleSetIconTheme(conn, req, manager)
- default:
- models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method))
- }
-}
-
-func handleGetState(conn net.Conn, req Request, manager *Manager) {
- state := manager.GetState()
- models.Respond(conn, req.ID, state)
-}
-
-func handleSetIconFile(conn net.Conn, req Request, manager *Manager) {
- iconPath, ok := req.Params["path"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'path' parameter")
- return
- }
-
- if err := manager.SetIconFile(iconPath); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "icon file set"})
-}
-
-func handleSetRealName(conn net.Conn, req Request, manager *Manager) {
- name, ok := req.Params["name"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'name' parameter")
- return
- }
-
- if err := manager.SetRealName(name); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "real name set"})
-}
-
-func handleSetEmail(conn net.Conn, req Request, manager *Manager) {
- email, ok := req.Params["email"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'email' parameter")
- return
- }
-
- if err := manager.SetEmail(email); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "email set"})
-}
-
-func handleSetLanguage(conn net.Conn, req Request, manager *Manager) {
- language, ok := req.Params["language"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'language' parameter")
- return
- }
-
- if err := manager.SetLanguage(language); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "language set"})
-}
-
-func handleSetLocation(conn net.Conn, req Request, manager *Manager) {
- location, ok := req.Params["location"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'location' parameter")
- return
- }
-
- if err := manager.SetLocation(location); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "location set"})
-}
-
-func handleGetUserIconFile(conn net.Conn, req Request, manager *Manager) {
- username, ok := req.Params["username"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'username' parameter")
- return
- }
-
- iconFile, err := manager.GetUserIconFile(username)
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Value: iconFile})
-}
-
-func handleGetColorScheme(conn net.Conn, req Request, manager *Manager) {
- if err := manager.updateSettingsState(); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- state := manager.GetState()
- models.Respond(conn, req.ID, map[string]uint32{"colorScheme": state.Settings.ColorScheme})
-}
-
-func handleSetIconTheme(conn net.Conn, req Request, manager *Manager) {
- iconTheme, ok := req.Params["iconTheme"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'iconTheme' parameter")
- return
- }
-
- if err := manager.SetIconTheme(iconTheme); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "icon theme set"})
-}
diff --git a/nix/inputs/dms-cli/internal/server/freedesktop/handlers_test.go b/nix/inputs/dms-cli/internal/server/freedesktop/handlers_test.go
deleted file mode 100644
index c72beb9..0000000
--- a/nix/inputs/dms-cli/internal/server/freedesktop/handlers_test.go
+++ /dev/null
@@ -1,581 +0,0 @@
-package freedesktop
-
-import (
- "bytes"
- "encoding/json"
- "net"
- "sync"
- "testing"
-
- mockdbus "github.com/AvengeMedia/danklinux/internal/mocks/github.com/godbus/dbus/v5"
- "github.com/AvengeMedia/danklinux/internal/server/models"
- "github.com/godbus/dbus/v5"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
- "github.com/stretchr/testify/require"
-)
-
-type mockNetConn struct {
- net.Conn
- readBuf *bytes.Buffer
- writeBuf *bytes.Buffer
- closed bool
-}
-
-func newMockNetConn() *mockNetConn {
- return &mockNetConn{
- readBuf: &bytes.Buffer{},
- writeBuf: &bytes.Buffer{},
- }
-}
-
-func (m *mockNetConn) Read(b []byte) (n int, err error) {
- return m.readBuf.Read(b)
-}
-
-func (m *mockNetConn) Write(b []byte) (n int, err error) {
- return m.writeBuf.Write(b)
-}
-
-func (m *mockNetConn) Close() error {
- m.closed = true
- return nil
-}
-
-func mockGetAllAccountsProperties() *dbus.Call {
- props := map[string]dbus.Variant{
- "IconFile": dbus.MakeVariant("/path/to/icon.png"),
- "RealName": dbus.MakeVariant("Test"),
- "UserName": dbus.MakeVariant("test"),
- "AccountType": dbus.MakeVariant(int32(0)),
- "HomeDirectory": dbus.MakeVariant("/home/test"),
- "Shell": dbus.MakeVariant("/bin/bash"),
- "Email": dbus.MakeVariant(""),
- "Language": dbus.MakeVariant(""),
- "Location": dbus.MakeVariant(""),
- "Locked": dbus.MakeVariant(false),
- "PasswordMode": dbus.MakeVariant(int32(1)),
- }
- return &dbus.Call{Err: nil, Body: []interface{}{props}}
-}
-
-func TestRespondError_Freedesktop(t *testing.T) {
- conn := newMockNetConn()
- models.RespondError(conn, 123, "test error")
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Equal(t, "test error", resp.Error)
- assert.Nil(t, resp.Result)
-}
-
-func TestRespond_Freedesktop(t *testing.T) {
- conn := newMockNetConn()
- result := SuccessResult{Success: true, Message: "test"}
- models.Respond(conn, 123, result)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
- assert.Equal(t, "test", resp.Result.Message)
-}
-
-func TestHandleGetState(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: true,
- UserName: "testuser",
- RealName: "Test User",
- UID: 1000,
- },
- Settings: SettingsState{
- Available: true,
- ColorScheme: 1,
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- conn := newMockNetConn()
- req := Request{ID: 123, Method: "freedesktop.getState"}
-
- handleGetState(conn, req, manager)
-
- var resp models.Response[FreedeskState]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Accounts.Available)
- assert.Equal(t, "testuser", resp.Result.Accounts.UserName)
- assert.True(t, resp.Result.Settings.Available)
- assert.Equal(t, uint32(1), resp.Result.Settings.ColorScheme)
-}
-
-func TestHandleSetIconFile(t *testing.T) {
- t.Run("missing path parameter", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{},
- stateMutex: sync.RWMutex{},
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "freedesktop.accounts.setIconFile",
- Params: map[string]interface{}{},
- }
-
- handleSetIconFile(conn, req, manager)
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "missing or invalid 'path' parameter")
- })
-
- t.Run("successful set icon file", func(t *testing.T) {
- mockAccountsObj := mockdbus.NewMockBusObject(t)
- mockCall := &dbus.Call{Err: nil}
- mockAccountsObj.EXPECT().Call("org.freedesktop.Accounts.User.SetIconFile", dbus.Flags(0), "/path/to/icon.png").Return(mockCall)
- mockAccountsObj.EXPECT().CallWithContext(mock.Anything, "org.freedesktop.DBus.Properties.GetAll", dbus.Flags(0), "org.freedesktop.Accounts.User").Return(mockGetAllAccountsProperties())
-
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: true,
- },
- },
- stateMutex: sync.RWMutex{},
- accountsObj: mockAccountsObj,
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "freedesktop.accounts.setIconFile",
- Params: map[string]interface{}{
- "path": "/path/to/icon.png",
- },
- }
-
- handleSetIconFile(conn, req, manager)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
- assert.Equal(t, "icon file set", resp.Result.Message)
- })
-
- t.Run("accounts not available", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: false,
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "freedesktop.accounts.setIconFile",
- Params: map[string]interface{}{
- "path": "/path/to/icon.png",
- },
- }
-
- handleSetIconFile(conn, req, manager)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "accounts service not available")
- })
-}
-
-func TestHandleSetRealName(t *testing.T) {
- t.Run("missing name parameter", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{},
- stateMutex: sync.RWMutex{},
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "freedesktop.accounts.setRealName",
- Params: map[string]interface{}{},
- }
-
- handleSetRealName(conn, req, manager)
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "missing or invalid 'name' parameter")
- })
-
- t.Run("successful set real name", func(t *testing.T) {
- mockAccountsObj := mockdbus.NewMockBusObject(t)
- mockCall := &dbus.Call{Err: nil}
- mockAccountsObj.EXPECT().Call("org.freedesktop.Accounts.User.SetRealName", dbus.Flags(0), "New Name").Return(mockCall)
- mockAccountsObj.EXPECT().CallWithContext(mock.Anything, "org.freedesktop.DBus.Properties.GetAll", dbus.Flags(0), "org.freedesktop.Accounts.User").Return(mockGetAllAccountsProperties())
-
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: true,
- },
- },
- stateMutex: sync.RWMutex{},
- accountsObj: mockAccountsObj,
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "freedesktop.accounts.setRealName",
- Params: map[string]interface{}{
- "name": "New Name",
- },
- }
-
- handleSetRealName(conn, req, manager)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
- assert.Equal(t, "real name set", resp.Result.Message)
- })
-}
-
-func TestHandleSetEmail(t *testing.T) {
- t.Run("missing email parameter", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{},
- stateMutex: sync.RWMutex{},
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "freedesktop.accounts.setEmail",
- Params: map[string]interface{}{},
- }
-
- handleSetEmail(conn, req, manager)
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "missing or invalid 'email' parameter")
- })
-
- t.Run("successful set email", func(t *testing.T) {
- mockAccountsObj := mockdbus.NewMockBusObject(t)
- mockCall := &dbus.Call{Err: nil}
- mockAccountsObj.EXPECT().Call("org.freedesktop.Accounts.User.SetEmail", dbus.Flags(0), "test@example.com").Return(mockCall)
- mockAccountsObj.EXPECT().CallWithContext(mock.Anything, "org.freedesktop.DBus.Properties.GetAll", dbus.Flags(0), "org.freedesktop.Accounts.User").Return(mockGetAllAccountsProperties())
-
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: true,
- },
- },
- stateMutex: sync.RWMutex{},
- accountsObj: mockAccountsObj,
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "freedesktop.accounts.setEmail",
- Params: map[string]interface{}{
- "email": "test@example.com",
- },
- }
-
- handleSetEmail(conn, req, manager)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
- assert.Equal(t, "email set", resp.Result.Message)
- })
-}
-
-func TestHandleSetLanguage(t *testing.T) {
- t.Run("missing language parameter", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{},
- stateMutex: sync.RWMutex{},
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "freedesktop.accounts.setLanguage",
- Params: map[string]interface{}{},
- }
-
- handleSetLanguage(conn, req, manager)
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "missing or invalid 'language' parameter")
- })
-}
-
-func TestHandleSetLocation(t *testing.T) {
- t.Run("missing location parameter", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{},
- stateMutex: sync.RWMutex{},
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "freedesktop.accounts.setLocation",
- Params: map[string]interface{}{},
- }
-
- handleSetLocation(conn, req, manager)
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "missing or invalid 'location' parameter")
- })
-}
-
-func TestHandleGetUserIconFile(t *testing.T) {
- t.Run("missing username parameter", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{},
- stateMutex: sync.RWMutex{},
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "freedesktop.accounts.getUserIconFile",
- Params: map[string]interface{}{},
- }
-
- handleGetUserIconFile(conn, req, manager)
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "missing or invalid 'username' parameter")
- })
-
- t.Run("accounts not available", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: false,
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "freedesktop.accounts.getUserIconFile",
- Params: map[string]interface{}{
- "username": "testuser",
- },
- }
-
- handleGetUserIconFile(conn, req, manager)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "accounts service not available")
- })
-}
-
-func TestHandleGetColorScheme(t *testing.T) {
- t.Run("settings not available", func(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Settings: SettingsState{
- Available: false,
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- conn := newMockNetConn()
- req := Request{ID: 123, Method: "freedesktop.settings.getColorScheme"}
-
- handleGetColorScheme(conn, req, manager)
-
- var resp models.Response[map[string]uint32]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "settings portal not available")
- })
-
- t.Run("successful get color scheme", func(t *testing.T) {
- mockSettingsObj := mockdbus.NewMockBusObject(t)
- mockCall := &dbus.Call{
- Err: nil,
- Body: []interface{}{dbus.MakeVariant(uint32(1))},
- }
- mockSettingsObj.EXPECT().Call("org.freedesktop.portal.Settings.ReadOne", dbus.Flags(0), "org.freedesktop.appearance", "color-scheme").Return(mockCall)
-
- manager := &Manager{
- state: &FreedeskState{
- Settings: SettingsState{
- Available: true,
- },
- },
- stateMutex: sync.RWMutex{},
- settingsObj: mockSettingsObj,
- }
-
- conn := newMockNetConn()
- req := Request{ID: 123, Method: "freedesktop.settings.getColorScheme"}
-
- handleGetColorScheme(conn, req, manager)
-
- var resp models.Response[map[string]uint32]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.Equal(t, uint32(1), (*resp.Result)["colorScheme"])
- })
-}
-
-func TestHandleRequest(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: true,
- UserName: "testuser",
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- t.Run("unknown method", func(t *testing.T) {
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "freedesktop.unknown",
- }
-
- HandleRequest(conn, req, manager)
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "unknown method")
- })
-
- t.Run("valid method - getState", func(t *testing.T) {
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "freedesktop.getState",
- }
-
- HandleRequest(conn, req, manager)
-
- var resp models.Response[FreedeskState]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- })
-
- t.Run("all method routes", func(t *testing.T) {
- tests := []string{
- "freedesktop.accounts.setIconFile",
- "freedesktop.accounts.setRealName",
- "freedesktop.accounts.setEmail",
- "freedesktop.accounts.setLanguage",
- "freedesktop.accounts.setLocation",
- "freedesktop.accounts.getUserIconFile",
- "freedesktop.settings.getColorScheme",
- }
-
- for _, method := range tests {
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: method,
- Params: map[string]interface{}{},
- }
-
- HandleRequest(conn, req, manager)
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- // Will have errors due to missing params or service unavailable
- // but the method routing should work
- }
- })
-}
diff --git a/nix/inputs/dms-cli/internal/server/freedesktop/manager.go b/nix/inputs/dms-cli/internal/server/freedesktop/manager.go
deleted file mode 100644
index ef85b96..0000000
--- a/nix/inputs/dms-cli/internal/server/freedesktop/manager.go
+++ /dev/null
@@ -1,251 +0,0 @@
-package freedesktop
-
-import (
- "context"
- "fmt"
- "os"
- "sync"
-
- "github.com/godbus/dbus/v5"
-)
-
-func NewManager() (*Manager, error) {
- systemConn, err := dbus.ConnectSystemBus()
- if err != nil {
- return nil, fmt.Errorf("failed to connect to system bus: %w", err)
- }
-
- sessionConn, err := dbus.ConnectSessionBus()
- if err != nil {
- sessionConn = nil
- }
-
- m := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{},
- Settings: SettingsState{},
- },
- stateMutex: sync.RWMutex{},
- systemConn: systemConn,
- sessionConn: sessionConn,
- currentUID: uint64(os.Getuid()),
- subscribers: make(map[string]chan FreedeskState),
- subMutex: sync.RWMutex{},
- }
-
- m.initializeAccounts()
- m.initializeSettings()
-
- return m, nil
-}
-
-func (m *Manager) initializeAccounts() error {
- accountsManager := m.systemConn.Object(dbusAccountsDest, dbus.ObjectPath(dbusAccountsPath))
-
- var userPath dbus.ObjectPath
- err := accountsManager.Call(dbusAccountsInterface+".FindUserById", 0, int64(m.currentUID)).Store(&userPath)
- if err != nil {
- m.stateMutex.Lock()
- m.state.Accounts.Available = false
- m.stateMutex.Unlock()
- return err
- }
-
- m.accountsObj = m.systemConn.Object(dbusAccountsDest, userPath)
-
- m.stateMutex.Lock()
- m.state.Accounts.Available = true
- m.state.Accounts.UserPath = string(userPath)
- m.state.Accounts.UID = m.currentUID
- m.stateMutex.Unlock()
-
- if err := m.updateAccountsState(); err != nil {
- return fmt.Errorf("failed to update accounts state: %w", err)
- }
-
- return nil
-}
-
-func (m *Manager) initializeSettings() error {
- if m.sessionConn == nil {
- m.stateMutex.Lock()
- m.state.Settings.Available = false
- m.stateMutex.Unlock()
- return fmt.Errorf("no session bus connection")
- }
-
- m.settingsObj = m.sessionConn.Object(dbusPortalDest, dbus.ObjectPath(dbusPortalPath))
-
- var variant dbus.Variant
- err := m.settingsObj.Call(dbusPortalSettingsInterface+".ReadOne", 0, "org.freedesktop.appearance", "color-scheme").Store(&variant)
- if err != nil {
- m.stateMutex.Lock()
- m.state.Settings.Available = false
- m.stateMutex.Unlock()
- return err
- }
-
- m.stateMutex.Lock()
- m.state.Settings.Available = true
- m.stateMutex.Unlock()
-
- if err := m.updateSettingsState(); err != nil {
- return fmt.Errorf("failed to update settings state: %w", err)
- }
-
- return nil
-}
-
-func (m *Manager) updateAccountsState() error {
- if !m.state.Accounts.Available || m.accountsObj == nil {
- return fmt.Errorf("accounts service not available")
- }
-
- ctx := context.Background()
- props, err := m.getAccountProperties(ctx)
- if err != nil {
- return err
- }
-
- m.stateMutex.Lock()
- defer m.stateMutex.Unlock()
-
- if v, ok := props["IconFile"]; ok {
- if val, ok := v.Value().(string); ok {
- m.state.Accounts.IconFile = val
- }
- }
- if v, ok := props["RealName"]; ok {
- if val, ok := v.Value().(string); ok {
- m.state.Accounts.RealName = val
- }
- }
- if v, ok := props["UserName"]; ok {
- if val, ok := v.Value().(string); ok {
- m.state.Accounts.UserName = val
- }
- }
- if v, ok := props["AccountType"]; ok {
- if val, ok := v.Value().(int32); ok {
- m.state.Accounts.AccountType = val
- }
- }
- if v, ok := props["HomeDirectory"]; ok {
- if val, ok := v.Value().(string); ok {
- m.state.Accounts.HomeDirectory = val
- }
- }
- if v, ok := props["Shell"]; ok {
- if val, ok := v.Value().(string); ok {
- m.state.Accounts.Shell = val
- }
- }
- if v, ok := props["Email"]; ok {
- if val, ok := v.Value().(string); ok {
- m.state.Accounts.Email = val
- }
- }
- if v, ok := props["Language"]; ok {
- if val, ok := v.Value().(string); ok {
- m.state.Accounts.Language = val
- }
- }
- if v, ok := props["Location"]; ok {
- if val, ok := v.Value().(string); ok {
- m.state.Accounts.Location = val
- }
- }
- if v, ok := props["Locked"]; ok {
- if val, ok := v.Value().(bool); ok {
- m.state.Accounts.Locked = val
- }
- }
- if v, ok := props["PasswordMode"]; ok {
- if val, ok := v.Value().(int32); ok {
- m.state.Accounts.PasswordMode = val
- }
- }
-
- return nil
-}
-
-func (m *Manager) updateSettingsState() error {
- if !m.state.Settings.Available || m.settingsObj == nil {
- return fmt.Errorf("settings portal not available")
- }
-
- var variant dbus.Variant
- err := m.settingsObj.Call(dbusPortalSettingsInterface+".ReadOne", 0, "org.freedesktop.appearance", "color-scheme").Store(&variant)
- if err != nil {
- return err
- }
-
- if colorScheme, ok := variant.Value().(uint32); ok {
- m.stateMutex.Lock()
- m.state.Settings.ColorScheme = colorScheme
- m.stateMutex.Unlock()
- }
-
- return nil
-}
-
-func (m *Manager) getAccountProperties(ctx context.Context) (map[string]dbus.Variant, error) {
- var props map[string]dbus.Variant
- err := m.accountsObj.CallWithContext(ctx, dbusPropsInterface+".GetAll", 0, dbusAccountsUserInterface).Store(&props)
- if err != nil {
- return nil, err
- }
- return props, nil
-}
-
-func (m *Manager) GetState() FreedeskState {
- m.stateMutex.RLock()
- defer m.stateMutex.RUnlock()
- return *m.state
-}
-
-func (m *Manager) Subscribe(id string) chan FreedeskState {
- ch := make(chan FreedeskState, 64)
- m.subMutex.Lock()
- m.subscribers[id] = ch
- m.subMutex.Unlock()
- return ch
-}
-
-func (m *Manager) Unsubscribe(id string) {
- m.subMutex.Lock()
- if ch, ok := m.subscribers[id]; ok {
- close(ch)
- delete(m.subscribers, id)
- }
- m.subMutex.Unlock()
-}
-
-func (m *Manager) NotifySubscribers() {
- m.subMutex.RLock()
- defer m.subMutex.RUnlock()
-
- state := m.GetState()
- for _, ch := range m.subscribers {
- select {
- case ch <- state:
- default:
- }
- }
-}
-
-func (m *Manager) Close() {
- m.subMutex.Lock()
- for id, ch := range m.subscribers {
- close(ch)
- delete(m.subscribers, id)
- }
- m.subMutex.Unlock()
-
- if m.systemConn != nil {
- m.systemConn.Close()
- }
- if m.sessionConn != nil {
- m.sessionConn.Close()
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/freedesktop/manager_test.go b/nix/inputs/dms-cli/internal/server/freedesktop/manager_test.go
deleted file mode 100644
index 85b9b07..0000000
--- a/nix/inputs/dms-cli/internal/server/freedesktop/manager_test.go
+++ /dev/null
@@ -1,154 +0,0 @@
-package freedesktop
-
-import (
- "sync"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestManager_GetState(t *testing.T) {
- state := &FreedeskState{
- Accounts: AccountsState{
- Available: true,
- UserName: "testuser",
- RealName: "Test User",
- UID: 1000,
- },
- Settings: SettingsState{
- Available: true,
- ColorScheme: 1,
- },
- }
-
- manager := &Manager{
- state: state,
- stateMutex: sync.RWMutex{},
- }
-
- result := manager.GetState()
- assert.True(t, result.Accounts.Available)
- assert.Equal(t, "testuser", result.Accounts.UserName)
- assert.Equal(t, "Test User", result.Accounts.RealName)
- assert.Equal(t, uint64(1000), result.Accounts.UID)
- assert.True(t, result.Settings.Available)
- assert.Equal(t, uint32(1), result.Settings.ColorScheme)
-}
-
-func TestManager_GetState_ThreadSafe(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: true,
- UserName: "testuser",
- },
- Settings: SettingsState{
- Available: true,
- ColorScheme: 1,
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- // Test concurrent reads
- done := make(chan bool)
- for i := 0; i < 10; i++ {
- go func() {
- state := manager.GetState()
- assert.True(t, state.Accounts.Available)
- assert.Equal(t, "testuser", state.Accounts.UserName)
- done <- true
- }()
- }
-
- // Wait for all goroutines to complete
- for i := 0; i < 10; i++ {
- <-done
- }
-}
-
-func TestManager_Close(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{},
- stateMutex: sync.RWMutex{},
- systemConn: nil, // Would be set in real scenario
- sessionConn: nil,
- }
-
- // Should not panic even with nil connections
- assert.NotPanics(t, func() {
- manager.Close()
- })
-}
-
-func TestNewManager(t *testing.T) {
- // This test will fail in environments without freedesktop D-Bus services
- // It's primarily for local testing with proper desktop environment
- t.Run("attempts to create manager", func(t *testing.T) {
- manager, err := NewManager()
- if err != nil {
- // Expected in test environments without freedesktop services
- assert.Nil(t, manager)
- } else {
- assert.NotNil(t, manager)
- assert.NotNil(t, manager.state)
- assert.NotNil(t, manager.systemConn)
-
- // Clean up
- manager.Close()
- }
- })
-}
-
-func TestManager_GetState_EmptyState(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{},
- stateMutex: sync.RWMutex{},
- }
-
- result := manager.GetState()
- assert.False(t, result.Accounts.Available)
- assert.Empty(t, result.Accounts.UserName)
- assert.False(t, result.Settings.Available)
- assert.Equal(t, uint32(0), result.Settings.ColorScheme)
-}
-
-func TestManager_AccountsState_Modification(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Accounts: AccountsState{
- Available: true,
- UserName: "testuser",
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- // Get state and modify it
- state := manager.GetState()
- state.Accounts.UserName = "modifieduser"
-
- // Original state should remain unchanged (copy semantics)
- original := manager.GetState()
- assert.Equal(t, "testuser", original.Accounts.UserName)
-}
-
-func TestManager_SettingsState_Modification(t *testing.T) {
- manager := &Manager{
- state: &FreedeskState{
- Settings: SettingsState{
- Available: true,
- ColorScheme: 0,
- },
- },
- stateMutex: sync.RWMutex{},
- }
-
- // Get state and modify it
- state := manager.GetState()
- state.Settings.ColorScheme = 1
-
- // Original state should remain unchanged (copy semantics)
- original := manager.GetState()
- assert.Equal(t, uint32(0), original.Settings.ColorScheme)
-}
diff --git a/nix/inputs/dms-cli/internal/server/freedesktop/types.go b/nix/inputs/dms-cli/internal/server/freedesktop/types.go
deleted file mode 100644
index e46a0e8..0000000
--- a/nix/inputs/dms-cli/internal/server/freedesktop/types.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package freedesktop
-
-import (
- "sync"
-
- "github.com/godbus/dbus/v5"
-)
-
-type AccountsState struct {
- Available bool `json:"available"`
- UserPath string `json:"userPath"`
- IconFile string `json:"iconFile"`
- RealName string `json:"realName"`
- UserName string `json:"userName"`
- AccountType int32 `json:"accountType"`
- HomeDirectory string `json:"homeDirectory"`
- Shell string `json:"shell"`
- Email string `json:"email"`
- Language string `json:"language"`
- Location string `json:"location"`
- Locked bool `json:"locked"`
- PasswordMode int32 `json:"passwordMode"`
- UID uint64 `json:"uid"`
-}
-
-type SettingsState struct {
- Available bool `json:"available"`
- ColorScheme uint32 `json:"colorScheme"`
-}
-
-type FreedeskState struct {
- Accounts AccountsState `json:"accounts"`
- Settings SettingsState `json:"settings"`
-}
-
-type Manager struct {
- state *FreedeskState
- stateMutex sync.RWMutex
- systemConn *dbus.Conn
- sessionConn *dbus.Conn
- accountsObj dbus.BusObject
- settingsObj dbus.BusObject
- currentUID uint64
- subscribers map[string]chan FreedeskState
- subMutex sync.RWMutex
-}
diff --git a/nix/inputs/dms-cli/internal/server/freedesktop/types_test.go b/nix/inputs/dms-cli/internal/server/freedesktop/types_test.go
deleted file mode 100644
index deb0327..0000000
--- a/nix/inputs/dms-cli/internal/server/freedesktop/types_test.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package freedesktop
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestAccountsState_Struct(t *testing.T) {
- state := AccountsState{
- Available: true,
- UserPath: "/org/freedesktop/Accounts/User1000",
- RealName: "Test User",
- UserName: "testuser",
- Locked: false,
- UID: 1000,
- }
-
- assert.True(t, state.Available)
- assert.Equal(t, "/org/freedesktop/Accounts/User1000", state.UserPath)
- assert.Equal(t, "Test User", state.RealName)
- assert.Equal(t, "testuser", state.UserName)
- assert.Equal(t, uint64(1000), state.UID)
- assert.False(t, state.Locked)
-}
-
-func TestSettingsState_Struct(t *testing.T) {
- state := SettingsState{
- Available: true,
- ColorScheme: 1, // Dark mode
- }
-
- assert.True(t, state.Available)
- assert.Equal(t, uint32(1), state.ColorScheme)
-}
-
-func TestFreedeskState_Struct(t *testing.T) {
- state := FreedeskState{
- Accounts: AccountsState{
- Available: true,
- UserName: "testuser",
- UID: 1000,
- },
- Settings: SettingsState{
- Available: true,
- ColorScheme: 0, // Light mode
- },
- }
-
- assert.True(t, state.Accounts.Available)
- assert.Equal(t, "testuser", state.Accounts.UserName)
- assert.True(t, state.Settings.Available)
- assert.Equal(t, uint32(0), state.Settings.ColorScheme)
-}
-
-func TestAccountsState_DefaultValues(t *testing.T) {
- state := AccountsState{}
-
- assert.False(t, state.Available)
- assert.Empty(t, state.UserPath)
- assert.Empty(t, state.UserName)
- assert.Equal(t, uint64(0), state.UID)
-}
-
-func TestSettingsState_DefaultValues(t *testing.T) {
- state := SettingsState{}
-
- assert.False(t, state.Available)
- assert.Equal(t, uint32(0), state.ColorScheme)
-}
diff --git a/nix/inputs/dms-cli/internal/server/loginctl/actions.go b/nix/inputs/dms-cli/internal/server/loginctl/actions.go
deleted file mode 100644
index 858248e..0000000
--- a/nix/inputs/dms-cli/internal/server/loginctl/actions.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package loginctl
-
-import (
- "fmt"
-)
-
-func (m *Manager) Lock() error {
- if m.sessionObj == nil {
- return fmt.Errorf("session object not available")
- }
- err := m.sessionObj.Call(dbusSessionInterface+".Lock", 0).Err
- if err != nil {
- if refreshErr := m.refreshSessionBinding(); refreshErr == nil {
- err = m.sessionObj.Call(dbusSessionInterface+".Lock", 0).Err
- }
- if err != nil {
- return fmt.Errorf("failed to lock session: %w", err)
- }
- }
- return nil
-}
-
-func (m *Manager) Unlock() error {
- err := m.sessionObj.Call(dbusSessionInterface+".Unlock", 0).Err
- if err != nil {
- if refreshErr := m.refreshSessionBinding(); refreshErr == nil {
- err = m.sessionObj.Call(dbusSessionInterface+".Unlock", 0).Err
- }
- if err != nil {
- return fmt.Errorf("failed to unlock session: %w", err)
- }
- }
- return nil
-}
-
-func (m *Manager) Activate() error {
- err := m.sessionObj.Call(dbusSessionInterface+".Activate", 0).Err
- if err != nil {
- if refreshErr := m.refreshSessionBinding(); refreshErr == nil {
- err = m.sessionObj.Call(dbusSessionInterface+".Activate", 0).Err
- }
- if err != nil {
- return fmt.Errorf("failed to activate session: %w", err)
- }
- }
- return nil
-}
-
-func (m *Manager) SetIdleHint(idle bool) error {
- err := m.sessionObj.Call(dbusSessionInterface+".SetIdleHint", 0, idle).Err
- if err != nil {
- if refreshErr := m.refreshSessionBinding(); refreshErr == nil {
- err = m.sessionObj.Call(dbusSessionInterface+".SetIdleHint", 0, idle).Err
- }
- if err != nil {
- return fmt.Errorf("failed to set idle hint: %w", err)
- }
- }
- return nil
-}
-
-func (m *Manager) Terminate() error {
- err := m.sessionObj.Call(dbusSessionInterface+".Terminate", 0).Err
- if err != nil {
- if refreshErr := m.refreshSessionBinding(); refreshErr == nil {
- err = m.sessionObj.Call(dbusSessionInterface+".Terminate", 0).Err
- }
- if err != nil {
- return fmt.Errorf("failed to terminate session: %w", err)
- }
- }
- return nil
-}
-
-func (m *Manager) SetLockBeforeSuspend(enabled bool) {
- m.lockBeforeSuspend.Store(enabled)
-}
-
-func (m *Manager) SetSleepInhibitorEnabled(enabled bool) {
- m.sleepInhibitorEnabled.Store(enabled)
- if enabled {
- // Re-acquire inhibitor if enabled
- m.acquireSleepInhibitor()
- } else {
- // Release inhibitor if disabled
- m.releaseSleepInhibitor()
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/loginctl/constants.go b/nix/inputs/dms-cli/internal/server/loginctl/constants.go
deleted file mode 100644
index f93f8d6..0000000
--- a/nix/inputs/dms-cli/internal/server/loginctl/constants.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package loginctl
-
-const (
- dbusDest = "org.freedesktop.login1"
- dbusPath = "/org/freedesktop/login1"
- dbusManagerInterface = "org.freedesktop.login1.Manager"
- dbusSessionInterface = "org.freedesktop.login1.Session"
- dbusPropsInterface = "org.freedesktop.DBus.Properties"
-)
diff --git a/nix/inputs/dms-cli/internal/server/loginctl/handlers.go b/nix/inputs/dms-cli/internal/server/loginctl/handlers.go
deleted file mode 100644
index 1d495c4..0000000
--- a/nix/inputs/dms-cli/internal/server/loginctl/handlers.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package loginctl
-
-import (
- "encoding/json"
- "fmt"
- "net"
-
- "github.com/AvengeMedia/danklinux/internal/server/models"
-)
-
-type Request struct {
- ID int `json:"id,omitempty"`
- Method string `json:"method"`
- Params map[string]interface{} `json:"params,omitempty"`
-}
-
-type SuccessResult struct {
- Success bool `json:"success"`
- Message string `json:"message"`
-}
-
-func HandleRequest(conn net.Conn, req Request, manager *Manager) {
- switch req.Method {
- case "loginctl.getState":
- handleGetState(conn, req, manager)
- case "loginctl.lock":
- handleLock(conn, req, manager)
- case "loginctl.unlock":
- handleUnlock(conn, req, manager)
- case "loginctl.activate":
- handleActivate(conn, req, manager)
- case "loginctl.setIdleHint":
- handleSetIdleHint(conn, req, manager)
- case "loginctl.setLockBeforeSuspend":
- handleSetLockBeforeSuspend(conn, req, manager)
- case "loginctl.setSleepInhibitorEnabled":
- handleSetSleepInhibitorEnabled(conn, req, manager)
- case "loginctl.lockerReady":
- handleLockerReady(conn, req, manager)
- case "loginctl.terminate":
- handleTerminate(conn, req, manager)
- case "loginctl.subscribe":
- handleSubscribe(conn, req, manager)
- default:
- models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method))
- }
-}
-
-func handleGetState(conn net.Conn, req Request, manager *Manager) {
- state := manager.GetState()
- models.Respond(conn, req.ID, state)
-}
-
-func handleLock(conn net.Conn, req Request, manager *Manager) {
- if err := manager.Lock(); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "locked"})
-}
-
-func handleUnlock(conn net.Conn, req Request, manager *Manager) {
- if err := manager.Unlock(); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "unlocked"})
-}
-
-func handleActivate(conn net.Conn, req Request, manager *Manager) {
- if err := manager.Activate(); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "activated"})
-}
-
-func handleSetIdleHint(conn net.Conn, req Request, manager *Manager) {
- idle, ok := req.Params["idle"].(bool)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'idle' parameter")
- return
- }
-
- if err := manager.SetIdleHint(idle); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "idle hint set"})
-}
-
-func handleSetLockBeforeSuspend(conn net.Conn, req Request, manager *Manager) {
- enabled, ok := req.Params["enabled"].(bool)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'enabled' parameter")
- return
- }
-
- manager.SetLockBeforeSuspend(enabled)
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "lock before suspend set"})
-}
-
-func handleSetSleepInhibitorEnabled(conn net.Conn, req Request, manager *Manager) {
- enabled, ok := req.Params["enabled"].(bool)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'enabled' parameter")
- return
- }
-
- manager.SetSleepInhibitorEnabled(enabled)
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "sleep inhibitor setting updated"})
-}
-
-func handleLockerReady(conn net.Conn, req Request, manager *Manager) {
- manager.lockTimerMu.Lock()
- if manager.lockTimer != nil {
- manager.lockTimer.Stop()
- manager.lockTimer = nil
- }
- manager.lockTimerMu.Unlock()
-
- id := manager.sleepCycleID.Load()
- manager.releaseForCycle(id)
-
- if manager.inSleepCycle.Load() {
- manager.signalLockerReady()
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "ok"})
-}
-
-func handleTerminate(conn net.Conn, req Request, manager *Manager) {
- if err := manager.Terminate(); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "terminated"})
-}
-
-func handleSubscribe(conn net.Conn, req Request, manager *Manager) {
- clientID := fmt.Sprintf("client-%p", conn)
- stateChan := manager.Subscribe(clientID)
- defer manager.Unsubscribe(clientID)
-
- initialState := manager.GetState()
- event := SessionEvent{
- Type: EventStateChanged,
- Data: initialState,
- }
- if err := json.NewEncoder(conn).Encode(models.Response[SessionEvent]{
- ID: req.ID,
- Result: &event,
- }); err != nil {
- return
- }
-
- for state := range stateChan {
- event := SessionEvent{
- Type: EventStateChanged,
- Data: state,
- }
- if err := json.NewEncoder(conn).Encode(models.Response[SessionEvent]{
- Result: &event,
- }); err != nil {
- return
- }
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/loginctl/handlers_test.go b/nix/inputs/dms-cli/internal/server/loginctl/handlers_test.go
deleted file mode 100644
index 97e6108..0000000
--- a/nix/inputs/dms-cli/internal/server/loginctl/handlers_test.go
+++ /dev/null
@@ -1,508 +0,0 @@
-package loginctl
-
-import (
- "bytes"
- "encoding/json"
- "net"
- "sync"
- "testing"
- "time"
-
- mockdbus "github.com/AvengeMedia/danklinux/internal/mocks/github.com/godbus/dbus/v5"
- "github.com/AvengeMedia/danklinux/internal/server/models"
- "github.com/godbus/dbus/v5"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
- "github.com/stretchr/testify/require"
-)
-
-type mockNetConn struct {
- net.Conn
- readBuf *bytes.Buffer
- writeBuf *bytes.Buffer
- closed bool
-}
-
-func newMockNetConn() *mockNetConn {
- return &mockNetConn{
- readBuf: &bytes.Buffer{},
- writeBuf: &bytes.Buffer{},
- }
-}
-
-func (m *mockNetConn) Read(b []byte) (n int, err error) {
- return m.readBuf.Read(b)
-}
-
-func (m *mockNetConn) Write(b []byte) (n int, err error) {
- return m.writeBuf.Write(b)
-}
-
-func (m *mockNetConn) Close() error {
- m.closed = true
- return nil
-}
-
-func TestRespondError_Loginctl(t *testing.T) {
- conn := newMockNetConn()
- models.RespondError(conn, 123, "test error")
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Equal(t, "test error", resp.Error)
- assert.Nil(t, resp.Result)
-}
-
-func TestRespond_Loginctl(t *testing.T) {
- conn := newMockNetConn()
- result := SuccessResult{Success: true, Message: "test"}
- models.Respond(conn, 123, result)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
- assert.Equal(t, "test", resp.Result.Message)
-}
-
-func TestHandleGetState(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- SessionID: "1",
- Locked: false,
- Active: true,
- SessionType: "wayland",
- SessionClass: "user",
- UserName: "testuser",
- },
- stateMutex: sync.RWMutex{},
- }
-
- conn := newMockNetConn()
- req := Request{ID: 123, Method: "loginctl.getState"}
-
- handleGetState(conn, req, manager)
-
- var resp models.Response[SessionState]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.Equal(t, "1", resp.Result.SessionID)
- assert.False(t, resp.Result.Locked)
- assert.True(t, resp.Result.Active)
-}
-
-func TestHandleLock(t *testing.T) {
- t.Run("successful lock", func(t *testing.T) {
- mockSessionObj := mockdbus.NewMockBusObject(t)
- mockCall := &dbus.Call{Err: nil}
- mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Lock", dbus.Flags(0)).Return(mockCall)
-
- manager := &Manager{
- state: &SessionState{},
- stateMutex: sync.RWMutex{},
- sessionObj: mockSessionObj,
- }
-
- conn := newMockNetConn()
- req := Request{ID: 123, Method: "loginctl.lock"}
- handleLock(conn, req, manager)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
- assert.Equal(t, "locked", resp.Result.Message)
- })
-
- t.Run("lock fails", func(t *testing.T) {
- mockSessionObj := mockdbus.NewMockBusObject(t)
- mockCall := &dbus.Call{Err: assert.AnError}
- mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Lock", dbus.Flags(0)).Return(mockCall)
-
- manager := &Manager{
- state: &SessionState{},
- stateMutex: sync.RWMutex{},
- sessionObj: mockSessionObj,
- }
-
- conn := newMockNetConn()
- req := Request{ID: 123, Method: "loginctl.lock"}
- handleLock(conn, req, manager)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "failed to lock session")
- })
-}
-
-func TestHandleUnlock(t *testing.T) {
- t.Run("successful unlock", func(t *testing.T) {
- mockSessionObj := mockdbus.NewMockBusObject(t)
- mockCall := &dbus.Call{Err: nil}
- mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Unlock", dbus.Flags(0)).Return(mockCall)
-
- manager := &Manager{
- state: &SessionState{},
- stateMutex: sync.RWMutex{},
- sessionObj: mockSessionObj,
- }
-
- conn := newMockNetConn()
- req := Request{ID: 123, Method: "loginctl.unlock"}
- handleUnlock(conn, req, manager)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
- assert.Equal(t, "unlocked", resp.Result.Message)
- })
-
- t.Run("unlock fails", func(t *testing.T) {
- mockSessionObj := mockdbus.NewMockBusObject(t)
- mockCall := &dbus.Call{Err: assert.AnError}
- mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Unlock", dbus.Flags(0)).Return(mockCall)
-
- manager := &Manager{
- state: &SessionState{},
- stateMutex: sync.RWMutex{},
- sessionObj: mockSessionObj,
- }
-
- conn := newMockNetConn()
- req := Request{ID: 123, Method: "loginctl.unlock"}
- handleUnlock(conn, req, manager)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "failed to unlock session")
- })
-}
-
-func TestHandleActivate(t *testing.T) {
- t.Run("successful activate", func(t *testing.T) {
- mockSessionObj := mockdbus.NewMockBusObject(t)
- mockCall := &dbus.Call{Err: nil}
- mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Activate", dbus.Flags(0)).Return(mockCall)
-
- manager := &Manager{
- state: &SessionState{},
- stateMutex: sync.RWMutex{},
- sessionObj: mockSessionObj,
- }
-
- conn := newMockNetConn()
- req := Request{ID: 123, Method: "loginctl.activate"}
- handleActivate(conn, req, manager)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
- assert.Equal(t, "activated", resp.Result.Message)
- })
-
- t.Run("activate fails", func(t *testing.T) {
- mockSessionObj := mockdbus.NewMockBusObject(t)
- mockCall := &dbus.Call{Err: assert.AnError}
- mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Activate", dbus.Flags(0)).Return(mockCall)
-
- manager := &Manager{
- state: &SessionState{},
- stateMutex: sync.RWMutex{},
- sessionObj: mockSessionObj,
- }
-
- conn := newMockNetConn()
- req := Request{ID: 123, Method: "loginctl.activate"}
- handleActivate(conn, req, manager)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "failed to activate session")
- })
-}
-
-func TestHandleSetIdleHint(t *testing.T) {
- t.Run("missing idle parameter", func(t *testing.T) {
- manager := &Manager{
- state: &SessionState{},
- stateMutex: sync.RWMutex{},
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "loginctl.setIdleHint",
- Params: map[string]interface{}{},
- }
-
- handleSetIdleHint(conn, req, manager)
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "missing or invalid 'idle' parameter")
- })
-
- t.Run("successful set idle hint true", func(t *testing.T) {
- mockSessionObj := mockdbus.NewMockBusObject(t)
- mockCall := &dbus.Call{Err: nil}
- mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.SetIdleHint", dbus.Flags(0), true).Return(mockCall)
-
- manager := &Manager{
- state: &SessionState{},
- stateMutex: sync.RWMutex{},
- sessionObj: mockSessionObj,
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "loginctl.setIdleHint",
- Params: map[string]interface{}{
- "idle": true,
- },
- }
-
- handleSetIdleHint(conn, req, manager)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
- assert.Equal(t, "idle hint set", resp.Result.Message)
- })
-
- t.Run("set idle hint fails", func(t *testing.T) {
- mockSessionObj := mockdbus.NewMockBusObject(t)
- mockCall := &dbus.Call{Err: assert.AnError}
- mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.SetIdleHint", dbus.Flags(0), false).Return(mockCall)
-
- manager := &Manager{
- state: &SessionState{},
- stateMutex: sync.RWMutex{},
- sessionObj: mockSessionObj,
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "loginctl.setIdleHint",
- Params: map[string]interface{}{
- "idle": false,
- },
- }
-
- handleSetIdleHint(conn, req, manager)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "failed to set idle hint")
- })
-}
-
-func TestHandleTerminate(t *testing.T) {
- t.Run("successful terminate", func(t *testing.T) {
- mockSessionObj := mockdbus.NewMockBusObject(t)
- mockCall := &dbus.Call{Err: nil}
- mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Terminate", dbus.Flags(0)).Return(mockCall)
-
- manager := &Manager{
- state: &SessionState{},
- stateMutex: sync.RWMutex{},
- sessionObj: mockSessionObj,
- }
-
- conn := newMockNetConn()
- req := Request{ID: 123, Method: "loginctl.terminate"}
- handleTerminate(conn, req, manager)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
- assert.Equal(t, "terminated", resp.Result.Message)
- })
-
- t.Run("terminate fails", func(t *testing.T) {
- mockSessionObj := mockdbus.NewMockBusObject(t)
- mockCall := &dbus.Call{Err: assert.AnError}
- mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Terminate", dbus.Flags(0)).Return(mockCall)
-
- manager := &Manager{
- state: &SessionState{},
- stateMutex: sync.RWMutex{},
- sessionObj: mockSessionObj,
- }
-
- conn := newMockNetConn()
- req := Request{ID: 123, Method: "loginctl.terminate"}
- handleTerminate(conn, req, manager)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "failed to terminate session")
- })
-}
-
-func TestHandleRequest(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- SessionID: "1",
- Locked: false,
- },
- stateMutex: sync.RWMutex{},
- }
-
- t.Run("unknown method", func(t *testing.T) {
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "loginctl.unknown",
- }
-
- HandleRequest(conn, req, manager)
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "unknown method")
- })
-
- t.Run("valid method - getState", func(t *testing.T) {
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "loginctl.getState",
- }
-
- HandleRequest(conn, req, manager)
-
- var resp models.Response[SessionState]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- })
-
- t.Run("lock method", func(t *testing.T) {
- mockSessionObj := mockdbus.NewMockBusObject(t)
- mockCall := &dbus.Call{Err: nil}
- mockSessionObj.EXPECT().Call("org.freedesktop.login1.Session.Lock", mock.Anything).Return(mockCall)
-
- manager.sessionObj = mockSessionObj
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "loginctl.lock",
- }
-
- HandleRequest(conn, req, manager)
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- })
-}
-
-func TestHandleSubscribe(t *testing.T) {
- // Subscription requires long-running connection - just test initial response
- manager := &Manager{
- state: &SessionState{
- SessionID: "1",
- Locked: false,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- }
-
- conn := newMockNetConn()
- req := Request{ID: 123, Method: "loginctl.subscribe"}
-
- done := make(chan bool)
- // Run handleSubscribe in goroutine since it blocks
- go func() {
- handleSubscribe(conn, req, manager)
- done <- true
- }()
-
- // Give it a moment to send initial state
- time.Sleep(50 * time.Millisecond)
-
- // Close connection to stop the subscription
- conn.Close()
-
- // Try to decode the initial response
- if conn.writeBuf.Len() > 0 {
- var resp models.Response[SessionEvent]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- if err == nil {
- assert.Equal(t, 123, resp.ID)
- require.NotNil(t, resp.Result)
- assert.Equal(t, EventStateChanged, resp.Result.Type)
- assert.Equal(t, "1", resp.Result.Data.SessionID)
- }
- }
-
- // Wait for goroutine to finish or timeout
- select {
- case <-done:
- case <-time.After(100 * time.Millisecond):
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/loginctl/manager.go b/nix/inputs/dms-cli/internal/server/loginctl/manager.go
deleted file mode 100644
index 58b091c..0000000
--- a/nix/inputs/dms-cli/internal/server/loginctl/manager.go
+++ /dev/null
@@ -1,597 +0,0 @@
-package loginctl
-
-import (
- "context"
- "fmt"
- "os"
- "sync"
- "time"
-
- "github.com/godbus/dbus/v5"
-)
-
-func NewManager() (*Manager, error) {
- conn, err := dbus.ConnectSystemBus()
- if err != nil {
- return nil, fmt.Errorf("failed to connect to system bus: %w", err)
- }
-
- sessionID := os.Getenv("XDG_SESSION_ID")
- if sessionID == "" {
- sessionID = "self"
- }
-
- m := &Manager{
- state: &SessionState{
- SessionID: sessionID,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- stopChan: make(chan struct{}),
- conn: conn,
- dirty: make(chan struct{}, 1),
- signals: make(chan *dbus.Signal, 256),
- }
- m.sleepInhibitorEnabled.Store(true)
-
- if err := m.initialize(); err != nil {
- conn.Close()
- return nil, err
- }
-
- if err := m.acquireSleepInhibitor(); err != nil {
- fmt.Fprintf(os.Stderr, "sleep inhibitor unavailable: %v\n", err)
- }
-
- m.notifierWg.Add(1)
- go m.notifier()
-
- if err := m.startSignalPump(); err != nil {
- m.Close()
- return nil, err
- }
-
- return m, nil
-}
-
-func (m *Manager) initialize() error {
- m.managerObj = m.conn.Object(dbusDest, dbus.ObjectPath(dbusPath))
-
- m.initializeFallbackDelay()
-
- sessionPath, err := m.getSession(m.state.SessionID)
- if err != nil {
- return fmt.Errorf("failed to get session path: %w", err)
- }
-
- m.stateMutex.Lock()
- m.state.SessionPath = string(sessionPath)
- m.sessionPath = sessionPath
- m.stateMutex.Unlock()
-
- m.sessionObj = m.conn.Object(dbusDest, sessionPath)
-
- if err := m.updateSessionState(); err != nil {
- return err
- }
-
- return nil
-}
-
-func (m *Manager) getSession(id string) (dbus.ObjectPath, error) {
- var out dbus.ObjectPath
- err := m.managerObj.Call(dbusManagerInterface+".GetSession", 0, id).Store(&out)
- if err != nil {
- return "", err
- }
- return out, nil
-}
-
-func (m *Manager) refreshSessionBinding() error {
- if m.managerObj == nil || m.conn == nil {
- return fmt.Errorf("manager not fully initialized")
- }
-
- sessionPath, err := m.getSession(m.state.SessionID)
- if err != nil {
- return fmt.Errorf("failed to get session path: %w", err)
- }
-
- m.stateMutex.RLock()
- currentPath := m.sessionPath
- m.stateMutex.RUnlock()
-
- if sessionPath == currentPath {
- return nil
- }
-
- m.stopSignalPump()
-
- m.stateMutex.Lock()
- m.state.SessionPath = string(sessionPath)
- m.sessionPath = sessionPath
- m.stateMutex.Unlock()
-
- m.sessionObj = m.conn.Object(dbusDest, sessionPath)
-
- if err := m.updateSessionState(); err != nil {
- return err
- }
-
- m.signals = make(chan *dbus.Signal, 256)
- return m.startSignalPump()
-}
-
-func (m *Manager) updateSessionState() error {
- ctx := context.Background()
- props, err := m.getSessionProperties(ctx)
- if err != nil {
- return err
- }
-
- m.stateMutex.Lock()
- defer m.stateMutex.Unlock()
-
- if v, ok := props["Active"]; ok {
- if val, ok := v.Value().(bool); ok {
- m.state.Active = val
- }
- }
- if v, ok := props["IdleHint"]; ok {
- if val, ok := v.Value().(bool); ok {
- m.state.IdleHint = val
- }
- }
- if v, ok := props["IdleSinceHint"]; ok {
- if val, ok := v.Value().(uint64); ok {
- m.state.IdleSinceHint = val
- }
- }
- if v, ok := props["LockedHint"]; ok {
- if val, ok := v.Value().(bool); ok {
- m.state.LockedHint = val
- m.state.Locked = val
- }
- }
- if v, ok := props["Type"]; ok {
- if val, ok := v.Value().(string); ok {
- m.state.SessionType = val
- }
- }
- if v, ok := props["Class"]; ok {
- if val, ok := v.Value().(string); ok {
- m.state.SessionClass = val
- }
- }
- if v, ok := props["User"]; ok {
- if userArr, ok := v.Value().([]interface{}); ok && len(userArr) >= 1 {
- if uid, ok := userArr[0].(uint32); ok {
- m.state.User = uid
- }
- }
- }
- if v, ok := props["Name"]; ok {
- if val, ok := v.Value().(string); ok {
- m.state.UserName = val
- }
- }
- if v, ok := props["RemoteHost"]; ok {
- if val, ok := v.Value().(string); ok {
- m.state.RemoteHost = val
- }
- }
- if v, ok := props["Service"]; ok {
- if val, ok := v.Value().(string); ok {
- m.state.Service = val
- }
- }
- if v, ok := props["TTY"]; ok {
- if val, ok := v.Value().(string); ok {
- m.state.TTY = val
- }
- }
- if v, ok := props["Display"]; ok {
- if val, ok := v.Value().(string); ok {
- m.state.Display = val
- }
- }
- if v, ok := props["Remote"]; ok {
- if val, ok := v.Value().(bool); ok {
- m.state.Remote = val
- }
- }
- if v, ok := props["Seat"]; ok {
- if seatArr, ok := v.Value().([]interface{}); ok && len(seatArr) >= 1 {
- if seatID, ok := seatArr[0].(string); ok {
- m.state.Seat = seatID
- }
- }
- }
- if v, ok := props["VTNr"]; ok {
- if val, ok := v.Value().(uint32); ok {
- m.state.VTNr = val
- }
- }
-
- return nil
-}
-
-func (m *Manager) getSessionProperties(ctx context.Context) (map[string]dbus.Variant, error) {
- var props map[string]dbus.Variant
- err := m.sessionObj.CallWithContext(ctx, dbusPropsInterface+".GetAll", 0, dbusSessionInterface).Store(&props)
- if err != nil {
- return nil, err
- }
- return props, nil
-}
-
-func (m *Manager) acquireSleepInhibitor() error {
- if !m.sleepInhibitorEnabled.Load() {
- return nil
- }
-
- m.inhibitMu.Lock()
- defer m.inhibitMu.Unlock()
-
- if m.inhibitFile != nil {
- return nil
- }
-
- if m.managerObj == nil {
- return fmt.Errorf("manager object not available")
- }
-
- file, err := m.inhibit("sleep", "DankMaterialShell", "Lock before suspend", "delay")
- if err != nil {
- return err
- }
-
- m.inhibitFile = file
- return nil
-}
-
-func (m *Manager) inhibit(what, who, why, mode string) (*os.File, error) {
- var fd dbus.UnixFD
- err := m.managerObj.Call(dbusManagerInterface+".Inhibit", 0, what, who, why, mode).Store(&fd)
- if err != nil {
- return nil, err
- }
- return os.NewFile(uintptr(fd), "inhibit"), nil
-}
-
-func (m *Manager) releaseSleepInhibitor() {
- m.inhibitMu.Lock()
- f := m.inhibitFile
- m.inhibitFile = nil
- m.inhibitMu.Unlock()
- if f != nil {
- f.Close()
- }
-}
-
-func (m *Manager) releaseForCycle(id uint64) {
- if !m.inSleepCycle.Load() || m.sleepCycleID.Load() != id {
- return
- }
- m.releaseSleepInhibitor()
-}
-
-func (m *Manager) initializeFallbackDelay() {
- var maxDelayUSec uint64
- err := m.managerObj.Call(
- dbusPropsInterface+".Get",
- 0,
- dbusManagerInterface,
- "InhibitDelayMaxUSec",
- ).Store(&maxDelayUSec)
-
- if err != nil {
- m.fallbackDelay = 2 * time.Second
- return
- }
-
- maxDelay := time.Duration(maxDelayUSec) * time.Microsecond
- computed := (maxDelay * 8) / 10
-
- if computed < 2*time.Second {
- m.fallbackDelay = 2 * time.Second
- } else if computed > 4*time.Second {
- m.fallbackDelay = 4 * time.Second
- } else {
- m.fallbackDelay = computed
- }
-}
-
-func (m *Manager) newLockerReadyCh() chan struct{} {
- m.lockerReadyChMu.Lock()
- defer m.lockerReadyChMu.Unlock()
- m.lockerReadyCh = make(chan struct{})
- return m.lockerReadyCh
-}
-
-func (m *Manager) signalLockerReady() {
- m.lockerReadyChMu.Lock()
- ch := m.lockerReadyCh
- if ch != nil {
- close(ch)
- m.lockerReadyCh = nil
- }
- m.lockerReadyChMu.Unlock()
-}
-
-func (m *Manager) snapshotState() SessionState {
- m.stateMutex.RLock()
- defer m.stateMutex.RUnlock()
- return *m.state
-}
-
-func stateChangedMeaningfully(old, new *SessionState) bool {
- if old.Locked != new.Locked {
- return true
- }
- if old.LockedHint != new.LockedHint {
- return true
- }
- if old.Active != new.Active {
- return true
- }
- if old.IdleHint != new.IdleHint {
- return true
- }
- if old.PreparingForSleep != new.PreparingForSleep {
- return true
- }
- return false
-}
-
-func (m *Manager) GetState() SessionState {
- return m.snapshotState()
-}
-
-func (m *Manager) Subscribe(id string) chan SessionState {
- ch := make(chan SessionState, 64)
- m.subMutex.Lock()
- m.subscribers[id] = ch
- m.subMutex.Unlock()
- return ch
-}
-
-func (m *Manager) Unsubscribe(id string) {
- m.subMutex.Lock()
- if ch, ok := m.subscribers[id]; ok {
- close(ch)
- delete(m.subscribers, id)
- }
- m.subMutex.Unlock()
-}
-
-func (m *Manager) notifier() {
- defer m.notifierWg.Done()
- const minGap = 100 * time.Millisecond
- timer := time.NewTimer(minGap)
- timer.Stop()
- var pending bool
- for {
- select {
- case <-m.stopChan:
- timer.Stop()
- return
- case <-m.dirty:
- if pending {
- continue
- }
- pending = true
- timer.Reset(minGap)
- case <-timer.C:
- if !pending {
- continue
- }
- m.subMutex.RLock()
- if len(m.subscribers) == 0 {
- m.subMutex.RUnlock()
- pending = false
- continue
- }
-
- currentState := m.snapshotState()
-
- if m.lastNotifiedState != nil && !stateChangedMeaningfully(m.lastNotifiedState, ¤tState) {
- m.subMutex.RUnlock()
- pending = false
- continue
- }
-
- for _, ch := range m.subscribers {
- select {
- case ch <- currentState:
- default:
- }
- }
- m.subMutex.RUnlock()
-
- stateCopy := currentState
- m.lastNotifiedState = &stateCopy
- pending = false
- }
- }
-}
-
-func (m *Manager) notifySubscribers() {
- select {
- case m.dirty <- struct{}{}:
- default:
- }
-}
-
-func (m *Manager) startSignalPump() error {
- m.conn.Signal(m.signals)
-
- if err := m.conn.AddMatchSignal(
- dbus.WithMatchObjectPath(m.sessionPath),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- ); err != nil {
- m.conn.RemoveSignal(m.signals)
- return err
- }
- if err := m.conn.AddMatchSignal(
- dbus.WithMatchObjectPath(m.sessionPath),
- dbus.WithMatchInterface(dbusSessionInterface),
- dbus.WithMatchMember("Lock"),
- ); err != nil {
- m.conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(m.sessionPath),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- )
- m.conn.RemoveSignal(m.signals)
- return err
- }
- if err := m.conn.AddMatchSignal(
- dbus.WithMatchObjectPath(m.sessionPath),
- dbus.WithMatchInterface(dbusSessionInterface),
- dbus.WithMatchMember("Unlock"),
- ); err != nil {
- m.conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(m.sessionPath),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- )
- m.conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(m.sessionPath),
- dbus.WithMatchInterface(dbusSessionInterface),
- dbus.WithMatchMember("Lock"),
- )
- m.conn.RemoveSignal(m.signals)
- return err
- }
- if err := m.conn.AddMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath(dbusPath)),
- dbus.WithMatchInterface(dbusManagerInterface),
- dbus.WithMatchMember("PrepareForSleep"),
- ); err != nil {
- m.conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(m.sessionPath),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- )
- m.conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(m.sessionPath),
- dbus.WithMatchInterface(dbusSessionInterface),
- dbus.WithMatchMember("Lock"),
- )
- m.conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(m.sessionPath),
- dbus.WithMatchInterface(dbusSessionInterface),
- dbus.WithMatchMember("Unlock"),
- )
- m.conn.RemoveSignal(m.signals)
- return err
- }
-
- if err := m.conn.AddMatchSignal(
- dbus.WithMatchObjectPath("/org/freedesktop/DBus"),
- dbus.WithMatchInterface("org.freedesktop.DBus"),
- dbus.WithMatchMember("NameOwnerChanged"),
- ); err != nil {
- m.conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(m.sessionPath),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- )
- m.conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(m.sessionPath),
- dbus.WithMatchInterface(dbusSessionInterface),
- dbus.WithMatchMember("Lock"),
- )
- m.conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(m.sessionPath),
- dbus.WithMatchInterface(dbusSessionInterface),
- dbus.WithMatchMember("Unlock"),
- )
- m.conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath(dbusPath)),
- dbus.WithMatchInterface(dbusManagerInterface),
- dbus.WithMatchMember("PrepareForSleep"),
- )
- m.conn.RemoveSignal(m.signals)
- return err
- }
-
- m.sigWG.Add(1)
- go func() {
- defer m.sigWG.Done()
- for {
- select {
- case <-m.stopChan:
- return
- case sig, ok := <-m.signals:
- if !ok {
- return
- }
- if sig == nil {
- continue
- }
- m.handleDBusSignal(sig)
- }
- }
- }()
- return nil
-}
-
-func (m *Manager) stopSignalPump() {
- if m.conn == nil {
- return
- }
- m.conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(m.sessionPath),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- )
- m.conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(m.sessionPath),
- dbus.WithMatchInterface(dbusSessionInterface),
- dbus.WithMatchMember("Lock"),
- )
- m.conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(m.sessionPath),
- dbus.WithMatchInterface(dbusSessionInterface),
- dbus.WithMatchMember("Unlock"),
- )
- m.conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath(dbusPath)),
- dbus.WithMatchInterface(dbusManagerInterface),
- dbus.WithMatchMember("PrepareForSleep"),
- )
- m.conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath("/org/freedesktop/DBus"),
- dbus.WithMatchInterface("org.freedesktop.DBus"),
- dbus.WithMatchMember("NameOwnerChanged"),
- )
-
- m.conn.RemoveSignal(m.signals)
- close(m.signals)
-
- m.sigWG.Wait()
-}
-
-func (m *Manager) Close() {
- close(m.stopChan)
- m.notifierWg.Wait()
-
- m.stopSignalPump()
-
- m.releaseSleepInhibitor()
-
- m.subMutex.Lock()
- for _, ch := range m.subscribers {
- close(ch)
- }
- m.subscribers = make(map[string]chan SessionState)
- m.subMutex.Unlock()
-
- if m.conn != nil {
- m.conn.Close()
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/loginctl/manager_test.go b/nix/inputs/dms-cli/internal/server/loginctl/manager_test.go
deleted file mode 100644
index 30e7246..0000000
--- a/nix/inputs/dms-cli/internal/server/loginctl/manager_test.go
+++ /dev/null
@@ -1,336 +0,0 @@
-package loginctl
-
-import (
- "sync"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestManager_GetState(t *testing.T) {
- state := &SessionState{
- SessionID: "1",
- Locked: false,
- Active: true,
- IdleHint: false,
- SessionType: "wayland",
- SessionClass: "user",
- UserName: "testuser",
- }
-
- manager := &Manager{
- state: state,
- stateMutex: sync.RWMutex{},
- }
-
- result := manager.GetState()
- assert.Equal(t, "1", result.SessionID)
- assert.False(t, result.Locked)
- assert.True(t, result.Active)
- assert.Equal(t, "wayland", result.SessionType)
- assert.Equal(t, "testuser", result.UserName)
-}
-
-func TestManager_Subscribe(t *testing.T) {
- manager := &Manager{
- state: &SessionState{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- }
-
- ch := manager.Subscribe("test-client")
- assert.NotNil(t, ch)
- assert.Equal(t, 64, cap(ch))
-
- manager.subMutex.RLock()
- _, exists := manager.subscribers["test-client"]
- manager.subMutex.RUnlock()
- assert.True(t, exists)
-}
-
-func TestManager_Unsubscribe(t *testing.T) {
- manager := &Manager{
- state: &SessionState{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- }
-
- // Subscribe first
- ch := manager.Subscribe("test-client")
-
- // Unsubscribe
- manager.Unsubscribe("test-client")
-
- // Check channel is closed
- _, ok := <-ch
- assert.False(t, ok)
-
- // Check client is removed
- manager.subMutex.RLock()
- _, exists := manager.subscribers["test-client"]
- manager.subMutex.RUnlock()
- assert.False(t, exists)
-}
-
-func TestManager_Unsubscribe_NonExistent(t *testing.T) {
- manager := &Manager{
- state: &SessionState{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- }
-
- // Unsubscribe a non-existent client should not panic
- assert.NotPanics(t, func() {
- manager.Unsubscribe("non-existent")
- })
-}
-
-func TestManager_NotifySubscribers(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- SessionID: "1",
- Locked: false,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- }
- manager.notifierWg.Add(1)
- go manager.notifier()
-
- // Subscribe a client
- ch := make(chan SessionState, 10)
- manager.subMutex.Lock()
- manager.subscribers["test-client"] = ch
- manager.subMutex.Unlock()
-
- // Notify subscribers
- manager.notifySubscribers()
-
- // Check that state was sent (wait for debounce timer + some slack)
- select {
- case state := <-ch:
- assert.Equal(t, "1", state.SessionID)
- assert.False(t, state.Locked)
- case <-time.After(200 * time.Millisecond):
- t.Fatal("did not receive state update")
- }
-
- close(manager.stopChan)
- manager.notifierWg.Wait()
-}
-
-func TestManager_NotifySubscribers_Debounce(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- SessionID: "1",
- Locked: false,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- }
- manager.notifierWg.Add(1)
- go manager.notifier()
-
- // Subscribe a client
- ch := make(chan SessionState, 10)
- manager.subMutex.Lock()
- manager.subscribers["test-client"] = ch
- manager.subMutex.Unlock()
-
- // Send multiple rapid notifications
- manager.notifySubscribers()
- manager.notifySubscribers()
- manager.notifySubscribers()
-
- // Should only receive one state update due to debouncing
- receivedCount := 0
- timeout := time.After(200 * time.Millisecond)
- for {
- select {
- case <-ch:
- receivedCount++
- case <-timeout:
- assert.Equal(t, 1, receivedCount, "should receive exactly one debounced update")
- close(manager.stopChan)
- manager.notifierWg.Wait()
- return
- }
- }
-}
-
-func TestManager_Close(t *testing.T) {
- manager := &Manager{
- state: &SessionState{},
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- stopChan: make(chan struct{}),
- }
-
- // Add subscribers
- ch1 := make(chan SessionState, 1)
- ch2 := make(chan SessionState, 1)
- manager.subMutex.Lock()
- manager.subscribers["client1"] = ch1
- manager.subscribers["client2"] = ch2
- manager.subMutex.Unlock()
-
- // Close manager
- manager.Close()
-
- // Check that stopChan is closed
- select {
- case <-manager.stopChan:
- // Expected
- case <-time.After(100 * time.Millisecond):
- t.Fatal("stopChan not closed")
- }
-
- // Check that subscriber channels are closed
- _, ok1 := <-ch1
- _, ok2 := <-ch2
- assert.False(t, ok1, "ch1 should be closed")
- assert.False(t, ok2, "ch2 should be closed")
-
- // Check that subscribers map is reset
- assert.Len(t, manager.subscribers, 0)
-}
-
-func TestManager_GetState_ThreadSafe(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- SessionID: "1",
- Locked: false,
- Active: true,
- },
- stateMutex: sync.RWMutex{},
- }
-
- // Test concurrent reads
- done := make(chan bool)
- for i := 0; i < 10; i++ {
- go func() {
- state := manager.GetState()
- assert.Equal(t, "1", state.SessionID)
- assert.True(t, state.Active)
- done <- true
- }()
- }
-
- // Wait for all goroutines to complete
- for i := 0; i < 10; i++ {
- select {
- case <-done:
- case <-time.After(1 * time.Second):
- t.Fatal("timeout waiting for goroutines")
- }
- }
-}
-
-func TestStateChangedMeaningfully(t *testing.T) {
- tests := []struct {
- name string
- old *SessionState
- new *SessionState
- expected bool
- }{
- {
- name: "no change",
- old: &SessionState{Locked: false, Active: true, IdleHint: false},
- new: &SessionState{Locked: false, Active: true, IdleHint: false},
- expected: false,
- },
- {
- name: "locked changed",
- old: &SessionState{Locked: false, Active: true, IdleHint: false},
- new: &SessionState{Locked: true, Active: true, IdleHint: false},
- expected: true,
- },
- {
- name: "active changed",
- old: &SessionState{Locked: false, Active: true, IdleHint: false},
- new: &SessionState{Locked: false, Active: false, IdleHint: false},
- expected: true,
- },
- {
- name: "idle hint changed",
- old: &SessionState{Locked: false, Active: true, IdleHint: false},
- new: &SessionState{Locked: false, Active: true, IdleHint: true},
- expected: true,
- },
- {
- name: "locked hint changed",
- old: &SessionState{Locked: false, Active: true, LockedHint: false},
- new: &SessionState{Locked: false, Active: true, LockedHint: true},
- expected: true,
- },
- {
- name: "preparing for sleep changed",
- old: &SessionState{Locked: false, Active: true, PreparingForSleep: false},
- new: &SessionState{Locked: false, Active: true, PreparingForSleep: true},
- expected: true,
- },
- {
- name: "non-meaningful change (username)",
- old: &SessionState{Locked: false, Active: true, UserName: "user1"},
- new: &SessionState{Locked: false, Active: true, UserName: "user2"},
- expected: false,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := stateChangedMeaningfully(tt.old, tt.new)
- assert.Equal(t, tt.expected, result)
- })
- }
-}
-
-func TestManager_SnapshotState(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- SessionID: "1",
- Locked: false,
- Active: true,
- UserName: "testuser",
- },
- stateMutex: sync.RWMutex{},
- }
-
- snapshot := manager.snapshotState()
- assert.Equal(t, "1", snapshot.SessionID)
- assert.False(t, snapshot.Locked)
- assert.True(t, snapshot.Active)
- assert.Equal(t, "testuser", snapshot.UserName)
-
- // Modifying snapshot should not affect manager's state
- snapshot.Locked = true
- assert.False(t, manager.state.Locked)
-}
-
-func TestNewManager(t *testing.T) {
- // This test will fail in environments without systemd/login1 D-Bus
- // It's primarily for local testing with systemd
- t.Run("attempts to create manager", func(t *testing.T) {
- manager, err := NewManager()
- if err != nil {
- // Expected in test environments without systemd
- assert.Nil(t, manager)
- } else {
- assert.NotNil(t, manager)
- assert.NotNil(t, manager.state)
- assert.NotNil(t, manager.subscribers)
- assert.NotNil(t, manager.stopChan)
-
- // Clean up
- manager.Close()
- }
- })
-}
diff --git a/nix/inputs/dms-cli/internal/server/loginctl/monitor.go b/nix/inputs/dms-cli/internal/server/loginctl/monitor.go
deleted file mode 100644
index c430105..0000000
--- a/nix/inputs/dms-cli/internal/server/loginctl/monitor.go
+++ /dev/null
@@ -1,157 +0,0 @@
-package loginctl
-
-import (
- "time"
-
- "github.com/godbus/dbus/v5"
-)
-
-func (m *Manager) handleDBusSignal(sig *dbus.Signal) {
- switch sig.Name {
- case dbusSessionInterface + ".Lock":
- m.stateMutex.Lock()
- m.state.Locked = true
- m.state.LockedHint = true
- m.stateMutex.Unlock()
- m.notifySubscribers()
-
- if m.sleepInhibitorEnabled.Load() && m.inSleepCycle.Load() {
- id := m.sleepCycleID.Load()
- m.lockTimerMu.Lock()
- if m.lockTimer != nil {
- m.lockTimer.Stop()
- }
- m.lockTimer = time.AfterFunc(m.fallbackDelay, func() {
- m.releaseForCycle(id)
- })
- m.lockTimerMu.Unlock()
- }
-
- case dbusSessionInterface + ".Unlock":
- m.stateMutex.Lock()
- m.state.Locked = false
- m.state.LockedHint = false
- m.stateMutex.Unlock()
- m.notifySubscribers()
-
- // Cancel the lock timer if it's still running
- m.lockTimerMu.Lock()
- if m.lockTimer != nil {
- m.lockTimer.Stop()
- m.lockTimer = nil
- }
- m.lockTimerMu.Unlock()
-
- // Re-acquire the sleep inhibitor (acquireSleepInhibitor checks the enabled flag)
- m.acquireSleepInhibitor()
-
- case dbusManagerInterface + ".PrepareForSleep":
- if len(sig.Body) == 0 {
- return
- }
- preparing, _ := sig.Body[0].(bool)
-
- if preparing {
- cycleID := m.sleepCycleID.Add(1)
- m.inSleepCycle.Store(true)
-
- if m.lockBeforeSuspend.Load() {
- m.Lock()
- }
-
- readyCh := m.newLockerReadyCh()
- go func(id uint64, ch <-chan struct{}) {
- <-ch
- if m.inSleepCycle.Load() && m.sleepCycleID.Load() == id {
- m.releaseSleepInhibitor()
- }
- }(cycleID, readyCh)
- } else {
- m.inSleepCycle.Store(false)
- m.signalLockerReady()
- m.refreshSessionBinding()
- m.acquireSleepInhibitor()
- }
-
- m.stateMutex.Lock()
- m.state.PreparingForSleep = preparing
- m.stateMutex.Unlock()
- m.notifySubscribers()
-
- case dbusPropsInterface + ".PropertiesChanged":
- m.handlePropertiesChanged(sig)
-
- case "org.freedesktop.DBus.NameOwnerChanged":
- if len(sig.Body) == 3 {
- name, _ := sig.Body[0].(string)
- oldOwner, _ := sig.Body[1].(string)
- newOwner, _ := sig.Body[2].(string)
- if name == dbusDest && oldOwner != "" && newOwner != "" {
- m.updateSessionState()
- if !m.inSleepCycle.Load() {
- m.acquireSleepInhibitor()
- }
- m.notifySubscribers()
- }
- }
- }
-}
-
-func (m *Manager) handlePropertiesChanged(sig *dbus.Signal) {
- if len(sig.Body) < 2 {
- return
- }
-
- iface, ok := sig.Body[0].(string)
- if !ok || iface != dbusSessionInterface {
- return
- }
-
- changes, ok := sig.Body[1].(map[string]dbus.Variant)
- if !ok {
- return
- }
-
- var needsUpdate bool
-
- for key, variant := range changes {
- switch key {
- case "Active":
- if val, ok := variant.Value().(bool); ok {
- m.stateMutex.Lock()
- m.state.Active = val
- m.stateMutex.Unlock()
- needsUpdate = true
- }
-
- case "IdleHint":
- if val, ok := variant.Value().(bool); ok {
- m.stateMutex.Lock()
- m.state.IdleHint = val
- m.stateMutex.Unlock()
- needsUpdate = true
- }
-
- case "IdleSinceHint":
- if val, ok := variant.Value().(uint64); ok {
- m.stateMutex.Lock()
- m.state.IdleSinceHint = val
- m.stateMutex.Unlock()
- needsUpdate = true
- }
-
- case "LockedHint":
- if val, ok := variant.Value().(bool); ok {
- m.stateMutex.Lock()
- m.state.LockedHint = val
- m.state.Locked = val
- m.stateMutex.Unlock()
- needsUpdate = true
- }
- }
- }
-
- if needsUpdate {
- m.notifySubscribers()
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/loginctl/monitor_test.go b/nix/inputs/dms-cli/internal/server/loginctl/monitor_test.go
deleted file mode 100644
index e348622..0000000
--- a/nix/inputs/dms-cli/internal/server/loginctl/monitor_test.go
+++ /dev/null
@@ -1,325 +0,0 @@
-package loginctl
-
-import (
- "sync"
- "testing"
-
- "github.com/godbus/dbus/v5"
- "github.com/stretchr/testify/assert"
-)
-
-func TestManager_HandleDBusSignal_Lock(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- Locked: false,
- LockedHint: false,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- dirty: make(chan struct{}, 1),
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.login1.Session.Lock",
- }
-
- manager.handleDBusSignal(sig)
-
- manager.stateMutex.RLock()
- defer manager.stateMutex.RUnlock()
- assert.True(t, manager.state.Locked)
- assert.True(t, manager.state.LockedHint)
-}
-
-func TestManager_HandleDBusSignal_Unlock(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- Locked: true,
- LockedHint: true,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- dirty: make(chan struct{}, 1),
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.login1.Session.Unlock",
- }
-
- manager.handleDBusSignal(sig)
-
- manager.stateMutex.RLock()
- defer manager.stateMutex.RUnlock()
- assert.False(t, manager.state.Locked)
- assert.False(t, manager.state.LockedHint)
-}
-
-func TestManager_HandleDBusSignal_PrepareForSleep(t *testing.T) {
- t.Run("preparing for sleep - true", func(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- PreparingForSleep: false,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- dirty: make(chan struct{}, 1),
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.login1.Manager.PrepareForSleep",
- Body: []interface{}{true},
- }
-
- manager.handleDBusSignal(sig)
-
- manager.stateMutex.RLock()
- defer manager.stateMutex.RUnlock()
- assert.True(t, manager.state.PreparingForSleep)
- })
-
- t.Run("preparing for sleep - false", func(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- PreparingForSleep: true,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- dirty: make(chan struct{}, 1),
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.login1.Manager.PrepareForSleep",
- Body: []interface{}{false},
- }
-
- manager.handleDBusSignal(sig)
-
- manager.stateMutex.RLock()
- defer manager.stateMutex.RUnlock()
- assert.False(t, manager.state.PreparingForSleep)
- })
-
- t.Run("empty body", func(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- PreparingForSleep: false,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- dirty: make(chan struct{}, 1),
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.login1.Manager.PrepareForSleep",
- Body: []interface{}{},
- }
-
- manager.handleDBusSignal(sig)
-
- // State should remain unchanged
- manager.stateMutex.RLock()
- defer manager.stateMutex.RUnlock()
- assert.False(t, manager.state.PreparingForSleep)
- })
-}
-
-func TestManager_HandlePropertiesChanged(t *testing.T) {
- t.Run("active property changed", func(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- Active: false,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- dirty: make(chan struct{}, 1),
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.DBus.Properties.PropertiesChanged",
- Body: []interface{}{
- "org.freedesktop.login1.Session",
- map[string]dbus.Variant{
- "Active": dbus.MakeVariant(true),
- },
- },
- }
-
- manager.handlePropertiesChanged(sig)
-
- manager.stateMutex.RLock()
- defer manager.stateMutex.RUnlock()
- assert.True(t, manager.state.Active)
- })
-
- t.Run("idle hint property changed", func(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- IdleHint: false,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- dirty: make(chan struct{}, 1),
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.DBus.Properties.PropertiesChanged",
- Body: []interface{}{
- "org.freedesktop.login1.Session",
- map[string]dbus.Variant{
- "IdleHint": dbus.MakeVariant(true),
- },
- },
- }
-
- manager.handlePropertiesChanged(sig)
-
- manager.stateMutex.RLock()
- defer manager.stateMutex.RUnlock()
- assert.True(t, manager.state.IdleHint)
- })
-
- t.Run("idle since hint property changed", func(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- IdleSinceHint: 0,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- dirty: make(chan struct{}, 1),
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.DBus.Properties.PropertiesChanged",
- Body: []interface{}{
- "org.freedesktop.login1.Session",
- map[string]dbus.Variant{
- "IdleSinceHint": dbus.MakeVariant(uint64(123456789)),
- },
- },
- }
-
- manager.handlePropertiesChanged(sig)
-
- manager.stateMutex.RLock()
- defer manager.stateMutex.RUnlock()
- assert.Equal(t, uint64(123456789), manager.state.IdleSinceHint)
- })
-
- t.Run("locked hint property changed", func(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- LockedHint: false,
- Locked: false,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- dirty: make(chan struct{}, 1),
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.DBus.Properties.PropertiesChanged",
- Body: []interface{}{
- "org.freedesktop.login1.Session",
- map[string]dbus.Variant{
- "LockedHint": dbus.MakeVariant(true),
- },
- },
- }
-
- manager.handlePropertiesChanged(sig)
-
- manager.stateMutex.RLock()
- defer manager.stateMutex.RUnlock()
- assert.True(t, manager.state.LockedHint)
- assert.True(t, manager.state.Locked)
- })
-
- t.Run("wrong interface", func(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- Active: false,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- dirty: make(chan struct{}, 1),
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.DBus.Properties.PropertiesChanged",
- Body: []interface{}{
- "org.freedesktop.SomeOtherInterface",
- map[string]dbus.Variant{
- "Active": dbus.MakeVariant(true),
- },
- },
- }
-
- manager.handlePropertiesChanged(sig)
-
- // State should remain unchanged
- manager.stateMutex.RLock()
- defer manager.stateMutex.RUnlock()
- assert.False(t, manager.state.Active)
- })
-
- t.Run("empty body", func(t *testing.T) {
- manager := &Manager{
- state: &SessionState{},
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- dirty: make(chan struct{}, 1),
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.DBus.Properties.PropertiesChanged",
- Body: []interface{}{},
- }
-
- // Should not panic
- assert.NotPanics(t, func() {
- manager.handlePropertiesChanged(sig)
- })
- })
-
- t.Run("multiple properties changed", func(t *testing.T) {
- manager := &Manager{
- state: &SessionState{
- Active: false,
- IdleHint: false,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan SessionState),
- subMutex: sync.RWMutex{},
- dirty: make(chan struct{}, 1),
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.DBus.Properties.PropertiesChanged",
- Body: []interface{}{
- "org.freedesktop.login1.Session",
- map[string]dbus.Variant{
- "Active": dbus.MakeVariant(true),
- "IdleHint": dbus.MakeVariant(true),
- },
- },
- }
-
- manager.handlePropertiesChanged(sig)
-
- manager.stateMutex.RLock()
- defer manager.stateMutex.RUnlock()
- assert.True(t, manager.state.Active)
- assert.True(t, manager.state.IdleHint)
- })
-}
diff --git a/nix/inputs/dms-cli/internal/server/loginctl/types.go b/nix/inputs/dms-cli/internal/server/loginctl/types.go
deleted file mode 100644
index 559396b..0000000
--- a/nix/inputs/dms-cli/internal/server/loginctl/types.go
+++ /dev/null
@@ -1,76 +0,0 @@
-package loginctl
-
-import (
- "os"
- "sync"
- "sync/atomic"
- "time"
-
- "github.com/godbus/dbus/v5"
-)
-
-type SessionState struct {
- SessionID string `json:"sessionId"`
- SessionPath string `json:"sessionPath"`
- Locked bool `json:"locked"`
- Active bool `json:"active"`
- IdleHint bool `json:"idleHint"`
- IdleSinceHint uint64 `json:"idleSinceHint"`
- LockedHint bool `json:"lockedHint"`
- SessionType string `json:"sessionType"`
- SessionClass string `json:"sessionClass"`
- User uint32 `json:"user"`
- UserName string `json:"userName"`
- RemoteHost string `json:"remoteHost"`
- Service string `json:"service"`
- TTY string `json:"tty"`
- Display string `json:"display"`
- Remote bool `json:"remote"`
- Seat string `json:"seat"`
- VTNr uint32 `json:"vtnr"`
- PreparingForSleep bool `json:"preparingForSleep"`
-}
-
-type EventType string
-
-const (
- EventStateChanged EventType = "state_changed"
- EventLock EventType = "lock"
- EventUnlock EventType = "unlock"
- EventPrepareForSleep EventType = "prepare_for_sleep"
- EventIdleHintChanged EventType = "idle_hint_changed"
- EventLockedHintChanged EventType = "locked_hint_changed"
-)
-
-type SessionEvent struct {
- Type EventType `json:"type"`
- Data SessionState `json:"data"`
-}
-
-type Manager struct {
- state *SessionState
- stateMutex sync.RWMutex
- subscribers map[string]chan SessionState
- subMutex sync.RWMutex
- stopChan chan struct{}
- conn *dbus.Conn
- sessionPath dbus.ObjectPath
- managerObj dbus.BusObject
- sessionObj dbus.BusObject
- dirty chan struct{}
- notifierWg sync.WaitGroup
- lastNotifiedState *SessionState
- signals chan *dbus.Signal
- sigWG sync.WaitGroup
- inhibitMu sync.Mutex
- inhibitFile *os.File
- lockBeforeSuspend atomic.Bool
- inSleepCycle atomic.Bool
- sleepCycleID atomic.Uint64
- lockerReadyChMu sync.Mutex
- lockerReadyCh chan struct{}
- lockTimerMu sync.Mutex
- lockTimer *time.Timer
- sleepInhibitorEnabled atomic.Bool
- fallbackDelay time.Duration
-}
diff --git a/nix/inputs/dms-cli/internal/server/loginctl/types_test.go b/nix/inputs/dms-cli/internal/server/loginctl/types_test.go
deleted file mode 100644
index d5063ea..0000000
--- a/nix/inputs/dms-cli/internal/server/loginctl/types_test.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package loginctl
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestEventType_Constants(t *testing.T) {
- assert.Equal(t, EventType("state_changed"), EventStateChanged)
- assert.Equal(t, EventType("lock"), EventLock)
- assert.Equal(t, EventType("unlock"), EventUnlock)
- assert.Equal(t, EventType("prepare_for_sleep"), EventPrepareForSleep)
- assert.Equal(t, EventType("idle_hint_changed"), EventIdleHintChanged)
- assert.Equal(t, EventType("locked_hint_changed"), EventLockedHintChanged)
-}
-
-func TestSessionState_Struct(t *testing.T) {
- state := SessionState{
- SessionID: "1",
- SessionPath: "/org/freedesktop/login1/session/_31",
- Locked: false,
- Active: true,
- IdleHint: false,
- IdleSinceHint: 0,
- LockedHint: false,
- SessionType: "wayland",
- SessionClass: "user",
- User: 1000,
- UserName: "testuser",
- RemoteHost: "",
- Service: "gdm-password",
- TTY: "tty2",
- Display: ":1",
- Remote: false,
- Seat: "seat0",
- VTNr: 2,
- PreparingForSleep: false,
- }
-
- assert.Equal(t, "1", state.SessionID)
- assert.True(t, state.Active)
- assert.False(t, state.Locked)
- assert.Equal(t, "wayland", state.SessionType)
- assert.Equal(t, uint32(1000), state.User)
- assert.Equal(t, "testuser", state.UserName)
-}
-
-func TestSessionEvent_Struct(t *testing.T) {
- state := SessionState{
- SessionID: "1",
- Locked: true,
- }
-
- event := SessionEvent{
- Type: EventLock,
- Data: state,
- }
-
- assert.Equal(t, EventLock, event.Type)
- assert.Equal(t, "1", event.Data.SessionID)
- assert.True(t, event.Data.Locked)
-}
diff --git a/nix/inputs/dms-cli/internal/server/models/types.go b/nix/inputs/dms-cli/internal/server/models/types.go
deleted file mode 100644
index 583c36e..0000000
--- a/nix/inputs/dms-cli/internal/server/models/types.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package models
-
-import (
- "encoding/json"
- "net"
-
- "github.com/AvengeMedia/danklinux/internal/log"
-)
-
-type Request struct {
- ID int `json:"id,omitempty"`
- Method string `json:"method"`
- Params map[string]interface{} `json:"params,omitempty"`
-}
-
-type Response[T any] struct {
- ID int `json:"id,omitempty"`
- Result *T `json:"result,omitempty"`
- Error string `json:"error,omitempty"`
-}
-
-func RespondError(conn net.Conn, id int, errMsg string) {
- log.Errorf("DMS API Error: id=%d error=%s", id, errMsg)
- resp := Response[any]{ID: id, Error: errMsg}
- json.NewEncoder(conn).Encode(resp)
-}
-
-func Respond[T any](conn net.Conn, id int, result T) {
- resp := Response[T]{ID: id, Result: &result}
- json.NewEncoder(conn).Encode(resp)
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/API.md b/nix/inputs/dms-cli/internal/server/network/API.md
deleted file mode 100644
index 0163389..0000000
--- a/nix/inputs/dms-cli/internal/server/network/API.md
+++ /dev/null
@@ -1,552 +0,0 @@
-# NetworkManager API Documentation
-
-## Overview
-
-The network manager API provides methods for managing WiFi connections, monitoring network state, and handling credential prompts through NetworkManager. Communication occurs over a message-based protocol (websocket, IPC, etc.) with event subscriptions for state updates.
-
-## API Methods
-
-### network.wifi.connect
-
-Initiate a WiFi connection.
-
-**Request:**
-```json
-{
- "method": "network.wifi.connect",
- "params": {
- "ssid": "NetworkName",
- "password": "optional-password",
- "interactive": true
- }
-}
-```
-
-**Parameters:**
-- `ssid` (string, required): Network SSID
-- `password` (string, optional): Pre-shared key for WPA/WPA2/WPA3 networks
-- `interactive` (boolean, optional): Enable credential prompting if authentication fails or password is missing. Automatically set to `true` when connecting to secured networks without providing a password.
-
-**Response:**
-```json
-{
- "success": true,
- "message": "connecting"
-}
-```
-
-**Behavior:**
-- Returns immediately; connection happens asynchronously
-- State updates delivered via `network` service subscription
-- Credential prompts delivered via `network.credentials` service subscription
-
-### network.credentials.submit
-
-Submit credentials in response to a prompt.
-
-**Request:**
-```json
-{
- "method": "network.credentials.submit",
- "params": {
- "token": "correlation-token",
- "secrets": {
- "psk": "password"
- },
- "save": true
- }
-}
-```
-
-**Parameters:**
-- `token` (string, required): Token from credential prompt
-- `secrets` (object, required): Key-value map of credential fields
-- `save` (boolean, optional): Whether to persist credentials (default: false)
-
-**Common secret fields:**
-- `psk`: Pre-shared key for WPA2/WPA3 personal networks
-- `identity`: Username for 802.1X enterprise networks
-- `password`: Password for 802.1X enterprise networks
-
-### network.credentials.cancel
-
-Cancel a credential prompt.
-
-**Request:**
-```json
-{
- "method": "network.credentials.cancel",
- "params": {
- "token": "correlation-token"
- }
-}
-```
-
-## Event Subscriptions
-
-### Subscribing to Events
-
-Subscribe to receive network state updates and credential prompts:
-
-```json
-{
- "method": "subscribe",
- "params": {
- "services": ["network", "network.credentials"]
- }
-}
-```
-
-Both services are required for full connection handling. Missing `network.credentials` means credential prompts won't be received.
-
-### network Service Events
-
-State updates are sent whenever network configuration changes:
-
-```json
-{
- "service": "network",
- "data": {
- "networkStatus": "wifi",
- "isConnecting": false,
- "connectingSSID": "",
- "wifiConnected": true,
- "wifiSSID": "MyNetwork",
- "wifiIP": "192.168.1.100",
- "lastError": ""
- }
-}
-```
-
-**State fields:**
-- `networkStatus`: Current connection type (`wifi`, `ethernet`, `disconnected`)
-- `isConnecting`: Whether a connection attempt is in progress
-- `connectingSSID`: SSID being connected to (empty when idle)
-- `wifiConnected`: Whether associated with an access point
-- `wifiSSID`: Currently connected network name
-- `wifiIP`: Assigned IP address (empty until DHCP completes)
-- `lastError`: Error message from last failed connection attempt
-
-### network.credentials Service Events
-
-Credential prompts are sent when authentication is required:
-
-```json
-{
- "service": "network.credentials",
- "data": {
- "token": "unique-prompt-id",
- "ssid": "NetworkName",
- "setting": "802-11-wireless-security",
- "fields": ["psk"],
- "hints": ["wpa3", "sae"],
- "reason": "Credentials required"
- }
-}
-```
-
-**Prompt fields:**
-- `token`: Unique identifier for this prompt (use in submit/cancel)
-- `ssid`: Network requesting credentials
-- `setting`: Authentication type (`802-11-wireless-security` for personal WiFi, `802-1x` for enterprise)
-- `fields`: Array of required credential field names
-- `hints`: Additional context about the network type
-- `reason`: Human-readable explanation (e.g., "Previous password was incorrect")
-
-## Connection Flow
-
-### Typical Timeline
-
-```
-T+0ms Call network.wifi.connect
-T+10ms Receive {"success": true, "message": "connecting"}
-T+100ms State update: isConnecting=true, connectingSSID="Network"
-T+500ms Credential prompt (if needed)
-T+1000ms Submit credentials
-T+3000ms State update: wifiConnected=true, wifiIP="192.168.x.x"
-```
-
-### State Machine
-
-```
-IDLE
- |
- | network.wifi.connect
- v
-CONNECTING (isConnecting=true, connectingSSID set)
- |
- +-- Needs credentials
- | |
- | v
- | PROMPTING (credential prompt event)
- | |
- | | network.credentials.submit
- | v
- | back to CONNECTING
- |
- +-- Success
- | |
- | v
- | CONNECTED (wifiConnected=true, wifiIP set, isConnecting=false)
- |
- +-- Failure
- |
- v
- ERROR (isConnecting=false, !wifiConnected, lastError set)
-```
-
-## Connection Success Detection
-
-A connection is successful when all of the following are true:
-
-1. `wifiConnected` is `true`
-2. `wifiIP` is set and non-empty
-3. `wifiSSID` matches the target network
-4. `isConnecting` is `false`
-
-Do not rely on `wifiConnected` alone - the device may be associated with an access point but not have an IP address yet.
-
-**Example:**
-```javascript
-function isConnectionComplete(state, targetSSID) {
- return state.wifiConnected &&
- state.wifiIP &&
- state.wifiIP !== "" &&
- state.wifiSSID === targetSSID &&
- !state.isConnecting;
-}
-```
-
-## Error Handling
-
-### Error Detection
-
-Errors occur when a connection attempt stops without success:
-
-```javascript
-function checkForFailure(state, wasConnecting, targetSSID) {
- // Was connecting, now idle, but not connected
- if (wasConnecting &&
- !state.isConnecting &&
- state.connectingSSID === "" &&
- !state.wifiConnected) {
- return state.lastError || "Connection failed";
- }
- return null;
-}
-```
-
-### Common Error Scenarios
-
-#### Wrong Password
-
-**Detection methods:**
-
-1. Quick failure (< 3 seconds from start)
-2. `lastError` contains "password", "auth", or "secrets"
-3. Second credential prompt with `reason: "Previous password was incorrect"`
-
-**Handling:**
-```javascript
-if (prompt.reason === "Previous password was incorrect") {
- // Show error, clear password field, re-focus input
-}
-```
-
-#### Network Out of Range
-
-**Detection:**
-- `lastError` contains "not-found" or "connection-attempt-failed"
-
-#### Connection Timeout
-
-**Detection:**
-- `isConnecting` remains true for > 30 seconds
-
-**Implementation:**
-```javascript
-let timeout = setTimeout(() => {
- if (currentState.isConnecting) {
- handleTimeout();
- }
-}, 30000);
-```
-
-#### DHCP Failure
-
-**Detection:**
-- `wifiConnected` is true
-- `wifiIP` is empty after 15+ seconds
-
-### Error Message Translation
-
-Map technical errors to user-friendly messages:
-
-| lastError value | Meaning | User message |
-|----------------|---------|--------------|
-| `secrets-required` | Password needed | "Please enter password" |
-| `authentication-failed` | Wrong password | "Incorrect password" |
-| `connection-removed` | Profile deleted | "Network configuration removed" |
-| `connection-attempt-failed` | Generic failure | "Failed to connect" |
-| `network-not-found` | Out of range | "Network not found" |
-| `(timeout)` | Timeout | "Connection timed out" |
-
-## Credential Handling
-
-### Secret Agent Architecture
-
-The credential system uses a broker pattern:
-
-```
-NetworkManager -> SecretAgent -> PromptBroker -> UI -> User
- ^
- |
- User Response
- |
-NetworkManager <- SecretAgent <- PromptBroker <- UI
-```
-
-### Implementing a Broker
-
-```go
-type CustomBroker struct {
- ui UIInterface
- pending map[string]chan network.PromptReply
-}
-
-func (b *CustomBroker) Ask(ctx context.Context, req network.PromptRequest) (string, error) {
- token := generateToken()
- b.pending[token] = make(chan network.PromptReply, 1)
-
- // Send to UI
- b.ui.ShowCredentialPrompt(token, req)
-
- return token, nil
-}
-
-func (b *CustomBroker) Wait(ctx context.Context, token string) (network.PromptReply, error) {
- select {
- case <-ctx.Done():
- return network.PromptReply{}, errors.New("timeout")
- case reply := <-b.pending[token]:
- return reply, nil
- }
-}
-
-func (b *CustomBroker) Resolve(token string, reply network.PromptReply) error {
- if ch, ok := b.pending[token]; ok {
- ch <- reply
- close(ch)
- delete(b.pending, token)
- }
- return nil
-}
-```
-
-### Credential Field Types
-
-**Personal WiFi (802-11-wireless-security):**
-- Fields: `["psk"]`
-- UI: Single password input
-
-**Enterprise WiFi (802-1x):**
-- Fields: `["identity", "password"]`
-- UI: Username and password inputs
-
-### Building Secrets Object
-
-```javascript
-function buildSecrets(setting, fields, formData) {
- let secrets = {};
-
- if (setting === "802-11-wireless-security") {
- secrets.psk = formData.password;
- } else if (setting === "802-1x") {
- secrets.identity = formData.username;
- secrets.password = formData.password;
- }
-
- return secrets;
-}
-```
-
-## Best Practices
-
-### Track Target Network
-
-Always store which network you're connecting to:
-
-```javascript
-let targetSSID = null;
-
-function connect(ssid) {
- targetSSID = ssid;
- // send request
-}
-
-function onStateUpdate(state) {
- if (!targetSSID) return;
-
- if (state.wifiSSID === targetSSID && state.wifiConnected && state.wifiIP) {
- // Success for the network we care about
- targetSSID = null;
- }
-}
-```
-
-### Implement Timeouts
-
-Never wait indefinitely for a connection:
-
-```javascript
-const CONNECTION_TIMEOUT = 30000; // 30 seconds
-const DHCP_TIMEOUT = 15000; // 15 seconds
-
-let timer = setTimeout(() => {
- if (stillConnecting) {
- handleTimeout();
- }
-}, CONNECTION_TIMEOUT);
-```
-
-### Handle Credential Re-prompts
-
-Wrong passwords trigger a second prompt:
-
-```javascript
-function onCredentialPrompt(prompt) {
- if (prompt.reason.includes("incorrect")) {
- // Show error, but keep dialog open
- showError("Wrong password");
- clearPasswordField();
- } else {
- // First time prompt
- showDialog(prompt);
- }
-}
-```
-
-### Clean Up State
-
-Reset tracking variables on success, failure, or cancellation:
-
-```javascript
-function cleanup() {
- clearTimeout(timer);
- targetSSID = null;
- closeDialogs();
-}
-```
-
-### Subscribe to Both Services
-
-Missing `network.credentials` means prompts won't arrive:
-
-```javascript
-// Correct
-services: ["network", "network.credentials"]
-
-// Wrong - will miss credential prompts
-services: ["network"]
-```
-
-## Testing
-
-### Connection Test Checklist
-
-- [ ] Connect to open network
-- [ ] Connect to WPA2 network with password provided
-- [ ] Connect to WPA2 network without password (triggers prompt)
-- [ ] Enter wrong password (verify error and re-prompt)
-- [ ] Cancel credential prompt
-- [ ] Connection timeout after 30 seconds
-- [ ] DHCP timeout detection
-- [ ] Network out of range
-- [ ] Reconnect to already-configured network
-
-### Verifying Secret Agent Setup
-
-Check connection profile flags:
-```bash
-nmcli connection show "NetworkName" | grep flags
-# Should show: 802-11-wireless-security.psk-flags: 1 (agent-owned)
-```
-
-Check agent registration in logs:
-```
-INFO: Registered with NetworkManager as secret agent
-```
-
-## Security
-
-- Never log credential values (passwords, PSKs)
-- Clear password fields when dialogs close
-- Implement prompt timeouts (default: 2 minutes)
-- Validate user input before submission
-- Use secure channels for credential transmission
-
-## Troubleshooting
-
-### Credential prompt doesn't appear
-
-**Check:**
-- Subscribed to both `network` and `network.credentials`
-- Connection has `interactive: true`
-- Secret flags set to AGENT_OWNED (value: 1)
-- Broker registered successfully
-
-### Connection succeeds without prompting
-
-**Cause:** NetworkManager found saved credentials
-
-**Solution:** Delete existing connection first, or use different credentials
-
-### State updates seem delayed
-
-**Expected behavior:** State changes occur in rapid succession during connection
-
-**Solution:** Debounce UI updates; only act on final state
-
-### Multiple rapid credential prompts
-
-**Cause:** Connection profile has incorrect flags or conflicting agents
-
-**Solution:**
-- Check only one agent is running
-- Verify psk-flags value
-- Check NetworkManager logs for agent conflicts
-
-## Data Structures Reference
-
-### PromptRequest
-```go
-type PromptRequest struct {
- SSID string `json:"ssid"`
- SettingName string `json:"setting"`
- Fields []string `json:"fields"`
- Hints []string `json:"hints"`
- Reason string `json:"reason"`
-}
-```
-
-### PromptReply
-```go
-type PromptReply struct {
- Secrets map[string]string `json:"secrets"`
- Save bool `json:"save"`
- Cancel bool `json:"cancel"`
-}
-```
-
-### NetworkState
-```go
-type NetworkState struct {
- NetworkStatus string `json:"networkStatus"`
- IsConnecting bool `json:"isConnecting"`
- ConnectingSSID string `json:"connectingSSID"`
- WifiConnected bool `json:"wifiConnected"`
- WifiSSID string `json:"wifiSSID"`
- WifiIP string `json:"wifiIP"`
- LastError string `json:"lastError"`
-}
-```
diff --git a/nix/inputs/dms-cli/internal/server/network/agent_iwd.go b/nix/inputs/dms-cli/internal/server/network/agent_iwd.go
deleted file mode 100644
index 99be64b..0000000
--- a/nix/inputs/dms-cli/internal/server/network/agent_iwd.go
+++ /dev/null
@@ -1,311 +0,0 @@
-package network
-
-import (
- "context"
- "errors"
- "fmt"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/errdefs"
- "github.com/godbus/dbus/v5"
-)
-
-const (
- iwdAgentManagerPath = "/net/connman/iwd"
- iwdAgentManagerIface = "net.connman.iwd.AgentManager"
- iwdAgentInterface = "net.connman.iwd.Agent"
- iwdAgentObjectPath = "/com/danklinux/iwdagent"
-)
-
-type ConnectionStateChecker interface {
- IsConnectingTo(ssid string) bool
-}
-
-type IWDAgent struct {
- conn *dbus.Conn
- objPath dbus.ObjectPath
- prompts PromptBroker
- onUserCanceled func()
- onPromptRetry func(ssid string)
- lastRequestSSID string
- stateChecker ConnectionStateChecker
-}
-
-const iwdAgentIntrospectXML = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`
-
-func NewIWDAgent(prompts PromptBroker) (*IWDAgent, error) {
- c, err := dbus.ConnectSystemBus()
- if err != nil {
- return nil, fmt.Errorf("failed to connect to system bus: %w", err)
- }
-
- agent := &IWDAgent{
- conn: c,
- objPath: dbus.ObjectPath(iwdAgentObjectPath),
- prompts: prompts,
- }
-
- if err := c.Export(agent, agent.objPath, iwdAgentInterface); err != nil {
- c.Close()
- return nil, fmt.Errorf("failed to export IWD agent: %w", err)
- }
-
- if err := c.Export(agent, agent.objPath, "org.freedesktop.DBus.Introspectable"); err != nil {
- c.Close()
- return nil, fmt.Errorf("failed to export introspection: %w", err)
- }
-
- mgr := c.Object("net.connman.iwd", dbus.ObjectPath(iwdAgentManagerPath))
- call := mgr.Call(iwdAgentManagerIface+".RegisterAgent", 0, agent.objPath)
- if call.Err != nil {
- c.Close()
- return nil, fmt.Errorf("failed to register agent with iwd: %w", call.Err)
- }
-
- return agent, nil
-}
-
-func (a *IWDAgent) Close() {
- if a.conn != nil {
- mgr := a.conn.Object("net.connman.iwd", dbus.ObjectPath(iwdAgentManagerPath))
- mgr.Call(iwdAgentManagerIface+".UnregisterAgent", 0, a.objPath)
- a.conn.Close()
- }
-}
-
-func (a *IWDAgent) SetStateChecker(checker ConnectionStateChecker) {
- a.stateChecker = checker
-}
-
-func (a *IWDAgent) getNetworkName(networkPath dbus.ObjectPath) string {
- netObj := a.conn.Object("net.connman.iwd", networkPath)
- nameVar, err := netObj.GetProperty("net.connman.iwd.Network.Name")
- if err == nil {
- if name, ok := nameVar.Value().(string); ok {
- return name
- }
- }
- return string(networkPath)
-}
-
-func (a *IWDAgent) RequestPassphrase(network dbus.ObjectPath) (string, *dbus.Error) {
- ssid := a.getNetworkName(network)
-
- if a.stateChecker != nil && !a.stateChecker.IsConnectingTo(ssid) {
- return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- if a.prompts == nil {
- if a.onUserCanceled != nil {
- a.onUserCanceled()
- }
- return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- if a.lastRequestSSID == ssid {
- if a.onPromptRetry != nil {
- a.onPromptRetry(ssid)
- }
- }
- a.lastRequestSSID = ssid
-
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
- defer cancel()
-
- token, err := a.prompts.Ask(ctx, PromptRequest{
- SSID: ssid,
- Fields: []string{"psk"},
- })
- if err != nil {
- if a.onUserCanceled != nil {
- a.onUserCanceled()
- }
- return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- reply, err := a.prompts.Wait(ctx, token)
- if err != nil {
- if reply.Cancel || errors.Is(err, errdefs.ErrSecretPromptCancelled) {
- if a.onUserCanceled != nil {
- a.onUserCanceled()
- }
- }
- return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- if passphrase, ok := reply.Secrets["psk"]; ok {
- return passphrase, nil
- }
-
- if a.onUserCanceled != nil {
- a.onUserCanceled()
- }
- return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
-}
-
-func (a *IWDAgent) RequestPrivateKeyPassphrase(network dbus.ObjectPath) (string, *dbus.Error) {
- ssid := a.getNetworkName(network)
-
- if a.stateChecker != nil && !a.stateChecker.IsConnectingTo(ssid) {
- return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- if a.prompts == nil {
- return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- if a.lastRequestSSID == ssid {
- if a.onPromptRetry != nil {
- a.onPromptRetry(ssid)
- }
- }
- a.lastRequestSSID = ssid
-
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
- defer cancel()
-
- token, err := a.prompts.Ask(ctx, PromptRequest{
- SSID: ssid,
- Fields: []string{"private-key-password"},
- })
- if err != nil {
- return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- reply, err := a.prompts.Wait(ctx, token)
- if err != nil || reply.Cancel {
- return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- if passphrase, ok := reply.Secrets["private-key-password"]; ok {
- return passphrase, nil
- }
-
- return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
-}
-
-func (a *IWDAgent) RequestUserNameAndPassword(network dbus.ObjectPath) (string, string, *dbus.Error) {
- ssid := a.getNetworkName(network)
-
- if a.stateChecker != nil && !a.stateChecker.IsConnectingTo(ssid) {
- return "", "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- if a.prompts == nil {
- return "", "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- if a.lastRequestSSID == ssid {
- if a.onPromptRetry != nil {
- a.onPromptRetry(ssid)
- }
- }
- a.lastRequestSSID = ssid
-
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
- defer cancel()
-
- token, err := a.prompts.Ask(ctx, PromptRequest{
- SSID: ssid,
- Fields: []string{"identity", "password"},
- })
- if err != nil {
- return "", "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- reply, err := a.prompts.Wait(ctx, token)
- if err != nil || reply.Cancel {
- return "", "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- username, hasUser := reply.Secrets["identity"]
- password, hasPass := reply.Secrets["password"]
-
- if hasUser && hasPass {
- return username, password, nil
- }
-
- return "", "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
-}
-
-func (a *IWDAgent) RequestUserPassword(network dbus.ObjectPath, user string) (string, *dbus.Error) {
- ssid := a.getNetworkName(network)
-
- if a.stateChecker != nil && !a.stateChecker.IsConnectingTo(ssid) {
- return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- if a.prompts == nil {
- return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- if a.lastRequestSSID == ssid {
- if a.onPromptRetry != nil {
- a.onPromptRetry(ssid)
- }
- }
- a.lastRequestSSID = ssid
-
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
- defer cancel()
-
- token, err := a.prompts.Ask(ctx, PromptRequest{
- SSID: ssid,
- Fields: []string{"password"},
- })
- if err != nil {
- return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- reply, err := a.prompts.Wait(ctx, token)
- if err != nil || reply.Cancel {
- return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
- }
-
- if password, ok := reply.Secrets["password"]; ok {
- return password, nil
- }
-
- return "", dbus.NewError("net.connman.iwd.Agent.Error.Canceled", nil)
-}
-
-func (a *IWDAgent) Cancel(reason string) *dbus.Error {
- return nil
-}
-
-func (a *IWDAgent) Release() *dbus.Error {
- return nil
-}
-
-func (a *IWDAgent) Introspect() (string, *dbus.Error) {
- return iwdAgentIntrospectXML, nil
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/agent_networkmanager.go b/nix/inputs/dms-cli/internal/server/network/agent_networkmanager.go
deleted file mode 100644
index 3b8fae5..0000000
--- a/nix/inputs/dms-cli/internal/server/network/agent_networkmanager.go
+++ /dev/null
@@ -1,499 +0,0 @@
-package network
-
-import (
- "context"
- "errors"
- "fmt"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/errdefs"
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/godbus/dbus/v5"
-)
-
-const (
- nmAgentManagerPath = "/org/freedesktop/NetworkManager/AgentManager"
- nmAgentManagerIface = "org.freedesktop.NetworkManager.AgentManager"
- nmSecretAgentIface = "org.freedesktop.NetworkManager.SecretAgent"
- agentObjectPath = "/org/freedesktop/NetworkManager/SecretAgent"
- agentIdentifier = "com.danklinux.NMAgent"
-)
-
-type SecretAgent struct {
- conn *dbus.Conn
- objPath dbus.ObjectPath
- id string
- prompts PromptBroker
- manager *Manager
- backend *NetworkManagerBackend
-}
-
-type nmVariantMap map[string]dbus.Variant
-type nmSettingMap map[string]nmVariantMap
-
-const introspectXML = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`
-
-func NewSecretAgent(prompts PromptBroker, manager *Manager, backend *NetworkManagerBackend) (*SecretAgent, error) {
- c, err := dbus.ConnectSystemBus()
- if err != nil {
- return nil, fmt.Errorf("failed to connect to system bus: %w", err)
- }
-
- sa := &SecretAgent{
- conn: c,
- objPath: dbus.ObjectPath(agentObjectPath),
- id: agentIdentifier,
- prompts: prompts,
- manager: manager,
- backend: backend,
- }
-
- if err := c.Export(sa, sa.objPath, nmSecretAgentIface); err != nil {
- c.Close()
- return nil, fmt.Errorf("failed to export secret agent: %w", err)
- }
-
- if err := c.Export(sa, sa.objPath, "org.freedesktop.DBus.Introspectable"); err != nil {
- c.Close()
- return nil, fmt.Errorf("failed to export introspection: %w", err)
- }
-
- mgr := c.Object("org.freedesktop.NetworkManager", dbus.ObjectPath(nmAgentManagerPath))
- call := mgr.Call(nmAgentManagerIface+".Register", 0, sa.id)
- if call.Err != nil {
- c.Close()
- return nil, fmt.Errorf("failed to register agent with NetworkManager: %w", call.Err)
- }
-
- log.Infof("[SecretAgent] Registered with NetworkManager (id=%s, unique name=%s, fixed path=%s)", sa.id, c.Names()[0], sa.objPath)
- return sa, nil
-}
-
-func (a *SecretAgent) Close() {
- if a.conn != nil {
- mgr := a.conn.Object("org.freedesktop.NetworkManager", dbus.ObjectPath(nmAgentManagerPath))
- mgr.Call(nmAgentManagerIface+".Unregister", 0, a.id)
- a.conn.Close()
- }
-}
-
-func (a *SecretAgent) GetSecrets(
- conn map[string]nmVariantMap,
- path dbus.ObjectPath,
- settingName string,
- hints []string,
- flags uint32,
-) (nmSettingMap, *dbus.Error) {
- log.Infof("[SecretAgent] GetSecrets called: path=%s, setting=%s, hints=%v, flags=%d",
- path, settingName, hints, flags)
-
- const (
- NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION = 0x1
- NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW = 0x2
- NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED = 0x4
- )
-
- connType, displayName, vpnSvc := readConnTypeAndName(conn)
- ssid := readSSID(conn)
- fields := fieldsNeeded(settingName, hints)
-
- log.Infof("[SecretAgent] connType=%s, name=%s, vpnSvc=%s, fields=%v, flags=%d", connType, displayName, vpnSvc, fields, flags)
-
- if a.backend != nil {
- a.backend.stateMutex.RLock()
- isConnecting := a.backend.state.IsConnecting
- connectingSSID := a.backend.state.ConnectingSSID
- isConnectingVPN := a.backend.state.IsConnectingVPN
- connectingVPNUUID := a.backend.state.ConnectingVPNUUID
- a.backend.stateMutex.RUnlock()
-
- switch connType {
- case "802-11-wireless":
- // If we're connecting to a WiFi network, only respond if it's the one we're connecting to
- if isConnecting && connectingSSID != ssid {
- log.Infof("[SecretAgent] Ignoring WiFi request for SSID '%s' - we're connecting to '%s'", ssid, connectingSSID)
- return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil)
- }
- case "vpn", "wireguard":
- var connUuid string
- if c, ok := conn["connection"]; ok {
- if v, ok := c["uuid"]; ok {
- if s, ok2 := v.Value().(string); ok2 {
- connUuid = s
- }
- }
- }
-
- // If we're connecting to a VPN, only respond if it's the one we're connecting to
- // This prevents interfering with nmcli/other tools when our app isn't connecting
- if isConnectingVPN && connUuid != connectingVPNUUID {
- log.Infof("[SecretAgent] Ignoring VPN request for UUID '%s' - we're connecting to '%s'", connUuid, connectingVPNUUID)
- return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil)
- }
- }
- }
-
- if len(fields) == 0 {
- // For VPN connections with no hints, we can't provide a proper UI.
- // Defer to other agents (like nm-applet or VPN-specific auth dialogs)
- // that can handle the VPN type properly (e.g., OpenConnect with SAML, etc.)
- if settingName == "vpn" {
- log.Infof("[SecretAgent] VPN with empty hints - deferring to other agents for %s", vpnSvc)
- return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil)
- }
-
- const (
- NM_SETTING_SECRET_FLAG_NONE = 0
- NM_SETTING_SECRET_FLAG_AGENT_OWNED = 1
- NM_SETTING_SECRET_FLAG_NOT_SAVED = 2
- NM_SETTING_SECRET_FLAG_NOT_REQUIRED = 4
- )
-
- var passwordFlags uint32 = 0xFFFF
- switch settingName {
- case "802-11-wireless-security":
- if wifiSecSettings, ok := conn["802-11-wireless-security"]; ok {
- if flagsVariant, ok := wifiSecSettings["psk-flags"]; ok {
- if pwdFlags, ok := flagsVariant.Value().(uint32); ok {
- passwordFlags = pwdFlags
- }
- }
- }
- case "802-1x":
- if dot1xSettings, ok := conn["802-1x"]; ok {
- if flagsVariant, ok := dot1xSettings["password-flags"]; ok {
- if pwdFlags, ok := flagsVariant.Value().(uint32); ok {
- passwordFlags = pwdFlags
- }
- }
- }
- }
-
- if passwordFlags == 0xFFFF {
- log.Warnf("[SecretAgent] Could not determine password-flags for empty hints - returning NoSecrets error")
- return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil)
- } else if passwordFlags&NM_SETTING_SECRET_FLAG_NOT_REQUIRED != 0 {
- log.Infof("[SecretAgent] Secrets not required (flags=%d)", passwordFlags)
- out := nmSettingMap{}
- out[settingName] = nmVariantMap{}
- return out, nil
- } else if passwordFlags&NM_SETTING_SECRET_FLAG_AGENT_OWNED != 0 {
- log.Warnf("[SecretAgent] Secrets are agent-owned but we don't store secrets (flags=%d) - returning NoSecrets error", passwordFlags)
- return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil)
- } else {
- log.Infof("[SecretAgent] No secrets needed, using system stored secrets (flags=%d)", passwordFlags)
- out := nmSettingMap{}
- out[settingName] = nmVariantMap{}
- return out, nil
- }
- }
-
- reason := reasonFromFlags(flags)
- if a.manager != nil && connType == "802-11-wireless" && a.manager.WasRecentlyFailed(ssid) {
- reason = "wrong-password"
- }
-
- var connId, connUuid string
- if c, ok := conn["connection"]; ok {
- if v, ok := c["id"]; ok {
- if s, ok2 := v.Value().(string); ok2 {
- connId = s
- }
- }
- if v, ok := c["uuid"]; ok {
- if s, ok2 := v.Value().(string); ok2 {
- connUuid = s
- }
- }
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
- defer cancel()
-
- token, err := a.prompts.Ask(ctx, PromptRequest{
- Name: displayName,
- SSID: ssid,
- ConnType: connType,
- VpnService: vpnSvc,
- SettingName: settingName,
- Fields: fields,
- Hints: hints,
- Reason: reason,
- ConnectionId: connId,
- ConnectionUuid: connUuid,
- ConnectionPath: string(path),
- })
- if err != nil {
- log.Warnf("[SecretAgent] Failed to create prompt: %v", err)
- return nil, dbus.MakeFailedError(err)
- }
-
- log.Infof("[SecretAgent] Waiting for user input (token=%s)", token)
- reply, err := a.prompts.Wait(ctx, token)
- if err != nil {
- log.Warnf("[SecretAgent] Prompt failed or cancelled: %v", err)
-
- if reply.Cancel || errors.Is(err, errdefs.ErrSecretPromptCancelled) {
- return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.UserCanceled", nil)
- }
-
- if errors.Is(err, errdefs.ErrSecretPromptTimeout) {
- return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.Failed", nil)
- }
- return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.Failed", nil)
- }
-
- log.Infof("[SecretAgent] User provided secrets, save=%v", reply.Save)
-
- out := nmSettingMap{}
- sec := nmVariantMap{}
- for k, v := range reply.Secrets {
- sec[k] = dbus.MakeVariant(v)
- }
- out[settingName] = sec
-
- switch settingName {
- case "802-1x":
- log.Infof("[SecretAgent] Returning 802-1x enterprise secrets with %d fields", len(sec))
- case "vpn":
- log.Infof("[SecretAgent] Returning VPN secrets with %d fields for %s", len(sec), vpnSvc)
- }
-
- // If save=true, persist secrets in background after returning to NetworkManager
- // This MUST happen after we return secrets, in a goroutine
- if reply.Save {
- go func() {
- log.Infof("[SecretAgent] Persisting secrets with Update2: path=%s, setting=%s", path, settingName)
-
- // Get existing connection settings
- connObj := a.conn.Object("org.freedesktop.NetworkManager", path)
- var existingSettings map[string]map[string]dbus.Variant
- if err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.GetSettings", 0).Store(&existingSettings); err != nil {
- log.Warnf("[SecretAgent] GetSettings failed: %v", err)
- return
- }
-
- // Build minimal settings with ONLY the section we're updating
- // This avoids D-Bus type serialization issues with complex types like IPv6 addresses
- settings := make(map[string]map[string]dbus.Variant)
-
- // Copy connection section (required for Update2)
- if connSection, ok := existingSettings["connection"]; ok {
- settings["connection"] = connSection
- }
-
- // Update settings based on type
- switch settingName {
- case "vpn":
- // Set password-flags=0 and add secrets to vpn section
- vpn, ok := existingSettings["vpn"]
- if !ok {
- vpn = make(map[string]dbus.Variant)
- }
-
- // Get existing data map (vpn.data is string->string)
- var data map[string]string
- if dataVariant, ok := vpn["data"]; ok {
- if dm, ok := dataVariant.Value().(map[string]string); ok {
- data = make(map[string]string)
- for k, v := range dm {
- data[k] = v
- }
- } else {
- data = make(map[string]string)
- }
- } else {
- data = make(map[string]string)
- }
-
- // Update password-flags to 0 (system-stored)
- data["password-flags"] = "0"
- vpn["data"] = dbus.MakeVariant(data)
-
- // Add secrets (vpn.secrets is string->string)
- secs := make(map[string]string)
- for k, v := range reply.Secrets {
- secs[k] = v
- }
- vpn["secrets"] = dbus.MakeVariant(secs)
- settings["vpn"] = vpn
-
- log.Infof("[SecretAgent] Updated VPN settings: password-flags=0, secrets with %d fields", len(secs))
-
- case "802-11-wireless-security":
- // Set psk-flags=0 for WiFi
- wifiSec, ok := existingSettings["802-11-wireless-security"]
- if !ok {
- wifiSec = make(map[string]dbus.Variant)
- }
- wifiSec["psk-flags"] = dbus.MakeVariant(uint32(0))
-
- // Add PSK secret
- if psk, ok := reply.Secrets["psk"]; ok {
- wifiSec["psk"] = dbus.MakeVariant(psk)
- log.Infof("[SecretAgent] Updated WiFi settings: psk-flags=0")
- }
- settings["802-11-wireless-security"] = wifiSec
-
- case "802-1x":
- // Set password-flags=0 for 802.1x
- dot1x, ok := existingSettings["802-1x"]
- if !ok {
- dot1x = make(map[string]dbus.Variant)
- }
- dot1x["password-flags"] = dbus.MakeVariant(uint32(0))
-
- // Add password secret
- if password, ok := reply.Secrets["password"]; ok {
- dot1x["password"] = dbus.MakeVariant(password)
- log.Infof("[SecretAgent] Updated 802.1x settings: password-flags=0")
- }
- settings["802-1x"] = dot1x
- }
-
- // Call Update2 with correct signature:
- // Update2(IN settings, IN flags, IN args) -> OUT result
- // flags: 0x1 = to-disk
- var result map[string]dbus.Variant
- err := connObj.Call("org.freedesktop.NetworkManager.Settings.Connection.Update2", 0,
- settings, uint32(0x1), map[string]dbus.Variant{}).Store(&result)
- if err != nil {
- log.Warnf("[SecretAgent] Update2(to-disk) failed: %v", err)
- } else {
- log.Infof("[SecretAgent] Successfully persisted secrets to disk for %s", settingName)
- }
- }()
- }
-
- return out, nil
-}
-
-func (a *SecretAgent) DeleteSecrets(conn map[string]nmVariantMap, path dbus.ObjectPath) *dbus.Error {
- ssid := readSSID(conn)
- log.Infof("[SecretAgent] DeleteSecrets called: path=%s, SSID=%s", path, ssid)
- return nil
-}
-
-func (a *SecretAgent) DeleteSecrets2(path dbus.ObjectPath, setting string) *dbus.Error {
- log.Infof("[SecretAgent] DeleteSecrets2 (alternate) called: path=%s, setting=%s", path, setting)
- return nil
-}
-
-func (a *SecretAgent) CancelGetSecrets(path dbus.ObjectPath, settingName string) *dbus.Error {
- log.Infof("[SecretAgent] CancelGetSecrets called: path=%s, setting=%s", path, settingName)
-
- if a.prompts != nil {
- if err := a.prompts.Cancel(string(path), settingName); err != nil {
- log.Warnf("[SecretAgent] Failed to cancel prompt: %v", err)
- }
- }
-
- return nil
-}
-
-func (a *SecretAgent) Introspect() (string, *dbus.Error) {
- return introspectXML, nil
-}
-
-func readSSID(conn map[string]nmVariantMap) string {
- if w, ok := conn["802-11-wireless"]; ok {
- if v, ok := w["ssid"]; ok {
- if b, ok := v.Value().([]byte); ok {
- return string(b)
- }
- if s, ok := v.Value().(string); ok {
- return s
- }
- }
- }
- return ""
-}
-
-func readConnTypeAndName(conn map[string]nmVariantMap) (string, string, string) {
- var connType, name, svc string
- if c, ok := conn["connection"]; ok {
- if v, ok := c["type"]; ok {
- if s, ok2 := v.Value().(string); ok2 {
- connType = s
- }
- }
- if v, ok := c["id"]; ok {
- if s, ok2 := v.Value().(string); ok2 {
- name = s
- }
- }
- }
- if vpn, ok := conn["vpn"]; ok {
- if v, ok := vpn["service-type"]; ok {
- if s, ok2 := v.Value().(string); ok2 {
- svc = s
- }
- }
- }
- if name == "" && connType == "802-11-wireless" {
- name = readSSID(conn)
- }
- return connType, name, svc
-}
-
-func fieldsNeeded(setting string, hints []string) []string {
- switch setting {
- case "802-11-wireless-security":
- return []string{"psk"}
- case "802-1x":
- return []string{"identity", "password"}
- case "vpn":
- return hints
- default:
- return []string{}
- }
-}
-
-func reasonFromFlags(flags uint32) string {
- const (
- NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE = 0x0
- NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION = 0x1
- NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW = 0x2
- NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED = 0x4
- NM_SECRET_AGENT_GET_SECRETS_FLAG_WPS_PBC_ACTIVE = 0x8
- NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM = 0x80000000
- NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS = 0x40000000
- )
-
- if flags&NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW != 0 {
- return "wrong-password"
- }
- if flags&NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED != 0 {
- return "user-requested"
- }
- return "required"
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend.go b/nix/inputs/dms-cli/internal/server/network/backend.go
deleted file mode 100644
index 3925e2a..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package network
-
-type Backend interface {
- Initialize() error
- Close()
-
- GetWiFiEnabled() (bool, error)
- SetWiFiEnabled(enabled bool) error
-
- ScanWiFi() error
- GetWiFiNetworkDetails(ssid string) (*NetworkInfoResponse, error)
-
- ConnectWiFi(req ConnectionRequest) error
- DisconnectWiFi() error
- ForgetWiFiNetwork(ssid string) error
- SetWiFiAutoconnect(ssid string, autoconnect bool) error
-
- GetWiredConnections() ([]WiredConnection, error)
- GetWiredNetworkDetails(uuid string) (*WiredNetworkInfoResponse, error)
- ConnectEthernet() error
- DisconnectEthernet() error
- ActivateWiredConnection(uuid string) error
-
- ListVPNProfiles() ([]VPNProfile, error)
- ListActiveVPN() ([]VPNActive, error)
- ConnectVPN(uuidOrName string, singleActive bool) error
- DisconnectVPN(uuidOrName string) error
- DisconnectAllVPN() error
- ClearVPNCredentials(uuidOrName string) error
-
- GetCurrentState() (*BackendState, error)
-
- StartMonitoring(onStateChange func()) error
- StopMonitoring()
-
- GetPromptBroker() PromptBroker
- SetPromptBroker(broker PromptBroker) error
- SubmitCredentials(token string, secrets map[string]string, save bool) error
- CancelCredentials(token string) error
-}
-
-type BackendState struct {
- Backend string
- NetworkStatus NetworkStatus
- EthernetIP string
- EthernetDevice string
- EthernetConnected bool
- EthernetConnectionUuid string
- WiFiIP string
- WiFiDevice string
- WiFiConnected bool
- WiFiEnabled bool
- WiFiSSID string
- WiFiBSSID string
- WiFiSignal uint8
- WiFiNetworks []WiFiNetwork
- WiredConnections []WiredConnection
- VPNProfiles []VPNProfile
- VPNActive []VPNActive
- IsConnecting bool
- ConnectingSSID string
- IsConnectingVPN bool
- ConnectingVPNUUID string
- LastError string
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_hybrid_iwd_networkd.go b/nix/inputs/dms-cli/internal/server/network/backend_hybrid_iwd_networkd.go
deleted file mode 100644
index 1df3a9a..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_hybrid_iwd_networkd.go
+++ /dev/null
@@ -1,198 +0,0 @@
-package network
-
-import (
- "fmt"
- "sync"
-)
-
-type HybridIwdNetworkdBackend struct {
- wifi *IWDBackend
- l3 *SystemdNetworkdBackend
- onStateChange func()
- stateMutex sync.RWMutex
-}
-
-func NewHybridIwdNetworkdBackend(w *IWDBackend, n *SystemdNetworkdBackend) (*HybridIwdNetworkdBackend, error) {
- return &HybridIwdNetworkdBackend{
- wifi: w,
- l3: n,
- }, nil
-}
-
-func (b *HybridIwdNetworkdBackend) Initialize() error {
- if err := b.wifi.Initialize(); err != nil {
- return fmt.Errorf("iwd init: %w", err)
- }
- if err := b.l3.Initialize(); err != nil {
- return fmt.Errorf("networkd init: %w", err)
- }
- return nil
-}
-
-func (b *HybridIwdNetworkdBackend) Close() {
- b.wifi.Close()
- b.l3.Close()
-}
-
-func (b *HybridIwdNetworkdBackend) StartMonitoring(onStateChange func()) error {
- b.onStateChange = onStateChange
-
- mergedCallback := func() {
- ws, _ := b.wifi.GetCurrentState()
- ls, _ := b.l3.GetCurrentState()
-
- if ws != nil && ls != nil && ws.WiFiDevice != "" && ls.WiFiIP != "" {
- b.wifi.MarkIPConfigSeen()
- }
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
- }
-
- if err := b.wifi.StartMonitoring(mergedCallback); err != nil {
- return fmt.Errorf("wifi monitoring: %w", err)
- }
- if err := b.l3.StartMonitoring(mergedCallback); err != nil {
- return fmt.Errorf("l3 monitoring: %w", err)
- }
-
- return nil
-}
-
-func (b *HybridIwdNetworkdBackend) StopMonitoring() {
- b.wifi.StopMonitoring()
- b.l3.StopMonitoring()
-}
-
-func (b *HybridIwdNetworkdBackend) GetCurrentState() (*BackendState, error) {
- ws, err := b.wifi.GetCurrentState()
- if err != nil {
- return nil, err
- }
- ls, err := b.l3.GetCurrentState()
- if err != nil {
- return nil, err
- }
-
- merged := *ws
- merged.Backend = "iwd+networkd"
-
- merged.WiFiIP = ls.WiFiIP
- merged.EthernetConnected = ls.EthernetConnected
- merged.EthernetIP = ls.EthernetIP
- merged.EthernetDevice = ls.EthernetDevice
- merged.EthernetConnectionUuid = ls.EthernetConnectionUuid
- merged.WiredConnections = ls.WiredConnections
-
- if ls.EthernetConnected && ls.EthernetIP != "" {
- merged.NetworkStatus = StatusEthernet
- } else if ws.WiFiConnected && ls.WiFiIP != "" {
- merged.NetworkStatus = StatusWiFi
- } else {
- merged.NetworkStatus = StatusDisconnected
- }
-
- return &merged, nil
-}
-
-func (b *HybridIwdNetworkdBackend) GetWiFiEnabled() (bool, error) {
- return b.wifi.GetWiFiEnabled()
-}
-
-func (b *HybridIwdNetworkdBackend) SetWiFiEnabled(enabled bool) error {
- return b.wifi.SetWiFiEnabled(enabled)
-}
-
-func (b *HybridIwdNetworkdBackend) ScanWiFi() error {
- return b.wifi.ScanWiFi()
-}
-
-func (b *HybridIwdNetworkdBackend) GetWiFiNetworkDetails(ssid string) (*NetworkInfoResponse, error) {
- return b.wifi.GetWiFiNetworkDetails(ssid)
-}
-
-func (b *HybridIwdNetworkdBackend) ConnectWiFi(req ConnectionRequest) error {
- if err := b.wifi.ConnectWiFi(req); err != nil {
- return err
- }
-
- ws, err := b.wifi.GetCurrentState()
- if err == nil && ws.WiFiDevice != "" {
- b.l3.EnsureDhcpUp(ws.WiFiDevice)
- }
-
- return nil
-}
-
-func (b *HybridIwdNetworkdBackend) DisconnectWiFi() error {
- return b.wifi.DisconnectWiFi()
-}
-
-func (b *HybridIwdNetworkdBackend) ForgetWiFiNetwork(ssid string) error {
- return b.wifi.ForgetWiFiNetwork(ssid)
-}
-
-func (b *HybridIwdNetworkdBackend) GetWiredConnections() ([]WiredConnection, error) {
- return b.l3.GetWiredConnections()
-}
-
-func (b *HybridIwdNetworkdBackend) GetWiredNetworkDetails(uuid string) (*WiredNetworkInfoResponse, error) {
- return b.l3.GetWiredNetworkDetails(uuid)
-}
-
-func (b *HybridIwdNetworkdBackend) ConnectEthernet() error {
- return b.l3.ConnectEthernet()
-}
-
-func (b *HybridIwdNetworkdBackend) DisconnectEthernet() error {
- return b.l3.DisconnectEthernet()
-}
-
-func (b *HybridIwdNetworkdBackend) ActivateWiredConnection(uuid string) error {
- return b.l3.ActivateWiredConnection(uuid)
-}
-
-func (b *HybridIwdNetworkdBackend) ListVPNProfiles() ([]VPNProfile, error) {
- return []VPNProfile{}, nil
-}
-
-func (b *HybridIwdNetworkdBackend) ListActiveVPN() ([]VPNActive, error) {
- return []VPNActive{}, nil
-}
-
-func (b *HybridIwdNetworkdBackend) ConnectVPN(uuidOrName string, singleActive bool) error {
- return fmt.Errorf("VPN not supported in hybrid mode")
-}
-
-func (b *HybridIwdNetworkdBackend) DisconnectVPN(uuidOrName string) error {
- return fmt.Errorf("VPN not supported in hybrid mode")
-}
-
-func (b *HybridIwdNetworkdBackend) DisconnectAllVPN() error {
- return fmt.Errorf("VPN not supported in hybrid mode")
-}
-
-func (b *HybridIwdNetworkdBackend) ClearVPNCredentials(uuidOrName string) error {
- return fmt.Errorf("VPN not supported in hybrid mode")
-}
-
-func (b *HybridIwdNetworkdBackend) GetPromptBroker() PromptBroker {
- return b.wifi.GetPromptBroker()
-}
-
-func (b *HybridIwdNetworkdBackend) SetPromptBroker(broker PromptBroker) error {
- return b.wifi.SetPromptBroker(broker)
-}
-
-func (b *HybridIwdNetworkdBackend) SubmitCredentials(token string, secrets map[string]string, save bool) error {
- return b.wifi.SubmitCredentials(token, secrets, save)
-}
-
-func (b *HybridIwdNetworkdBackend) CancelCredentials(token string) error {
- return b.wifi.CancelCredentials(token)
-}
-
-func (b *HybridIwdNetworkdBackend) SetWiFiAutoconnect(ssid string, autoconnect bool) error {
- return b.wifi.SetWiFiAutoconnect(ssid, autoconnect)
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_hybrid_test.go b/nix/inputs/dms-cli/internal/server/network/backend_hybrid_test.go
deleted file mode 100644
index cd061ed..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_hybrid_test.go
+++ /dev/null
@@ -1,135 +0,0 @@
-package network
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestHybridIwdNetworkdBackend_New(t *testing.T) {
- wifi, _ := NewIWDBackend()
- l3, _ := NewSystemdNetworkdBackend()
-
- hybrid, err := NewHybridIwdNetworkdBackend(wifi, l3)
- assert.NoError(t, err)
- assert.NotNil(t, hybrid)
- assert.NotNil(t, hybrid.wifi)
- assert.NotNil(t, hybrid.l3)
-}
-
-func TestHybridIwdNetworkdBackend_GetCurrentState_MergesState(t *testing.T) {
- wifi, _ := NewIWDBackend()
- l3, _ := NewSystemdNetworkdBackend()
- hybrid, _ := NewHybridIwdNetworkdBackend(wifi, l3)
-
- wifi.state.WiFiConnected = true
- wifi.state.WiFiSSID = "TestNetwork"
- wifi.state.WiFiBSSID = "00:11:22:33:44:55"
- wifi.state.WiFiSignal = 75
- wifi.state.WiFiDevice = "wlan0"
-
- l3.state.WiFiIP = "192.168.1.100"
- l3.state.EthernetConnected = false
-
- state, err := hybrid.GetCurrentState()
- assert.NoError(t, err)
- assert.NotNil(t, state)
- assert.Equal(t, "iwd+networkd", state.Backend)
- assert.Equal(t, "TestNetwork", state.WiFiSSID)
- assert.Equal(t, "00:11:22:33:44:55", state.WiFiBSSID)
- assert.Equal(t, uint8(75), state.WiFiSignal)
- assert.Equal(t, "192.168.1.100", state.WiFiIP)
- assert.True(t, state.WiFiConnected)
- assert.False(t, state.EthernetConnected)
- assert.Equal(t, StatusWiFi, state.NetworkStatus)
-}
-
-func TestHybridIwdNetworkdBackend_GetCurrentState_EthernetPriority(t *testing.T) {
- wifi, _ := NewIWDBackend()
- l3, _ := NewSystemdNetworkdBackend()
- hybrid, _ := NewHybridIwdNetworkdBackend(wifi, l3)
-
- wifi.state.WiFiConnected = true
- wifi.state.WiFiSSID = "TestNetwork"
-
- l3.state.WiFiIP = "192.168.1.100"
- l3.state.EthernetConnected = true
- l3.state.EthernetIP = "192.168.1.50"
- l3.state.EthernetDevice = "eth0"
-
- state, err := hybrid.GetCurrentState()
- assert.NoError(t, err)
- assert.Equal(t, StatusEthernet, state.NetworkStatus)
- assert.Equal(t, "192.168.1.50", state.EthernetIP)
- assert.Equal(t, "eth0", state.EthernetDevice)
-}
-
-func TestHybridIwdNetworkdBackend_GetCurrentState_WiFiNoIP(t *testing.T) {
- wifi, _ := NewIWDBackend()
- l3, _ := NewSystemdNetworkdBackend()
- hybrid, _ := NewHybridIwdNetworkdBackend(wifi, l3)
-
- wifi.state.WiFiConnected = true
- wifi.state.WiFiSSID = "TestNetwork"
-
- l3.state.WiFiIP = ""
- l3.state.EthernetConnected = false
-
- state, err := hybrid.GetCurrentState()
- assert.NoError(t, err)
- assert.Equal(t, StatusDisconnected, state.NetworkStatus)
- assert.True(t, state.WiFiConnected)
- assert.Empty(t, state.WiFiIP)
-}
-
-func TestHybridIwdNetworkdBackend_WiFiDelegation(t *testing.T) {
- wifi, _ := NewIWDBackend()
- l3, _ := NewSystemdNetworkdBackend()
- hybrid, _ := NewHybridIwdNetworkdBackend(wifi, l3)
-
- enabled, err := hybrid.GetWiFiEnabled()
- assert.NoError(t, err)
- assert.True(t, enabled)
-
- state, err := hybrid.GetCurrentState()
- assert.NoError(t, err)
- assert.NotNil(t, state)
- assert.Equal(t, "iwd+networkd", state.Backend)
-}
-
-func TestHybridIwdNetworkdBackend_WiredDelegation(t *testing.T) {
- wifi, _ := NewIWDBackend()
- l3, _ := NewSystemdNetworkdBackend()
- hybrid, _ := NewHybridIwdNetworkdBackend(wifi, l3)
-
- conns, err := hybrid.GetWiredConnections()
- assert.NoError(t, err)
- assert.Empty(t, conns)
-}
-
-func TestHybridIwdNetworkdBackend_VPNNotSupported(t *testing.T) {
- wifi, _ := NewIWDBackend()
- l3, _ := NewSystemdNetworkdBackend()
- hybrid, _ := NewHybridIwdNetworkdBackend(wifi, l3)
-
- profiles, err := hybrid.ListVPNProfiles()
- assert.NoError(t, err)
- assert.Empty(t, profiles)
-
- active, err := hybrid.ListActiveVPN()
- assert.NoError(t, err)
- assert.Empty(t, active)
-
- err = hybrid.ConnectVPN("test", false)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not supported")
-}
-
-func TestHybridIwdNetworkdBackend_PromptBrokerDelegation(t *testing.T) {
- wifi, _ := NewIWDBackend()
- l3, _ := NewSystemdNetworkdBackend()
- hybrid, _ := NewHybridIwdNetworkdBackend(wifi, l3)
-
- broker := hybrid.GetPromptBroker()
- assert.Nil(t, broker)
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_iwd.go b/nix/inputs/dms-cli/internal/server/network/backend_iwd.go
deleted file mode 100644
index 0a7d611..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_iwd.go
+++ /dev/null
@@ -1,222 +0,0 @@
-package network
-
-import (
- "fmt"
- "sync"
- "time"
-
- "github.com/godbus/dbus/v5"
-)
-
-const (
- iwdBusName = "net.connman.iwd"
- iwdObjectPath = "/"
- iwdAdapterInterface = "net.connman.iwd.Adapter"
- iwdDeviceInterface = "net.connman.iwd.Device"
- iwdStationInterface = "net.connman.iwd.Station"
- iwdNetworkInterface = "net.connman.iwd.Network"
- iwdKnownNetworkInterface = "net.connman.iwd.KnownNetwork"
- dbusObjectManager = "org.freedesktop.DBus.ObjectManager"
- dbusPropertiesInterface = "org.freedesktop.DBus.Properties"
-)
-
-type connectAttempt struct {
- ssid string
- netPath dbus.ObjectPath
- start time.Time
- deadline time.Time
- sawAuthish bool
- connectedAt time.Time
- sawIPConfig bool
- sawPromptRetry bool
- finalized bool
- mu sync.Mutex
-}
-
-type IWDBackend struct {
- conn *dbus.Conn
- state *BackendState
- stateMutex sync.RWMutex
- promptBroker PromptBroker
- onStateChange func()
-
- devicePath dbus.ObjectPath
- stationPath dbus.ObjectPath
- adapterPath dbus.ObjectPath
-
- iwdAgent *IWDAgent
-
- stopChan chan struct{}
- sigWG sync.WaitGroup
- curAttempt *connectAttempt
- attemptMutex sync.RWMutex
- recentScans map[string]time.Time
- recentScansMu sync.Mutex
-}
-
-func NewIWDBackend() (*IWDBackend, error) {
- backend := &IWDBackend{
- state: &BackendState{
- Backend: "iwd",
- WiFiEnabled: true,
- },
- stopChan: make(chan struct{}),
- recentScans: make(map[string]time.Time),
- }
-
- return backend, nil
-}
-
-func (b *IWDBackend) Initialize() error {
- conn, err := dbus.ConnectSystemBus()
- if err != nil {
- return fmt.Errorf("failed to connect to system bus: %w", err)
- }
- b.conn = conn
-
- if err := b.discoverDevices(); err != nil {
- conn.Close()
- return fmt.Errorf("failed to discover iwd devices: %w", err)
- }
-
- if err := b.updateState(); err != nil {
- conn.Close()
- return fmt.Errorf("failed to get initial state: %w", err)
- }
-
- return nil
-}
-
-func (b *IWDBackend) Close() {
- close(b.stopChan)
- b.sigWG.Wait()
-
- if b.iwdAgent != nil {
- b.iwdAgent.Close()
- }
-
- if b.conn != nil {
- b.conn.Close()
- }
-}
-
-func (b *IWDBackend) discoverDevices() error {
- obj := b.conn.Object(iwdBusName, iwdObjectPath)
-
- var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant
- err := obj.Call(dbusObjectManager+".GetManagedObjects", 0).Store(&objects)
- if err != nil {
- return fmt.Errorf("failed to get managed objects: %w", err)
- }
-
- for path, interfaces := range objects {
- if _, hasStation := interfaces[iwdStationInterface]; hasStation {
- b.stationPath = path
- }
- if _, hasDevice := interfaces[iwdDeviceInterface]; hasDevice {
- b.devicePath = path
-
- if devProps, ok := interfaces[iwdDeviceInterface]; ok {
- if nameVar, ok := devProps["Name"]; ok {
- if name, ok := nameVar.Value().(string); ok {
- b.stateMutex.Lock()
- b.state.WiFiDevice = name
- b.stateMutex.Unlock()
- }
- }
- }
- }
- if _, hasAdapter := interfaces[iwdAdapterInterface]; hasAdapter {
- b.adapterPath = path
- }
- }
-
- if b.stationPath == "" || b.devicePath == "" {
- return fmt.Errorf("no WiFi device found")
- }
-
- return nil
-}
-
-func (b *IWDBackend) GetCurrentState() (*BackendState, error) {
- state := *b.state
- state.WiFiNetworks = append([]WiFiNetwork(nil), b.state.WiFiNetworks...)
- state.WiredConnections = append([]WiredConnection(nil), b.state.WiredConnections...)
-
- return &state, nil
-}
-
-func (b *IWDBackend) OnUserCanceledPrompt() {
- b.setConnectError("user-canceled")
- if b.onStateChange != nil {
- b.onStateChange()
- }
-}
-
-func (b *IWDBackend) OnPromptRetry(ssid string) {
- b.attemptMutex.RLock()
- att := b.curAttempt
- b.attemptMutex.RUnlock()
-
- if att != nil && att.ssid == ssid {
- att.mu.Lock()
- att.sawPromptRetry = true
- att.mu.Unlock()
- }
-}
-
-func (b *IWDBackend) MarkIPConfigSeen() {
- b.attemptMutex.RLock()
- att := b.curAttempt
- b.attemptMutex.RUnlock()
- if att != nil {
- att.mu.Lock()
- att.sawIPConfig = true
- att.mu.Unlock()
- }
-}
-
-func (b *IWDBackend) GetPromptBroker() PromptBroker {
- return b.promptBroker
-}
-
-func (b *IWDBackend) SetPromptBroker(broker PromptBroker) error {
- if broker == nil {
- return fmt.Errorf("broker cannot be nil")
- }
-
- b.promptBroker = broker
- return nil
-}
-
-func (b *IWDBackend) SubmitCredentials(token string, secrets map[string]string, save bool) error {
- if b.promptBroker == nil {
- return fmt.Errorf("prompt broker not initialized")
- }
-
- return b.promptBroker.Resolve(token, PromptReply{
- Secrets: secrets,
- Save: save,
- Cancel: false,
- })
-}
-
-func (b *IWDBackend) CancelCredentials(token string) error {
- if b.promptBroker == nil {
- return fmt.Errorf("prompt broker not initialized")
- }
-
- return b.promptBroker.Resolve(token, PromptReply{
- Cancel: true,
- })
-}
-
-func (b *IWDBackend) StopMonitoring() {
- select {
- case <-b.stopChan:
- return
- default:
- close(b.stopChan)
- }
- b.sigWG.Wait()
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_iwd_signals.go b/nix/inputs/dms-cli/internal/server/network/backend_iwd_signals.go
deleted file mode 100644
index 62b4d5b..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_iwd_signals.go
+++ /dev/null
@@ -1,355 +0,0 @@
-package network
-
-import (
- "fmt"
- "time"
-
- "github.com/godbus/dbus/v5"
-)
-
-func (b *IWDBackend) StartMonitoring(onStateChange func()) error {
- b.onStateChange = onStateChange
-
- if b.promptBroker != nil {
- agent, err := NewIWDAgent(b.promptBroker)
- if err != nil {
- return fmt.Errorf("failed to start IWD agent: %w", err)
- }
- agent.onUserCanceled = b.OnUserCanceledPrompt
- agent.onPromptRetry = b.OnPromptRetry
- b.iwdAgent = agent
- }
-
- sigChan := make(chan *dbus.Signal, 100)
- b.conn.Signal(sigChan)
-
- if b.devicePath != "" {
- err := b.conn.AddMatchSignal(
- dbus.WithMatchObjectPath(b.devicePath),
- dbus.WithMatchInterface(dbusPropertiesInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- )
- if err != nil {
- return fmt.Errorf("failed to add device signal match: %w", err)
- }
- }
-
- if b.stationPath != "" {
- err := b.conn.AddMatchSignal(
- dbus.WithMatchObjectPath(b.stationPath),
- dbus.WithMatchInterface(dbusPropertiesInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- )
- if err != nil {
- return fmt.Errorf("failed to add station signal match: %w", err)
- }
- }
-
- b.sigWG.Add(1)
- go b.signalHandler(sigChan)
-
- return nil
-}
-
-func (b *IWDBackend) signalHandler(sigChan chan *dbus.Signal) {
- defer b.sigWG.Done()
-
- for {
- select {
- case <-b.stopChan:
- b.conn.RemoveSignal(sigChan)
- close(sigChan)
- return
-
- case sig := <-sigChan:
- if sig == nil {
- return
- }
-
- if sig.Name != dbusPropertiesInterface+".PropertiesChanged" {
- continue
- }
-
- if len(sig.Body) < 2 {
- continue
- }
-
- iface, ok := sig.Body[0].(string)
- if !ok {
- continue
- }
-
- changed, ok := sig.Body[1].(map[string]dbus.Variant)
- if !ok {
- continue
- }
-
- stateChanged := false
-
- switch iface {
- case iwdDeviceInterface:
- if sig.Path == b.devicePath {
- if poweredVar, ok := changed["Powered"]; ok {
- if powered, ok := poweredVar.Value().(bool); ok {
- b.stateMutex.Lock()
- if b.state.WiFiEnabled != powered {
- b.state.WiFiEnabled = powered
- stateChanged = true
- }
- b.stateMutex.Unlock()
- }
- }
- }
-
- case iwdStationInterface:
- if sig.Path == b.stationPath {
- if scanningVar, ok := changed["Scanning"]; ok {
- if scanning, ok := scanningVar.Value().(bool); ok && !scanning {
- networks, err := b.updateWiFiNetworks()
- if err == nil {
- b.stateMutex.Lock()
- b.state.WiFiNetworks = networks
- b.stateMutex.Unlock()
- stateChanged = true
- }
-
- b.stateMutex.RLock()
- wifiConnected := b.state.WiFiConnected
- b.stateMutex.RUnlock()
-
- if wifiConnected {
- stationObj := b.conn.Object(iwdBusName, b.stationPath)
- connNetVar, err := stationObj.GetProperty(iwdStationInterface + ".ConnectedNetwork")
- if err == nil && connNetVar.Value() != nil {
- if netPath, ok := connNetVar.Value().(dbus.ObjectPath); ok && netPath != "/" {
- var orderedNetworks [][]dbus.Variant
- err = stationObj.Call(iwdStationInterface+".GetOrderedNetworks", 0).Store(&orderedNetworks)
- if err == nil {
- for _, netData := range orderedNetworks {
- if len(netData) < 2 {
- continue
- }
- currentNetPath, ok := netData[0].Value().(dbus.ObjectPath)
- if !ok || currentNetPath != netPath {
- continue
- }
- signalStrength, ok := netData[1].Value().(int16)
- if !ok {
- continue
- }
- signalDbm := signalStrength / 100
- signal := uint8(signalDbm + 100)
- if signalDbm > 0 {
- signal = 100
- } else if signalDbm < -100 {
- signal = 0
- }
- b.stateMutex.Lock()
- if b.state.WiFiSignal != signal {
- b.state.WiFiSignal = signal
- stateChanged = true
- }
- b.stateMutex.Unlock()
- break
- }
- }
- }
- }
- }
- }
- }
-
- if stateVar, ok := changed["State"]; ok {
- if state, ok := stateVar.Value().(string); ok {
- b.attemptMutex.RLock()
- att := b.curAttempt
- b.attemptMutex.RUnlock()
-
- var connPath dbus.ObjectPath
- if v, ok := changed["ConnectedNetwork"]; ok {
- if v.Value() != nil {
- if p, ok := v.Value().(dbus.ObjectPath); ok {
- connPath = p
- }
- }
- }
- if connPath == "" {
- station := b.conn.Object(iwdBusName, b.stationPath)
- if cnVar, err := station.GetProperty(iwdStationInterface + ".ConnectedNetwork"); err == nil && cnVar.Value() != nil {
- cnVar.Store(&connPath)
- }
- }
-
- b.stateMutex.RLock()
- prevConnected := b.state.WiFiConnected
- prevSSID := b.state.WiFiSSID
- b.stateMutex.RUnlock()
-
- targetPath := dbus.ObjectPath("")
- if att != nil {
- targetPath = att.netPath
- }
-
- isTarget := att != nil && targetPath != "" && connPath == targetPath
-
- if att != nil {
- switch state {
- case "authenticating", "associating", "associated", "roaming":
- att.mu.Lock()
- att.sawAuthish = true
- att.mu.Unlock()
- }
- }
-
- if att != nil && state == "connected" && isTarget {
- att.mu.Lock()
- if att.connectedAt.IsZero() {
- att.connectedAt = time.Now()
- }
- att.mu.Unlock()
- }
-
- if att != nil && state == "configuring" {
- att.mu.Lock()
- att.sawIPConfig = true
- att.mu.Unlock()
- }
-
- switch state {
- case "connected":
- b.stateMutex.Lock()
- b.state.WiFiConnected = true
- b.state.NetworkStatus = StatusWiFi
- b.state.IsConnecting = false
- b.state.ConnectingSSID = ""
- b.state.LastError = ""
- b.stateMutex.Unlock()
-
- if connPath != "" && connPath != "/" {
- netObj := b.conn.Object(iwdBusName, connPath)
- if nameVar, err := netObj.GetProperty(iwdNetworkInterface + ".Name"); err == nil {
- if name, ok := nameVar.Value().(string); ok {
- b.stateMutex.Lock()
- b.state.WiFiSSID = name
- b.stateMutex.Unlock()
- }
- }
- }
-
- stateChanged = true
-
- if att != nil && isTarget {
- go func(attLocal *connectAttempt, tgt dbus.ObjectPath) {
- time.Sleep(3 * time.Second)
- station := b.conn.Object(iwdBusName, b.stationPath)
- var nowState string
- if stVar, err := station.GetProperty(iwdStationInterface + ".State"); err == nil {
- stVar.Store(&nowState)
- }
- var nowConn dbus.ObjectPath
- if cnVar, err := station.GetProperty(iwdStationInterface + ".ConnectedNetwork"); err == nil && cnVar.Value() != nil {
- cnVar.Store(&nowConn)
- }
-
- if nowState == "connected" && nowConn == tgt {
- b.finalizeAttempt(attLocal, "")
- b.attemptMutex.Lock()
- if b.curAttempt == attLocal {
- b.curAttempt = nil
- }
- b.attemptMutex.Unlock()
- }
- }(att, targetPath)
- }
-
- case "disconnecting", "disconnected":
- if att != nil {
- wasConnectedToTarget := prevConnected && prevSSID == att.ssid
- if wasConnectedToTarget || isTarget {
- code := b.classifyAttempt(att)
- b.finalizeAttempt(att, code)
- b.attemptMutex.Lock()
- if b.curAttempt == att {
- b.curAttempt = nil
- }
- b.attemptMutex.Unlock()
- }
- }
-
- b.stateMutex.Lock()
- b.state.WiFiConnected = false
- if state == "disconnected" {
- b.state.NetworkStatus = StatusDisconnected
- }
- b.stateMutex.Unlock()
- stateChanged = true
- }
- }
- }
-
- if connNetVar, ok := changed["ConnectedNetwork"]; ok {
- if netPath, ok := connNetVar.Value().(dbus.ObjectPath); ok && netPath != "/" {
- netObj := b.conn.Object(iwdBusName, netPath)
- nameVar, err := netObj.GetProperty(iwdNetworkInterface + ".Name")
- if err == nil {
- if name, ok := nameVar.Value().(string); ok {
- b.stateMutex.Lock()
- if b.state.WiFiSSID != name {
- b.state.WiFiSSID = name
- stateChanged = true
- }
- b.stateMutex.Unlock()
- }
- }
-
- stationObj := b.conn.Object(iwdBusName, b.stationPath)
- var orderedNetworks [][]dbus.Variant
- err = stationObj.Call(iwdStationInterface+".GetOrderedNetworks", 0).Store(&orderedNetworks)
- if err == nil {
- for _, netData := range orderedNetworks {
- if len(netData) < 2 {
- continue
- }
- currentNetPath, ok := netData[0].Value().(dbus.ObjectPath)
- if !ok || currentNetPath != netPath {
- continue
- }
- signalStrength, ok := netData[1].Value().(int16)
- if !ok {
- continue
- }
- signalDbm := signalStrength / 100
- signal := uint8(signalDbm + 100)
- if signalDbm > 0 {
- signal = 100
- } else if signalDbm < -100 {
- signal = 0
- }
- b.stateMutex.Lock()
- if b.state.WiFiSignal != signal {
- b.state.WiFiSignal = signal
- stateChanged = true
- }
- b.stateMutex.Unlock()
- break
- }
- }
- } else {
- b.stateMutex.Lock()
- if b.state.WiFiSSID != "" {
- b.state.WiFiSSID = ""
- b.state.WiFiSignal = 0
- stateChanged = true
- }
- b.stateMutex.Unlock()
- }
- }
- }
- }
-
- if stateChanged && b.onStateChange != nil {
- b.onStateChange()
- }
- }
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_iwd_test.go b/nix/inputs/dms-cli/internal/server/network/backend_iwd_test.go
deleted file mode 100644
index 829e413..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_iwd_test.go
+++ /dev/null
@@ -1,212 +0,0 @@
-package network
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestIWDBackend_MarkIPConfigSeen(t *testing.T) {
- backend, _ := NewIWDBackend()
-
- att := &connectAttempt{
- ssid: "TestNetwork",
- netPath: "/net/connman/iwd/0/1/test",
- start: time.Now(),
- deadline: time.Now().Add(15 * time.Second),
- }
-
- backend.attemptMutex.Lock()
- backend.curAttempt = att
- backend.attemptMutex.Unlock()
-
- backend.MarkIPConfigSeen()
-
- att.mu.Lock()
- assert.True(t, att.sawIPConfig, "sawIPConfig should be true after MarkIPConfigSeen")
- att.mu.Unlock()
-}
-
-func TestIWDBackend_MarkIPConfigSeen_NoAttempt(t *testing.T) {
- backend, _ := NewIWDBackend()
-
- backend.attemptMutex.Lock()
- backend.curAttempt = nil
- backend.attemptMutex.Unlock()
-
- backend.MarkIPConfigSeen()
-}
-
-func TestIWDBackend_OnPromptRetry(t *testing.T) {
- backend, _ := NewIWDBackend()
-
- att := &connectAttempt{
- ssid: "TestNetwork",
- netPath: "/net/connman/iwd/0/1/test",
- start: time.Now(),
- deadline: time.Now().Add(15 * time.Second),
- }
-
- backend.attemptMutex.Lock()
- backend.curAttempt = att
- backend.attemptMutex.Unlock()
-
- backend.OnPromptRetry("TestNetwork")
-
- att.mu.Lock()
- assert.True(t, att.sawPromptRetry, "sawPromptRetry should be true after OnPromptRetry")
- att.mu.Unlock()
-}
-
-func TestIWDBackend_OnPromptRetry_WrongSSID(t *testing.T) {
- backend, _ := NewIWDBackend()
-
- att := &connectAttempt{
- ssid: "TestNetwork",
- netPath: "/net/connman/iwd/0/1/test",
- start: time.Now(),
- deadline: time.Now().Add(15 * time.Second),
- }
-
- backend.attemptMutex.Lock()
- backend.curAttempt = att
- backend.attemptMutex.Unlock()
-
- backend.OnPromptRetry("DifferentNetwork")
-
- att.mu.Lock()
- assert.False(t, att.sawPromptRetry, "sawPromptRetry should remain false for different SSID")
- att.mu.Unlock()
-}
-
-func TestIWDBackend_ClassifyAttempt_BadCredentials_PromptRetry(t *testing.T) {
- backend, _ := NewIWDBackend()
-
- att := &connectAttempt{
- ssid: "TestNetwork",
- netPath: "/test",
- start: time.Now().Add(-5 * time.Second),
- deadline: time.Now().Add(10 * time.Second),
- sawPromptRetry: true,
- }
-
- code := backend.classifyAttempt(att)
- assert.Equal(t, "bad-credentials", code)
-}
-
-func TestIWDBackend_ClassifyAttempt_DhcpTimeout(t *testing.T) {
- backend, _ := NewIWDBackend()
-
- att := &connectAttempt{
- ssid: "TestNetwork",
- netPath: "/test",
- start: time.Now().Add(-13 * time.Second),
- deadline: time.Now().Add(2 * time.Second),
- sawAuthish: true,
- sawIPConfig: false,
- }
-
- code := backend.classifyAttempt(att)
- assert.Equal(t, "dhcp-timeout", code)
-}
-
-func TestIWDBackend_ClassifyAttempt_AssocTimeout(t *testing.T) {
- backend, _ := NewIWDBackend()
-
- att := &connectAttempt{
- ssid: "TestNetwork",
- netPath: "/test",
- start: time.Now().Add(-5 * time.Second),
- deadline: time.Now().Add(10 * time.Second),
- }
-
- backend.recentScansMu.Lock()
- backend.recentScans["TestNetwork"] = time.Now()
- backend.recentScansMu.Unlock()
-
- code := backend.classifyAttempt(att)
- assert.Equal(t, "assoc-timeout", code)
-}
-
-func TestIWDBackend_ClassifyAttempt_NoSuchSSID(t *testing.T) {
- backend, _ := NewIWDBackend()
-
- att := &connectAttempt{
- ssid: "TestNetwork",
- netPath: "/test",
- start: time.Now().Add(-5 * time.Second),
- deadline: time.Now().Add(10 * time.Second),
- }
-
- code := backend.classifyAttempt(att)
- assert.Equal(t, "no-such-ssid", code)
-}
-
-func TestIWDBackend_MapIwdDBusError(t *testing.T) {
- backend, _ := NewIWDBackend()
-
- testCases := []struct {
- name string
- expected string
- }{
- {"net.connman.iwd.Error.AlreadyConnected", "already-connected"},
- {"net.connman.iwd.Error.AuthenticationFailed", "bad-credentials"},
- {"net.connman.iwd.Error.InvalidKey", "bad-credentials"},
- {"net.connman.iwd.Error.IncorrectPassphrase", "bad-credentials"},
- {"net.connman.iwd.Error.NotFound", "no-such-ssid"},
- {"net.connman.iwd.Error.NotSupported", "connection-failed"},
- {"net.connman.iwd.Agent.Error.Canceled", "user-canceled"},
- {"net.connman.iwd.Error.Unknown", "connection-failed"},
- }
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- code := backend.mapIwdDBusError(tc.name)
- assert.Equal(t, tc.expected, code)
- })
- }
-}
-
-func TestConnectAttempt_Finalization(t *testing.T) {
- backend, _ := NewIWDBackend()
- backend.state = &BackendState{}
-
- att := &connectAttempt{
- ssid: "TestNetwork",
- netPath: "/test",
- start: time.Now(),
- deadline: time.Now().Add(15 * time.Second),
- }
-
- backend.finalizeAttempt(att, "bad-credentials")
-
- att.mu.Lock()
- assert.True(t, att.finalized)
- att.mu.Unlock()
-
- backend.stateMutex.RLock()
- assert.False(t, backend.state.IsConnecting)
- assert.Empty(t, backend.state.ConnectingSSID)
- assert.Equal(t, "bad-credentials", backend.state.LastError)
- backend.stateMutex.RUnlock()
-}
-
-func TestConnectAttempt_DoubleFinalization(t *testing.T) {
- backend, _ := NewIWDBackend()
- backend.state = &BackendState{}
-
- att := &connectAttempt{
- ssid: "TestNetwork",
- netPath: "/test",
- start: time.Now(),
- deadline: time.Now().Add(15 * time.Second),
- }
-
- backend.finalizeAttempt(att, "bad-credentials")
- backend.finalizeAttempt(att, "dhcp-timeout")
-
- backend.stateMutex.RLock()
- assert.Equal(t, "bad-credentials", backend.state.LastError)
- backend.stateMutex.RUnlock()
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_iwd_unimplemented.go b/nix/inputs/dms-cli/internal/server/network/backend_iwd_unimplemented.go
deleted file mode 100644
index 374d0bf..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_iwd_unimplemented.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package network
-
-import "fmt"
-
-func (b *IWDBackend) GetWiredConnections() ([]WiredConnection, error) {
- return nil, fmt.Errorf("wired connections not supported by iwd")
-}
-
-func (b *IWDBackend) GetWiredNetworkDetails(uuid string) (*WiredNetworkInfoResponse, error) {
- return nil, fmt.Errorf("wired connections not supported by iwd")
-}
-
-func (b *IWDBackend) ConnectEthernet() error {
- return fmt.Errorf("wired connections not supported by iwd")
-}
-
-func (b *IWDBackend) DisconnectEthernet() error {
- return fmt.Errorf("wired connections not supported by iwd")
-}
-
-func (b *IWDBackend) ActivateWiredConnection(uuid string) error {
- return fmt.Errorf("wired connections not supported by iwd")
-}
-
-func (b *IWDBackend) ListVPNProfiles() ([]VPNProfile, error) {
- return nil, fmt.Errorf("VPN not supported by iwd backend")
-}
-
-func (b *IWDBackend) ListActiveVPN() ([]VPNActive, error) {
- return nil, fmt.Errorf("VPN not supported by iwd backend")
-}
-
-func (b *IWDBackend) ConnectVPN(uuidOrName string, singleActive bool) error {
- return fmt.Errorf("VPN not supported by iwd backend")
-}
-
-func (b *IWDBackend) DisconnectVPN(uuidOrName string) error {
- return fmt.Errorf("VPN not supported by iwd backend")
-}
-
-func (b *IWDBackend) DisconnectAllVPN() error {
- return fmt.Errorf("VPN not supported by iwd backend")
-}
-
-func (b *IWDBackend) ClearVPNCredentials(uuidOrName string) error {
- return fmt.Errorf("VPN not supported by iwd backend")
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_iwd_wifi.go b/nix/inputs/dms-cli/internal/server/network/backend_iwd_wifi.go
deleted file mode 100644
index a56ed06..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_iwd_wifi.go
+++ /dev/null
@@ -1,662 +0,0 @@
-package network
-
-import (
- "fmt"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/errdefs"
- "github.com/godbus/dbus/v5"
-)
-
-func (b *IWDBackend) updateState() error {
- if b.devicePath == "" {
- return nil
- }
-
- obj := b.conn.Object(iwdBusName, b.devicePath)
-
- poweredVar, err := obj.GetProperty(iwdDeviceInterface + ".Powered")
- if err == nil {
- if powered, ok := poweredVar.Value().(bool); ok {
- b.stateMutex.Lock()
- b.state.WiFiEnabled = powered
- b.stateMutex.Unlock()
- }
- }
-
- if b.stationPath == "" {
- return nil
- }
-
- stationObj := b.conn.Object(iwdBusName, b.stationPath)
-
- stateVar, err := stationObj.GetProperty(iwdStationInterface + ".State")
- if err == nil {
- if state, ok := stateVar.Value().(string); ok {
- b.stateMutex.Lock()
- b.state.WiFiConnected = (state == "connected")
- if state == "connected" {
- b.state.NetworkStatus = StatusWiFi
- } else {
- b.state.NetworkStatus = StatusDisconnected
- }
- b.stateMutex.Unlock()
- }
- }
-
- connNetVar, err := stationObj.GetProperty(iwdStationInterface + ".ConnectedNetwork")
- if err == nil && connNetVar.Value() != nil {
- if netPath, ok := connNetVar.Value().(dbus.ObjectPath); ok && netPath != "/" {
- netObj := b.conn.Object(iwdBusName, netPath)
-
- nameVar, err := netObj.GetProperty(iwdNetworkInterface + ".Name")
- if err == nil {
- if name, ok := nameVar.Value().(string); ok {
- b.stateMutex.Lock()
- b.state.WiFiSSID = name
- b.stateMutex.Unlock()
- }
- }
-
- var orderedNetworks [][]dbus.Variant
- err = stationObj.Call(iwdStationInterface+".GetOrderedNetworks", 0).Store(&orderedNetworks)
- if err == nil {
- for _, netData := range orderedNetworks {
- if len(netData) < 2 {
- continue
- }
- currentNetPath, ok := netData[0].Value().(dbus.ObjectPath)
- if !ok || currentNetPath != netPath {
- continue
- }
- signalStrength, ok := netData[1].Value().(int16)
- if !ok {
- continue
- }
- signalDbm := signalStrength / 100
- signal := uint8(signalDbm + 100)
- if signalDbm > 0 {
- signal = 100
- } else if signalDbm < -100 {
- signal = 0
- }
- b.stateMutex.Lock()
- b.state.WiFiSignal = signal
- b.stateMutex.Unlock()
- break
- }
- }
- }
- }
-
- networks, err := b.updateWiFiNetworks()
- if err == nil {
- b.stateMutex.Lock()
- b.state.WiFiNetworks = networks
- b.stateMutex.Unlock()
- }
-
- return nil
-}
-
-func (b *IWDBackend) GetWiFiEnabled() (bool, error) {
- b.stateMutex.RLock()
- defer b.stateMutex.RUnlock()
- return b.state.WiFiEnabled, nil
-}
-
-func (b *IWDBackend) SetWiFiEnabled(enabled bool) error {
- if b.devicePath == "" {
- return fmt.Errorf("no WiFi device available")
- }
-
- obj := b.conn.Object(iwdBusName, b.devicePath)
- call := obj.Call(dbusPropertiesInterface+".Set", 0, iwdDeviceInterface, "Powered", dbus.MakeVariant(enabled))
- if call.Err != nil {
- return fmt.Errorf("failed to set WiFi enabled: %w", call.Err)
- }
-
- b.stateMutex.Lock()
- b.state.WiFiEnabled = enabled
- b.stateMutex.Unlock()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- return nil
-}
-
-func (b *IWDBackend) ScanWiFi() error {
- if b.stationPath == "" {
- return fmt.Errorf("no WiFi device available")
- }
-
- obj := b.conn.Object(iwdBusName, b.stationPath)
-
- scanningVar, err := obj.GetProperty(iwdStationInterface + ".Scanning")
- if err != nil {
- return fmt.Errorf("failed to check scanning state: %w", err)
- }
-
- if scanning, ok := scanningVar.Value().(bool); ok && scanning {
- return fmt.Errorf("scan already in progress")
- }
-
- call := obj.Call(iwdStationInterface+".Scan", 0)
- if call.Err != nil {
- return fmt.Errorf("scan request failed: %w", call.Err)
- }
-
- return nil
-}
-
-func (b *IWDBackend) updateWiFiNetworks() ([]WiFiNetwork, error) {
- if b.stationPath == "" {
- return nil, fmt.Errorf("no WiFi device available")
- }
-
- obj := b.conn.Object(iwdBusName, b.stationPath)
-
- var orderedNetworks [][]dbus.Variant
- err := obj.Call(iwdStationInterface+".GetOrderedNetworks", 0).Store(&orderedNetworks)
- if err != nil {
- return nil, fmt.Errorf("failed to get networks: %w", err)
- }
-
- knownNetworks, err := b.getKnownNetworks()
- if err != nil {
- knownNetworks = make(map[string]bool)
- }
-
- autoconnectMap, err := b.getAutoconnectSettings()
- if err != nil {
- autoconnectMap = make(map[string]bool)
- }
-
- b.stateMutex.RLock()
- currentSSID := b.state.WiFiSSID
- wifiConnected := b.state.WiFiConnected
- b.stateMutex.RUnlock()
-
- networks := make([]WiFiNetwork, 0, len(orderedNetworks))
- for _, netData := range orderedNetworks {
- if len(netData) < 2 {
- continue
- }
-
- networkPath, ok := netData[0].Value().(dbus.ObjectPath)
- if !ok {
- continue
- }
-
- signalStrength, ok := netData[1].Value().(int16)
- if !ok {
- continue
- }
-
- netObj := b.conn.Object(iwdBusName, networkPath)
-
- nameVar, err := netObj.GetProperty(iwdNetworkInterface + ".Name")
- if err != nil {
- continue
- }
- name, ok := nameVar.Value().(string)
- if !ok {
- continue
- }
-
- typeVar, err := netObj.GetProperty(iwdNetworkInterface + ".Type")
- if err != nil {
- continue
- }
- netType, ok := typeVar.Value().(string)
- if !ok {
- continue
- }
-
- signalDbm := signalStrength / 100
- signal := uint8(signalDbm + 100)
- if signalDbm > 0 {
- signal = 100
- } else if signalDbm < -100 {
- signal = 0
- }
-
- secured := netType != "open"
-
- network := WiFiNetwork{
- SSID: name,
- Signal: signal,
- Secured: secured,
- Connected: wifiConnected && name == currentSSID,
- Saved: knownNetworks[name],
- Autoconnect: autoconnectMap[name],
- Enterprise: netType == "8021x",
- }
-
- networks = append(networks, network)
- }
-
- sortWiFiNetworks(networks)
-
- b.stateMutex.Lock()
- b.state.WiFiNetworks = networks
- b.stateMutex.Unlock()
-
- now := time.Now()
- b.recentScansMu.Lock()
- for _, net := range networks {
- b.recentScans[net.SSID] = now
- }
- b.recentScansMu.Unlock()
-
- return networks, nil
-}
-
-func (b *IWDBackend) getKnownNetworks() (map[string]bool, error) {
- obj := b.conn.Object(iwdBusName, iwdObjectPath)
-
- var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant
- err := obj.Call(dbusObjectManager+".GetManagedObjects", 0).Store(&objects)
- if err != nil {
- return nil, err
- }
-
- known := make(map[string]bool)
- for _, interfaces := range objects {
- if knownProps, ok := interfaces[iwdKnownNetworkInterface]; ok {
- if nameVar, ok := knownProps["Name"]; ok {
- if name, ok := nameVar.Value().(string); ok {
- known[name] = true
- }
- }
- }
- }
-
- return known, nil
-}
-
-func (b *IWDBackend) getAutoconnectSettings() (map[string]bool, error) {
- obj := b.conn.Object(iwdBusName, iwdObjectPath)
-
- var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant
- err := obj.Call(dbusObjectManager+".GetManagedObjects", 0).Store(&objects)
- if err != nil {
- return nil, err
- }
-
- autoconnectMap := make(map[string]bool)
- for _, interfaces := range objects {
- if knownProps, ok := interfaces[iwdKnownNetworkInterface]; ok {
- if nameVar, ok := knownProps["Name"]; ok {
- if name, ok := nameVar.Value().(string); ok {
- autoconnect := true
- if acVar, ok := knownProps["AutoConnect"]; ok {
- if ac, ok := acVar.Value().(bool); ok {
- autoconnect = ac
- }
- }
- autoconnectMap[name] = autoconnect
- }
- }
- }
- }
-
- return autoconnectMap, nil
-}
-
-func (b *IWDBackend) GetWiFiNetworkDetails(ssid string) (*NetworkInfoResponse, error) {
- b.stateMutex.RLock()
- networks := b.state.WiFiNetworks
- b.stateMutex.RUnlock()
-
- var found *WiFiNetwork
- for i := range networks {
- if networks[i].SSID == ssid {
- found = &networks[i]
- break
- }
- }
-
- if found == nil {
- return nil, fmt.Errorf("network not found: %s", ssid)
- }
-
- return &NetworkInfoResponse{
- SSID: ssid,
- Bands: []WiFiNetwork{*found},
- }, nil
-}
-
-func (b *IWDBackend) setConnectError(code string) {
- b.stateMutex.Lock()
- b.state.IsConnecting = false
- b.state.ConnectingSSID = ""
- b.state.LastError = code
- b.stateMutex.Unlock()
-}
-
-func (b *IWDBackend) seenInRecentScan(ssid string) bool {
- b.recentScansMu.Lock()
- defer b.recentScansMu.Unlock()
- lastSeen, ok := b.recentScans[ssid]
- return ok && time.Since(lastSeen) < 30*time.Second
-}
-
-func (b *IWDBackend) classifyAttempt(att *connectAttempt) string {
- att.mu.Lock()
- defer att.mu.Unlock()
-
- if att.sawPromptRetry {
- return errdefs.ErrBadCredentials
- }
-
- if !att.connectedAt.IsZero() && !att.sawIPConfig {
- connDuration := time.Since(att.connectedAt)
- if connDuration > 500*time.Millisecond && connDuration < 3*time.Second {
- return errdefs.ErrBadCredentials
- }
- }
-
- if (att.sawAuthish || !att.connectedAt.IsZero()) && !att.sawIPConfig {
- if time.Since(att.start) > 12*time.Second {
- return errdefs.ErrDhcpTimeout
- }
- }
-
- if !att.sawAuthish && att.connectedAt.IsZero() {
- if !b.seenInRecentScan(att.ssid) {
- return errdefs.ErrNoSuchSSID
- }
- return errdefs.ErrAssocTimeout
- }
-
- return errdefs.ErrAssocTimeout
-}
-
-func (b *IWDBackend) finalizeAttempt(att *connectAttempt, code string) {
- att.mu.Lock()
- if att.finalized {
- att.mu.Unlock()
- return
- }
- att.finalized = true
- att.mu.Unlock()
-
- b.stateMutex.Lock()
- b.state.IsConnecting = false
- b.state.ConnectingSSID = ""
- b.state.LastError = code
- b.stateMutex.Unlock()
-
- b.updateState()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-}
-
-func (b *IWDBackend) startAttemptWatchdog(att *connectAttempt) {
- b.sigWG.Add(1)
- go func() {
- defer b.sigWG.Done()
-
- ticker := time.NewTicker(250 * time.Millisecond)
- defer ticker.Stop()
-
- for {
- select {
- case <-ticker.C:
- att.mu.Lock()
- finalized := att.finalized
- att.mu.Unlock()
-
- if finalized || time.Now().After(att.deadline) {
- if !finalized {
- b.finalizeAttempt(att, b.classifyAttempt(att))
- }
- return
- }
-
- station := b.conn.Object(iwdBusName, b.stationPath)
- stVar, err := station.GetProperty(iwdStationInterface + ".State")
- if err != nil {
- continue
- }
- state, _ := stVar.Value().(string)
-
- cnVar, err := station.GetProperty(iwdStationInterface + ".ConnectedNetwork")
- if err != nil {
- continue
- }
- var connPath dbus.ObjectPath
- if cnVar.Value() != nil {
- connPath, _ = cnVar.Value().(dbus.ObjectPath)
- }
-
- att.mu.Lock()
- if connPath == att.netPath && state == "connected" && att.connectedAt.IsZero() {
- att.connectedAt = time.Now()
- }
- if state == "configuring" {
- att.sawIPConfig = true
- }
- att.mu.Unlock()
-
- case <-b.stopChan:
- return
- }
- }
- }()
-}
-
-func (b *IWDBackend) mapIwdDBusError(name string) string {
- switch name {
- case "net.connman.iwd.Error.AlreadyConnected":
- return errdefs.ErrAlreadyConnected
- case "net.connman.iwd.Error.AuthenticationFailed",
- "net.connman.iwd.Error.InvalidKey",
- "net.connman.iwd.Error.IncorrectPassphrase":
- return errdefs.ErrBadCredentials
- case "net.connman.iwd.Error.NotFound":
- return errdefs.ErrNoSuchSSID
- case "net.connman.iwd.Error.NotSupported":
- return errdefs.ErrConnectionFailed
- case "net.connman.iwd.Agent.Error.Canceled":
- return errdefs.ErrUserCanceled
- default:
- return errdefs.ErrConnectionFailed
- }
-}
-
-func (b *IWDBackend) ConnectWiFi(req ConnectionRequest) error {
- if b.stationPath == "" {
- b.setConnectError(errdefs.ErrWifiDisabled)
- if b.onStateChange != nil {
- b.onStateChange()
- }
- return fmt.Errorf("no WiFi device available")
- }
-
- networkPath, err := b.findNetworkPath(req.SSID)
- if err != nil {
- b.setConnectError(errdefs.ErrNoSuchSSID)
- if b.onStateChange != nil {
- b.onStateChange()
- }
- return fmt.Errorf("network not found: %w", err)
- }
-
- att := &connectAttempt{
- ssid: req.SSID,
- netPath: networkPath,
- start: time.Now(),
- deadline: time.Now().Add(15 * time.Second),
- }
-
- b.attemptMutex.Lock()
- b.curAttempt = att
- b.attemptMutex.Unlock()
-
- b.stateMutex.Lock()
- b.state.IsConnecting = true
- b.state.ConnectingSSID = req.SSID
- b.state.LastError = ""
- b.stateMutex.Unlock()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- netObj := b.conn.Object(iwdBusName, networkPath)
- go func() {
- call := netObj.Call(iwdNetworkInterface+".Connect", 0)
- if call.Err != nil {
- var code string
- if dbusErr, ok := call.Err.(dbus.Error); ok {
- code = b.mapIwdDBusError(dbusErr.Name)
- } else if dbusErrPtr, ok := call.Err.(*dbus.Error); ok {
- code = b.mapIwdDBusError(dbusErrPtr.Name)
- } else {
- code = errdefs.ErrConnectionFailed
- }
-
- att.mu.Lock()
- if att.sawPromptRetry {
- code = errdefs.ErrBadCredentials
- }
- att.mu.Unlock()
-
- b.finalizeAttempt(att, code)
- return
- }
-
- b.startAttemptWatchdog(att)
- }()
-
- return nil
-}
-
-func (b *IWDBackend) findNetworkPath(ssid string) (dbus.ObjectPath, error) {
- obj := b.conn.Object(iwdBusName, iwdObjectPath)
-
- var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant
- err := obj.Call(dbusObjectManager+".GetManagedObjects", 0).Store(&objects)
- if err != nil {
- return "", err
- }
-
- for path, interfaces := range objects {
- if netProps, ok := interfaces[iwdNetworkInterface]; ok {
- if nameVar, ok := netProps["Name"]; ok {
- if name, ok := nameVar.Value().(string); ok && name == ssid {
- return path, nil
- }
- }
- }
- }
-
- return "", fmt.Errorf("network not found")
-}
-
-func (b *IWDBackend) DisconnectWiFi() error {
- if b.stationPath == "" {
- return fmt.Errorf("no WiFi device available")
- }
-
- obj := b.conn.Object(iwdBusName, b.stationPath)
- call := obj.Call(iwdStationInterface+".Disconnect", 0)
- if call.Err != nil {
- return fmt.Errorf("failed to disconnect: %w", call.Err)
- }
-
- b.updateState()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- return nil
-}
-
-func (b *IWDBackend) ForgetWiFiNetwork(ssid string) error {
- b.stateMutex.RLock()
- currentSSID := b.state.WiFiSSID
- isConnected := b.state.WiFiConnected
- b.stateMutex.RUnlock()
-
- obj := b.conn.Object(iwdBusName, iwdObjectPath)
-
- var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant
- err := obj.Call(dbusObjectManager+".GetManagedObjects", 0).Store(&objects)
- if err != nil {
- return err
- }
-
- for path, interfaces := range objects {
- if knownProps, ok := interfaces[iwdKnownNetworkInterface]; ok {
- if nameVar, ok := knownProps["Name"]; ok {
- if name, ok := nameVar.Value().(string); ok && name == ssid {
- knownObj := b.conn.Object(iwdBusName, path)
- call := knownObj.Call(iwdKnownNetworkInterface+".Forget", 0)
- if call.Err != nil {
- return fmt.Errorf("failed to forget network: %w", call.Err)
- }
-
- if isConnected && currentSSID == ssid {
- b.stateMutex.Lock()
- b.state.WiFiConnected = false
- b.state.WiFiSSID = ""
- b.state.WiFiSignal = 0
- b.state.WiFiIP = ""
- b.state.NetworkStatus = StatusDisconnected
- b.stateMutex.Unlock()
- }
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- return nil
- }
- }
- }
- }
-
- return fmt.Errorf("network not found")
-}
-
-func (b *IWDBackend) SetWiFiAutoconnect(ssid string, autoconnect bool) error {
- obj := b.conn.Object(iwdBusName, iwdObjectPath)
-
- var objects map[dbus.ObjectPath]map[string]map[string]dbus.Variant
- err := obj.Call(dbusObjectManager+".GetManagedObjects", 0).Store(&objects)
- if err != nil {
- return err
- }
-
- for path, interfaces := range objects {
- if knownProps, ok := interfaces[iwdKnownNetworkInterface]; ok {
- if nameVar, ok := knownProps["Name"]; ok {
- if name, ok := nameVar.Value().(string); ok && name == ssid {
- knownObj := b.conn.Object(iwdBusName, path)
- call := knownObj.Call(dbusPropertiesInterface+".Set", 0, iwdKnownNetworkInterface, "AutoConnect", dbus.MakeVariant(autoconnect))
- if call.Err != nil {
- return fmt.Errorf("failed to set autoconnect: %w", call.Err)
- }
-
- b.updateState()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- return nil
- }
- }
- }
- }
-
- return fmt.Errorf("network not found")
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkd.go b/nix/inputs/dms-cli/internal/server/network/backend_networkd.go
deleted file mode 100644
index 2aabaca..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkd.go
+++ /dev/null
@@ -1,268 +0,0 @@
-package network
-
-import (
- "fmt"
- "net"
- "strings"
- "sync"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/godbus/dbus/v5"
-)
-
-const (
- networkdBusName = "org.freedesktop.network1"
- networkdManagerPath = "/org/freedesktop/network1"
- networkdManagerIface = "org.freedesktop.network1.Manager"
- networkdLinkIface = "org.freedesktop.network1.Link"
-)
-
-type linkInfo struct {
- ifindex int32
- name string
- path dbus.ObjectPath
- opState string
-}
-
-type SystemdNetworkdBackend struct {
- conn *dbus.Conn
- managerPath dbus.ObjectPath
- links map[string]*linkInfo
- linksMutex sync.RWMutex
- state *BackendState
- stateMutex sync.RWMutex
- onStateChange func()
- stopChan chan struct{}
- signals chan *dbus.Signal
- sigWG sync.WaitGroup
-}
-
-func NewSystemdNetworkdBackend() (*SystemdNetworkdBackend, error) {
- return &SystemdNetworkdBackend{
- managerPath: networkdManagerPath,
- links: make(map[string]*linkInfo),
- state: &BackendState{
- Backend: "networkd",
- WiFiNetworks: []WiFiNetwork{},
- },
- stopChan: make(chan struct{}),
- }, nil
-}
-
-func (b *SystemdNetworkdBackend) Initialize() error {
- c, err := dbus.ConnectSystemBus()
- if err != nil {
- return fmt.Errorf("connect bus: %w", err)
- }
- b.conn = c
-
- if err := b.enumerateLinks(); err != nil {
- c.Close()
- return fmt.Errorf("enumerate links: %w", err)
- }
-
- if err := b.updateState(); err != nil {
- c.Close()
- return fmt.Errorf("update initial state: %w", err)
- }
-
- return nil
-}
-
-func (b *SystemdNetworkdBackend) Close() {
- close(b.stopChan)
- b.StopMonitoring()
-
- if b.conn != nil {
- b.conn.Close()
- }
-}
-
-func (b *SystemdNetworkdBackend) enumerateLinks() error {
- obj := b.conn.Object(networkdBusName, b.managerPath)
-
- var links []struct {
- Ifindex int32
- Name string
- Path dbus.ObjectPath
- }
- err := obj.Call(networkdManagerIface+".ListLinks", 0).Store(&links)
- if err != nil {
- return fmt.Errorf("ListLinks: %w", err)
- }
-
- b.linksMutex.Lock()
- defer b.linksMutex.Unlock()
-
- for _, l := range links {
- b.links[l.Name] = &linkInfo{
- ifindex: l.Ifindex,
- name: l.Name,
- path: l.Path,
- }
- log.Debugf("networkd: enumerated link %s (ifindex=%d, path=%s)", l.Name, l.Ifindex, l.Path)
- }
-
- return nil
-}
-
-func (b *SystemdNetworkdBackend) updateState() error {
- b.linksMutex.RLock()
- defer b.linksMutex.RUnlock()
-
- var wiredIface *linkInfo
- var wifiIface *linkInfo
-
- for name, link := range b.links {
- if b.isVirtualInterface(name) {
- continue
- }
-
- linkObj := b.conn.Object(networkdBusName, link.path)
- opStateVar, err := linkObj.GetProperty(networkdLinkIface + ".OperationalState")
- if err == nil {
- if opState, ok := opStateVar.Value().(string); ok {
- link.opState = opState
- }
- }
-
- if strings.HasPrefix(name, "wlan") || strings.HasPrefix(name, "wlp") {
- if wifiIface == nil || link.opState == "routable" || link.opState == "carrier" {
- wifiIface = link
- }
- } else if !b.isVirtualInterface(name) {
- if wiredIface == nil || link.opState == "routable" || link.opState == "carrier" {
- wiredIface = link
- }
- }
- }
-
- var wiredConns []WiredConnection
- for name, link := range b.links {
- if b.isVirtualInterface(name) || strings.HasPrefix(name, "wlan") || strings.HasPrefix(name, "wlp") {
- continue
- }
-
- active := link.opState == "routable" || link.opState == "carrier"
- wiredConns = append(wiredConns, WiredConnection{
- Path: link.path,
- ID: name,
- UUID: "wired:" + name,
- Type: "ethernet",
- IsActive: active,
- })
- }
-
- b.stateMutex.Lock()
- defer b.stateMutex.Unlock()
-
- b.state.NetworkStatus = StatusDisconnected
- b.state.EthernetConnected = false
- b.state.EthernetIP = ""
- b.state.WiFiConnected = false
- b.state.WiFiIP = ""
- b.state.WiredConnections = wiredConns
-
- if wiredIface != nil {
- b.state.EthernetDevice = wiredIface.name
- log.Debugf("networkd: wired interface %s opState=%s", wiredIface.name, wiredIface.opState)
- if wiredIface.opState == "routable" || wiredIface.opState == "carrier" {
- b.state.EthernetConnected = true
- b.state.NetworkStatus = StatusEthernet
-
- if addrs := b.getAddresses(wiredIface.name); len(addrs) > 0 {
- b.state.EthernetIP = addrs[0]
- log.Debugf("networkd: ethernet IP %s on %s", addrs[0], wiredIface.name)
- }
- }
- }
-
- if wifiIface != nil {
- b.state.WiFiDevice = wifiIface.name
- log.Debugf("networkd: wifi interface %s opState=%s", wifiIface.name, wifiIface.opState)
- if wifiIface.opState == "routable" || wifiIface.opState == "carrier" {
- b.state.WiFiConnected = true
-
- if addrs := b.getAddresses(wifiIface.name); len(addrs) > 0 {
- b.state.WiFiIP = addrs[0]
- log.Debugf("networkd: wifi IP %s on %s", addrs[0], wifiIface.name)
- if b.state.NetworkStatus == StatusDisconnected {
- b.state.NetworkStatus = StatusWiFi
- }
- }
- }
- }
-
- return nil
-}
-
-func (b *SystemdNetworkdBackend) isVirtualInterface(name string) bool {
- virtualPrefixes := []string{
- "lo", "docker", "veth", "virbr", "br-", "vnet", "tun", "tap",
- "vboxnet", "vmnet", "kube", "cni", "flannel", "cali",
- }
- for _, prefix := range virtualPrefixes {
- if strings.HasPrefix(name, prefix) {
- return true
- }
- }
- return false
-}
-
-func (b *SystemdNetworkdBackend) getAddresses(ifname string) []string {
- iface, err := net.InterfaceByName(ifname)
- if err != nil {
- return nil
- }
-
- addrs, err := iface.Addrs()
- if err != nil {
- return nil
- }
-
- var result []string
- for _, addr := range addrs {
- if ipnet, ok := addr.(*net.IPNet); ok {
- if ipv4 := ipnet.IP.To4(); ipv4 != nil {
- result = append(result, ipv4.String())
- }
- }
- }
- return result
-}
-
-func (b *SystemdNetworkdBackend) GetCurrentState() (*BackendState, error) {
- b.stateMutex.RLock()
- defer b.stateMutex.RUnlock()
- s := *b.state
- return &s, nil
-}
-
-func (b *SystemdNetworkdBackend) GetPromptBroker() PromptBroker {
- return nil
-}
-
-func (b *SystemdNetworkdBackend) SetPromptBroker(broker PromptBroker) error {
- return nil
-}
-
-func (b *SystemdNetworkdBackend) SubmitCredentials(token string, secrets map[string]string, save bool) error {
- return fmt.Errorf("credentials not needed by networkd backend")
-}
-
-func (b *SystemdNetworkdBackend) CancelCredentials(token string) error {
- return fmt.Errorf("credentials not needed by networkd backend")
-}
-
-func (b *SystemdNetworkdBackend) EnsureDhcpUp(ifname string) error {
- b.linksMutex.RLock()
- link, exists := b.links[ifname]
- b.linksMutex.RUnlock()
-
- if !exists {
- return fmt.Errorf("interface %s not found", ifname)
- }
-
- linkObj := b.conn.Object(networkdBusName, link.path)
- return linkObj.Call(networkdLinkIface+".Reconfigure", 0).Err
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkd_ethernet.go b/nix/inputs/dms-cli/internal/server/network/backend_networkd_ethernet.go
deleted file mode 100644
index d0c9b94..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkd_ethernet.go
+++ /dev/null
@@ -1,110 +0,0 @@
-package network
-
-import (
- "fmt"
- "net"
- "strings"
-)
-
-func (b *SystemdNetworkdBackend) GetWiredConnections() ([]WiredConnection, error) {
- b.linksMutex.RLock()
- defer b.linksMutex.RUnlock()
-
- var conns []WiredConnection
- for name, link := range b.links {
- if b.isVirtualInterface(name) || strings.HasPrefix(name, "wlan") || strings.HasPrefix(name, "wlp") {
- continue
- }
-
- active := link.opState == "routable" || link.opState == "carrier"
- conns = append(conns, WiredConnection{
- Path: link.path,
- ID: name,
- UUID: "wired:" + name,
- Type: "ethernet",
- IsActive: active,
- })
- }
-
- return conns, nil
-}
-
-func (b *SystemdNetworkdBackend) GetWiredNetworkDetails(id string) (*WiredNetworkInfoResponse, error) {
- ifname := strings.TrimPrefix(id, "wired:")
-
- b.linksMutex.RLock()
- _, exists := b.links[ifname]
- b.linksMutex.RUnlock()
-
- if !exists {
- return nil, fmt.Errorf("interface %s not found", ifname)
- }
-
- iface, err := net.InterfaceByName(ifname)
- if err != nil {
- return nil, fmt.Errorf("get interface: %w", err)
- }
-
- addrs, _ := iface.Addrs()
- var ipv4s, ipv6s []string
- for _, addr := range addrs {
- if ipnet, ok := addr.(*net.IPNet); ok {
- if ipv4 := ipnet.IP.To4(); ipv4 != nil {
- ipv4s = append(ipv4s, ipnet.String())
- } else if ipv6 := ipnet.IP.To16(); ipv6 != nil {
- ipv6s = append(ipv6s, ipnet.String())
- }
- }
- }
-
- return &WiredNetworkInfoResponse{
- UUID: id,
- IFace: ifname,
- HwAddr: iface.HardwareAddr.String(),
- IPv4: WiredIPConfig{
- IPs: ipv4s,
- },
- IPv6: WiredIPConfig{
- IPs: ipv6s,
- },
- }, nil
-}
-
-func (b *SystemdNetworkdBackend) ConnectEthernet() error {
- b.linksMutex.RLock()
- var primaryWired *linkInfo
- for name, l := range b.links {
- if strings.HasPrefix(name, "lo") || strings.HasPrefix(name, "wlan") || strings.HasPrefix(name, "wlp") {
- continue
- }
- primaryWired = l
- break
- }
- b.linksMutex.RUnlock()
-
- if primaryWired == nil {
- return fmt.Errorf("no wired interface found")
- }
-
- linkObj := b.conn.Object(networkdBusName, primaryWired.path)
- return linkObj.Call(networkdLinkIface+".Reconfigure", 0).Err
-}
-
-func (b *SystemdNetworkdBackend) DisconnectEthernet() error {
- return fmt.Errorf("not supported by networkd backend")
-}
-
-func (b *SystemdNetworkdBackend) ActivateWiredConnection(id string) error {
- ifname := strings.TrimPrefix(id, "wired:")
-
- b.linksMutex.RLock()
- link, exists := b.links[ifname]
- b.linksMutex.RUnlock()
-
- if !exists {
- return fmt.Errorf("interface %s not found", ifname)
- }
-
- linkObj := b.conn.Object(networkdBusName, link.path)
- return linkObj.Call(networkdLinkIface+".Reconfigure", 0).Err
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkd_signals.go b/nix/inputs/dms-cli/internal/server/network/backend_networkd_signals.go
deleted file mode 100644
index a022ee6..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkd_signals.go
+++ /dev/null
@@ -1,68 +0,0 @@
-package network
-
-import (
- "fmt"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/godbus/dbus/v5"
-)
-
-func (b *SystemdNetworkdBackend) StartMonitoring(onStateChange func()) error {
- b.onStateChange = onStateChange
-
- b.signals = make(chan *dbus.Signal, 64)
- b.conn.Signal(b.signals)
-
- matchRules := []string{
- "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path_namespace='/org/freedesktop/network1'",
- "type='signal',interface='org.freedesktop.network1.Manager'",
- }
-
- for _, rule := range matchRules {
- if err := b.conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rule).Err; err != nil {
- return fmt.Errorf("add match %q: %w", rule, err)
- }
- }
-
- b.sigWG.Add(1)
- go b.signalLoop()
-
- return nil
-}
-
-func (b *SystemdNetworkdBackend) StopMonitoring() {
- b.sigWG.Wait()
-}
-
-func (b *SystemdNetworkdBackend) signalLoop() {
- defer b.sigWG.Done()
-
- for {
- select {
- case <-b.stopChan:
- return
- case sig := <-b.signals:
- if sig == nil {
- continue
- }
-
- if sig.Name == "org.freedesktop.DBus.Properties.PropertiesChanged" {
- if len(sig.Body) < 2 {
- continue
- }
- iface, ok := sig.Body[0].(string)
- if !ok || iface != networkdLinkIface {
- continue
- }
-
- b.enumerateLinks()
- if err := b.updateState(); err != nil {
- log.Warnf("networkd state update failed: %v", err)
- }
- if b.onStateChange != nil {
- b.onStateChange()
- }
- }
- }
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkd_test.go b/nix/inputs/dms-cli/internal/server/network/backend_networkd_test.go
deleted file mode 100644
index 383c775..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkd_test.go
+++ /dev/null
@@ -1,125 +0,0 @@
-package network
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestSystemdNetworkdBackend_New(t *testing.T) {
- backend, err := NewSystemdNetworkdBackend()
- assert.NoError(t, err)
- assert.NotNil(t, backend)
- assert.Equal(t, "networkd", backend.state.Backend)
- assert.NotNil(t, backend.links)
- assert.NotNil(t, backend.stopChan)
-}
-
-func TestSystemdNetworkdBackend_GetCurrentState(t *testing.T) {
- backend, _ := NewSystemdNetworkdBackend()
- backend.state.NetworkStatus = StatusEthernet
- backend.state.EthernetConnected = true
- backend.state.EthernetIP = "192.168.1.100"
-
- state, err := backend.GetCurrentState()
- assert.NoError(t, err)
- assert.NotNil(t, state)
- assert.Equal(t, StatusEthernet, state.NetworkStatus)
- assert.True(t, state.EthernetConnected)
- assert.Equal(t, "192.168.1.100", state.EthernetIP)
-}
-
-func TestSystemdNetworkdBackend_WiFiNotSupported(t *testing.T) {
- backend, _ := NewSystemdNetworkdBackend()
-
- err := backend.ScanWiFi()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not supported")
-
- req := ConnectionRequest{SSID: "test"}
- err = backend.ConnectWiFi(req)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not supported")
-
- err = backend.DisconnectWiFi()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not supported")
-
- err = backend.ForgetWiFiNetwork("test")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not supported")
-
- _, err = backend.GetWiFiNetworkDetails("test")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not supported")
-}
-
-func TestSystemdNetworkdBackend_VPNNotSupported(t *testing.T) {
- backend, _ := NewSystemdNetworkdBackend()
-
- profiles, err := backend.ListVPNProfiles()
- assert.NoError(t, err)
- assert.Empty(t, profiles)
-
- active, err := backend.ListActiveVPN()
- assert.NoError(t, err)
- assert.Empty(t, active)
-
- err = backend.ConnectVPN("test", false)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not supported")
-
- err = backend.DisconnectVPN("test")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not supported")
-
- err = backend.DisconnectAllVPN()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not supported")
-
- err = backend.ClearVPNCredentials("test")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not supported")
-}
-
-func TestSystemdNetworkdBackend_PromptBroker(t *testing.T) {
- backend, _ := NewSystemdNetworkdBackend()
-
- broker := backend.GetPromptBroker()
- assert.Nil(t, broker)
-
- err := backend.SetPromptBroker(nil)
- assert.NoError(t, err)
-
- err = backend.SubmitCredentials("token", nil, false)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not needed")
-
- err = backend.CancelCredentials("token")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not needed")
-}
-
-func TestSystemdNetworkdBackend_GetWiFiEnabled(t *testing.T) {
- backend, _ := NewSystemdNetworkdBackend()
-
- enabled, err := backend.GetWiFiEnabled()
- assert.NoError(t, err)
- assert.True(t, enabled)
-}
-
-func TestSystemdNetworkdBackend_SetWiFiEnabled(t *testing.T) {
- backend, _ := NewSystemdNetworkdBackend()
-
- err := backend.SetWiFiEnabled(false)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not supported")
-}
-
-func TestSystemdNetworkdBackend_DisconnectEthernet(t *testing.T) {
- backend, _ := NewSystemdNetworkdBackend()
-
- err := backend.DisconnectEthernet()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not supported")
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkd_unimplemented.go b/nix/inputs/dms-cli/internal/server/network/backend_networkd_unimplemented.go
deleted file mode 100644
index 1f44752..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkd_unimplemented.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package network
-
-import "fmt"
-
-func (b *SystemdNetworkdBackend) GetWiFiEnabled() (bool, error) {
- return true, nil
-}
-
-func (b *SystemdNetworkdBackend) SetWiFiEnabled(enabled bool) error {
- return fmt.Errorf("WiFi control not supported by networkd backend")
-}
-
-func (b *SystemdNetworkdBackend) ScanWiFi() error {
- return fmt.Errorf("WiFi scan not supported by networkd backend")
-}
-
-func (b *SystemdNetworkdBackend) GetWiFiNetworkDetails(ssid string) (*NetworkInfoResponse, error) {
- return nil, fmt.Errorf("WiFi details not supported by networkd backend")
-}
-
-func (b *SystemdNetworkdBackend) ConnectWiFi(req ConnectionRequest) error {
- return fmt.Errorf("WiFi connect not supported by networkd backend")
-}
-
-func (b *SystemdNetworkdBackend) DisconnectWiFi() error {
- return fmt.Errorf("WiFi disconnect not supported by networkd backend")
-}
-
-func (b *SystemdNetworkdBackend) ForgetWiFiNetwork(ssid string) error {
- return fmt.Errorf("WiFi forget not supported by networkd backend")
-}
-
-func (b *SystemdNetworkdBackend) ListVPNProfiles() ([]VPNProfile, error) {
- return []VPNProfile{}, nil
-}
-
-func (b *SystemdNetworkdBackend) ListActiveVPN() ([]VPNActive, error) {
- return []VPNActive{}, nil
-}
-
-func (b *SystemdNetworkdBackend) ConnectVPN(uuidOrName string, singleActive bool) error {
- return fmt.Errorf("VPN not supported by networkd backend")
-}
-
-func (b *SystemdNetworkdBackend) DisconnectVPN(uuidOrName string) error {
- return fmt.Errorf("VPN not supported by networkd backend")
-}
-
-func (b *SystemdNetworkdBackend) DisconnectAllVPN() error {
- return fmt.Errorf("VPN not supported by networkd backend")
-}
-
-func (b *SystemdNetworkdBackend) ClearVPNCredentials(uuidOrName string) error {
- return fmt.Errorf("VPN not supported by networkd backend")
-}
-
-func (b *SystemdNetworkdBackend) SetWiFiAutoconnect(ssid string, autoconnect bool) error {
- return fmt.Errorf("WiFi autoconnect not supported by networkd backend")
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager.go b/nix/inputs/dms-cli/internal/server/network/backend_networkmanager.go
deleted file mode 100644
index 2119408..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager.go
+++ /dev/null
@@ -1,307 +0,0 @@
-package network
-
-import (
- "fmt"
- "sync"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/Wifx/gonetworkmanager/v2"
- "github.com/godbus/dbus/v5"
-)
-
-const (
- dbusNMPath = "/org/freedesktop/NetworkManager"
- dbusNMInterface = "org.freedesktop.NetworkManager"
- dbusNMDeviceInterface = "org.freedesktop.NetworkManager.Device"
- dbusNMWirelessInterface = "org.freedesktop.NetworkManager.Device.Wireless"
- dbusNMAccessPointInterface = "org.freedesktop.NetworkManager.AccessPoint"
- dbusPropsInterface = "org.freedesktop.DBus.Properties"
-
- NmDeviceStateReasonWrongPassword = 8
- NmDeviceStateReasonSupplicantTimeout = 24
- NmDeviceStateReasonSupplicantFailed = 25
- NmDeviceStateReasonSecretsRequired = 7
- NmDeviceStateReasonNoSecrets = 6
- NmDeviceStateReasonNoSsid = 10
- NmDeviceStateReasonDhcpClientFailed = 14
- NmDeviceStateReasonIpConfigUnavailable = 18
- NmDeviceStateReasonSupplicantDisconnect = 23
- NmDeviceStateReasonCarrier = 40
- NmDeviceStateReasonNewActivation = 60
-)
-
-type NetworkManagerBackend struct {
- nmConn interface{}
- ethernetDevice interface{}
- wifiDevice interface{}
- settings interface{}
- wifiDev interface{}
-
- dbusConn *dbus.Conn
- signals chan *dbus.Signal
- sigWG sync.WaitGroup
- stopChan chan struct{}
-
- secretAgent *SecretAgent
- promptBroker PromptBroker
-
- state *BackendState
- stateMutex sync.RWMutex
-
- lastFailedSSID string
- lastFailedTime int64
- failedMutex sync.RWMutex
-
- onStateChange func()
-}
-
-func NewNetworkManagerBackend(nmConn ...gonetworkmanager.NetworkManager) (*NetworkManagerBackend, error) {
- var nm gonetworkmanager.NetworkManager
- var err error
-
- if len(nmConn) > 0 && nmConn[0] != nil {
- // Use injected connection (for testing)
- nm = nmConn[0]
- } else {
- // Create real connection
- nm, err = gonetworkmanager.NewNetworkManager()
- if err != nil {
- return nil, fmt.Errorf("failed to connect to NetworkManager: %w", err)
- }
- }
-
- backend := &NetworkManagerBackend{
- nmConn: nm,
- stopChan: make(chan struct{}),
- state: &BackendState{
- Backend: "networkmanager",
- },
- }
-
- return backend, nil
-}
-
-func (b *NetworkManagerBackend) Initialize() error {
- nm := b.nmConn.(gonetworkmanager.NetworkManager)
-
- if s, err := gonetworkmanager.NewSettings(); err == nil {
- b.settings = s
- }
-
- devices, err := nm.GetDevices()
- if err != nil {
- return fmt.Errorf("failed to get devices: %w", err)
- }
-
- for _, dev := range devices {
- devType, err := dev.GetPropertyDeviceType()
- if err != nil {
- continue
- }
-
- switch devType {
- case gonetworkmanager.NmDeviceTypeEthernet:
- if managed, _ := dev.GetPropertyManaged(); !managed {
- continue
- }
- b.ethernetDevice = dev
- if err := b.updateEthernetState(); err != nil {
- continue
- }
- _, err := b.listEthernetConnections()
- if err != nil {
- return fmt.Errorf("failed to get wired configurations: %w", err)
- }
-
- case gonetworkmanager.NmDeviceTypeWifi:
- b.wifiDevice = dev
- if w, err := gonetworkmanager.NewDeviceWireless(dev.GetPath()); err == nil {
- b.wifiDev = w
- }
- wifiEnabled, err := nm.GetPropertyWirelessEnabled()
- if err == nil {
- b.stateMutex.Lock()
- b.state.WiFiEnabled = wifiEnabled
- b.stateMutex.Unlock()
- }
- if err := b.updateWiFiState(); err != nil {
- continue
- }
- if wifiEnabled {
- if _, err := b.updateWiFiNetworks(); err != nil {
- log.Warnf("Failed to get initial networks: %v", err)
- }
- }
- }
- }
-
- if err := b.updatePrimaryConnection(); err != nil {
- return err
- }
-
- if _, err := b.ListVPNProfiles(); err != nil {
- log.Warnf("Failed to get initial VPN profiles: %v", err)
- }
-
- if _, err := b.ListActiveVPN(); err != nil {
- log.Warnf("Failed to get initial active VPNs: %v", err)
- }
-
- return nil
-}
-
-func (b *NetworkManagerBackend) Close() {
- close(b.stopChan)
- b.StopMonitoring()
-
- if b.secretAgent != nil {
- b.secretAgent.Close()
- }
-}
-
-func (b *NetworkManagerBackend) GetCurrentState() (*BackendState, error) {
- b.stateMutex.RLock()
- defer b.stateMutex.RUnlock()
-
- state := *b.state
- state.WiFiNetworks = append([]WiFiNetwork(nil), b.state.WiFiNetworks...)
- state.WiredConnections = append([]WiredConnection(nil), b.state.WiredConnections...)
- state.VPNProfiles = append([]VPNProfile(nil), b.state.VPNProfiles...)
- state.VPNActive = append([]VPNActive(nil), b.state.VPNActive...)
-
- return &state, nil
-}
-
-func (b *NetworkManagerBackend) StartMonitoring(onStateChange func()) error {
- b.onStateChange = onStateChange
-
- if err := b.startSecretAgent(); err != nil {
- return fmt.Errorf("failed to start secret agent: %w", err)
- }
-
- if err := b.startSignalPump(); err != nil {
- return err
- }
-
- return nil
-}
-
-func (b *NetworkManagerBackend) StopMonitoring() {
- b.stopSignalPump()
-}
-
-func (b *NetworkManagerBackend) GetPromptBroker() PromptBroker {
- return b.promptBroker
-}
-
-func (b *NetworkManagerBackend) SetPromptBroker(broker PromptBroker) error {
- if broker == nil {
- return fmt.Errorf("broker cannot be nil")
- }
-
- hadAgent := b.secretAgent != nil
-
- b.promptBroker = broker
-
- if b.secretAgent != nil {
- b.secretAgent.Close()
- b.secretAgent = nil
- }
-
- if hadAgent {
- return b.startSecretAgent()
- }
-
- return nil
-}
-
-func (b *NetworkManagerBackend) SubmitCredentials(token string, secrets map[string]string, save bool) error {
- if b.promptBroker == nil {
- return fmt.Errorf("prompt broker not initialized")
- }
-
- return b.promptBroker.Resolve(token, PromptReply{
- Secrets: secrets,
- Save: save,
- Cancel: false,
- })
-}
-
-func (b *NetworkManagerBackend) CancelCredentials(token string) error {
- if b.promptBroker == nil {
- return fmt.Errorf("prompt broker not initialized")
- }
-
- return b.promptBroker.Resolve(token, PromptReply{
- Cancel: true,
- })
-}
-
-func (b *NetworkManagerBackend) ensureWiFiDevice() error {
- if b.wifiDev != nil {
- return nil
- }
-
- if b.wifiDevice == nil {
- return fmt.Errorf("no WiFi device available")
- }
-
- dev := b.wifiDevice.(gonetworkmanager.Device)
- wifiDev, err := gonetworkmanager.NewDeviceWireless(dev.GetPath())
- if err != nil {
- return fmt.Errorf("failed to get wireless device: %w", err)
- }
- b.wifiDev = wifiDev
- return nil
-}
-
-func (b *NetworkManagerBackend) startSecretAgent() error {
- if b.promptBroker == nil {
- return fmt.Errorf("prompt broker not set")
- }
-
- agent, err := NewSecretAgent(b.promptBroker, nil, b)
- if err != nil {
- return err
- }
-
- b.secretAgent = agent
- return nil
-}
-
-func (b *NetworkManagerBackend) getActiveConnections() (map[string]bool, error) {
- nm := b.nmConn.(gonetworkmanager.NetworkManager)
-
- activeUUIDs := make(map[string]bool)
-
- activeConns, err := nm.GetPropertyActiveConnections()
- if err != nil {
- return activeUUIDs, fmt.Errorf("failed to get active connections: %w", err)
- }
-
- for _, activeConn := range activeConns {
- connType, err := activeConn.GetPropertyType()
- if err != nil {
- continue
- }
-
- if connType != "802-3-ethernet" {
- continue
- }
-
- state, err := activeConn.GetPropertyState()
- if err != nil {
- continue
- }
- if state < 1 || state > 2 {
- continue
- }
-
- uuid, err := activeConn.GetPropertyUUID()
- if err != nil {
- continue
- }
- activeUUIDs[uuid] = true
- }
- return activeUUIDs, nil
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_ethernet.go b/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_ethernet.go
deleted file mode 100644
index 965565e..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_ethernet.go
+++ /dev/null
@@ -1,317 +0,0 @@
-package network
-
-import (
- "fmt"
- "net"
- "strconv"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/Wifx/gonetworkmanager/v2"
-)
-
-func (b *NetworkManagerBackend) GetWiredConnections() ([]WiredConnection, error) {
- return b.listEthernetConnections()
-}
-
-func (b *NetworkManagerBackend) GetWiredNetworkDetails(uuid string) (*WiredNetworkInfoResponse, error) {
- if b.ethernetDevice == nil {
- return nil, fmt.Errorf("no ethernet device available")
- }
-
- dev := b.ethernetDevice.(gonetworkmanager.Device)
-
- iface, _ := dev.GetPropertyInterface()
- driver, _ := dev.GetPropertyDriver()
-
- hwAddr := "Not available"
- var speed uint32 = 0
- wiredDevice, err := gonetworkmanager.NewDeviceWired(dev.GetPath())
- if err == nil {
- hwAddr, _ = wiredDevice.GetPropertyHwAddress()
- speed, _ = wiredDevice.GetPropertySpeed()
- }
- var ipv4Config WiredIPConfig
- var ipv6Config WiredIPConfig
-
- activeConn, err := dev.GetPropertyActiveConnection()
- if err == nil && activeConn != nil {
- ip4Config, err := activeConn.GetPropertyIP4Config()
- if err == nil && ip4Config != nil {
- var ips []string
- addresses, err := ip4Config.GetPropertyAddressData()
- if err == nil && len(addresses) > 0 {
- for _, addr := range addresses {
- ips = append(ips, fmt.Sprintf("%s/%s", addr.Address, strconv.Itoa(int(addr.Prefix))))
- }
- }
-
- gateway, _ := ip4Config.GetPropertyGateway()
- dnsAddrs := ""
- dns, err := ip4Config.GetPropertyNameserverData()
- if err == nil && len(dns) > 0 {
- for _, d := range dns {
- if len(dnsAddrs) > 0 {
- dnsAddrs = strings.Join([]string{dnsAddrs, d.Address}, "; ")
- } else {
- dnsAddrs = d.Address
- }
- }
- }
-
- ipv4Config = WiredIPConfig{
- IPs: ips,
- Gateway: gateway,
- DNS: dnsAddrs,
- }
- }
-
- ip6Config, err := activeConn.GetPropertyIP6Config()
- if err == nil && ip6Config != nil {
- var ips []string
- addresses, err := ip6Config.GetPropertyAddressData()
- if err == nil && len(addresses) > 0 {
- for _, addr := range addresses {
- ips = append(ips, fmt.Sprintf("%s/%s", addr.Address, strconv.Itoa(int(addr.Prefix))))
- }
- }
-
- gateway, _ := ip6Config.GetPropertyGateway()
- dnsAddrs := ""
- dns, err := ip6Config.GetPropertyNameservers()
- if err == nil && len(dns) > 0 {
- for _, d := range dns {
- if len(d) == 16 {
- ip := net.IP(d)
- if len(dnsAddrs) > 0 {
- dnsAddrs = strings.Join([]string{dnsAddrs, ip.String()}, "; ")
- } else {
- dnsAddrs = ip.String()
- }
- }
- }
- }
-
- ipv6Config = WiredIPConfig{
- IPs: ips,
- Gateway: gateway,
- DNS: dnsAddrs,
- }
- }
- }
-
- return &WiredNetworkInfoResponse{
- UUID: uuid,
- IFace: iface,
- Driver: driver,
- HwAddr: hwAddr,
- Speed: strconv.Itoa(int(speed)),
- IPv4: ipv4Config,
- IPv6: ipv6Config,
- }, nil
-}
-
-func (b *NetworkManagerBackend) ConnectEthernet() error {
- if b.ethernetDevice == nil {
- return fmt.Errorf("no ethernet device available")
- }
-
- nm := b.nmConn.(gonetworkmanager.NetworkManager)
- dev := b.ethernetDevice.(gonetworkmanager.Device)
-
- settingsMgr, err := gonetworkmanager.NewSettings()
- if err != nil {
- return fmt.Errorf("failed to get settings: %w", err)
- }
-
- connections, err := settingsMgr.ListConnections()
- if err != nil {
- return fmt.Errorf("failed to get connections: %w", err)
- }
-
- for _, conn := range connections {
- connSettings, err := conn.GetSettings()
- if err != nil {
- continue
- }
-
- if connMeta, ok := connSettings["connection"]; ok {
- if connType, ok := connMeta["type"].(string); ok && connType == "802-3-ethernet" {
- _, err := nm.ActivateConnection(conn, dev, nil)
- if err != nil {
- return fmt.Errorf("failed to activate ethernet: %w", err)
- }
-
- b.updateEthernetState()
- b.listEthernetConnections()
- b.updatePrimaryConnection()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- return nil
- }
- }
- }
-
- settings := make(map[string]map[string]interface{})
- settings["connection"] = map[string]interface{}{
- "id": "Wired connection",
- "type": "802-3-ethernet",
- }
-
- _, err = nm.AddAndActivateConnection(settings, dev)
- if err != nil {
- return fmt.Errorf("failed to create and activate ethernet: %w", err)
- }
-
- b.updateEthernetState()
- b.listEthernetConnections()
- b.updatePrimaryConnection()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- return nil
-}
-
-func (b *NetworkManagerBackend) DisconnectEthernet() error {
- if b.ethernetDevice == nil {
- return fmt.Errorf("no ethernet device available")
- }
-
- dev := b.ethernetDevice.(gonetworkmanager.Device)
-
- err := dev.Disconnect()
- if err != nil {
- return fmt.Errorf("failed to disconnect: %w", err)
- }
-
- b.updateEthernetState()
- b.listEthernetConnections()
- b.updatePrimaryConnection()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- return nil
-}
-
-func (b *NetworkManagerBackend) ActivateWiredConnection(uuid string) error {
- if b.ethernetDevice == nil {
- return fmt.Errorf("no ethernet device available")
- }
-
- nm := b.nmConn.(gonetworkmanager.NetworkManager)
- dev := b.ethernetDevice.(gonetworkmanager.Device)
-
- settingsMgr, err := gonetworkmanager.NewSettings()
- if err != nil {
- return fmt.Errorf("failed to get settings: %w", err)
- }
-
- connections, err := settingsMgr.ListConnections()
- if err != nil {
- return fmt.Errorf("failed to get connections: %w", err)
- }
-
- var targetConnection gonetworkmanager.Connection
- for _, conn := range connections {
- settings, err := conn.GetSettings()
- if err != nil {
- continue
- }
-
- if connectionSettings, ok := settings["connection"]; ok {
- if connUUID, ok := connectionSettings["uuid"].(string); ok && connUUID == uuid {
- targetConnection = conn
- break
- }
- }
- }
-
- if targetConnection == nil {
- return fmt.Errorf("connection with UUID %s not found", uuid)
- }
-
- _, err = nm.ActivateConnection(targetConnection, dev, nil)
- if err != nil {
- return fmt.Errorf("error activation connection: %w", err)
- }
-
- b.updateEthernetState()
- b.listEthernetConnections()
- b.updatePrimaryConnection()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- return nil
-}
-
-func (b *NetworkManagerBackend) listEthernetConnections() ([]WiredConnection, error) {
- if b.ethernetDevice == nil {
- return nil, fmt.Errorf("no ethernet device available")
- }
-
- s := b.settings
- if s == nil {
- s, err := gonetworkmanager.NewSettings()
- if err != nil {
- return nil, fmt.Errorf("failed to get settings: %w", err)
- }
- b.settings = s
- }
-
- settingsMgr := s.(gonetworkmanager.Settings)
- connections, err := settingsMgr.ListConnections()
- if err != nil {
- return nil, fmt.Errorf("failed to get connections: %w", err)
- }
-
- wiredConfigs := make([]WiredConnection, 0)
- activeUUIDs, err := b.getActiveConnections()
-
- if err != nil {
- return nil, fmt.Errorf("failed to get active wired connections: %w", err)
- }
-
- currentUuid := ""
- for _, connection := range connections {
- path := connection.GetPath()
- settings, err := connection.GetSettings()
- if err != nil {
- log.Errorf("unable to get settings for %s: %v", path, err)
- continue
- }
-
- connectionSettings := settings["connection"]
- connType, _ := connectionSettings["type"].(string)
- connID, _ := connectionSettings["id"].(string)
- connUUID, _ := connectionSettings["uuid"].(string)
-
- if connType == "802-3-ethernet" {
- wiredConfigs = append(wiredConfigs, WiredConnection{
- Path: path,
- ID: connID,
- UUID: connUUID,
- Type: connType,
- IsActive: activeUUIDs[connUUID],
- })
- if activeUUIDs[connUUID] {
- currentUuid = connUUID
- }
- }
- }
-
- b.stateMutex.Lock()
- b.state.EthernetConnectionUuid = currentUuid
- b.state.WiredConnections = wiredConfigs
- b.stateMutex.Unlock()
-
- return wiredConfigs, nil
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_ethernet_test.go b/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_ethernet_test.go
deleted file mode 100644
index 601306a..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_ethernet_test.go
+++ /dev/null
@@ -1,94 +0,0 @@
-package network
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestNetworkManagerBackend_GetWiredConnections_NoDevice(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.ethernetDevice = nil
- _, err = backend.GetWiredConnections()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no ethernet device available")
-}
-
-func TestNetworkManagerBackend_GetWiredNetworkDetails_NoDevice(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.ethernetDevice = nil
- _, err = backend.GetWiredNetworkDetails("test-uuid")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no ethernet device available")
-}
-
-func TestNetworkManagerBackend_ConnectEthernet_NoDevice(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.ethernetDevice = nil
- err = backend.ConnectEthernet()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no ethernet device available")
-}
-
-func TestNetworkManagerBackend_DisconnectEthernet_NoDevice(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.ethernetDevice = nil
- err = backend.DisconnectEthernet()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no ethernet device available")
-}
-
-func TestNetworkManagerBackend_ActivateWiredConnection_NoDevice(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.ethernetDevice = nil
- err = backend.ActivateWiredConnection("test-uuid")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no ethernet device available")
-}
-
-func TestNetworkManagerBackend_ActivateWiredConnection_NotFound(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- if backend.ethernetDevice == nil {
- t.Skip("No ethernet device available")
- }
-
- err = backend.ActivateWiredConnection("non-existent-uuid-12345")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not found")
-}
-
-func TestNetworkManagerBackend_ListEthernetConnections_NoDevice(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.ethernetDevice = nil
- _, err = backend.listEthernetConnections()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no ethernet device available")
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_signals.go b/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_signals.go
deleted file mode 100644
index 153a9d8..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_signals.go
+++ /dev/null
@@ -1,321 +0,0 @@
-package network
-
-import (
- "github.com/Wifx/gonetworkmanager/v2"
- "github.com/godbus/dbus/v5"
-)
-
-func (b *NetworkManagerBackend) startSignalPump() error {
- conn, err := dbus.ConnectSystemBus()
- if err != nil {
- return err
- }
- b.dbusConn = conn
-
- signals := make(chan *dbus.Signal, 256)
- b.signals = signals
- conn.Signal(signals)
-
- if err := conn.AddMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath(dbusNMPath)),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- ); err != nil {
- conn.RemoveSignal(signals)
- conn.Close()
- return err
- }
-
- if err := conn.AddMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath("/org/freedesktop/NetworkManager/Settings")),
- dbus.WithMatchInterface("org.freedesktop.NetworkManager.Settings"),
- dbus.WithMatchMember("NewConnection"),
- ); err != nil {
- conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath(dbusNMPath)),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- )
- conn.RemoveSignal(signals)
- conn.Close()
- return err
- }
-
- if err := conn.AddMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath("/org/freedesktop/NetworkManager/Settings")),
- dbus.WithMatchInterface("org.freedesktop.NetworkManager.Settings"),
- dbus.WithMatchMember("ConnectionRemoved"),
- ); err != nil {
- conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath(dbusNMPath)),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- )
- conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath("/org/freedesktop/NetworkManager/Settings")),
- dbus.WithMatchInterface("org.freedesktop.NetworkManager.Settings"),
- dbus.WithMatchMember("NewConnection"),
- )
- conn.RemoveSignal(signals)
- conn.Close()
- return err
- }
-
- if b.wifiDevice != nil {
- dev := b.wifiDevice.(gonetworkmanager.Device)
- if err := conn.AddMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath(dev.GetPath())),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- ); err != nil {
- conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath(dbusNMPath)),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- )
- conn.RemoveSignal(signals)
- conn.Close()
- return err
- }
- }
-
- if b.ethernetDevice != nil {
- dev := b.ethernetDevice.(gonetworkmanager.Device)
- if err := conn.AddMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath(dev.GetPath())),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- ); err != nil {
- conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath(dbusNMPath)),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- )
- if b.wifiDevice != nil {
- dev := b.wifiDevice.(gonetworkmanager.Device)
- conn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath(dev.GetPath())),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- )
- }
- conn.RemoveSignal(signals)
- conn.Close()
- return err
- }
- }
-
- b.sigWG.Add(1)
- go func() {
- defer b.sigWG.Done()
- for {
- select {
- case <-b.stopChan:
- return
- case sig, ok := <-signals:
- if !ok {
- return
- }
- if sig == nil {
- continue
- }
- b.handleDBusSignal(sig)
- }
- }
- }()
- return nil
-}
-
-func (b *NetworkManagerBackend) stopSignalPump() {
- if b.dbusConn == nil {
- return
- }
-
- b.dbusConn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath(dbusNMPath)),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- )
-
- if b.wifiDevice != nil {
- dev := b.wifiDevice.(gonetworkmanager.Device)
- b.dbusConn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath(dev.GetPath())),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- )
- }
-
- if b.ethernetDevice != nil {
- dev := b.ethernetDevice.(gonetworkmanager.Device)
- b.dbusConn.RemoveMatchSignal(
- dbus.WithMatchObjectPath(dbus.ObjectPath(dev.GetPath())),
- dbus.WithMatchInterface(dbusPropsInterface),
- dbus.WithMatchMember("PropertiesChanged"),
- )
- }
-
- if b.signals != nil {
- b.dbusConn.RemoveSignal(b.signals)
- close(b.signals)
- }
-
- b.sigWG.Wait()
-
- b.dbusConn.Close()
-}
-
-func (b *NetworkManagerBackend) handleDBusSignal(sig *dbus.Signal) {
- if sig.Name == "org.freedesktop.NetworkManager.Settings.NewConnection" ||
- sig.Name == "org.freedesktop.NetworkManager.Settings.ConnectionRemoved" {
- b.ListVPNProfiles()
- if b.onStateChange != nil {
- b.onStateChange()
- }
- return
- }
-
- if len(sig.Body) < 2 {
- return
- }
-
- iface, ok := sig.Body[0].(string)
- if !ok {
- return
- }
-
- changes, ok := sig.Body[1].(map[string]dbus.Variant)
- if !ok {
- return
- }
-
- switch iface {
- case dbusNMInterface:
- b.handleNetworkManagerChange(changes)
-
- case dbusNMDeviceInterface:
- b.handleDeviceChange(changes)
-
- case dbusNMWirelessInterface:
- b.handleWiFiChange(changes)
-
- case dbusNMAccessPointInterface:
- b.handleAccessPointChange(changes)
- }
-}
-
-func (b *NetworkManagerBackend) handleNetworkManagerChange(changes map[string]dbus.Variant) {
- var needsUpdate bool
-
- for key := range changes {
- switch key {
- case "PrimaryConnection", "State", "ActiveConnections":
- needsUpdate = true
- case "WirelessEnabled":
- nm := b.nmConn.(gonetworkmanager.NetworkManager)
- if enabled, err := nm.GetPropertyWirelessEnabled(); err == nil {
- b.stateMutex.Lock()
- b.state.WiFiEnabled = enabled
- b.stateMutex.Unlock()
- needsUpdate = true
- }
- default:
- continue
- }
- }
-
- if needsUpdate {
- b.updatePrimaryConnection()
- if _, exists := changes["State"]; exists {
- b.updateEthernetState()
- b.updateWiFiState()
- }
- if _, exists := changes["ActiveConnections"]; exists {
- b.updateVPNConnectionState()
- b.ListActiveVPN()
- }
- if b.onStateChange != nil {
- b.onStateChange()
- }
- }
-}
-
-func (b *NetworkManagerBackend) handleDeviceChange(changes map[string]dbus.Variant) {
- var needsUpdate bool
- var stateChanged bool
-
- for key := range changes {
- switch key {
- case "State":
- stateChanged = true
- needsUpdate = true
- case "Ip4Config":
- needsUpdate = true
- default:
- continue
- }
- }
-
- if needsUpdate {
- b.updateEthernetState()
- b.updateWiFiState()
- if stateChanged {
- b.updatePrimaryConnection()
- }
- if b.onStateChange != nil {
- b.onStateChange()
- }
- }
-}
-
-func (b *NetworkManagerBackend) handleWiFiChange(changes map[string]dbus.Variant) {
- var needsStateUpdate bool
- var needsNetworkUpdate bool
-
- for key := range changes {
- switch key {
- case "ActiveAccessPoint":
- needsStateUpdate = true
- needsNetworkUpdate = true
- case "AccessPoints":
- needsNetworkUpdate = true
- default:
- continue
- }
- }
-
- if needsStateUpdate {
- b.updateWiFiState()
- }
- if needsNetworkUpdate {
- b.updateWiFiNetworks()
- }
- if needsStateUpdate || needsNetworkUpdate {
- if b.onStateChange != nil {
- b.onStateChange()
- }
- }
-}
-
-func (b *NetworkManagerBackend) handleAccessPointChange(changes map[string]dbus.Variant) {
- _, hasStrength := changes["Strength"]
- if !hasStrength {
- return
- }
-
- b.stateMutex.RLock()
- oldSignal := b.state.WiFiSignal
- b.stateMutex.RUnlock()
-
- b.updateWiFiState()
-
- b.stateMutex.RLock()
- newSignal := b.state.WiFiSignal
- b.stateMutex.RUnlock()
-
- if signalChangeSignificant(oldSignal, newSignal) {
- if b.onStateChange != nil {
- b.onStateChange()
- }
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_signals_test.go b/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_signals_test.go
deleted file mode 100644
index aa90a80..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_signals_test.go
+++ /dev/null
@@ -1,240 +0,0 @@
-package network
-
-import (
- "testing"
-
- "github.com/godbus/dbus/v5"
- "github.com/stretchr/testify/assert"
-)
-
-func TestNetworkManagerBackend_HandleDBusSignal_NewConnection(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.NetworkManager.Settings.NewConnection",
- Body: []interface{}{"/org/freedesktop/NetworkManager/Settings/1"},
- }
-
- assert.NotPanics(t, func() {
- backend.handleDBusSignal(sig)
- })
-}
-
-func TestNetworkManagerBackend_HandleDBusSignal_ConnectionRemoved(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.NetworkManager.Settings.ConnectionRemoved",
- Body: []interface{}{"/org/freedesktop/NetworkManager/Settings/1"},
- }
-
- assert.NotPanics(t, func() {
- backend.handleDBusSignal(sig)
- })
-}
-
-func TestNetworkManagerBackend_HandleDBusSignal_InvalidBody(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.DBus.Properties.PropertiesChanged",
- Body: []interface{}{"only-one-element"},
- }
-
- assert.NotPanics(t, func() {
- backend.handleDBusSignal(sig)
- })
-}
-
-func TestNetworkManagerBackend_HandleDBusSignal_InvalidInterface(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.DBus.Properties.PropertiesChanged",
- Body: []interface{}{123, map[string]dbus.Variant{}},
- }
-
- assert.NotPanics(t, func() {
- backend.handleDBusSignal(sig)
- })
-}
-
-func TestNetworkManagerBackend_HandleDBusSignal_InvalidChanges(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- sig := &dbus.Signal{
- Name: "org.freedesktop.DBus.Properties.PropertiesChanged",
- Body: []interface{}{dbusNMInterface, "not-a-map"},
- }
-
- assert.NotPanics(t, func() {
- backend.handleDBusSignal(sig)
- })
-}
-
-func TestNetworkManagerBackend_HandleNetworkManagerChange(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- changes := map[string]dbus.Variant{
- "PrimaryConnection": dbus.MakeVariant("/"),
- "State": dbus.MakeVariant(uint32(70)),
- }
-
- assert.NotPanics(t, func() {
- backend.handleNetworkManagerChange(changes)
- })
-}
-
-func TestNetworkManagerBackend_HandleNetworkManagerChange_WirelessEnabled(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- changes := map[string]dbus.Variant{
- "WirelessEnabled": dbus.MakeVariant(true),
- }
-
- assert.NotPanics(t, func() {
- backend.handleNetworkManagerChange(changes)
- })
-}
-
-func TestNetworkManagerBackend_HandleNetworkManagerChange_ActiveConnections(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- changes := map[string]dbus.Variant{
- "ActiveConnections": dbus.MakeVariant([]interface{}{}),
- }
-
- assert.NotPanics(t, func() {
- backend.handleNetworkManagerChange(changes)
- })
-}
-
-func TestNetworkManagerBackend_HandleDeviceChange(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- changes := map[string]dbus.Variant{
- "State": dbus.MakeVariant(uint32(100)),
- }
-
- assert.NotPanics(t, func() {
- backend.handleDeviceChange(changes)
- })
-}
-
-func TestNetworkManagerBackend_HandleDeviceChange_Ip4Config(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- changes := map[string]dbus.Variant{
- "Ip4Config": dbus.MakeVariant("/"),
- }
-
- assert.NotPanics(t, func() {
- backend.handleDeviceChange(changes)
- })
-}
-
-func TestNetworkManagerBackend_HandleWiFiChange_ActiveAccessPoint(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- changes := map[string]dbus.Variant{
- "ActiveAccessPoint": dbus.MakeVariant("/"),
- }
-
- assert.NotPanics(t, func() {
- backend.handleWiFiChange(changes)
- })
-}
-
-func TestNetworkManagerBackend_HandleWiFiChange_AccessPoints(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- changes := map[string]dbus.Variant{
- "AccessPoints": dbus.MakeVariant([]interface{}{}),
- }
-
- assert.NotPanics(t, func() {
- backend.handleWiFiChange(changes)
- })
-}
-
-func TestNetworkManagerBackend_HandleAccessPointChange_NoStrength(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- changes := map[string]dbus.Variant{
- "SomeOtherProperty": dbus.MakeVariant("value"),
- }
-
- assert.NotPanics(t, func() {
- backend.handleAccessPointChange(changes)
- })
-}
-
-func TestNetworkManagerBackend_HandleAccessPointChange_WithStrength(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.stateMutex.Lock()
- backend.state.WiFiSignal = 50
- backend.stateMutex.Unlock()
-
- changes := map[string]dbus.Variant{
- "Strength": dbus.MakeVariant(uint8(80)),
- }
-
- assert.NotPanics(t, func() {
- backend.handleAccessPointChange(changes)
- })
-}
-
-func TestNetworkManagerBackend_StopSignalPump_NoConnection(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.dbusConn = nil
- assert.NotPanics(t, func() {
- backend.stopSignalPump()
- })
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_state.go b/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_state.go
deleted file mode 100644
index 72c2268..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_state.go
+++ /dev/null
@@ -1,261 +0,0 @@
-package network
-
-import (
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/errdefs"
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/Wifx/gonetworkmanager/v2"
-)
-
-func (b *NetworkManagerBackend) updatePrimaryConnection() error {
- nm := b.nmConn.(gonetworkmanager.NetworkManager)
-
- activeConns, err := nm.GetPropertyActiveConnections()
- if err != nil {
- return err
- }
-
- hasActiveVPN := false
- for _, activeConn := range activeConns {
- connType, err := activeConn.GetPropertyType()
- if err != nil {
- continue
- }
- if connType == "vpn" || connType == "wireguard" {
- state, _ := activeConn.GetPropertyState()
- if state == 2 {
- hasActiveVPN = true
- break
- }
- }
- }
-
- if hasActiveVPN {
- b.stateMutex.Lock()
- b.state.NetworkStatus = StatusVPN
- b.stateMutex.Unlock()
- return nil
- }
-
- primaryConn, err := nm.GetPropertyPrimaryConnection()
- if err != nil {
- return err
- }
-
- if primaryConn == nil || primaryConn.GetPath() == "/" {
- b.stateMutex.Lock()
- b.state.NetworkStatus = StatusDisconnected
- b.stateMutex.Unlock()
- return nil
- }
-
- connType, err := primaryConn.GetPropertyType()
- if err != nil {
- return err
- }
-
- b.stateMutex.Lock()
- switch connType {
- case "802-3-ethernet":
- b.state.NetworkStatus = StatusEthernet
- case "802-11-wireless":
- b.state.NetworkStatus = StatusWiFi
- case "vpn", "wireguard":
- b.state.NetworkStatus = StatusVPN
- default:
- b.state.NetworkStatus = StatusDisconnected
- }
- b.stateMutex.Unlock()
-
- return nil
-}
-
-func (b *NetworkManagerBackend) updateEthernetState() error {
- if b.ethernetDevice == nil {
- return nil
- }
-
- dev := b.ethernetDevice.(gonetworkmanager.Device)
-
- iface, err := dev.GetPropertyInterface()
- if err != nil {
- return err
- }
-
- state, err := dev.GetPropertyState()
- if err != nil {
- return err
- }
-
- connected := state == gonetworkmanager.NmDeviceStateActivated
-
- var ip string
- if connected {
- ip = b.getDeviceIP(dev)
- }
-
- b.stateMutex.Lock()
- b.state.EthernetDevice = iface
- b.state.EthernetConnected = connected
- b.state.EthernetIP = ip
- b.stateMutex.Unlock()
-
- return nil
-}
-
-func (b *NetworkManagerBackend) getDeviceStateReason(dev gonetworkmanager.Device) uint32 {
- path := dev.GetPath()
- obj := b.dbusConn.Object("org.freedesktop.NetworkManager", path)
-
- variant, err := obj.GetProperty(dbusNMDeviceInterface + ".StateReason")
- if err != nil {
- return 0
- }
-
- if stateReasonStruct, ok := variant.Value().([]interface{}); ok && len(stateReasonStruct) >= 2 {
- if reason, ok := stateReasonStruct[1].(uint32); ok {
- return reason
- }
- }
-
- return 0
-}
-
-func (b *NetworkManagerBackend) classifyNMStateReason(reason uint32) string {
- switch reason {
- case NmDeviceStateReasonWrongPassword,
- NmDeviceStateReasonSupplicantTimeout,
- NmDeviceStateReasonSupplicantFailed,
- NmDeviceStateReasonSecretsRequired:
- return errdefs.ErrBadCredentials
- case NmDeviceStateReasonNoSecrets:
- return errdefs.ErrUserCanceled
- case NmDeviceStateReasonNoSsid:
- return errdefs.ErrNoSuchSSID
- case NmDeviceStateReasonDhcpClientFailed,
- NmDeviceStateReasonIpConfigUnavailable:
- return errdefs.ErrDhcpTimeout
- case NmDeviceStateReasonSupplicantDisconnect,
- NmDeviceStateReasonCarrier:
- return errdefs.ErrAssocTimeout
- default:
- return errdefs.ErrConnectionFailed
- }
-}
-
-func (b *NetworkManagerBackend) updateWiFiState() error {
- if b.wifiDevice == nil {
- return nil
- }
-
- dev := b.wifiDevice.(gonetworkmanager.Device)
-
- iface, err := dev.GetPropertyInterface()
- if err != nil {
- return err
- }
-
- state, err := dev.GetPropertyState()
- if err != nil {
- return err
- }
-
- connected := state == gonetworkmanager.NmDeviceStateActivated
- failed := state == gonetworkmanager.NmDeviceStateFailed
- disconnected := state == gonetworkmanager.NmDeviceStateDisconnected
-
- var ip, ssid, bssid string
- var signal uint8
-
- if connected {
- if err := b.ensureWiFiDevice(); err == nil && b.wifiDev != nil {
- w := b.wifiDev.(gonetworkmanager.DeviceWireless)
- activeAP, err := w.GetPropertyActiveAccessPoint()
- if err == nil && activeAP != nil && activeAP.GetPath() != "/" {
- ssid, _ = activeAP.GetPropertySSID()
- signal, _ = activeAP.GetPropertyStrength()
- bssid, _ = activeAP.GetPropertyHWAddress()
- }
- }
-
- ip = b.getDeviceIP(dev)
- }
-
- b.stateMutex.RLock()
- wasConnecting := b.state.IsConnecting
- connectingSSID := b.state.ConnectingSSID
- b.stateMutex.RUnlock()
-
- var reasonCode string
- if wasConnecting && connectingSSID != "" && (failed || (disconnected && !connected)) {
- reason := b.getDeviceStateReason(dev)
-
- if reason == NmDeviceStateReasonNewActivation || reason == 0 {
- return nil
- }
-
- log.Warnf("[updateWiFiState] Connection failed: SSID=%s, state=%d, reason=%d", connectingSSID, state, reason)
-
- reasonCode = b.classifyNMStateReason(reason)
-
- if reasonCode == errdefs.ErrConnectionFailed {
- b.failedMutex.RLock()
- if b.lastFailedSSID == connectingSSID {
- elapsed := time.Now().Unix() - b.lastFailedTime
- if elapsed < 5 {
- reasonCode = errdefs.ErrBadCredentials
- }
- }
- b.failedMutex.RUnlock()
- }
- }
-
- b.stateMutex.Lock()
- defer b.stateMutex.Unlock()
-
- wasConnecting = b.state.IsConnecting
- connectingSSID = b.state.ConnectingSSID
-
- if wasConnecting && connectingSSID != "" {
- if connected && ssid == connectingSSID {
- log.Infof("[updateWiFiState] Connection successful: %s", ssid)
- b.state.IsConnecting = false
- b.state.ConnectingSSID = ""
- b.state.LastError = ""
- } else if failed || (disconnected && !connected) {
- log.Warnf("[updateWiFiState] Connection failed: SSID=%s, state=%d", connectingSSID, state)
- b.state.IsConnecting = false
- b.state.ConnectingSSID = ""
- b.state.LastError = reasonCode
-
- b.failedMutex.Lock()
- b.lastFailedSSID = connectingSSID
- b.lastFailedTime = time.Now().Unix()
- b.failedMutex.Unlock()
- }
- }
-
- b.state.WiFiDevice = iface
- b.state.WiFiConnected = connected
- b.state.WiFiIP = ip
- b.state.WiFiSSID = ssid
- b.state.WiFiBSSID = bssid
- b.state.WiFiSignal = signal
-
- return nil
-}
-
-func (b *NetworkManagerBackend) getDeviceIP(dev gonetworkmanager.Device) string {
- ip4Config, err := dev.GetPropertyIP4Config()
- if err != nil || ip4Config == nil {
- return ""
- }
-
- addresses, err := ip4Config.GetPropertyAddressData()
- if err != nil || len(addresses) == 0 {
- return ""
- }
-
- return addresses[0].Address
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_state_test.go b/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_state_test.go
deleted file mode 100644
index ef9e1b8..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_state_test.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package network
-
-import (
- "testing"
-
- "github.com/AvengeMedia/danklinux/internal/errdefs"
- mock_gonetworkmanager "github.com/AvengeMedia/danklinux/internal/mocks/github.com/Wifx/gonetworkmanager/v2"
- "github.com/Wifx/gonetworkmanager/v2"
- "github.com/stretchr/testify/assert"
-)
-
-func TestNetworkManagerBackend_UpdatePrimaryConnection(t *testing.T) {
- mockNM := mock_gonetworkmanager.NewMockNetworkManager(t)
-
- backend, err := NewNetworkManagerBackend(mockNM)
- assert.NoError(t, err)
-
- mockNM.EXPECT().GetPropertyActiveConnections().Return([]gonetworkmanager.ActiveConnection{}, nil)
- mockNM.EXPECT().GetPropertyPrimaryConnection().Return(nil, nil)
-
- err = backend.updatePrimaryConnection()
- assert.NoError(t, err)
-}
-
-func TestNetworkManagerBackend_UpdateEthernetState_NoDevice(t *testing.T) {
- mockNM := mock_gonetworkmanager.NewMockNetworkManager(t)
-
- backend, err := NewNetworkManagerBackend(mockNM)
- assert.NoError(t, err)
-
- backend.ethernetDevice = nil
- err = backend.updateEthernetState()
- assert.NoError(t, err)
-}
-
-func TestNetworkManagerBackend_UpdateWiFiState_NoDevice(t *testing.T) {
- mockNM := mock_gonetworkmanager.NewMockNetworkManager(t)
-
- backend, err := NewNetworkManagerBackend(mockNM)
- assert.NoError(t, err)
-
- backend.wifiDevice = nil
- err = backend.updateWiFiState()
- assert.NoError(t, err)
-}
-
-func TestNetworkManagerBackend_ClassifyNMStateReason(t *testing.T) {
- mockNM := mock_gonetworkmanager.NewMockNetworkManager(t)
-
- backend, err := NewNetworkManagerBackend(mockNM)
- assert.NoError(t, err)
-
- testCases := []struct {
- reason uint32
- expected string
- }{
- {NmDeviceStateReasonWrongPassword, errdefs.ErrBadCredentials},
- {NmDeviceStateReasonNoSecrets, errdefs.ErrUserCanceled},
- {NmDeviceStateReasonSupplicantTimeout, errdefs.ErrBadCredentials},
- {NmDeviceStateReasonDhcpClientFailed, errdefs.ErrDhcpTimeout},
- {NmDeviceStateReasonNoSsid, errdefs.ErrNoSuchSSID},
- {999, errdefs.ErrConnectionFailed},
- }
-
- for _, tc := range testCases {
- result := backend.classifyNMStateReason(tc.reason)
- assert.Equal(t, tc.expected, result)
- }
-}
-
-func TestNetworkManagerBackend_GetDeviceIP_NoConfig(t *testing.T) {
- mockNM := mock_gonetworkmanager.NewMockNetworkManager(t)
- mockDevice := mock_gonetworkmanager.NewMockDevice(t)
-
- backend, err := NewNetworkManagerBackend(mockNM)
- assert.NoError(t, err)
-
- mockDevice.EXPECT().GetPropertyIP4Config().Return(nil, nil)
-
- ip := backend.getDeviceIP(mockDevice)
- assert.Empty(t, ip)
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_test.go b/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_test.go
deleted file mode 100644
index 4d9ba23..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_test.go
+++ /dev/null
@@ -1,154 +0,0 @@
-package network
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestNetworkManagerBackend_New(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- assert.NotNil(t, backend)
- assert.Equal(t, "networkmanager", backend.state.Backend)
- assert.NotNil(t, backend.stopChan)
- assert.NotNil(t, backend.state)
-}
-
-func TestNetworkManagerBackend_GetCurrentState(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.state.NetworkStatus = StatusWiFi
- backend.state.WiFiConnected = true
- backend.state.WiFiSSID = "TestNetwork"
- backend.state.WiFiIP = "192.168.1.100"
- backend.state.WiFiNetworks = []WiFiNetwork{
- {SSID: "TestNetwork", Signal: 80, Connected: true},
- }
- backend.state.WiredConnections = []WiredConnection{
- {ID: "Wired connection 1", UUID: "test-uuid"},
- }
-
- state, err := backend.GetCurrentState()
- assert.NoError(t, err)
- assert.NotNil(t, state)
- assert.Equal(t, StatusWiFi, state.NetworkStatus)
- assert.True(t, state.WiFiConnected)
- assert.Equal(t, "TestNetwork", state.WiFiSSID)
- assert.Len(t, state.WiFiNetworks, 1)
- assert.Len(t, state.WiredConnections, 1)
-
- assert.NotSame(t, &backend.state.WiFiNetworks, &state.WiFiNetworks)
- assert.NotSame(t, &backend.state.WiredConnections, &state.WiredConnections)
-}
-
-func TestNetworkManagerBackend_SetPromptBroker_Nil(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- err = backend.SetPromptBroker(nil)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "cannot be nil")
-}
-
-func TestNetworkManagerBackend_SubmitCredentials_NoBroker(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.promptBroker = nil
- err = backend.SubmitCredentials("token", map[string]string{"password": "test"}, false)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not initialized")
-}
-
-func TestNetworkManagerBackend_CancelCredentials_NoBroker(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.promptBroker = nil
- err = backend.CancelCredentials("token")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not initialized")
-}
-
-func TestNetworkManagerBackend_EnsureWiFiDevice_NoDevice(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.wifiDevice = nil
- backend.wifiDev = nil
-
- err = backend.ensureWiFiDevice()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no WiFi device available")
-}
-
-func TestNetworkManagerBackend_EnsureWiFiDevice_AlreadySet(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.wifiDev = "dummy-device"
-
- err = backend.ensureWiFiDevice()
- assert.NoError(t, err)
-}
-
-func TestNetworkManagerBackend_StartSecretAgent_NoBroker(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.promptBroker = nil
- err = backend.startSecretAgent()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "prompt broker not set")
-}
-
-func TestNetworkManagerBackend_Close(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- assert.NotPanics(t, func() {
- backend.Close()
- })
-}
-
-func TestNetworkManagerBackend_GetPromptBroker(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- broker := backend.GetPromptBroker()
- assert.Nil(t, broker)
-}
-
-func TestNetworkManagerBackend_StopMonitoring_NoSignals(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- assert.NotPanics(t, func() {
- backend.StopMonitoring()
- })
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_vpn.go b/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_vpn.go
deleted file mode 100644
index c5ffee0..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_vpn.go
+++ /dev/null
@@ -1,527 +0,0 @@
-package network
-
-import (
- "fmt"
- "sort"
- "strings"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/Wifx/gonetworkmanager/v2"
-)
-
-func (b *NetworkManagerBackend) ListVPNProfiles() ([]VPNProfile, error) {
- s := b.settings
- if s == nil {
- var err error
- s, err = gonetworkmanager.NewSettings()
- if err != nil {
- return nil, fmt.Errorf("failed to get settings: %w", err)
- }
- b.settings = s
- }
-
- settingsMgr := s.(gonetworkmanager.Settings)
- connections, err := settingsMgr.ListConnections()
- if err != nil {
- return nil, fmt.Errorf("failed to get connections: %w", err)
- }
-
- var profiles []VPNProfile
- for _, conn := range connections {
- settings, err := conn.GetSettings()
- if err != nil {
- continue
- }
-
- connMeta, ok := settings["connection"]
- if !ok {
- continue
- }
-
- connType, _ := connMeta["type"].(string)
- if connType != "vpn" && connType != "wireguard" {
- continue
- }
-
- connID, _ := connMeta["id"].(string)
- connUUID, _ := connMeta["uuid"].(string)
-
- profile := VPNProfile{
- Name: connID,
- UUID: connUUID,
- Type: connType,
- }
-
- if connType == "vpn" {
- if vpnSettings, ok := settings["vpn"]; ok {
- if svcType, ok := vpnSettings["service-type"].(string); ok {
- profile.ServiceType = svcType
- }
- }
- }
-
- profiles = append(profiles, profile)
- }
-
- sort.Slice(profiles, func(i, j int) bool {
- return strings.ToLower(profiles[i].Name) < strings.ToLower(profiles[j].Name)
- })
-
- b.stateMutex.Lock()
- b.state.VPNProfiles = profiles
- b.stateMutex.Unlock()
-
- return profiles, nil
-}
-
-func (b *NetworkManagerBackend) ListActiveVPN() ([]VPNActive, error) {
- nm := b.nmConn.(gonetworkmanager.NetworkManager)
-
- activeConns, err := nm.GetPropertyActiveConnections()
- if err != nil {
- return nil, fmt.Errorf("failed to get active connections: %w", err)
- }
-
- var active []VPNActive
- for _, activeConn := range activeConns {
- connType, err := activeConn.GetPropertyType()
- if err != nil {
- continue
- }
-
- if connType != "vpn" && connType != "wireguard" {
- continue
- }
-
- uuid, _ := activeConn.GetPropertyUUID()
- id, _ := activeConn.GetPropertyID()
- state, _ := activeConn.GetPropertyState()
-
- var stateStr string
- switch state {
- case 0:
- stateStr = "unknown"
- case 1:
- stateStr = "activating"
- case 2:
- stateStr = "activated"
- case 3:
- stateStr = "deactivating"
- case 4:
- stateStr = "deactivated"
- }
-
- vpnActive := VPNActive{
- Name: id,
- UUID: uuid,
- State: stateStr,
- Type: connType,
- Plugin: "",
- }
-
- if connType == "vpn" {
- conn, _ := activeConn.GetPropertyConnection()
- if conn != nil {
- connSettings, err := conn.GetSettings()
- if err == nil {
- if vpnSettings, ok := connSettings["vpn"]; ok {
- if svcType, ok := vpnSettings["service-type"].(string); ok {
- vpnActive.Plugin = svcType
- }
- }
- }
- }
- }
-
- active = append(active, vpnActive)
- }
-
- b.stateMutex.Lock()
- b.state.VPNActive = active
- b.stateMutex.Unlock()
-
- return active, nil
-}
-
-func (b *NetworkManagerBackend) ConnectVPN(uuidOrName string, singleActive bool) error {
- if singleActive {
- active, err := b.ListActiveVPN()
- if err == nil && len(active) > 0 {
- alreadyConnected := false
- for _, vpn := range active {
- if vpn.UUID == uuidOrName || vpn.Name == uuidOrName {
- alreadyConnected = true
- break
- }
- }
-
- if !alreadyConnected {
- if err := b.DisconnectAllVPN(); err != nil {
- log.Warnf("Failed to disconnect existing VPNs: %v", err)
- }
- time.Sleep(500 * time.Millisecond)
- } else {
- return nil
- }
- }
- }
-
- s := b.settings
- if s == nil {
- var err error
- s, err = gonetworkmanager.NewSettings()
- if err != nil {
- return fmt.Errorf("failed to get settings: %w", err)
- }
- b.settings = s
- }
-
- settingsMgr := s.(gonetworkmanager.Settings)
- connections, err := settingsMgr.ListConnections()
- if err != nil {
- return fmt.Errorf("failed to get connections: %w", err)
- }
-
- var targetConn gonetworkmanager.Connection
- for _, conn := range connections {
- settings, err := conn.GetSettings()
- if err != nil {
- continue
- }
-
- connMeta, ok := settings["connection"]
- if !ok {
- continue
- }
-
- connType, _ := connMeta["type"].(string)
- if connType != "vpn" && connType != "wireguard" {
- continue
- }
-
- connID, _ := connMeta["id"].(string)
- connUUID, _ := connMeta["uuid"].(string)
-
- if connUUID == uuidOrName || connID == uuidOrName {
- targetConn = conn
- break
- }
- }
-
- if targetConn == nil {
- return fmt.Errorf("VPN connection not found: %s", uuidOrName)
- }
-
- targetSettings, err := targetConn.GetSettings()
- if err != nil {
- return fmt.Errorf("failed to get connection settings: %w", err)
- }
-
- var targetUUID string
- if connMeta, ok := targetSettings["connection"]; ok {
- if uuid, ok := connMeta["uuid"].(string); ok {
- targetUUID = uuid
- }
- }
-
- b.stateMutex.Lock()
- b.state.IsConnectingVPN = true
- b.state.ConnectingVPNUUID = targetUUID
- b.stateMutex.Unlock()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- nm := b.nmConn.(gonetworkmanager.NetworkManager)
- activeConn, err := nm.ActivateConnection(targetConn, nil, nil)
- if err != nil {
- b.stateMutex.Lock()
- b.state.IsConnectingVPN = false
- b.state.ConnectingVPNUUID = ""
- b.stateMutex.Unlock()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- return fmt.Errorf("failed to activate VPN: %w", err)
- }
-
- if activeConn != nil {
- state, _ := activeConn.GetPropertyState()
- if state == 2 {
- b.stateMutex.Lock()
- b.state.IsConnectingVPN = false
- b.state.ConnectingVPNUUID = ""
- b.stateMutex.Unlock()
- b.ListActiveVPN()
- if b.onStateChange != nil {
- b.onStateChange()
- }
- }
- }
-
- return nil
-}
-
-func (b *NetworkManagerBackend) DisconnectVPN(uuidOrName string) error {
- nm := b.nmConn.(gonetworkmanager.NetworkManager)
-
- activeConns, err := nm.GetPropertyActiveConnections()
- if err != nil {
- return fmt.Errorf("failed to get active connections: %w", err)
- }
-
- log.Debugf("[DisconnectVPN] Looking for VPN: %s", uuidOrName)
-
- for _, activeConn := range activeConns {
- connType, err := activeConn.GetPropertyType()
- if err != nil {
- continue
- }
-
- if connType != "vpn" && connType != "wireguard" {
- continue
- }
-
- uuid, _ := activeConn.GetPropertyUUID()
- id, _ := activeConn.GetPropertyID()
- state, _ := activeConn.GetPropertyState()
-
- log.Debugf("[DisconnectVPN] Found active VPN: uuid=%s id=%s state=%d", uuid, id, state)
-
- if uuid == uuidOrName || id == uuidOrName {
- log.Infof("[DisconnectVPN] Deactivating VPN: %s (state=%d)", id, state)
- if err := nm.DeactivateConnection(activeConn); err != nil {
- return fmt.Errorf("failed to deactivate VPN: %w", err)
- }
- b.ListActiveVPN()
- if b.onStateChange != nil {
- b.onStateChange()
- }
- return nil
- }
- }
-
- log.Warnf("[DisconnectVPN] VPN not found in active connections: %s", uuidOrName)
-
- s := b.settings
- if s == nil {
- var err error
- s, err = gonetworkmanager.NewSettings()
- if err != nil {
- return fmt.Errorf("VPN connection not active and cannot access settings: %w", err)
- }
- b.settings = s
- }
-
- settingsMgr := s.(gonetworkmanager.Settings)
- connections, err := settingsMgr.ListConnections()
- if err != nil {
- return fmt.Errorf("VPN connection not active: %s", uuidOrName)
- }
-
- for _, conn := range connections {
- settings, err := conn.GetSettings()
- if err != nil {
- continue
- }
-
- connMeta, ok := settings["connection"]
- if !ok {
- continue
- }
-
- connType, _ := connMeta["type"].(string)
- if connType != "vpn" && connType != "wireguard" {
- continue
- }
-
- connID, _ := connMeta["id"].(string)
- connUUID, _ := connMeta["uuid"].(string)
-
- if connUUID == uuidOrName || connID == uuidOrName {
- log.Infof("[DisconnectVPN] VPN connection exists but not active: %s", connID)
- return nil
- }
- }
-
- return fmt.Errorf("VPN connection not found: %s", uuidOrName)
-}
-
-func (b *NetworkManagerBackend) DisconnectAllVPN() error {
- nm := b.nmConn.(gonetworkmanager.NetworkManager)
-
- activeConns, err := nm.GetPropertyActiveConnections()
- if err != nil {
- return fmt.Errorf("failed to get active connections: %w", err)
- }
-
- var lastErr error
- var disconnected bool
- for _, activeConn := range activeConns {
- connType, err := activeConn.GetPropertyType()
- if err != nil {
- continue
- }
-
- if connType != "vpn" && connType != "wireguard" {
- continue
- }
-
- if err := nm.DeactivateConnection(activeConn); err != nil {
- lastErr = err
- log.Warnf("Failed to deactivate VPN connection: %v", err)
- } else {
- disconnected = true
- }
- }
-
- if disconnected {
- b.ListActiveVPN()
- if b.onStateChange != nil {
- b.onStateChange()
- }
- }
-
- return lastErr
-}
-
-func (b *NetworkManagerBackend) ClearVPNCredentials(uuidOrName string) error {
- s := b.settings
- if s == nil {
- var err error
- s, err = gonetworkmanager.NewSettings()
- if err != nil {
- return fmt.Errorf("failed to get settings: %w", err)
- }
- b.settings = s
- }
-
- settingsMgr := s.(gonetworkmanager.Settings)
- connections, err := settingsMgr.ListConnections()
- if err != nil {
- return fmt.Errorf("failed to get connections: %w", err)
- }
-
- for _, conn := range connections {
- settings, err := conn.GetSettings()
- if err != nil {
- continue
- }
-
- connMeta, ok := settings["connection"]
- if !ok {
- continue
- }
-
- connType, _ := connMeta["type"].(string)
- if connType != "vpn" && connType != "wireguard" {
- continue
- }
-
- connID, _ := connMeta["id"].(string)
- connUUID, _ := connMeta["uuid"].(string)
-
- if connUUID == uuidOrName || connID == uuidOrName {
- if connType == "vpn" {
- if vpnSettings, ok := settings["vpn"]; ok {
- delete(vpnSettings, "secrets")
-
- if dataMap, ok := vpnSettings["data"].(map[string]string); ok {
- dataMap["password-flags"] = "1"
- vpnSettings["data"] = dataMap
- }
-
- vpnSettings["password-flags"] = uint32(1)
- }
-
- settings["vpn-secrets"] = make(map[string]interface{})
- }
-
- if err := conn.Update(settings); err != nil {
- return fmt.Errorf("failed to update connection: %w", err)
- }
-
- if err := conn.ClearSecrets(); err != nil {
- log.Warnf("ClearSecrets call failed (may not be critical): %v", err)
- }
-
- log.Infof("Cleared credentials for VPN: %s", connID)
- return nil
- }
- }
-
- return fmt.Errorf("VPN connection not found: %s", uuidOrName)
-}
-
-func (b *NetworkManagerBackend) updateVPNConnectionState() {
- b.stateMutex.RLock()
- isConnectingVPN := b.state.IsConnectingVPN
- connectingVPNUUID := b.state.ConnectingVPNUUID
- b.stateMutex.RUnlock()
-
- if !isConnectingVPN || connectingVPNUUID == "" {
- return
- }
-
- nm := b.nmConn.(gonetworkmanager.NetworkManager)
- activeConns, err := nm.GetPropertyActiveConnections()
- if err != nil {
- return
- }
-
- foundConnection := false
- for _, activeConn := range activeConns {
- connType, err := activeConn.GetPropertyType()
- if err != nil {
- continue
- }
-
- if connType != "vpn" && connType != "wireguard" {
- continue
- }
-
- uuid, err := activeConn.GetPropertyUUID()
- if err != nil {
- continue
- }
-
- state, _ := activeConn.GetPropertyState()
- stateReason, _ := activeConn.GetPropertyStateFlags()
-
- if uuid == connectingVPNUUID {
- foundConnection = true
-
- switch state {
- case 2:
- log.Infof("[updateVPNConnectionState] VPN connection successful: %s", uuid)
- b.stateMutex.Lock()
- b.state.IsConnectingVPN = false
- b.state.ConnectingVPNUUID = ""
- b.state.LastError = ""
- b.stateMutex.Unlock()
- return
- case 4:
- log.Warnf("[updateVPNConnectionState] VPN connection failed/deactivated: %s (state=%d, flags=%d)", uuid, state, stateReason)
- b.stateMutex.Lock()
- b.state.IsConnectingVPN = false
- b.state.ConnectingVPNUUID = ""
- b.state.LastError = "VPN connection failed"
- b.stateMutex.Unlock()
- return
- }
- }
- }
-
- if !foundConnection {
- log.Warnf("[updateVPNConnectionState] VPN connection no longer exists: %s", connectingVPNUUID)
- b.stateMutex.Lock()
- b.state.IsConnectingVPN = false
- b.state.ConnectingVPNUUID = ""
- b.state.LastError = "VPN connection failed"
- b.stateMutex.Unlock()
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_vpn_test.go b/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_vpn_test.go
deleted file mode 100644
index 52defdd..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_vpn_test.go
+++ /dev/null
@@ -1,138 +0,0 @@
-package network
-
-import (
- "testing"
-
- mock_gonetworkmanager "github.com/AvengeMedia/danklinux/internal/mocks/github.com/Wifx/gonetworkmanager/v2"
- "github.com/Wifx/gonetworkmanager/v2"
- "github.com/stretchr/testify/assert"
-)
-
-func TestNetworkManagerBackend_ListVPNProfiles(t *testing.T) {
- mockNM := mock_gonetworkmanager.NewMockNetworkManager(t)
- mockSettings := mock_gonetworkmanager.NewMockSettings(t)
-
- backend, err := NewNetworkManagerBackend(mockNM)
- assert.NoError(t, err)
- backend.settings = mockSettings
-
- mockSettings.EXPECT().ListConnections().Return([]gonetworkmanager.Connection{}, nil)
-
- profiles, err := backend.ListVPNProfiles()
- assert.NoError(t, err)
- assert.Empty(t, profiles)
-}
-
-func TestNetworkManagerBackend_ListActiveVPN(t *testing.T) {
- mockNM := mock_gonetworkmanager.NewMockNetworkManager(t)
-
- backend, err := NewNetworkManagerBackend(mockNM)
- assert.NoError(t, err)
-
- mockNM.EXPECT().GetPropertyActiveConnections().Return([]gonetworkmanager.ActiveConnection{}, nil)
-
- active, err := backend.ListActiveVPN()
- assert.NoError(t, err)
- assert.Empty(t, active)
-}
-
-func TestNetworkManagerBackend_ConnectVPN_NotFound(t *testing.T) {
- mockNM := mock_gonetworkmanager.NewMockNetworkManager(t)
- mockSettings := mock_gonetworkmanager.NewMockSettings(t)
-
- backend, err := NewNetworkManagerBackend(mockNM)
- assert.NoError(t, err)
- backend.settings = mockSettings
-
- mockSettings.EXPECT().ListConnections().Return([]gonetworkmanager.Connection{}, nil)
-
- err = backend.ConnectVPN("non-existent-vpn-12345", false)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not found")
-}
-
-func TestNetworkManagerBackend_ConnectVPN_SingleActive_NoActiveVPN(t *testing.T) {
- mockNM := mock_gonetworkmanager.NewMockNetworkManager(t)
- mockSettings := mock_gonetworkmanager.NewMockSettings(t)
-
- backend, err := NewNetworkManagerBackend(mockNM)
- assert.NoError(t, err)
- backend.settings = mockSettings
-
- mockSettings.EXPECT().ListConnections().Return([]gonetworkmanager.Connection{}, nil)
- mockNM.EXPECT().GetPropertyActiveConnections().Return([]gonetworkmanager.ActiveConnection{}, nil)
-
- err = backend.ConnectVPN("non-existent-vpn-12345", true)
- assert.Error(t, err)
-}
-
-func TestNetworkManagerBackend_DisconnectVPN_NotActive(t *testing.T) {
- mockNM := mock_gonetworkmanager.NewMockNetworkManager(t)
-
- backend, err := NewNetworkManagerBackend(mockNM)
- assert.NoError(t, err)
-
- mockNM.EXPECT().GetPropertyActiveConnections().Return([]gonetworkmanager.ActiveConnection{}, nil)
-
- err = backend.DisconnectVPN("non-existent-vpn-12345")
- assert.Error(t, err)
-}
-
-func TestNetworkManagerBackend_DisconnectAllVPN(t *testing.T) {
- mockNM := mock_gonetworkmanager.NewMockNetworkManager(t)
-
- backend, err := NewNetworkManagerBackend(mockNM)
- assert.NoError(t, err)
-
- mockNM.EXPECT().GetPropertyActiveConnections().Return([]gonetworkmanager.ActiveConnection{}, nil)
-
- err = backend.DisconnectAllVPN()
- assert.NoError(t, err)
-}
-
-func TestNetworkManagerBackend_ClearVPNCredentials_NotFound(t *testing.T) {
- mockNM := mock_gonetworkmanager.NewMockNetworkManager(t)
- mockSettings := mock_gonetworkmanager.NewMockSettings(t)
-
- backend, err := NewNetworkManagerBackend(mockNM)
- assert.NoError(t, err)
- backend.settings = mockSettings
-
- mockSettings.EXPECT().ListConnections().Return([]gonetworkmanager.Connection{}, nil)
-
- err = backend.ClearVPNCredentials("non-existent-vpn-12345")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "not found")
-}
-
-func TestNetworkManagerBackend_UpdateVPNConnectionState_NotConnecting(t *testing.T) {
- mockNM := mock_gonetworkmanager.NewMockNetworkManager(t)
-
- backend, err := NewNetworkManagerBackend(mockNM)
- assert.NoError(t, err)
-
- backend.stateMutex.Lock()
- backend.state.IsConnectingVPN = false
- backend.state.ConnectingVPNUUID = ""
- backend.stateMutex.Unlock()
-
- assert.NotPanics(t, func() {
- backend.updateVPNConnectionState()
- })
-}
-
-func TestNetworkManagerBackend_UpdateVPNConnectionState_EmptyUUID(t *testing.T) {
- mockNM := mock_gonetworkmanager.NewMockNetworkManager(t)
-
- backend, err := NewNetworkManagerBackend(mockNM)
- assert.NoError(t, err)
-
- backend.stateMutex.Lock()
- backend.state.IsConnectingVPN = true
- backend.state.ConnectingVPNUUID = ""
- backend.stateMutex.Unlock()
-
- assert.NotPanics(t, func() {
- backend.updateVPNConnectionState()
- })
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_wifi.go b/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_wifi.go
deleted file mode 100644
index 49fe925..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_wifi.go
+++ /dev/null
@@ -1,718 +0,0 @@
-package network
-
-import (
- "bytes"
- "fmt"
- "sort"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/Wifx/gonetworkmanager/v2"
-)
-
-func (b *NetworkManagerBackend) GetWiFiEnabled() (bool, error) {
- nm := b.nmConn.(gonetworkmanager.NetworkManager)
- return nm.GetPropertyWirelessEnabled()
-}
-
-func (b *NetworkManagerBackend) SetWiFiEnabled(enabled bool) error {
- nm := b.nmConn.(gonetworkmanager.NetworkManager)
- err := nm.SetPropertyWirelessEnabled(enabled)
- if err != nil {
- return fmt.Errorf("failed to set WiFi enabled: %w", err)
- }
-
- b.stateMutex.Lock()
- b.state.WiFiEnabled = enabled
- b.stateMutex.Unlock()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- return nil
-}
-
-func (b *NetworkManagerBackend) ScanWiFi() error {
- if b.wifiDevice == nil {
- return fmt.Errorf("no WiFi device available")
- }
-
- b.stateMutex.RLock()
- enabled := b.state.WiFiEnabled
- b.stateMutex.RUnlock()
-
- if !enabled {
- return fmt.Errorf("WiFi is disabled")
- }
-
- if err := b.ensureWiFiDevice(); err != nil {
- return err
- }
-
- w := b.wifiDev.(gonetworkmanager.DeviceWireless)
- err := w.RequestScan()
- if err != nil {
- return fmt.Errorf("scan request failed: %w", err)
- }
-
- _, err = b.updateWiFiNetworks()
- return err
-}
-
-func (b *NetworkManagerBackend) GetWiFiNetworkDetails(ssid string) (*NetworkInfoResponse, error) {
- if b.wifiDevice == nil {
- return nil, fmt.Errorf("no WiFi device available")
- }
-
- if err := b.ensureWiFiDevice(); err != nil {
- return nil, err
- }
- wifiDev := b.wifiDev
-
- w := wifiDev.(gonetworkmanager.DeviceWireless)
- apPaths, err := w.GetAccessPoints()
- if err != nil {
- return nil, fmt.Errorf("failed to get access points: %w", err)
- }
-
- s := b.settings
- if s == nil {
- s, err = gonetworkmanager.NewSettings()
- if err != nil {
- return nil, fmt.Errorf("failed to get settings: %w", err)
- }
- b.settings = s
- }
-
- settingsMgr := s.(gonetworkmanager.Settings)
- connections, err := settingsMgr.ListConnections()
- if err != nil {
- return nil, fmt.Errorf("failed to get connections: %w", err)
- }
-
- savedSSIDs := make(map[string]bool)
- autoconnectMap := make(map[string]bool)
- for _, conn := range connections {
- connSettings, err := conn.GetSettings()
- if err != nil {
- continue
- }
-
- if connMeta, ok := connSettings["connection"]; ok {
- if connType, ok := connMeta["type"].(string); ok && connType == "802-11-wireless" {
- if wifiSettings, ok := connSettings["802-11-wireless"]; ok {
- if ssidBytes, ok := wifiSettings["ssid"].([]byte); ok {
- savedSSID := string(ssidBytes)
- savedSSIDs[savedSSID] = true
- autoconnect := true
- if ac, ok := connMeta["autoconnect"].(bool); ok {
- autoconnect = ac
- }
- autoconnectMap[savedSSID] = autoconnect
- }
- }
- }
- }
- }
-
- b.stateMutex.RLock()
- currentSSID := b.state.WiFiSSID
- currentBSSID := b.state.WiFiBSSID
- b.stateMutex.RUnlock()
-
- var bands []WiFiNetwork
-
- for _, ap := range apPaths {
- apSSID, err := ap.GetPropertySSID()
- if err != nil || apSSID != ssid {
- continue
- }
-
- strength, _ := ap.GetPropertyStrength()
- flags, _ := ap.GetPropertyFlags()
- wpaFlags, _ := ap.GetPropertyWPAFlags()
- rsnFlags, _ := ap.GetPropertyRSNFlags()
- freq, _ := ap.GetPropertyFrequency()
- maxBitrate, _ := ap.GetPropertyMaxBitrate()
- bssid, _ := ap.GetPropertyHWAddress()
- mode, _ := ap.GetPropertyMode()
-
- secured := flags != uint32(gonetworkmanager.Nm80211APFlagsNone) ||
- wpaFlags != uint32(gonetworkmanager.Nm80211APSecNone) ||
- rsnFlags != uint32(gonetworkmanager.Nm80211APSecNone)
-
- enterprise := (rsnFlags&uint32(gonetworkmanager.Nm80211APSecKeyMgmt8021X) != 0) ||
- (wpaFlags&uint32(gonetworkmanager.Nm80211APSecKeyMgmt8021X) != 0)
-
- var modeStr string
- switch mode {
- case gonetworkmanager.Nm80211ModeAdhoc:
- modeStr = "adhoc"
- case gonetworkmanager.Nm80211ModeInfra:
- modeStr = "infrastructure"
- case gonetworkmanager.Nm80211ModeAp:
- modeStr = "ap"
- default:
- modeStr = "unknown"
- }
-
- channel := frequencyToChannel(freq)
-
- network := WiFiNetwork{
- SSID: ssid,
- BSSID: bssid,
- Signal: strength,
- Secured: secured,
- Enterprise: enterprise,
- Connected: ssid == currentSSID && bssid == currentBSSID,
- Saved: savedSSIDs[ssid],
- Autoconnect: autoconnectMap[ssid],
- Frequency: freq,
- Mode: modeStr,
- Rate: maxBitrate / 1000,
- Channel: channel,
- }
-
- bands = append(bands, network)
- }
-
- if len(bands) == 0 {
- return nil, fmt.Errorf("network not found: %s", ssid)
- }
-
- sort.Slice(bands, func(i, j int) bool {
- if bands[i].Connected && !bands[j].Connected {
- return true
- }
- if !bands[i].Connected && bands[j].Connected {
- return false
- }
- return bands[i].Signal > bands[j].Signal
- })
-
- return &NetworkInfoResponse{
- SSID: ssid,
- Bands: bands,
- }, nil
-}
-
-func (b *NetworkManagerBackend) ConnectWiFi(req ConnectionRequest) error {
- if b.wifiDevice == nil {
- return fmt.Errorf("no WiFi device available")
- }
-
- b.stateMutex.RLock()
- alreadyConnected := b.state.WiFiConnected && b.state.WiFiSSID == req.SSID
- b.stateMutex.RUnlock()
-
- if alreadyConnected && !req.Interactive {
- return nil
- }
-
- b.stateMutex.Lock()
- b.state.IsConnecting = true
- b.state.ConnectingSSID = req.SSID
- b.state.LastError = ""
- b.stateMutex.Unlock()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- nm := b.nmConn.(gonetworkmanager.NetworkManager)
-
- existingConn, err := b.findConnection(req.SSID)
- if err == nil && existingConn != nil {
- dev := b.wifiDevice.(gonetworkmanager.Device)
-
- _, err := nm.ActivateConnection(existingConn, dev, nil)
- if err != nil {
- log.Warnf("[ConnectWiFi] Failed to activate existing connection: %v", err)
- b.stateMutex.Lock()
- b.state.IsConnecting = false
- b.state.ConnectingSSID = ""
- b.state.LastError = fmt.Sprintf("failed to activate connection: %v", err)
- b.stateMutex.Unlock()
- if b.onStateChange != nil {
- b.onStateChange()
- }
- return fmt.Errorf("failed to activate connection: %w", err)
- }
-
- return nil
- }
-
- if err := b.createAndConnectWiFi(req); err != nil {
- log.Warnf("[ConnectWiFi] Failed to create and connect: %v", err)
- b.stateMutex.Lock()
- b.state.IsConnecting = false
- b.state.ConnectingSSID = ""
- b.state.LastError = err.Error()
- b.stateMutex.Unlock()
- if b.onStateChange != nil {
- b.onStateChange()
- }
- return err
- }
-
- return nil
-}
-
-func (b *NetworkManagerBackend) DisconnectWiFi() error {
- if b.wifiDevice == nil {
- return fmt.Errorf("no WiFi device available")
- }
-
- dev := b.wifiDevice.(gonetworkmanager.Device)
-
- err := dev.Disconnect()
- if err != nil {
- return fmt.Errorf("failed to disconnect: %w", err)
- }
-
- b.updateWiFiState()
- b.updatePrimaryConnection()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- return nil
-}
-
-func (b *NetworkManagerBackend) ForgetWiFiNetwork(ssid string) error {
- conn, err := b.findConnection(ssid)
- if err != nil {
- return fmt.Errorf("connection not found: %w", err)
- }
-
- b.stateMutex.RLock()
- currentSSID := b.state.WiFiSSID
- isConnected := b.state.WiFiConnected
- b.stateMutex.RUnlock()
-
- err = conn.Delete()
- if err != nil {
- return fmt.Errorf("failed to delete connection: %w", err)
- }
-
- if isConnected && currentSSID == ssid {
- b.stateMutex.Lock()
- b.state.WiFiConnected = false
- b.state.WiFiSSID = ""
- b.state.WiFiBSSID = ""
- b.state.WiFiSignal = 0
- b.state.WiFiIP = ""
- b.state.NetworkStatus = StatusDisconnected
- b.stateMutex.Unlock()
- }
-
- b.updateWiFiNetworks()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- return nil
-}
-
-func (b *NetworkManagerBackend) IsConnectingTo(ssid string) bool {
- b.stateMutex.RLock()
- defer b.stateMutex.RUnlock()
- return b.state.IsConnecting && b.state.ConnectingSSID == ssid
-}
-
-func (b *NetworkManagerBackend) updateWiFiNetworks() ([]WiFiNetwork, error) {
- if b.wifiDevice == nil {
- return nil, fmt.Errorf("no WiFi device available")
- }
-
- if err := b.ensureWiFiDevice(); err != nil {
- return nil, err
- }
- wifiDev := b.wifiDev
-
- w := wifiDev.(gonetworkmanager.DeviceWireless)
- apPaths, err := w.GetAccessPoints()
- if err != nil {
- return nil, fmt.Errorf("failed to get access points: %w", err)
- }
-
- s := b.settings
- if s == nil {
- s, err = gonetworkmanager.NewSettings()
- if err != nil {
- return nil, fmt.Errorf("failed to get settings: %w", err)
- }
- b.settings = s
- }
-
- settingsMgr := s.(gonetworkmanager.Settings)
- connections, err := settingsMgr.ListConnections()
- if err != nil {
- return nil, fmt.Errorf("failed to get connections: %w", err)
- }
-
- savedSSIDs := make(map[string]bool)
- autoconnectMap := make(map[string]bool)
- for _, conn := range connections {
- connSettings, err := conn.GetSettings()
- if err != nil {
- continue
- }
-
- if connMeta, ok := connSettings["connection"]; ok {
- if connType, ok := connMeta["type"].(string); ok && connType == "802-11-wireless" {
- if wifiSettings, ok := connSettings["802-11-wireless"]; ok {
- if ssidBytes, ok := wifiSettings["ssid"].([]byte); ok {
- ssid := string(ssidBytes)
- savedSSIDs[ssid] = true
- autoconnect := true
- if ac, ok := connMeta["autoconnect"].(bool); ok {
- autoconnect = ac
- }
- autoconnectMap[ssid] = autoconnect
- }
- }
- }
- }
- }
-
- b.stateMutex.RLock()
- currentSSID := b.state.WiFiSSID
- b.stateMutex.RUnlock()
-
- seenSSIDs := make(map[string]*WiFiNetwork)
- networks := []WiFiNetwork{}
-
- for _, ap := range apPaths {
- ssid, err := ap.GetPropertySSID()
- if err != nil || ssid == "" {
- continue
- }
-
- if existing, exists := seenSSIDs[ssid]; exists {
- strength, _ := ap.GetPropertyStrength()
- if strength > existing.Signal {
- existing.Signal = strength
- freq, _ := ap.GetPropertyFrequency()
- existing.Frequency = freq
- bssid, _ := ap.GetPropertyHWAddress()
- existing.BSSID = bssid
- }
- continue
- }
-
- strength, _ := ap.GetPropertyStrength()
- flags, _ := ap.GetPropertyFlags()
- wpaFlags, _ := ap.GetPropertyWPAFlags()
- rsnFlags, _ := ap.GetPropertyRSNFlags()
- freq, _ := ap.GetPropertyFrequency()
- maxBitrate, _ := ap.GetPropertyMaxBitrate()
- bssid, _ := ap.GetPropertyHWAddress()
- mode, _ := ap.GetPropertyMode()
-
- secured := flags != uint32(gonetworkmanager.Nm80211APFlagsNone) ||
- wpaFlags != uint32(gonetworkmanager.Nm80211APSecNone) ||
- rsnFlags != uint32(gonetworkmanager.Nm80211APSecNone)
-
- enterprise := (rsnFlags&uint32(gonetworkmanager.Nm80211APSecKeyMgmt8021X) != 0) ||
- (wpaFlags&uint32(gonetworkmanager.Nm80211APSecKeyMgmt8021X) != 0)
-
- var modeStr string
- switch mode {
- case gonetworkmanager.Nm80211ModeAdhoc:
- modeStr = "adhoc"
- case gonetworkmanager.Nm80211ModeInfra:
- modeStr = "infrastructure"
- case gonetworkmanager.Nm80211ModeAp:
- modeStr = "ap"
- default:
- modeStr = "unknown"
- }
-
- channel := frequencyToChannel(freq)
-
- network := WiFiNetwork{
- SSID: ssid,
- BSSID: bssid,
- Signal: strength,
- Secured: secured,
- Enterprise: enterprise,
- Connected: ssid == currentSSID,
- Saved: savedSSIDs[ssid],
- Autoconnect: autoconnectMap[ssid],
- Frequency: freq,
- Mode: modeStr,
- Rate: maxBitrate / 1000,
- Channel: channel,
- }
-
- seenSSIDs[ssid] = &network
- networks = append(networks, network)
- }
-
- sortWiFiNetworks(networks)
-
- b.stateMutex.Lock()
- b.state.WiFiNetworks = networks
- b.stateMutex.Unlock()
-
- return networks, nil
-}
-
-func (b *NetworkManagerBackend) findConnection(ssid string) (gonetworkmanager.Connection, error) {
- s := b.settings
- if s == nil {
- var err error
- s, err = gonetworkmanager.NewSettings()
- if err != nil {
- return nil, err
- }
- b.settings = s
- }
-
- settings := s.(gonetworkmanager.Settings)
- connections, err := settings.ListConnections()
- if err != nil {
- return nil, err
- }
-
- ssidBytes := []byte(ssid)
- for _, conn := range connections {
- connSettings, err := conn.GetSettings()
- if err != nil {
- continue
- }
-
- if connMeta, ok := connSettings["connection"]; ok {
- if connType, ok := connMeta["type"].(string); ok && connType == "802-11-wireless" {
- if wifiSettings, ok := connSettings["802-11-wireless"]; ok {
- if candidateSSID, ok := wifiSettings["ssid"].([]byte); ok {
- if bytes.Equal(candidateSSID, ssidBytes) {
- return conn, nil
- }
- }
- }
- }
- }
- }
-
- return nil, fmt.Errorf("connection not found")
-}
-
-func (b *NetworkManagerBackend) createAndConnectWiFi(req ConnectionRequest) error {
- if b.wifiDevice == nil {
- return fmt.Errorf("no WiFi device available")
- }
-
- nm := b.nmConn.(gonetworkmanager.NetworkManager)
- dev := b.wifiDevice.(gonetworkmanager.Device)
-
- if err := b.ensureWiFiDevice(); err != nil {
- return err
- }
- wifiDev := b.wifiDev
-
- w := wifiDev.(gonetworkmanager.DeviceWireless)
- apPaths, err := w.GetAccessPoints()
- if err != nil {
- return fmt.Errorf("failed to get access points: %w", err)
- }
-
- var targetAP gonetworkmanager.AccessPoint
- for _, ap := range apPaths {
- ssid, err := ap.GetPropertySSID()
- if err != nil || ssid != req.SSID {
- continue
- }
- targetAP = ap
- break
- }
-
- if targetAP == nil {
- return fmt.Errorf("access point not found: %s", req.SSID)
- }
-
- flags, _ := targetAP.GetPropertyFlags()
- wpaFlags, _ := targetAP.GetPropertyWPAFlags()
- rsnFlags, _ := targetAP.GetPropertyRSNFlags()
-
- const KeyMgmt8021x = uint32(512)
- const KeyMgmtPsk = uint32(256)
- const KeyMgmtSae = uint32(1024)
-
- isEnterprise := (wpaFlags&KeyMgmt8021x) != 0 || (rsnFlags&KeyMgmt8021x) != 0
- isPsk := (wpaFlags&KeyMgmtPsk) != 0 || (rsnFlags&KeyMgmtPsk) != 0
- isSae := (wpaFlags&KeyMgmtSae) != 0 || (rsnFlags&KeyMgmtSae) != 0
-
- secured := flags != uint32(gonetworkmanager.Nm80211APFlagsNone) ||
- wpaFlags != uint32(gonetworkmanager.Nm80211APSecNone) ||
- rsnFlags != uint32(gonetworkmanager.Nm80211APSecNone)
-
- if isEnterprise {
- log.Infof("[createAndConnectWiFi] Enterprise network detected (802.1x) - SSID: %s, interactive: %v",
- req.SSID, req.Interactive)
- }
-
- settings := make(map[string]map[string]interface{})
-
- settings["connection"] = map[string]interface{}{
- "id": req.SSID,
- "type": "802-11-wireless",
- "autoconnect": true,
- }
-
- settings["ipv4"] = map[string]interface{}{"method": "auto"}
- settings["ipv6"] = map[string]interface{}{"method": "auto"}
-
- if secured {
- settings["802-11-wireless"] = map[string]interface{}{
- "ssid": []byte(req.SSID),
- "mode": "infrastructure",
- "security": "802-11-wireless-security",
- }
-
- switch {
- case isEnterprise || req.Username != "":
- settings["802-11-wireless-security"] = map[string]interface{}{
- "key-mgmt": "wpa-eap",
- }
-
- x := map[string]interface{}{
- "eap": []string{"peap"},
- "phase2-auth": "mschapv2",
- "system-ca-certs": false,
- "password-flags": uint32(0),
- }
-
- if req.Username != "" {
- x["identity"] = req.Username
- }
- if req.Password != "" {
- x["password"] = req.Password
- }
-
- if req.AnonymousIdentity != "" {
- x["anonymous-identity"] = req.AnonymousIdentity
- }
- if req.DomainSuffixMatch != "" {
- x["domain-suffix-match"] = req.DomainSuffixMatch
- }
-
- settings["802-1x"] = x
-
- log.Infof("[createAndConnectWiFi] WPA-EAP settings: eap=peap, phase2-auth=mschapv2, identity=%s, interactive=%v, system-ca-certs=%v, domain-suffix-match=%q",
- req.Username, req.Interactive, x["system-ca-certs"], req.DomainSuffixMatch)
-
- case isPsk:
- sec := map[string]interface{}{
- "key-mgmt": "wpa-psk",
- "psk-flags": uint32(0),
- }
- if !req.Interactive {
- sec["psk"] = req.Password
- }
- settings["802-11-wireless-security"] = sec
-
- case isSae:
- sec := map[string]interface{}{
- "key-mgmt": "sae",
- "pmf": int32(3),
- "psk-flags": uint32(0),
- }
- if !req.Interactive {
- sec["psk"] = req.Password
- }
- settings["802-11-wireless-security"] = sec
-
- default:
- return fmt.Errorf("secured network but not SAE/PSK/802.1X (rsn=0x%x wpa=0x%x)", rsnFlags, wpaFlags)
- }
- } else {
- settings["802-11-wireless"] = map[string]interface{}{
- "ssid": []byte(req.SSID),
- "mode": "infrastructure",
- }
- }
-
- if req.Interactive {
- s := b.settings
- if s == nil {
- var settingsErr error
- s, settingsErr = gonetworkmanager.NewSettings()
- if settingsErr != nil {
- return fmt.Errorf("failed to get settings manager: %w", settingsErr)
- }
- b.settings = s
- }
-
- settingsMgr := s.(gonetworkmanager.Settings)
- conn, err := settingsMgr.AddConnection(settings)
- if err != nil {
- return fmt.Errorf("failed to add connection: %w", err)
- }
-
- if isEnterprise {
- log.Infof("[createAndConnectWiFi] Enterprise connection added, activating (secret agent will be called)")
- }
-
- _, err = nm.ActivateWirelessConnection(conn, dev, targetAP)
- if err != nil {
- return fmt.Errorf("failed to activate connection: %w", err)
- }
-
- log.Infof("[createAndConnectWiFi] Connection activation initiated, waiting for NetworkManager state changes...")
- } else {
- _, err = nm.AddAndActivateWirelessConnection(settings, dev, targetAP)
- if err != nil {
- return fmt.Errorf("failed to connect: %w", err)
- }
- log.Infof("[createAndConnectWiFi] Connection activation initiated, waiting for NetworkManager state changes...")
- }
-
- return nil
-}
-
-func (b *NetworkManagerBackend) SetWiFiAutoconnect(ssid string, autoconnect bool) error {
- conn, err := b.findConnection(ssid)
- if err != nil {
- return fmt.Errorf("connection not found: %w", err)
- }
-
- settings, err := conn.GetSettings()
- if err != nil {
- return fmt.Errorf("failed to get connection settings: %w", err)
- }
-
- if connMeta, ok := settings["connection"]; ok {
- connMeta["autoconnect"] = autoconnect
- } else {
- return fmt.Errorf("connection metadata not found")
- }
-
- if ipv4, ok := settings["ipv4"]; ok {
- delete(ipv4, "addresses")
- delete(ipv4, "routes")
- delete(ipv4, "dns")
- }
-
- if ipv6, ok := settings["ipv6"]; ok {
- delete(ipv6, "addresses")
- delete(ipv6, "routes")
- delete(ipv6, "dns")
- }
-
- err = conn.Update(settings)
- if err != nil {
- return fmt.Errorf("failed to update connection: %w", err)
- }
-
- b.updateWiFiNetworks()
-
- if b.onStateChange != nil {
- b.onStateChange()
- }
-
- return nil
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_wifi_test.go b/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_wifi_test.go
deleted file mode 100644
index 09f439a..0000000
--- a/nix/inputs/dms-cli/internal/server/network/backend_networkmanager_wifi_test.go
+++ /dev/null
@@ -1,198 +0,0 @@
-package network
-
-import (
- "testing"
-
- mock_gonetworkmanager "github.com/AvengeMedia/danklinux/internal/mocks/github.com/Wifx/gonetworkmanager/v2"
- "github.com/stretchr/testify/assert"
-)
-
-func TestNetworkManagerBackend_GetWiFiEnabled(t *testing.T) {
- mockNM := mock_gonetworkmanager.NewMockNetworkManager(t)
-
- backend, err := NewNetworkManagerBackend(mockNM)
- assert.NoError(t, err)
-
- mockNM.EXPECT().GetPropertyWirelessEnabled().Return(true, nil)
-
- enabled, err := backend.GetWiFiEnabled()
- assert.NoError(t, err)
- assert.True(t, enabled)
-}
-
-func TestNetworkManagerBackend_SetWiFiEnabled(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- originalState, err := backend.GetWiFiEnabled()
- if err != nil {
- t.Skipf("Cannot get WiFi state: %v", err)
- }
-
- defer func() {
- backend.SetWiFiEnabled(originalState)
- }()
-
- err = backend.SetWiFiEnabled(!originalState)
- assert.NoError(t, err)
-
- backend.stateMutex.RLock()
- assert.Equal(t, !originalState, backend.state.WiFiEnabled)
- backend.stateMutex.RUnlock()
-}
-
-func TestNetworkManagerBackend_ScanWiFi_NoDevice(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.wifiDevice = nil
- err = backend.ScanWiFi()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no WiFi device available")
-}
-
-func TestNetworkManagerBackend_ScanWiFi_Disabled(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- if backend.wifiDevice == nil {
- t.Skip("No WiFi device available")
- }
-
- backend.stateMutex.Lock()
- backend.state.WiFiEnabled = false
- backend.stateMutex.Unlock()
-
- err = backend.ScanWiFi()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "WiFi is disabled")
-}
-
-func TestNetworkManagerBackend_GetWiFiNetworkDetails_NoDevice(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.wifiDevice = nil
- _, err = backend.GetWiFiNetworkDetails("TestNetwork")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no WiFi device available")
-}
-
-func TestNetworkManagerBackend_ConnectWiFi_NoDevice(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.wifiDevice = nil
- req := ConnectionRequest{SSID: "TestNetwork", Password: "password"}
- err = backend.ConnectWiFi(req)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no WiFi device available")
-}
-
-func TestNetworkManagerBackend_ConnectWiFi_AlreadyConnected(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- if backend.wifiDevice == nil {
- t.Skip("No WiFi device available")
- }
-
- backend.stateMutex.Lock()
- backend.state.WiFiConnected = true
- backend.state.WiFiSSID = "TestNetwork"
- backend.stateMutex.Unlock()
-
- req := ConnectionRequest{SSID: "TestNetwork", Password: "password"}
- err = backend.ConnectWiFi(req)
- assert.NoError(t, err)
-}
-
-func TestNetworkManagerBackend_DisconnectWiFi_NoDevice(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.wifiDevice = nil
- err = backend.DisconnectWiFi()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no WiFi device available")
-}
-
-func TestNetworkManagerBackend_IsConnectingTo(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.stateMutex.Lock()
- backend.state.IsConnecting = true
- backend.state.ConnectingSSID = "TestNetwork"
- backend.stateMutex.Unlock()
-
- assert.True(t, backend.IsConnectingTo("TestNetwork"))
- assert.False(t, backend.IsConnectingTo("OtherNetwork"))
-}
-
-func TestNetworkManagerBackend_IsConnectingTo_NotConnecting(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.stateMutex.Lock()
- backend.state.IsConnecting = false
- backend.state.ConnectingSSID = ""
- backend.stateMutex.Unlock()
-
- assert.False(t, backend.IsConnectingTo("TestNetwork"))
-}
-
-func TestNetworkManagerBackend_UpdateWiFiNetworks_NoDevice(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.wifiDevice = nil
- _, err = backend.updateWiFiNetworks()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no WiFi device available")
-}
-
-func TestNetworkManagerBackend_FindConnection_NoSettings(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.settings = nil
- _, err = backend.findConnection("NonExistentNetwork")
- assert.Error(t, err)
-}
-
-func TestNetworkManagerBackend_CreateAndConnectWiFi_NoDevice(t *testing.T) {
- backend, err := NewNetworkManagerBackend()
- if err != nil {
- t.Skipf("NetworkManager not available: %v", err)
- }
-
- backend.wifiDevice = nil
- backend.wifiDev = nil
- req := ConnectionRequest{SSID: "TestNetwork", Password: "password"}
- err = backend.createAndConnectWiFi(req)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no WiFi device available")
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/broker.go b/nix/inputs/dms-cli/internal/server/network/broker.go
deleted file mode 100644
index 5290fb5..0000000
--- a/nix/inputs/dms-cli/internal/server/network/broker.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package network
-
-import (
- "context"
- "crypto/rand"
- "encoding/hex"
-)
-
-type PromptBroker interface {
- Ask(ctx context.Context, req PromptRequest) (token string, err error)
- Wait(ctx context.Context, token string) (PromptReply, error)
- Resolve(token string, reply PromptReply) error
- Cancel(path string, setting string) error
-}
-
-func generateToken() (string, error) {
- bytes := make([]byte, 16)
- if _, err := rand.Read(bytes); err != nil {
- return "", err
- }
- return hex.EncodeToString(bytes), nil
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/connection_test.go b/nix/inputs/dms-cli/internal/server/network/connection_test.go
deleted file mode 100644
index 1f4a8a7..0000000
--- a/nix/inputs/dms-cli/internal/server/network/connection_test.go
+++ /dev/null
@@ -1,109 +0,0 @@
-package network_test
-
-import (
- "errors"
- "testing"
-
- mocks_network "github.com/AvengeMedia/danklinux/internal/mocks/network"
- "github.com/AvengeMedia/danklinux/internal/server/network"
- "github.com/stretchr/testify/assert"
-)
-
-func TestConnectionRequest_Validation(t *testing.T) {
- t.Run("basic WiFi connection", func(t *testing.T) {
- req := network.ConnectionRequest{
- SSID: "TestNetwork",
- Password: "testpass123",
- }
-
- assert.NotEmpty(t, req.SSID)
- assert.NotEmpty(t, req.Password)
- assert.Empty(t, req.Username)
- })
-
- t.Run("enterprise WiFi connection", func(t *testing.T) {
- req := network.ConnectionRequest{
- SSID: "EnterpriseNetwork",
- Password: "testpass123",
- Username: "testuser",
- }
-
- assert.NotEmpty(t, req.SSID)
- assert.NotEmpty(t, req.Password)
- assert.NotEmpty(t, req.Username)
- })
-
- t.Run("open WiFi connection", func(t *testing.T) {
- req := network.ConnectionRequest{
- SSID: "OpenNetwork",
- }
-
- assert.NotEmpty(t, req.SSID)
- assert.Empty(t, req.Password)
- assert.Empty(t, req.Username)
- })
-}
-
-func TestManager_ConnectWiFi_NoDevice(t *testing.T) {
- backend := mocks_network.NewMockBackend(t)
- req := network.ConnectionRequest{
- SSID: "TestNetwork",
- Password: "testpass123",
- }
- backend.EXPECT().ConnectWiFi(req).Return(errors.New("no WiFi device available"))
-
- manager := network.NewTestManager(backend, &network.NetworkState{})
-
- err := manager.ConnectWiFi(req)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no WiFi device available")
-}
-
-func TestManager_DisconnectWiFi_NoDevice(t *testing.T) {
- backend := mocks_network.NewMockBackend(t)
- backend.EXPECT().DisconnectWiFi().Return(errors.New("no WiFi device available"))
-
- manager := network.NewTestManager(backend, &network.NetworkState{})
-
- err := manager.DisconnectWiFi()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no WiFi device available")
-}
-
-func TestManager_ForgetWiFiNetwork_NotFound(t *testing.T) {
- backend := mocks_network.NewMockBackend(t)
- backend.EXPECT().ForgetWiFiNetwork("NonExistentNetwork").Return(errors.New("connection not found"))
-
- manager := network.NewTestManager(backend, &network.NetworkState{})
-
- err := manager.ForgetWiFiNetwork("NonExistentNetwork")
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "connection not found")
-}
-
-func TestManager_ConnectEthernet_NoDevice(t *testing.T) {
- backend := mocks_network.NewMockBackend(t)
- backend.EXPECT().ConnectEthernet().Return(errors.New("no ethernet device available"))
-
- manager := network.NewTestManager(backend, &network.NetworkState{})
-
- err := manager.ConnectEthernet()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no ethernet device available")
-}
-
-func TestManager_DisconnectEthernet_NoDevice(t *testing.T) {
- backend := mocks_network.NewMockBackend(t)
- backend.EXPECT().DisconnectEthernet().Return(errors.New("no ethernet device available"))
-
- manager := network.NewTestManager(backend, &network.NetworkState{})
-
- err := manager.DisconnectEthernet()
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "no ethernet device available")
-}
-
-// Note: More comprehensive tests for connection operations would require
-// mocking the NetworkManager D-Bus interfaces, which is beyond the scope
-// of these unit tests. The tests above cover the basic error cases and
-// validation logic. Integration tests would be needed for full coverage.
diff --git a/nix/inputs/dms-cli/internal/server/network/detect.go b/nix/inputs/dms-cli/internal/server/network/detect.go
deleted file mode 100644
index 6031e42..0000000
--- a/nix/inputs/dms-cli/internal/server/network/detect.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package network
-
-import (
- "fmt"
-
- "github.com/godbus/dbus/v5"
-)
-
-type BackendType int
-
-const (
- BackendNone BackendType = iota
- BackendNetworkManager
- BackendIwd
- BackendConnMan
- BackendNetworkd
-)
-
-func nameHasOwner(bus *dbus.Conn, name string) (bool, error) {
- obj := bus.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
- var owned bool
- if err := obj.Call("org.freedesktop.DBus.NameHasOwner", 0, name).Store(&owned); err != nil {
- return false, err
- }
- return owned, nil
-}
-
-type DetectResult struct {
- Backend BackendType
- HasNM bool
- HasIwd bool
- HasConnMan bool
- HasWpaSupp bool
- HasNetworkd bool
- ChosenReason string
-}
-
-func DetectNetworkStack() (*DetectResult, error) {
- bus, err := dbus.ConnectSystemBus()
- if err != nil {
- return nil, fmt.Errorf("connect system bus: %w", err)
- }
- defer bus.Close()
-
- hasNM, _ := nameHasOwner(bus, "org.freedesktop.NetworkManager")
- hasIwd, _ := nameHasOwner(bus, "net.connman.iwd")
- hasConn, _ := nameHasOwner(bus, "net.connman")
- hasWpa, _ := nameHasOwner(bus, "fi.w1.wpa_supplicant1")
- hasNetworkd, _ := nameHasOwner(bus, "org.freedesktop.network1")
-
- res := &DetectResult{
- HasNM: hasNM,
- HasIwd: hasIwd,
- HasConnMan: hasConn,
- HasWpaSupp: hasWpa,
- HasNetworkd: hasNetworkd,
- }
-
- switch {
- case hasNM:
- res.Backend = BackendNetworkManager
- if hasIwd {
- res.ChosenReason = "NetworkManager present; iwd also running (likely NM's Wi-Fi backend). Using NM API."
- } else {
- res.ChosenReason = "NetworkManager present. Using NM API."
- }
- case hasConn && hasIwd:
- res.Backend = BackendConnMan
- res.ChosenReason = "ConnMan + iwd detected. Use ConnMan API (iwd is its Wi-Fi daemon)."
- case hasIwd && hasNetworkd:
- res.Backend = BackendNetworkd
- res.ChosenReason = "iwd + systemd-networkd detected. Using iwd for Wi-Fi association and networkd for IP/DHCP."
- case hasIwd:
- res.Backend = BackendIwd
- res.ChosenReason = "iwd detected without NM/ConnMan. Using iwd API."
- case hasNetworkd:
- res.Backend = BackendNetworkd
- res.ChosenReason = "systemd-networkd detected (no NM/ConnMan). Using networkd for L3 and wired."
- default:
- res.Backend = BackendNone
- if hasWpa {
- res.ChosenReason = "No NM/ConnMan/iwd; wpa_supplicant present. Consider a wpa_supplicant path."
- } else {
- res.ChosenReason = "No known network manager bus names found."
- }
- }
-
- return res, nil
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/detect_test.go b/nix/inputs/dms-cli/internal/server/network/detect_test.go
deleted file mode 100644
index 5678860..0000000
--- a/nix/inputs/dms-cli/internal/server/network/detect_test.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package network
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestBackendType_Constants(t *testing.T) {
- assert.Equal(t, BackendType(0), BackendNone)
- assert.Equal(t, BackendType(1), BackendNetworkManager)
- assert.Equal(t, BackendType(2), BackendIwd)
- assert.Equal(t, BackendType(3), BackendConnMan)
- assert.Equal(t, BackendType(4), BackendNetworkd)
-}
-
-func TestDetectResult_HasNetworkdField(t *testing.T) {
- result := &DetectResult{
- Backend: BackendNetworkd,
- HasNetworkd: true,
- HasIwd: true,
- }
-
- assert.True(t, result.HasNetworkd)
- assert.True(t, result.HasIwd)
- assert.Equal(t, BackendNetworkd, result.Backend)
-}
-
-func TestDetectNetworkStack_Integration(t *testing.T) {
- result, err := DetectNetworkStack()
- assert.NoError(t, err)
- assert.NotNil(t, result)
- assert.NotEmpty(t, result.ChosenReason)
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/handlers.go b/nix/inputs/dms-cli/internal/server/network/handlers.go
deleted file mode 100644
index 9af367e..0000000
--- a/nix/inputs/dms-cli/internal/server/network/handlers.go
+++ /dev/null
@@ -1,487 +0,0 @@
-package network
-
-import (
- "encoding/json"
- "fmt"
- "net"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/AvengeMedia/danklinux/internal/server/models"
-)
-
-type Request struct {
- ID int `json:"id,omitempty"`
- Method string `json:"method"`
- Params map[string]interface{} `json:"params,omitempty"`
-}
-
-type SuccessResult struct {
- Success bool `json:"success"`
- Message string `json:"message"`
-}
-
-func HandleRequest(conn net.Conn, req Request, manager *Manager) {
- switch req.Method {
- case "network.getState":
- handleGetState(conn, req, manager)
- case "network.wifi.scan":
- handleScanWiFi(conn, req, manager)
- case "network.wifi.networks":
- handleGetWiFiNetworks(conn, req, manager)
- case "network.wifi.connect":
- handleConnectWiFi(conn, req, manager)
- case "network.wifi.disconnect":
- handleDisconnectWiFi(conn, req, manager)
- case "network.wifi.forget":
- handleForgetWiFi(conn, req, manager)
- case "network.wifi.toggle":
- handleToggleWiFi(conn, req, manager)
- case "network.wifi.enable":
- handleEnableWiFi(conn, req, manager)
- case "network.wifi.disable":
- handleDisableWiFi(conn, req, manager)
- case "network.ethernet.connect.config":
- handleConnectEthernetSpecificConfig(conn, req, manager)
- case "network.ethernet.connect":
- handleConnectEthernet(conn, req, manager)
- case "network.ethernet.disconnect":
- handleDisconnectEthernet(conn, req, manager)
- case "network.preference.set":
- handleSetPreference(conn, req, manager)
- case "network.info":
- handleGetNetworkInfo(conn, req, manager)
- case "network.ethernet.info":
- handleGetWiredNetworkInfo(conn, req, manager)
- case "network.subscribe":
- handleSubscribe(conn, req, manager)
- case "network.credentials.submit":
- handleCredentialsSubmit(conn, req, manager)
- case "network.credentials.cancel":
- handleCredentialsCancel(conn, req, manager)
- case "network.vpn.profiles":
- handleListVPNProfiles(conn, req, manager)
- case "network.vpn.active":
- handleListActiveVPN(conn, req, manager)
- case "network.vpn.connect":
- handleConnectVPN(conn, req, manager)
- case "network.vpn.disconnect":
- handleDisconnectVPN(conn, req, manager)
- case "network.vpn.disconnectAll":
- handleDisconnectAllVPN(conn, req, manager)
- case "network.vpn.clearCredentials":
- handleClearVPNCredentials(conn, req, manager)
- case "network.wifi.setAutoconnect":
- handleSetWiFiAutoconnect(conn, req, manager)
- default:
- models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method))
- }
-}
-
-func handleCredentialsSubmit(conn net.Conn, req Request, manager *Manager) {
- token, ok := req.Params["token"].(string)
- if !ok {
- log.Warnf("handleCredentialsSubmit: missing or invalid token parameter")
- models.RespondError(conn, req.ID, "missing or invalid 'token' parameter")
- return
- }
-
- secretsRaw, ok := req.Params["secrets"].(map[string]interface{})
- if !ok {
- log.Warnf("handleCredentialsSubmit: missing or invalid secrets parameter")
- models.RespondError(conn, req.ID, "missing or invalid 'secrets' parameter")
- return
- }
-
- secrets := make(map[string]string)
- for k, v := range secretsRaw {
- if str, ok := v.(string); ok {
- secrets[k] = str
- }
- }
-
- save := true
- if saveParam, ok := req.Params["save"].(bool); ok {
- save = saveParam
- }
-
- if err := manager.SubmitCredentials(token, secrets, save); err != nil {
- log.Warnf("handleCredentialsSubmit: failed to submit credentials: %v", err)
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- log.Infof("handleCredentialsSubmit: credentials submitted successfully")
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "credentials submitted"})
-}
-
-func handleCredentialsCancel(conn net.Conn, req Request, manager *Manager) {
- token, ok := req.Params["token"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'token' parameter")
- return
- }
-
- if err := manager.CancelCredentials(token); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "credentials cancelled"})
-}
-
-func handleGetState(conn net.Conn, req Request, manager *Manager) {
- state := manager.GetState()
- models.Respond(conn, req.ID, state)
-}
-
-func handleScanWiFi(conn net.Conn, req Request, manager *Manager) {
- if err := manager.ScanWiFi(); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "scanning"})
-}
-
-func handleGetWiFiNetworks(conn net.Conn, req Request, manager *Manager) {
- networks := manager.GetWiFiNetworks()
- models.Respond(conn, req.ID, networks)
-}
-
-func handleConnectWiFi(conn net.Conn, req Request, manager *Manager) {
- ssid, ok := req.Params["ssid"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'ssid' parameter")
- return
- }
-
- var connReq ConnectionRequest
- connReq.SSID = ssid
-
- if password, ok := req.Params["password"].(string); ok {
- connReq.Password = password
- }
- if username, ok := req.Params["username"].(string); ok {
- connReq.Username = username
- }
-
- if interactive, ok := req.Params["interactive"].(bool); ok {
- connReq.Interactive = interactive
- } else {
- state := manager.GetState()
- alreadyConnected := state.WiFiConnected && state.WiFiSSID == ssid
-
- if alreadyConnected {
- connReq.Interactive = false
- } else {
- networkInfo, err := manager.GetNetworkInfo(ssid)
- isSaved := err == nil && networkInfo.Saved
-
- if isSaved {
- connReq.Interactive = false
- } else if err == nil && networkInfo.Secured && connReq.Password == "" && connReq.Username == "" {
- connReq.Interactive = true
- }
- }
- }
-
- if anonymousIdentity, ok := req.Params["anonymousIdentity"].(string); ok {
- connReq.AnonymousIdentity = anonymousIdentity
- }
- if domainSuffixMatch, ok := req.Params["domainSuffixMatch"].(string); ok {
- connReq.DomainSuffixMatch = domainSuffixMatch
- }
-
- if err := manager.ConnectWiFi(connReq); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "connecting"})
-}
-
-func handleDisconnectWiFi(conn net.Conn, req Request, manager *Manager) {
- if err := manager.DisconnectWiFi(); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "disconnected"})
-}
-
-func handleForgetWiFi(conn net.Conn, req Request, manager *Manager) {
- ssid, ok := req.Params["ssid"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'ssid' parameter")
- return
- }
-
- if err := manager.ForgetWiFiNetwork(ssid); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "forgotten"})
-}
-
-func handleToggleWiFi(conn net.Conn, req Request, manager *Manager) {
- if err := manager.ToggleWiFi(); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- state := manager.GetState()
- models.Respond(conn, req.ID, map[string]bool{"enabled": state.WiFiEnabled})
-}
-
-func handleEnableWiFi(conn net.Conn, req Request, manager *Manager) {
- if err := manager.EnableWiFi(); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, map[string]bool{"enabled": true})
-}
-
-func handleDisableWiFi(conn net.Conn, req Request, manager *Manager) {
- if err := manager.DisableWiFi(); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, map[string]bool{"enabled": false})
-}
-
-func handleConnectEthernetSpecificConfig(conn net.Conn, req Request, manager *Manager) {
- uuid, ok := req.Params["uuid"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'uuid' parameter")
- return
- }
- if err := manager.activateConnection(uuid); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "connecting"})
-}
-
-func handleConnectEthernet(conn net.Conn, req Request, manager *Manager) {
- if err := manager.ConnectEthernet(); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "connecting"})
-}
-
-func handleDisconnectEthernet(conn net.Conn, req Request, manager *Manager) {
- if err := manager.DisconnectEthernet(); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "disconnected"})
-}
-
-func handleSetPreference(conn net.Conn, req Request, manager *Manager) {
- preference, ok := req.Params["preference"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'preference' parameter")
- return
- }
-
- if err := manager.SetConnectionPreference(ConnectionPreference(preference)); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, map[string]string{"preference": preference})
-}
-
-func handleGetNetworkInfo(conn net.Conn, req Request, manager *Manager) {
- ssid, ok := req.Params["ssid"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'ssid' parameter")
- return
- }
-
- network, err := manager.GetNetworkInfoDetailed(ssid)
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, network)
-}
-
-func handleGetWiredNetworkInfo(conn net.Conn, req Request, manager *Manager) {
- uuid, ok := req.Params["uuid"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'uuid' parameter")
- return
- }
-
- network, err := manager.GetWiredNetworkInfoDetailed(uuid)
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, network)
-}
-
-func handleSubscribe(conn net.Conn, req Request, manager *Manager) {
- clientID := fmt.Sprintf("client-%p", conn)
- stateChan := manager.Subscribe(clientID)
- defer manager.Unsubscribe(clientID)
-
- initialState := manager.GetState()
- event := NetworkEvent{
- Type: EventStateChanged,
- Data: initialState,
- }
- if err := json.NewEncoder(conn).Encode(models.Response[NetworkEvent]{
- ID: req.ID,
- Result: &event,
- }); err != nil {
- return
- }
-
- for state := range stateChan {
- event := NetworkEvent{
- Type: EventStateChanged,
- Data: state,
- }
- if err := json.NewEncoder(conn).Encode(models.Response[NetworkEvent]{
- Result: &event,
- }); err != nil {
- return
- }
- }
-}
-
-func handleListVPNProfiles(conn net.Conn, req Request, manager *Manager) {
- profiles, err := manager.ListVPNProfiles()
- if err != nil {
- log.Warnf("handleListVPNProfiles: failed to list profiles: %v", err)
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to list VPN profiles: %v", err))
- return
- }
-
- models.Respond(conn, req.ID, profiles)
-}
-
-func handleListActiveVPN(conn net.Conn, req Request, manager *Manager) {
- active, err := manager.ListActiveVPN()
- if err != nil {
- log.Warnf("handleListActiveVPN: failed to list active VPNs: %v", err)
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to list active VPNs: %v", err))
- return
- }
-
- models.Respond(conn, req.ID, active)
-}
-
-func handleConnectVPN(conn net.Conn, req Request, manager *Manager) {
- uuidOrName, ok := req.Params["uuidOrName"].(string)
- if !ok {
- name, nameOk := req.Params["name"].(string)
- uuid, uuidOk := req.Params["uuid"].(string)
- if nameOk {
- uuidOrName = name
- } else if uuidOk {
- uuidOrName = uuid
- } else {
- log.Warnf("handleConnectVPN: missing uuidOrName/name/uuid parameter")
- models.RespondError(conn, req.ID, "missing 'uuidOrName', 'name', or 'uuid' parameter")
- return
- }
- }
-
- // Default to true - only allow one VPN connection at a time
- singleActive := true
- if sa, ok := req.Params["singleActive"].(bool); ok {
- singleActive = sa
- }
-
- if err := manager.ConnectVPN(uuidOrName, singleActive); err != nil {
- log.Warnf("handleConnectVPN: failed to connect: %v", err)
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to connect VPN: %v", err))
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "VPN connection initiated"})
-}
-
-func handleDisconnectVPN(conn net.Conn, req Request, manager *Manager) {
- uuidOrName, ok := req.Params["uuidOrName"].(string)
- if !ok {
- name, nameOk := req.Params["name"].(string)
- uuid, uuidOk := req.Params["uuid"].(string)
- if nameOk {
- uuidOrName = name
- } else if uuidOk {
- uuidOrName = uuid
- } else {
- log.Warnf("handleDisconnectVPN: missing uuidOrName/name/uuid parameter")
- models.RespondError(conn, req.ID, "missing 'uuidOrName', 'name', or 'uuid' parameter")
- return
- }
- }
-
- if err := manager.DisconnectVPN(uuidOrName); err != nil {
- log.Warnf("handleDisconnectVPN: failed to disconnect: %v", err)
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to disconnect VPN: %v", err))
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "VPN disconnected"})
-}
-
-func handleDisconnectAllVPN(conn net.Conn, req Request, manager *Manager) {
- if err := manager.DisconnectAllVPN(); err != nil {
- log.Warnf("handleDisconnectAllVPN: failed: %v", err)
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to disconnect all VPNs: %v", err))
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "All VPNs disconnected"})
-}
-
-func handleClearVPNCredentials(conn net.Conn, req Request, manager *Manager) {
- uuidOrName, ok := req.Params["uuid"].(string)
- if !ok {
- uuidOrName, ok = req.Params["name"].(string)
- }
- if !ok {
- uuidOrName, ok = req.Params["uuidOrName"].(string)
- }
- if !ok {
- log.Warnf("handleClearVPNCredentials: missing uuidOrName/name/uuid parameter")
- models.RespondError(conn, req.ID, "missing uuidOrName/name/uuid parameter")
- return
- }
-
- if err := manager.ClearVPNCredentials(uuidOrName); err != nil {
- log.Warnf("handleClearVPNCredentials: failed: %v", err)
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to clear VPN credentials: %v", err))
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "VPN credentials cleared"})
-}
-
-func handleSetWiFiAutoconnect(conn net.Conn, req Request, manager *Manager) {
- ssid, ok := req.Params["ssid"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'ssid' parameter")
- return
- }
-
- autoconnect, ok := req.Params["autoconnect"].(bool)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'autoconnect' parameter")
- return
- }
-
- if err := manager.SetWiFiAutoconnect(ssid, autoconnect); err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to set autoconnect: %v", err))
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "autoconnect updated"})
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/handlers_test.go b/nix/inputs/dms-cli/internal/server/network/handlers_test.go
deleted file mode 100644
index 00126da..0000000
--- a/nix/inputs/dms-cli/internal/server/network/handlers_test.go
+++ /dev/null
@@ -1,263 +0,0 @@
-package network
-
-import (
- "bytes"
- "encoding/json"
- "net"
- "testing"
-
- "github.com/AvengeMedia/danklinux/internal/server/models"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-type mockNetConn struct {
- net.Conn
- readBuf *bytes.Buffer
- writeBuf *bytes.Buffer
- closed bool
-}
-
-func newMockNetConn() *mockNetConn {
- return &mockNetConn{
- readBuf: &bytes.Buffer{},
- writeBuf: &bytes.Buffer{},
- }
-}
-
-func (m *mockNetConn) Read(b []byte) (n int, err error) {
- return m.readBuf.Read(b)
-}
-
-func (m *mockNetConn) Write(b []byte) (n int, err error) {
- return m.writeBuf.Write(b)
-}
-
-func (m *mockNetConn) Close() error {
- m.closed = true
- return nil
-}
-
-func TestRespondError_Network(t *testing.T) {
- conn := newMockNetConn()
- models.RespondError(conn, 123, "test error")
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Equal(t, "test error", resp.Error)
- assert.Nil(t, resp.Result)
-}
-
-func TestRespond_Network(t *testing.T) {
- conn := newMockNetConn()
- result := SuccessResult{Success: true, Message: "test"}
- models.Respond(conn, 123, result)
-
- var resp models.Response[SuccessResult]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
- assert.Equal(t, "test", resp.Result.Message)
-}
-
-func TestHandleGetState(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{
- NetworkStatus: StatusWiFi,
- WiFiSSID: "TestNetwork",
- WiFiConnected: true,
- },
- }
-
- conn := newMockNetConn()
- req := Request{ID: 123, Method: "network.getState"}
-
- handleGetState(conn, req, manager)
-
- var resp models.Response[NetworkState]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.Equal(t, StatusWiFi, resp.Result.NetworkStatus)
- assert.Equal(t, "TestNetwork", resp.Result.WiFiSSID)
-}
-
-func TestHandleGetWiFiNetworks(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{
- WiFiNetworks: []WiFiNetwork{
- {SSID: "Network1", Signal: 90},
- {SSID: "Network2", Signal: 80},
- },
- },
- }
-
- conn := newMockNetConn()
- req := Request{ID: 123, Method: "network.wifi.networks"}
-
- handleGetWiFiNetworks(conn, req, manager)
-
- var resp models.Response[[]WiFiNetwork]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.Len(t, *resp.Result, 2)
- assert.Equal(t, "Network1", (*resp.Result)[0].SSID)
-}
-
-func TestHandleConnectWiFi(t *testing.T) {
- t.Run("missing ssid parameter", func(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{},
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "network.wifi.connect",
- Params: map[string]interface{}{},
- }
-
- handleConnectWiFi(conn, req, manager)
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "missing or invalid 'ssid' parameter")
- })
-}
-
-func TestHandleSetPreference(t *testing.T) {
- t.Run("missing preference parameter", func(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{},
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "network.preference.set",
- Params: map[string]interface{}{},
- }
-
- handleSetPreference(conn, req, manager)
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "missing or invalid 'preference' parameter")
- })
-}
-
-func TestHandleGetNetworkInfo(t *testing.T) {
- t.Run("missing ssid parameter", func(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{},
- }
-
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "network.info",
- Params: map[string]interface{}{},
- }
-
- handleGetNetworkInfo(conn, req, manager)
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "missing or invalid 'ssid' parameter")
- })
-}
-
-func TestHandleRequest(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{
- NetworkStatus: StatusWiFi,
- },
- }
-
- t.Run("unknown method", func(t *testing.T) {
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "network.unknown",
- }
-
- HandleRequest(conn, req, manager)
-
- var resp models.Response[any]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Contains(t, resp.Error, "unknown method")
- })
-
- t.Run("valid method - getState", func(t *testing.T) {
- conn := newMockNetConn()
- req := Request{
- ID: 123,
- Method: "network.getState",
- }
-
- HandleRequest(conn, req, manager)
-
- var resp models.Response[NetworkState]
- err := json.NewDecoder(conn.writeBuf).Decode(&resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- })
-}
-
-func TestHandleSubscribe(t *testing.T) {
- // This test is complex due to the streaming nature of subscriptions
- // Better suited as an integration test
- t.Skip("Subscription test requires connection lifecycle management - integration test needed")
-}
-
-func TestManager_Subscribe_Unsubscribe(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{},
- subscribers: make(map[string]chan NetworkState),
- }
-
- t.Run("subscribe creates channel", func(t *testing.T) {
- ch := manager.Subscribe("client1")
- assert.NotNil(t, ch)
- assert.Len(t, manager.subscribers, 1)
- })
-
- t.Run("unsubscribe removes channel", func(t *testing.T) {
- manager.Unsubscribe("client1")
- assert.Len(t, manager.subscribers, 0)
- })
-
- t.Run("unsubscribe non-existent client is safe", func(t *testing.T) {
- assert.NotPanics(t, func() {
- manager.Unsubscribe("non-existent")
- })
- })
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/helpers.go b/nix/inputs/dms-cli/internal/server/network/helpers.go
deleted file mode 100644
index 4669f52..0000000
--- a/nix/inputs/dms-cli/internal/server/network/helpers.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package network
-
-import "sort"
-
-func frequencyToChannel(freq uint32) uint32 {
- if freq >= 2412 && freq <= 2484 {
- if freq == 2484 {
- return 14
- }
- return (freq-2412)/5 + 1
- }
-
- if freq >= 5170 && freq <= 5825 {
- return (freq-5170)/5 + 34
- }
-
- if freq >= 5955 && freq <= 7115 {
- return (freq-5955)/5 + 1
- }
-
- return 0
-}
-
-func sortWiFiNetworks(networks []WiFiNetwork) {
- sort.Slice(networks, func(i, j int) bool {
- if networks[i].Connected && !networks[j].Connected {
- return true
- }
- if !networks[i].Connected && networks[j].Connected {
- return false
- }
-
- if networks[i].Saved && !networks[j].Saved {
- return true
- }
- if !networks[i].Saved && networks[j].Saved {
- return false
- }
-
- if !networks[i].Secured && networks[j].Secured {
- if networks[i].Signal >= 50 {
- return true
- }
- }
- if networks[i].Secured && !networks[j].Secured {
- if networks[j].Signal >= 50 {
- return false
- }
- }
-
- return networks[i].Signal > networks[j].Signal
- })
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/manager.go b/nix/inputs/dms-cli/internal/server/network/manager.go
deleted file mode 100644
index c1c18c1..0000000
--- a/nix/inputs/dms-cli/internal/server/network/manager.go
+++ /dev/null
@@ -1,530 +0,0 @@
-package network
-
-import (
- "fmt"
- "sync"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/log"
-)
-
-func NewManager() (*Manager, error) {
- detection, err := DetectNetworkStack()
- if err != nil {
- return nil, fmt.Errorf("failed to detect network stack: %w", err)
- }
-
- log.Infof("Network backend detection: %s", detection.ChosenReason)
-
- var backend Backend
- switch detection.Backend {
- case BackendNetworkManager:
- nm, err := NewNetworkManagerBackend()
- if err != nil {
- return nil, fmt.Errorf("failed to create NetworkManager backend: %w", err)
- }
- backend = nm
-
- case BackendIwd:
- iwd, err := NewIWDBackend()
- if err != nil {
- return nil, fmt.Errorf("failed to create iwd backend: %w", err)
- }
- backend = iwd
-
- case BackendNetworkd:
- if detection.HasIwd && !detection.HasNM {
- wifi, err := NewIWDBackend()
- if err != nil {
- return nil, fmt.Errorf("failed to create iwd backend: %w", err)
- }
- l3, err := NewSystemdNetworkdBackend()
- if err != nil {
- return nil, fmt.Errorf("failed to create networkd backend: %w", err)
- }
- hybrid, err := NewHybridIwdNetworkdBackend(wifi, l3)
- if err != nil {
- return nil, fmt.Errorf("failed to create hybrid backend: %w", err)
- }
- backend = hybrid
- } else {
- nd, err := NewSystemdNetworkdBackend()
- if err != nil {
- return nil, fmt.Errorf("failed to create networkd backend: %w", err)
- }
- backend = nd
- }
-
- default:
- return nil, fmt.Errorf("no supported network backend found: %s", detection.ChosenReason)
- }
-
- m := &Manager{
- backend: backend,
- state: &NetworkState{
- NetworkStatus: StatusDisconnected,
- Preference: PreferenceAuto,
- WiFiNetworks: []WiFiNetwork{},
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan NetworkState),
- subMutex: sync.RWMutex{},
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- credentialSubscribers: make(map[string]chan CredentialPrompt),
- credSubMutex: sync.RWMutex{},
- }
-
- broker := NewSubscriptionBroker(m.broadcastCredentialPrompt)
- if err := backend.SetPromptBroker(broker); err != nil {
- return nil, fmt.Errorf("failed to set prompt broker: %w", err)
- }
-
- if err := backend.Initialize(); err != nil {
- return nil, fmt.Errorf("failed to initialize backend: %w", err)
- }
-
- if err := m.syncStateFromBackend(); err != nil {
- return nil, fmt.Errorf("failed to sync initial state: %w", err)
- }
-
- m.notifierWg.Add(1)
- go m.notifier()
-
- if err := backend.StartMonitoring(m.onBackendStateChange); err != nil {
- m.Close()
- return nil, fmt.Errorf("failed to start monitoring: %w", err)
- }
-
- return m, nil
-}
-
-func (m *Manager) syncStateFromBackend() error {
- backendState, err := m.backend.GetCurrentState()
- if err != nil {
- return err
- }
-
- m.stateMutex.Lock()
- m.state.Backend = backendState.Backend
- m.state.NetworkStatus = backendState.NetworkStatus
- m.state.EthernetIP = backendState.EthernetIP
- m.state.EthernetDevice = backendState.EthernetDevice
- m.state.EthernetConnected = backendState.EthernetConnected
- m.state.EthernetConnectionUuid = backendState.EthernetConnectionUuid
- m.state.WiFiIP = backendState.WiFiIP
- m.state.WiFiDevice = backendState.WiFiDevice
- m.state.WiFiConnected = backendState.WiFiConnected
- m.state.WiFiEnabled = backendState.WiFiEnabled
- m.state.WiFiSSID = backendState.WiFiSSID
- m.state.WiFiBSSID = backendState.WiFiBSSID
- m.state.WiFiSignal = backendState.WiFiSignal
- m.state.WiFiNetworks = backendState.WiFiNetworks
- m.state.WiredConnections = backendState.WiredConnections
- m.state.VPNProfiles = backendState.VPNProfiles
- m.state.VPNActive = backendState.VPNActive
- m.state.IsConnecting = backendState.IsConnecting
- m.state.ConnectingSSID = backendState.ConnectingSSID
- m.state.LastError = backendState.LastError
- m.stateMutex.Unlock()
-
- return nil
-}
-
-func (m *Manager) onBackendStateChange() {
- if err := m.syncStateFromBackend(); err != nil {
- log.Errorf("failed to sync state from backend: %v", err)
- }
- m.notifySubscribers()
-}
-
-func signalChangeSignificant(old, new uint8) bool {
- if old == 0 || new == 0 {
- return true
- }
- diff := int(new) - int(old)
- if diff < 0 {
- diff = -diff
- }
- return diff >= 5
-}
-
-func (m *Manager) snapshotState() NetworkState {
- m.stateMutex.RLock()
- defer m.stateMutex.RUnlock()
- s := *m.state
- s.WiFiNetworks = append([]WiFiNetwork(nil), m.state.WiFiNetworks...)
- s.WiredConnections = append([]WiredConnection(nil), m.state.WiredConnections...)
- s.VPNProfiles = append([]VPNProfile(nil), m.state.VPNProfiles...)
- s.VPNActive = append([]VPNActive(nil), m.state.VPNActive...)
- return s
-}
-
-func stateChangedMeaningfully(old, new *NetworkState) bool {
- if old.NetworkStatus != new.NetworkStatus {
- return true
- }
- if old.Preference != new.Preference {
- return true
- }
- if old.EthernetConnected != new.EthernetConnected {
- return true
- }
- if old.EthernetIP != new.EthernetIP {
- return true
- }
- if old.WiFiConnected != new.WiFiConnected {
- return true
- }
- if old.WiFiEnabled != new.WiFiEnabled {
- return true
- }
- if old.WiFiSSID != new.WiFiSSID {
- return true
- }
- if old.WiFiBSSID != new.WiFiBSSID {
- return true
- }
- if old.WiFiIP != new.WiFiIP {
- return true
- }
- if !signalChangeSignificant(old.WiFiSignal, new.WiFiSignal) {
- if old.WiFiSignal != new.WiFiSignal {
- return false
- }
- } else if old.WiFiSignal != new.WiFiSignal {
- return true
- }
- if old.IsConnecting != new.IsConnecting {
- return true
- }
- if old.ConnectingSSID != new.ConnectingSSID {
- return true
- }
- if old.LastError != new.LastError {
- return true
- }
- if len(old.WiFiNetworks) != len(new.WiFiNetworks) {
- return true
- }
- if len(old.WiredConnections) != len(new.WiredConnections) {
- return true
- }
-
- for i := range old.WiFiNetworks {
- oldNet := &old.WiFiNetworks[i]
- newNet := &new.WiFiNetworks[i]
- if oldNet.SSID != newNet.SSID {
- return true
- }
- if oldNet.Connected != newNet.Connected {
- return true
- }
- if oldNet.Saved != newNet.Saved {
- return true
- }
- if oldNet.Autoconnect != newNet.Autoconnect {
- return true
- }
- }
-
- for i := range old.WiredConnections {
- oldNet := &old.WiredConnections[i]
- newNet := &new.WiredConnections[i]
- if oldNet.ID != newNet.ID {
- return true
- }
- if oldNet.IsActive != newNet.IsActive {
- return true
- }
- }
-
- // Check VPN profiles count
- if len(old.VPNProfiles) != len(new.VPNProfiles) {
- return true
- }
-
- // Check active VPN connections count or state
- if len(old.VPNActive) != len(new.VPNActive) {
- return true
- }
-
- // Check if any active VPN changed
- for i := range old.VPNActive {
- oldVPN := &old.VPNActive[i]
- newVPN := &new.VPNActive[i]
- if oldVPN.UUID != newVPN.UUID {
- return true
- }
- if oldVPN.State != newVPN.State {
- return true
- }
- }
-
- return false
-}
-
-func (m *Manager) GetState() NetworkState {
- return m.snapshotState()
-}
-
-func (m *Manager) Subscribe(id string) chan NetworkState {
- ch := make(chan NetworkState, 64)
- m.subMutex.Lock()
- m.subscribers[id] = ch
- m.subMutex.Unlock()
- return ch
-}
-
-func (m *Manager) Unsubscribe(id string) {
- m.subMutex.Lock()
- if ch, ok := m.subscribers[id]; ok {
- close(ch)
- delete(m.subscribers, id)
- }
- m.subMutex.Unlock()
-}
-
-func (m *Manager) SubscribeCredentials(id string) chan CredentialPrompt {
- ch := make(chan CredentialPrompt, 16)
- m.credSubMutex.Lock()
- m.credentialSubscribers[id] = ch
- m.credSubMutex.Unlock()
- return ch
-}
-
-func (m *Manager) UnsubscribeCredentials(id string) {
- m.credSubMutex.Lock()
- if ch, ok := m.credentialSubscribers[id]; ok {
- close(ch)
- delete(m.credentialSubscribers, id)
- }
- m.credSubMutex.Unlock()
-}
-
-func (m *Manager) broadcastCredentialPrompt(prompt CredentialPrompt) {
- m.credSubMutex.RLock()
- defer m.credSubMutex.RUnlock()
-
- for _, ch := range m.credentialSubscribers {
- select {
- case ch <- prompt:
- default:
- }
- }
-}
-
-func (m *Manager) notifier() {
- defer m.notifierWg.Done()
- const minGap = 100 * time.Millisecond
- timer := time.NewTimer(minGap)
- timer.Stop()
- var pending bool
- for {
- select {
- case <-m.stopChan:
- timer.Stop()
- return
- case <-m.dirty:
- if pending {
- continue
- }
- pending = true
- timer.Reset(minGap)
- case <-timer.C:
- if !pending {
- continue
- }
- m.subMutex.RLock()
- if len(m.subscribers) == 0 {
- m.subMutex.RUnlock()
- pending = false
- continue
- }
-
- currentState := m.snapshotState()
-
- if m.lastNotifiedState != nil && !stateChangedMeaningfully(m.lastNotifiedState, ¤tState) {
- m.subMutex.RUnlock()
- pending = false
- continue
- }
-
- for _, ch := range m.subscribers {
- select {
- case ch <- currentState:
- default:
- }
- }
- m.subMutex.RUnlock()
-
- stateCopy := currentState
- m.lastNotifiedState = &stateCopy
- pending = false
- }
- }
-}
-
-func (m *Manager) notifySubscribers() {
- select {
- case m.dirty <- struct{}{}:
- default:
- }
-}
-
-func (m *Manager) SetPromptBroker(broker PromptBroker) error {
- return m.backend.SetPromptBroker(broker)
-}
-
-func (m *Manager) SubmitCredentials(token string, secrets map[string]string, save bool) error {
- return m.backend.SubmitCredentials(token, secrets, save)
-}
-
-func (m *Manager) CancelCredentials(token string) error {
- return m.backend.CancelCredentials(token)
-}
-
-func (m *Manager) GetPromptBroker() PromptBroker {
- return m.backend.GetPromptBroker()
-}
-
-func (m *Manager) Close() {
- close(m.stopChan)
- m.notifierWg.Wait()
-
- if m.backend != nil {
- m.backend.Close()
- }
-
- m.subMutex.Lock()
- for _, ch := range m.subscribers {
- close(ch)
- }
- m.subscribers = make(map[string]chan NetworkState)
- m.subMutex.Unlock()
-}
-
-func (m *Manager) ScanWiFi() error {
- return m.backend.ScanWiFi()
-}
-
-func (m *Manager) GetWiFiNetworks() []WiFiNetwork {
- m.stateMutex.RLock()
- defer m.stateMutex.RUnlock()
- networks := make([]WiFiNetwork, len(m.state.WiFiNetworks))
- copy(networks, m.state.WiFiNetworks)
- return networks
-}
-
-func (m *Manager) GetNetworkInfo(ssid string) (*WiFiNetwork, error) {
- m.stateMutex.RLock()
- defer m.stateMutex.RUnlock()
-
- for _, network := range m.state.WiFiNetworks {
- if network.SSID == ssid {
- return &network, nil
- }
- }
-
- return nil, fmt.Errorf("network not found: %s", ssid)
-}
-
-func (m *Manager) GetNetworkInfoDetailed(ssid string) (*NetworkInfoResponse, error) {
- return m.backend.GetWiFiNetworkDetails(ssid)
-}
-
-func (m *Manager) ToggleWiFi() error {
- enabled, err := m.backend.GetWiFiEnabled()
- if err != nil {
- return fmt.Errorf("failed to get WiFi state: %w", err)
- }
-
- err = m.backend.SetWiFiEnabled(!enabled)
- if err != nil {
- return fmt.Errorf("failed to toggle WiFi: %w", err)
- }
-
- return nil
-}
-
-func (m *Manager) EnableWiFi() error {
- err := m.backend.SetWiFiEnabled(true)
- if err != nil {
- return fmt.Errorf("failed to enable WiFi: %w", err)
- }
-
- return nil
-}
-
-func (m *Manager) DisableWiFi() error {
- err := m.backend.SetWiFiEnabled(false)
- if err != nil {
- return fmt.Errorf("failed to disable WiFi: %w", err)
- }
-
- return nil
-}
-
-func (m *Manager) ConnectWiFi(req ConnectionRequest) error {
- return m.backend.ConnectWiFi(req)
-}
-
-func (m *Manager) DisconnectWiFi() error {
- return m.backend.DisconnectWiFi()
-}
-
-func (m *Manager) ForgetWiFiNetwork(ssid string) error {
- return m.backend.ForgetWiFiNetwork(ssid)
-}
-
-func (m *Manager) GetWiredConfigs() []WiredConnection {
- m.stateMutex.RLock()
- defer m.stateMutex.RUnlock()
- configs := make([]WiredConnection, len(m.state.WiredConnections))
- copy(configs, m.state.WiredConnections)
- return configs
-}
-
-func (m *Manager) GetWiredNetworkInfoDetailed(uuid string) (*WiredNetworkInfoResponse, error) {
- return m.backend.GetWiredNetworkDetails(uuid)
-}
-
-func (m *Manager) ConnectEthernet() error {
- return m.backend.ConnectEthernet()
-}
-
-func (m *Manager) DisconnectEthernet() error {
- return m.backend.DisconnectEthernet()
-}
-
-func (m *Manager) activateConnection(uuid string) error {
- return m.backend.ActivateWiredConnection(uuid)
-}
-
-func (m *Manager) ListVPNProfiles() ([]VPNProfile, error) {
- return m.backend.ListVPNProfiles()
-}
-
-func (m *Manager) ListActiveVPN() ([]VPNActive, error) {
- return m.backend.ListActiveVPN()
-}
-
-func (m *Manager) ConnectVPN(uuidOrName string, singleActive bool) error {
- return m.backend.ConnectVPN(uuidOrName, singleActive)
-}
-
-func (m *Manager) DisconnectVPN(uuidOrName string) error {
- return m.backend.DisconnectVPN(uuidOrName)
-}
-
-func (m *Manager) DisconnectAllVPN() error {
- return m.backend.DisconnectAllVPN()
-}
-
-func (m *Manager) ClearVPNCredentials(uuidOrName string) error {
- return m.backend.ClearVPNCredentials(uuidOrName)
-}
-
-func (m *Manager) SetWiFiAutoconnect(ssid string, autoconnect bool) error {
- return m.backend.SetWiFiAutoconnect(ssid, autoconnect)
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/manager_test.go b/nix/inputs/dms-cli/internal/server/network/manager_test.go
deleted file mode 100644
index f6dbf80..0000000
--- a/nix/inputs/dms-cli/internal/server/network/manager_test.go
+++ /dev/null
@@ -1,231 +0,0 @@
-package network
-
-import (
- "sync"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestManager_GetState(t *testing.T) {
- state := &NetworkState{
- NetworkStatus: StatusWiFi,
- WiFiSSID: "TestNetwork",
- WiFiConnected: true,
- }
-
- manager := &Manager{
- state: state,
- stateMutex: sync.RWMutex{},
- }
-
- result := manager.GetState()
- assert.Equal(t, StatusWiFi, result.NetworkStatus)
- assert.Equal(t, "TestNetwork", result.WiFiSSID)
- assert.True(t, result.WiFiConnected)
-}
-
-func TestManager_NotifySubscribers(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{
- NetworkStatus: StatusWiFi,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan NetworkState),
- subMutex: sync.RWMutex{},
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- }
- manager.notifierWg.Add(1)
- go manager.notifier()
-
- // Subscribe a client
- ch := make(chan NetworkState, 10)
- manager.subMutex.Lock()
- manager.subscribers["test-client"] = ch
- manager.subMutex.Unlock()
-
- // Notify subscribers
- manager.notifySubscribers()
-
- // Check that state was sent (wait for debounce timer + some slack)
- select {
- case state := <-ch:
- assert.Equal(t, StatusWiFi, state.NetworkStatus)
- case <-time.After(200 * time.Millisecond):
- t.Fatal("did not receive state update")
- }
-
- close(manager.stopChan)
- manager.notifierWg.Wait()
-}
-
-func TestManager_NotifySubscribers_Debounce(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{
- NetworkStatus: StatusWiFi,
- },
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan NetworkState),
- subMutex: sync.RWMutex{},
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- }
- manager.notifierWg.Add(1)
- go manager.notifier()
-
- // Subscribe a client
- ch := make(chan NetworkState, 10)
- manager.subMutex.Lock()
- manager.subscribers["test-client"] = ch
- manager.subMutex.Unlock()
-
- // Send multiple rapid notifications
- manager.notifySubscribers()
- manager.notifySubscribers()
- manager.notifySubscribers()
-
- // Should only receive one state update due to debouncing
- receivedCount := 0
- timeout := time.After(200 * time.Millisecond)
- for {
- select {
- case <-ch:
- receivedCount++
- case <-timeout:
- assert.Equal(t, 1, receivedCount, "should receive exactly one debounced update")
- close(manager.stopChan)
- manager.notifierWg.Wait()
- return
- }
- }
-}
-
-func TestManager_Close(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{},
- stateMutex: sync.RWMutex{},
- subscribers: make(map[string]chan NetworkState),
- subMutex: sync.RWMutex{},
- stopChan: make(chan struct{}),
- }
-
- // Add subscribers
- ch1 := make(chan NetworkState, 1)
- ch2 := make(chan NetworkState, 1)
- manager.subMutex.Lock()
- manager.subscribers["client1"] = ch1
- manager.subscribers["client2"] = ch2
- manager.subMutex.Unlock()
-
- // Close manager
- manager.Close()
-
- // Check that stopChan is closed
- select {
- case <-manager.stopChan:
- // Expected
- case <-time.After(100 * time.Millisecond):
- t.Fatal("stopChan not closed")
- }
-
- // Check that subscriber channels are closed
- _, ok1 := <-ch1
- _, ok2 := <-ch2
- assert.False(t, ok1, "ch1 should be closed")
- assert.False(t, ok2, "ch2 should be closed")
-
- // Check that subscribers map is reset
- assert.Len(t, manager.subscribers, 0)
-}
-
-func TestManager_Subscribe(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{},
- subscribers: make(map[string]chan NetworkState),
- subMutex: sync.RWMutex{},
- }
-
- ch := manager.Subscribe("test-client")
- assert.NotNil(t, ch)
- assert.Equal(t, 64, cap(ch))
-
- manager.subMutex.RLock()
- _, exists := manager.subscribers["test-client"]
- manager.subMutex.RUnlock()
- assert.True(t, exists)
-}
-
-func TestManager_Unsubscribe(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{},
- subscribers: make(map[string]chan NetworkState),
- subMutex: sync.RWMutex{},
- }
-
- // Subscribe first
- ch := manager.Subscribe("test-client")
-
- // Unsubscribe
- manager.Unsubscribe("test-client")
-
- // Check channel is closed
- _, ok := <-ch
- assert.False(t, ok)
-
- // Check client is removed
- manager.subMutex.RLock()
- _, exists := manager.subscribers["test-client"]
- manager.subMutex.RUnlock()
- assert.False(t, exists)
-}
-
-func TestNewManager(t *testing.T) {
- // This test will fail in environments without NetworkManager D-Bus
- // It's primarily for local testing
- t.Run("attempts to create manager", func(t *testing.T) {
- manager, err := NewManager()
- if err != nil {
- // Expected in test environments
- assert.Nil(t, manager)
- } else {
- assert.NotNil(t, manager)
- assert.NotNil(t, manager.state)
- assert.NotNil(t, manager.subscribers)
- assert.NotNil(t, manager.stopChan)
-
- // Clean up
- manager.Close()
- }
- })
-}
-
-func TestManager_GetState_ThreadSafe(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{
- NetworkStatus: StatusWiFi,
- WiFiSSID: "TestNetwork",
- },
- stateMutex: sync.RWMutex{},
- }
-
- // Test concurrent reads
- done := make(chan bool)
- for i := 0; i < 10; i++ {
- go func() {
- state := manager.GetState()
- assert.Equal(t, StatusWiFi, state.NetworkStatus)
- done <- true
- }()
- }
-
- // Wait for all goroutines to complete
- for i := 0; i < 10; i++ {
- select {
- case <-done:
- case <-time.After(1 * time.Second):
- t.Fatal("timeout waiting for goroutines")
- }
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/monitor.go b/nix/inputs/dms-cli/internal/server/network/monitor.go
deleted file mode 100644
index 1ae2e9d..0000000
--- a/nix/inputs/dms-cli/internal/server/network/monitor.go
+++ /dev/null
@@ -1 +0,0 @@
-package network
diff --git a/nix/inputs/dms-cli/internal/server/network/priority.go b/nix/inputs/dms-cli/internal/server/network/priority.go
deleted file mode 100644
index d047bcc..0000000
--- a/nix/inputs/dms-cli/internal/server/network/priority.go
+++ /dev/null
@@ -1,138 +0,0 @@
-package network
-
-import (
- "fmt"
- "time"
-
- "github.com/Wifx/gonetworkmanager/v2"
-)
-
-func (m *Manager) SetConnectionPreference(pref ConnectionPreference) error {
- switch pref {
- case PreferenceWiFi, PreferenceEthernet, PreferenceAuto:
- default:
- return fmt.Errorf("invalid preference: %s", pref)
- }
-
- m.stateMutex.Lock()
- m.state.Preference = pref
- m.stateMutex.Unlock()
-
- if _, ok := m.backend.(*NetworkManagerBackend); !ok {
- m.notifySubscribers()
- return nil
- }
-
- switch pref {
- case PreferenceWiFi:
- return m.prioritizeWiFi()
- case PreferenceEthernet:
- return m.prioritizeEthernet()
- case PreferenceAuto:
- return m.balancePriorities()
- }
-
- return nil
-}
-
-func (m *Manager) prioritizeWiFi() error {
- if err := m.setConnectionMetrics("802-11-wireless", 50); err != nil {
- return err
- }
-
- if err := m.setConnectionMetrics("802-3-ethernet", 100); err != nil {
- return err
- }
-
- m.notifySubscribers()
- return nil
-}
-
-func (m *Manager) prioritizeEthernet() error {
- if err := m.setConnectionMetrics("802-3-ethernet", 50); err != nil {
- return err
- }
-
- if err := m.setConnectionMetrics("802-11-wireless", 100); err != nil {
- return err
- }
-
- m.notifySubscribers()
- return nil
-}
-
-func (m *Manager) balancePriorities() error {
- if err := m.setConnectionMetrics("802-3-ethernet", 50); err != nil {
- return err
- }
-
- if err := m.setConnectionMetrics("802-11-wireless", 50); err != nil {
- return err
- }
-
- m.notifySubscribers()
- return nil
-}
-
-func (m *Manager) setConnectionMetrics(connType string, metric uint32) error {
- settingsMgr, err := gonetworkmanager.NewSettings()
- if err != nil {
- return fmt.Errorf("failed to get settings: %w", err)
- }
-
- connections, err := settingsMgr.ListConnections()
- if err != nil {
- return fmt.Errorf("failed to get connections: %w", err)
- }
-
- for _, conn := range connections {
- connSettings, err := conn.GetSettings()
- if err != nil {
- continue
- }
-
- if connMeta, ok := connSettings["connection"]; ok {
- if cType, ok := connMeta["type"].(string); ok && cType == connType {
- if connSettings["ipv4"] == nil {
- connSettings["ipv4"] = make(map[string]interface{})
- }
- if ipv4Map := connSettings["ipv4"]; ipv4Map != nil {
- ipv4Map["route-metric"] = int64(metric)
- }
-
- if connSettings["ipv6"] == nil {
- connSettings["ipv6"] = make(map[string]interface{})
- }
- if ipv6Map := connSettings["ipv6"]; ipv6Map != nil {
- ipv6Map["route-metric"] = int64(metric)
- }
-
- err = conn.Update(connSettings)
- if err != nil {
- continue
- }
- }
- }
- }
-
- return nil
-}
-
-func (m *Manager) GetConnectionPreference() ConnectionPreference {
- m.stateMutex.RLock()
- defer m.stateMutex.RUnlock()
- return m.state.Preference
-}
-
-func (m *Manager) WasRecentlyFailed(ssid string) bool {
- if nm, ok := m.backend.(*NetworkManagerBackend); ok {
- nm.failedMutex.RLock()
- defer nm.failedMutex.RUnlock()
-
- if nm.lastFailedSSID == ssid {
- elapsed := time.Now().Unix() - nm.lastFailedTime
- return elapsed < 10
- }
- }
- return false
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/priority_test.go b/nix/inputs/dms-cli/internal/server/network/priority_test.go
deleted file mode 100644
index c0c65e3..0000000
--- a/nix/inputs/dms-cli/internal/server/network/priority_test.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package network
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestManager_SetConnectionPreference(t *testing.T) {
- t.Run("invalid preference", func(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{
- Preference: PreferenceAuto,
- },
- }
-
- err := manager.SetConnectionPreference(ConnectionPreference("invalid"))
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "invalid preference")
- })
-}
-
-func TestManager_GetConnectionPreference(t *testing.T) {
- tests := []struct {
- name string
- preference ConnectionPreference
- }{
- {"auto", PreferenceAuto},
- {"wifi", PreferenceWiFi},
- {"ethernet", PreferenceEthernet},
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{
- Preference: tt.preference,
- },
- }
-
- result := manager.GetConnectionPreference()
- assert.Equal(t, tt.preference, result)
- })
- }
-}
-
-// Note: Full testing of priority operations would require mocking NetworkManager
-// D-Bus interfaces. The tests above cover the basic logic and error handling.
-// Integration tests would be needed for complete coverage of network connection
-// priority updates and reactivation.
diff --git a/nix/inputs/dms-cli/internal/server/network/subscription_broker.go b/nix/inputs/dms-cli/internal/server/network/subscription_broker.go
deleted file mode 100644
index 3697751..0000000
--- a/nix/inputs/dms-cli/internal/server/network/subscription_broker.go
+++ /dev/null
@@ -1,146 +0,0 @@
-package network
-
-import (
- "context"
- "fmt"
- "sync"
-
- "github.com/AvengeMedia/danklinux/internal/errdefs"
- "github.com/AvengeMedia/danklinux/internal/log"
-)
-
-type SubscriptionBroker struct {
- mu sync.RWMutex
- pending map[string]chan PromptReply
- requests map[string]PromptRequest
- pathSettingToToken map[string]string
- broadcastPrompt func(CredentialPrompt)
-}
-
-func NewSubscriptionBroker(broadcastPrompt func(CredentialPrompt)) PromptBroker {
- return &SubscriptionBroker{
- pending: make(map[string]chan PromptReply),
- requests: make(map[string]PromptRequest),
- pathSettingToToken: make(map[string]string),
- broadcastPrompt: broadcastPrompt,
- }
-}
-
-func (b *SubscriptionBroker) Ask(ctx context.Context, req PromptRequest) (string, error) {
- pathSettingKey := fmt.Sprintf("%s:%s", req.ConnectionPath, req.SettingName)
-
- b.mu.Lock()
- existingToken, alreadyPending := b.pathSettingToToken[pathSettingKey]
- b.mu.Unlock()
-
- if alreadyPending {
- log.Infof("[SubscriptionBroker] Duplicate prompt for %s, returning existing token", pathSettingKey)
- return existingToken, nil
- }
-
- token, err := generateToken()
- if err != nil {
- return "", err
- }
-
- replyChan := make(chan PromptReply, 1)
- b.mu.Lock()
- b.pending[token] = replyChan
- b.requests[token] = req
- b.pathSettingToToken[pathSettingKey] = token
- b.mu.Unlock()
-
- if b.broadcastPrompt != nil {
- prompt := CredentialPrompt{
- Token: token,
- Name: req.Name,
- SSID: req.SSID,
- ConnType: req.ConnType,
- VpnService: req.VpnService,
- Setting: req.SettingName,
- Fields: req.Fields,
- Hints: req.Hints,
- Reason: req.Reason,
- ConnectionId: req.ConnectionId,
- ConnectionUuid: req.ConnectionUuid,
- }
- b.broadcastPrompt(prompt)
- }
-
- return token, nil
-}
-
-func (b *SubscriptionBroker) Wait(ctx context.Context, token string) (PromptReply, error) {
- b.mu.RLock()
- replyChan, exists := b.pending[token]
- b.mu.RUnlock()
-
- if !exists {
- return PromptReply{}, fmt.Errorf("unknown token: %s", token)
- }
-
- select {
- case <-ctx.Done():
- b.cleanup(token)
- return PromptReply{}, errdefs.ErrSecretPromptTimeout
- case reply := <-replyChan:
- b.cleanup(token)
- if reply.Cancel {
- return reply, errdefs.ErrSecretPromptCancelled
- }
- return reply, nil
- }
-}
-
-func (b *SubscriptionBroker) Resolve(token string, reply PromptReply) error {
- b.mu.RLock()
- replyChan, exists := b.pending[token]
- b.mu.RUnlock()
-
- if !exists {
- log.Warnf("[SubscriptionBroker] Resolve: unknown or expired token: %s", token)
- return fmt.Errorf("unknown or expired token: %s", token)
- }
-
- select {
- case replyChan <- reply:
- return nil
- default:
- log.Warnf("[SubscriptionBroker] Resolve: failed to deliver reply for token %s (channel full or closed)", token)
- return fmt.Errorf("failed to deliver reply for token: %s", token)
- }
-}
-
-func (b *SubscriptionBroker) cleanup(token string) {
- b.mu.Lock()
- defer b.mu.Unlock()
-
- if req, exists := b.requests[token]; exists {
- pathSettingKey := fmt.Sprintf("%s:%s", req.ConnectionPath, req.SettingName)
- delete(b.pathSettingToToken, pathSettingKey)
- }
-
- delete(b.pending, token)
- delete(b.requests, token)
-}
-
-func (b *SubscriptionBroker) Cancel(path string, setting string) error {
- pathSettingKey := fmt.Sprintf("%s:%s", path, setting)
-
- b.mu.Lock()
- token, exists := b.pathSettingToToken[pathSettingKey]
- b.mu.Unlock()
-
- if !exists {
- log.Infof("[SubscriptionBroker] Cancel: no pending prompt for %s", pathSettingKey)
- return nil
- }
-
- log.Infof("[SubscriptionBroker] Cancelling prompt for %s (token=%s)", pathSettingKey, token)
-
- reply := PromptReply{
- Cancel: true,
- }
-
- return b.Resolve(token, reply)
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/testing.go b/nix/inputs/dms-cli/internal/server/network/testing.go
deleted file mode 100644
index f4ff197..0000000
--- a/nix/inputs/dms-cli/internal/server/network/testing.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package network
-
-// NewTestManager creates a Manager for testing with a provided backend
-func NewTestManager(backend Backend, state *NetworkState) *Manager {
- if state == nil {
- state = &NetworkState{}
- }
- return &Manager{
- backend: backend,
- state: state,
- subscribers: make(map[string]chan NetworkState),
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/types.go b/nix/inputs/dms-cli/internal/server/network/types.go
deleted file mode 100644
index a46a916..0000000
--- a/nix/inputs/dms-cli/internal/server/network/types.go
+++ /dev/null
@@ -1,190 +0,0 @@
-package network
-
-import (
- "sync"
-
- "github.com/godbus/dbus/v5"
-)
-
-type NetworkStatus string
-
-const (
- StatusDisconnected NetworkStatus = "disconnected"
- StatusEthernet NetworkStatus = "ethernet"
- StatusWiFi NetworkStatus = "wifi"
- StatusVPN NetworkStatus = "vpn"
-)
-
-type ConnectionPreference string
-
-const (
- PreferenceAuto ConnectionPreference = "auto"
- PreferenceWiFi ConnectionPreference = "wifi"
- PreferenceEthernet ConnectionPreference = "ethernet"
-)
-
-type WiFiNetwork struct {
- SSID string `json:"ssid"`
- BSSID string `json:"bssid"`
- Signal uint8 `json:"signal"`
- Secured bool `json:"secured"`
- Enterprise bool `json:"enterprise"`
- Connected bool `json:"connected"`
- Saved bool `json:"saved"`
- Autoconnect bool `json:"autoconnect"`
- Frequency uint32 `json:"frequency"`
- Mode string `json:"mode"`
- Rate uint32 `json:"rate"`
- Channel uint32 `json:"channel"`
-}
-
-type VPNProfile struct {
- Name string `json:"name"`
- UUID string `json:"uuid"`
- Type string `json:"type"`
- ServiceType string `json:"serviceType"`
-}
-
-type VPNActive struct {
- Name string `json:"name"`
- UUID string `json:"uuid"`
- Device string `json:"device,omitempty"`
- State string `json:"state,omitempty"`
- Type string `json:"type"`
- Plugin string `json:"serviceType"`
-}
-
-type VPNState struct {
- Profiles []VPNProfile `json:"profiles"`
- Active []VPNActive `json:"activeConnections"`
-}
-
-type NetworkState struct {
- Backend string `json:"backend"`
- NetworkStatus NetworkStatus `json:"networkStatus"`
- Preference ConnectionPreference `json:"preference"`
- EthernetIP string `json:"ethernetIP"`
- EthernetDevice string `json:"ethernetDevice"`
- EthernetConnected bool `json:"ethernetConnected"`
- EthernetConnectionUuid string `json:"ethernetConnectionUuid"`
- WiFiIP string `json:"wifiIP"`
- WiFiDevice string `json:"wifiDevice"`
- WiFiConnected bool `json:"wifiConnected"`
- WiFiEnabled bool `json:"wifiEnabled"`
- WiFiSSID string `json:"wifiSSID"`
- WiFiBSSID string `json:"wifiBSSID"`
- WiFiSignal uint8 `json:"wifiSignal"`
- WiFiNetworks []WiFiNetwork `json:"wifiNetworks"`
- WiredConnections []WiredConnection `json:"wiredConnections"`
- VPNProfiles []VPNProfile `json:"vpnProfiles"`
- VPNActive []VPNActive `json:"vpnActive"`
- IsConnecting bool `json:"isConnecting"`
- ConnectingSSID string `json:"connectingSSID"`
- LastError string `json:"lastError"`
-}
-
-type ConnectionRequest struct {
- SSID string `json:"ssid"`
- Password string `json:"password,omitempty"`
- Username string `json:"username,omitempty"`
- AnonymousIdentity string `json:"anonymousIdentity,omitempty"`
- DomainSuffixMatch string `json:"domainSuffixMatch,omitempty"`
- Interactive bool `json:"interactive,omitempty"`
-}
-
-type WiredConnection struct {
- Path dbus.ObjectPath `json:"path"`
- ID string `json:"id"`
- UUID string `json:"uuid"`
- Type string `json:"type"`
- IsActive bool `json:"isActive"`
-}
-
-type PriorityUpdate struct {
- Preference ConnectionPreference `json:"preference"`
-}
-
-type Manager struct {
- backend Backend
- state *NetworkState
- stateMutex sync.RWMutex
- subscribers map[string]chan NetworkState
- subMutex sync.RWMutex
- stopChan chan struct{}
- dirty chan struct{}
- notifierWg sync.WaitGroup
- lastNotifiedState *NetworkState
- credentialSubscribers map[string]chan CredentialPrompt
- credSubMutex sync.RWMutex
-}
-
-type EventType string
-
-const (
- EventStateChanged EventType = "state_changed"
- EventNetworksUpdated EventType = "networks_updated"
- EventConnecting EventType = "connecting"
- EventConnected EventType = "connected"
- EventDisconnected EventType = "disconnected"
- EventError EventType = "error"
-)
-
-type NetworkEvent struct {
- Type EventType `json:"type"`
- Data NetworkState `json:"data"`
-}
-
-type PromptRequest struct {
- Name string `json:"name"`
- SSID string `json:"ssid"`
- ConnType string `json:"connType"`
- VpnService string `json:"vpnService"`
- SettingName string `json:"setting"`
- Fields []string `json:"fields"`
- Hints []string `json:"hints"`
- Reason string `json:"reason"`
- ConnectionId string `json:"connectionId"`
- ConnectionUuid string `json:"connectionUuid"`
- ConnectionPath string `json:"connectionPath"`
-}
-
-type PromptReply struct {
- Secrets map[string]string `json:"secrets"`
- Save bool `json:"save"`
- Cancel bool `json:"cancel"`
-}
-
-type CredentialPrompt struct {
- Token string `json:"token"`
- Name string `json:"name"`
- SSID string `json:"ssid"`
- ConnType string `json:"connType"`
- VpnService string `json:"vpnService"`
- Setting string `json:"setting"`
- Fields []string `json:"fields"`
- Hints []string `json:"hints"`
- Reason string `json:"reason"`
- ConnectionId string `json:"connectionId"`
- ConnectionUuid string `json:"connectionUuid"`
-}
-
-type NetworkInfoResponse struct {
- SSID string `json:"ssid"`
- Bands []WiFiNetwork `json:"bands"`
-}
-
-type WiredNetworkInfoResponse struct {
- UUID string `json:"uuid"`
- IFace string `json:"iface"`
- Driver string `json:"driver"`
- HwAddr string `json:"hwAddr"`
- Speed string `json:"speed"`
- IPv4 WiredIPConfig `json:"IPv4s"`
- IPv6 WiredIPConfig `json:"IPv6s"`
-}
-
-type WiredIPConfig struct {
- IPs []string `json:"ips"`
- Gateway string `json:"gateway"`
- DNS string `json:"dns"`
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/types_test.go b/nix/inputs/dms-cli/internal/server/network/types_test.go
deleted file mode 100644
index 1c3e0bf..0000000
--- a/nix/inputs/dms-cli/internal/server/network/types_test.go
+++ /dev/null
@@ -1,178 +0,0 @@
-package network
-
-import (
- "encoding/json"
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestNetworkStatus_Constants(t *testing.T) {
- assert.Equal(t, NetworkStatus("disconnected"), StatusDisconnected)
- assert.Equal(t, NetworkStatus("ethernet"), StatusEthernet)
- assert.Equal(t, NetworkStatus("wifi"), StatusWiFi)
-}
-
-func TestConnectionPreference_Constants(t *testing.T) {
- assert.Equal(t, ConnectionPreference("auto"), PreferenceAuto)
- assert.Equal(t, ConnectionPreference("wifi"), PreferenceWiFi)
- assert.Equal(t, ConnectionPreference("ethernet"), PreferenceEthernet)
-}
-
-func TestEventType_Constants(t *testing.T) {
- assert.Equal(t, EventType("state_changed"), EventStateChanged)
- assert.Equal(t, EventType("networks_updated"), EventNetworksUpdated)
- assert.Equal(t, EventType("connecting"), EventConnecting)
- assert.Equal(t, EventType("connected"), EventConnected)
- assert.Equal(t, EventType("disconnected"), EventDisconnected)
- assert.Equal(t, EventType("error"), EventError)
-}
-
-func TestWiFiNetwork_JSON(t *testing.T) {
- network := WiFiNetwork{
- SSID: "TestNetwork",
- BSSID: "00:11:22:33:44:55",
- Signal: 85,
- Secured: true,
- Enterprise: false,
- Connected: true,
- Saved: true,
- Frequency: 2437,
- Mode: "infrastructure",
- Rate: 300,
- Channel: 6,
- }
-
- data, err := json.Marshal(network)
- require.NoError(t, err)
-
- var decoded WiFiNetwork
- err = json.Unmarshal(data, &decoded)
- require.NoError(t, err)
-
- assert.Equal(t, network.SSID, decoded.SSID)
- assert.Equal(t, network.BSSID, decoded.BSSID)
- assert.Equal(t, network.Signal, decoded.Signal)
- assert.Equal(t, network.Secured, decoded.Secured)
- assert.Equal(t, network.Enterprise, decoded.Enterprise)
- assert.Equal(t, network.Connected, decoded.Connected)
- assert.Equal(t, network.Saved, decoded.Saved)
- assert.Equal(t, network.Frequency, decoded.Frequency)
- assert.Equal(t, network.Mode, decoded.Mode)
- assert.Equal(t, network.Rate, decoded.Rate)
- assert.Equal(t, network.Channel, decoded.Channel)
-}
-
-func TestNetworkState_JSON(t *testing.T) {
- state := NetworkState{
- NetworkStatus: StatusWiFi,
- Preference: PreferenceAuto,
- EthernetIP: "192.168.1.100",
- EthernetDevice: "eth0",
- EthernetConnected: false,
- WiFiIP: "192.168.1.101",
- WiFiDevice: "wlan0",
- WiFiConnected: true,
- WiFiEnabled: true,
- WiFiSSID: "TestNetwork",
- WiFiBSSID: "00:11:22:33:44:55",
- WiFiSignal: 85,
- WiFiNetworks: []WiFiNetwork{
- {SSID: "Network1", Signal: 90},
- {SSID: "Network2", Signal: 60},
- },
- IsConnecting: false,
- ConnectingSSID: "",
- LastError: "",
- }
-
- data, err := json.Marshal(state)
- require.NoError(t, err)
-
- var decoded NetworkState
- err = json.Unmarshal(data, &decoded)
- require.NoError(t, err)
-
- assert.Equal(t, state.NetworkStatus, decoded.NetworkStatus)
- assert.Equal(t, state.Preference, decoded.Preference)
- assert.Equal(t, state.WiFiIP, decoded.WiFiIP)
- assert.Equal(t, state.WiFiSSID, decoded.WiFiSSID)
- assert.Equal(t, len(state.WiFiNetworks), len(decoded.WiFiNetworks))
-}
-
-func TestConnectionRequest_JSON(t *testing.T) {
- t.Run("with password", func(t *testing.T) {
- req := ConnectionRequest{
- SSID: "TestNetwork",
- Password: "testpass123",
- }
-
- data, err := json.Marshal(req)
- require.NoError(t, err)
-
- var decoded ConnectionRequest
- err = json.Unmarshal(data, &decoded)
- require.NoError(t, err)
-
- assert.Equal(t, req.SSID, decoded.SSID)
- assert.Equal(t, req.Password, decoded.Password)
- assert.Empty(t, decoded.Username)
- })
-
- t.Run("with username and password (enterprise)", func(t *testing.T) {
- req := ConnectionRequest{
- SSID: "EnterpriseNetwork",
- Password: "testpass123",
- Username: "testuser",
- }
-
- data, err := json.Marshal(req)
- require.NoError(t, err)
-
- var decoded ConnectionRequest
- err = json.Unmarshal(data, &decoded)
- require.NoError(t, err)
-
- assert.Equal(t, req.SSID, decoded.SSID)
- assert.Equal(t, req.Password, decoded.Password)
- assert.Equal(t, req.Username, decoded.Username)
- })
-}
-
-func TestPriorityUpdate_JSON(t *testing.T) {
- update := PriorityUpdate{
- Preference: PreferenceWiFi,
- }
-
- data, err := json.Marshal(update)
- require.NoError(t, err)
-
- var decoded PriorityUpdate
- err = json.Unmarshal(data, &decoded)
- require.NoError(t, err)
-
- assert.Equal(t, update.Preference, decoded.Preference)
-}
-
-func TestNetworkEvent_JSON(t *testing.T) {
- event := NetworkEvent{
- Type: EventStateChanged,
- Data: NetworkState{
- NetworkStatus: StatusWiFi,
- WiFiSSID: "TestNetwork",
- WiFiConnected: true,
- },
- }
-
- data, err := json.Marshal(event)
- require.NoError(t, err)
-
- var decoded NetworkEvent
- err = json.Unmarshal(data, &decoded)
- require.NoError(t, err)
-
- assert.Equal(t, event.Type, decoded.Type)
- assert.Equal(t, event.Data.NetworkStatus, decoded.Data.NetworkStatus)
- assert.Equal(t, event.Data.WiFiSSID, decoded.Data.WiFiSSID)
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/wifi_test.go b/nix/inputs/dms-cli/internal/server/network/wifi_test.go
deleted file mode 100644
index c771e75..0000000
--- a/nix/inputs/dms-cli/internal/server/network/wifi_test.go
+++ /dev/null
@@ -1,152 +0,0 @@
-package network
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestFrequencyToChannel(t *testing.T) {
- tests := []struct {
- name string
- frequency uint32
- channel uint32
- }{
- {"2.4 GHz channel 1", 2412, 1},
- {"2.4 GHz channel 6", 2437, 6},
- {"2.4 GHz channel 11", 2462, 11},
- {"2.4 GHz channel 14", 2484, 14},
- {"5 GHz channel 36", 5180, 36},
- {"5 GHz channel 40", 5200, 40},
- {"5 GHz channel 165", 5825, 165},
- {"6 GHz channel 1", 5955, 1},
- {"6 GHz channel 233", 7115, 233},
- {"Unknown frequency", 1000, 0},
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := frequencyToChannel(tt.frequency)
- assert.Equal(t, tt.channel, result)
- })
- }
-}
-
-func TestSortWiFiNetworks(t *testing.T) {
- t.Run("connected network comes first", func(t *testing.T) {
- networks := []WiFiNetwork{
- {SSID: "Network1", Signal: 90, Connected: false},
- {SSID: "Network2", Signal: 80, Connected: true},
- {SSID: "Network3", Signal: 70, Connected: false},
- }
-
- sortWiFiNetworks(networks)
-
- assert.Equal(t, "Network2", networks[0].SSID)
- assert.True(t, networks[0].Connected)
- })
-
- t.Run("sorts by signal strength", func(t *testing.T) {
- networks := []WiFiNetwork{
- {SSID: "Weak", Signal: 40, Secured: true},
- {SSID: "Strong", Signal: 90, Secured: true},
- {SSID: "Medium", Signal: 60, Secured: true},
- }
-
- sortWiFiNetworks(networks)
-
- assert.Equal(t, "Strong", networks[0].SSID)
- assert.Equal(t, "Medium", networks[1].SSID)
- assert.Equal(t, "Weak", networks[2].SSID)
- })
-
- t.Run("prioritizes open networks with good signal", func(t *testing.T) {
- networks := []WiFiNetwork{
- {SSID: "SecureWeak", Signal: 40, Secured: true},
- {SSID: "OpenStrong", Signal: 60, Secured: false},
- {SSID: "SecureStrong", Signal: 90, Secured: true},
- }
-
- sortWiFiNetworks(networks)
-
- // The sorting gives priority to open networks with good signal (>= 50)
- // OpenStrong (60 signal, open) should come before SecureWeak (40 signal, secured)
- assert.Equal(t, "OpenStrong", networks[0].SSID)
-
- // Verify open network comes before weak secure network
- openIdx := -1
- weakSecureIdx := -1
- for i, n := range networks {
- if n.SSID == "OpenStrong" {
- openIdx = i
- }
- if n.SSID == "SecureWeak" {
- weakSecureIdx = i
- }
- }
- assert.Less(t, openIdx, weakSecureIdx, "OpenStrong should come before SecureWeak")
- })
-
- t.Run("prioritizes saved networks after connected", func(t *testing.T) {
- networks := []WiFiNetwork{
- {SSID: "UnsavedStrong", Signal: 95, Saved: false},
- {SSID: "SavedMedium", Signal: 60, Saved: true},
- {SSID: "SavedWeak", Signal: 50, Saved: true},
- {SSID: "UnsavedMedium", Signal: 70, Saved: false},
- }
-
- sortWiFiNetworks(networks)
-
- assert.Equal(t, "SavedMedium", networks[0].SSID)
- assert.Equal(t, "SavedWeak", networks[1].SSID)
- assert.Equal(t, "UnsavedStrong", networks[2].SSID)
- assert.Equal(t, "UnsavedMedium", networks[3].SSID)
- })
-}
-
-func TestManager_GetWiFiNetworks(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{
- WiFiNetworks: []WiFiNetwork{
- {SSID: "Network1", Signal: 90},
- {SSID: "Network2", Signal: 80},
- },
- },
- }
-
- networks := manager.GetWiFiNetworks()
-
- assert.Len(t, networks, 2)
- assert.Equal(t, "Network1", networks[0].SSID)
- assert.Equal(t, "Network2", networks[1].SSID)
-
- // Verify it's a copy, not the original
- networks[0].SSID = "Modified"
- assert.Equal(t, "Network1", manager.state.WiFiNetworks[0].SSID)
-}
-
-func TestManager_GetNetworkInfo(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{
- WiFiNetworks: []WiFiNetwork{
- {SSID: "Network1", Signal: 90, BSSID: "00:11:22:33:44:55"},
- {SSID: "Network2", Signal: 80, BSSID: "AA:BB:CC:DD:EE:FF"},
- },
- },
- }
-
- t.Run("finds existing network", func(t *testing.T) {
- network, err := manager.GetNetworkInfo("Network1")
- assert.NoError(t, err)
- assert.NotNil(t, network)
- assert.Equal(t, "Network1", network.SSID)
- assert.Equal(t, uint8(90), network.Signal)
- })
-
- t.Run("returns error for non-existent network", func(t *testing.T) {
- network, err := manager.GetNetworkInfo("NonExistent")
- assert.Error(t, err)
- assert.Nil(t, network)
- assert.Contains(t, err.Error(), "network not found")
- })
-}
diff --git a/nix/inputs/dms-cli/internal/server/network/wired_test.go b/nix/inputs/dms-cli/internal/server/network/wired_test.go
deleted file mode 100644
index 175b343..0000000
--- a/nix/inputs/dms-cli/internal/server/network/wired_test.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package network
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestManager_GetWiredConfigs(t *testing.T) {
- manager := &Manager{
- state: &NetworkState{
- EthernetConnected: true,
- WiredConnections: []WiredConnection{
- {ID: "Test", IsActive: true},
- },
- },
- }
-
- configs := manager.GetWiredConfigs()
-
- assert.Len(t, configs, 1)
- assert.Equal(t, "Test", configs[0].ID)
-}
diff --git a/nix/inputs/dms-cli/internal/server/plugins/handlers.go b/nix/inputs/dms-cli/internal/server/plugins/handlers.go
deleted file mode 100644
index 0035049..0000000
--- a/nix/inputs/dms-cli/internal/server/plugins/handlers.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package plugins
-
-import (
- "fmt"
- "net"
-
- "github.com/AvengeMedia/danklinux/internal/server/models"
-)
-
-func HandleRequest(conn net.Conn, req models.Request) {
- switch req.Method {
- case "plugins.list":
- HandleList(conn, req)
- case "plugins.listInstalled":
- HandleListInstalled(conn, req)
- case "plugins.install":
- HandleInstall(conn, req)
- case "plugins.uninstall":
- HandleUninstall(conn, req)
- case "plugins.update":
- HandleUpdate(conn, req)
- case "plugins.search":
- HandleSearch(conn, req)
- default:
- models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method))
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/plugins/handlers_test.go b/nix/inputs/dms-cli/internal/server/plugins/handlers_test.go
deleted file mode 100644
index e21d052..0000000
--- a/nix/inputs/dms-cli/internal/server/plugins/handlers_test.go
+++ /dev/null
@@ -1,196 +0,0 @@
-package plugins
-
-import (
- "encoding/json"
- "testing"
-
- "github.com/AvengeMedia/danklinux/internal/mocks/net"
- "github.com/AvengeMedia/danklinux/internal/server/models"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
-)
-
-func TestHandleList(t *testing.T) {
- conn := net.NewMockConn(t)
- conn.EXPECT().Write(mock.Anything).Return(0, nil).Maybe()
-
- req := models.Request{
- ID: 123,
- Method: "plugins.list",
- Params: map[string]interface{}{},
- }
-
- HandleList(conn, req)
-}
-
-func TestHandleListInstalled(t *testing.T) {
- conn := net.NewMockConn(t)
- conn.EXPECT().Write(mock.Anything).Return(0, nil).Maybe()
-
- req := models.Request{
- ID: 123,
- Method: "plugins.listInstalled",
- Params: map[string]interface{}{},
- }
-
- HandleListInstalled(conn, req)
-}
-
-func TestHandleInstallMissingName(t *testing.T) {
- conn := net.NewMockConn(t)
- var written []byte
- conn.EXPECT().Write(mock.Anything).RunAndReturn(func(b []byte) (int, error) {
- written = b
- return len(b), nil
- }).Maybe()
-
- req := models.Request{
- ID: 123,
- Method: "plugins.install",
- Params: map[string]interface{}{},
- }
-
- HandleInstall(conn, req)
-
- var resp models.Response[SuccessResult]
- err := json.Unmarshal(written, &resp)
- assert.NoError(t, err)
- assert.NotEmpty(t, resp.Error)
- assert.Contains(t, resp.Error, "missing or invalid 'name' parameter")
-}
-
-func TestHandleInstallInvalidName(t *testing.T) {
- conn := net.NewMockConn(t)
- var written []byte
- conn.EXPECT().Write(mock.Anything).RunAndReturn(func(b []byte) (int, error) {
- written = b
- return len(b), nil
- }).Maybe()
-
- req := models.Request{
- ID: 123,
- Method: "plugins.install",
- Params: map[string]interface{}{
- "name": 123,
- },
- }
-
- HandleInstall(conn, req)
-
- var resp models.Response[SuccessResult]
- err := json.Unmarshal(written, &resp)
- assert.NoError(t, err)
- assert.NotEmpty(t, resp.Error)
-}
-
-func TestHandleUninstallMissingName(t *testing.T) {
- conn := net.NewMockConn(t)
- var written []byte
- conn.EXPECT().Write(mock.Anything).RunAndReturn(func(b []byte) (int, error) {
- written = b
- return len(b), nil
- }).Maybe()
-
- req := models.Request{
- ID: 123,
- Method: "plugins.uninstall",
- Params: map[string]interface{}{},
- }
-
- HandleUninstall(conn, req)
-
- var resp models.Response[SuccessResult]
- err := json.Unmarshal(written, &resp)
- assert.NoError(t, err)
- assert.NotEmpty(t, resp.Error)
-}
-
-func TestHandleUpdateMissingName(t *testing.T) {
- conn := net.NewMockConn(t)
- var written []byte
- conn.EXPECT().Write(mock.Anything).RunAndReturn(func(b []byte) (int, error) {
- written = b
- return len(b), nil
- }).Maybe()
-
- req := models.Request{
- ID: 123,
- Method: "plugins.update",
- Params: map[string]interface{}{},
- }
-
- HandleUpdate(conn, req)
-
- var resp models.Response[SuccessResult]
- err := json.Unmarshal(written, &resp)
- assert.NoError(t, err)
- assert.NotEmpty(t, resp.Error)
-}
-
-func TestHandleSearchMissingQuery(t *testing.T) {
- conn := net.NewMockConn(t)
- var written []byte
- conn.EXPECT().Write(mock.Anything).RunAndReturn(func(b []byte) (int, error) {
- written = b
- return len(b), nil
- }).Maybe()
-
- req := models.Request{
- ID: 123,
- Method: "plugins.search",
- Params: map[string]interface{}{},
- }
-
- HandleSearch(conn, req)
-
- var resp models.Response[[]PluginInfo]
- err := json.Unmarshal(written, &resp)
- assert.NoError(t, err)
- assert.NotEmpty(t, resp.Error)
-}
-
-func TestSortPluginInfoByFirstParty(t *testing.T) {
- plugins := []PluginInfo{
- {Name: "third-party", Repo: "https://github.com/other/test"},
- {Name: "first-party", Repo: "https://github.com/AvengeMedia/test"},
- }
-
- SortPluginInfoByFirstParty(plugins)
-
- assert.Equal(t, "first-party", plugins[0].Name)
- assert.Equal(t, "third-party", plugins[1].Name)
-}
-
-func TestPluginInfoJSON(t *testing.T) {
- info := PluginInfo{
- Name: "test",
- Description: "test description",
- Installed: true,
- FirstParty: true,
- }
-
- data, err := json.Marshal(info)
- assert.NoError(t, err)
-
- var unmarshaled PluginInfo
- err = json.Unmarshal(data, &unmarshaled)
- assert.NoError(t, err)
- assert.Equal(t, info.Name, unmarshaled.Name)
- assert.Equal(t, info.Installed, unmarshaled.Installed)
-}
-
-func TestSuccessResult(t *testing.T) {
- result := SuccessResult{
- Success: true,
- Message: "test message",
- }
-
- data, err := json.Marshal(result)
- assert.NoError(t, err)
-
- var unmarshaled SuccessResult
- err = json.Unmarshal(data, &unmarshaled)
- assert.NoError(t, err)
- assert.True(t, unmarshaled.Success)
- assert.Equal(t, "test message", unmarshaled.Message)
-}
diff --git a/nix/inputs/dms-cli/internal/server/plugins/install.go b/nix/inputs/dms-cli/internal/server/plugins/install.go
deleted file mode 100644
index 2ef6a8b..0000000
--- a/nix/inputs/dms-cli/internal/server/plugins/install.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package plugins
-
-import (
- "fmt"
- "net"
-
- "github.com/AvengeMedia/danklinux/internal/plugins"
- "github.com/AvengeMedia/danklinux/internal/server/models"
-)
-
-func HandleInstall(conn net.Conn, req models.Request) {
- idOrName, ok := req.Params["name"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'name' parameter")
- return
- }
-
- registry, err := plugins.NewRegistry()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err))
- return
- }
-
- pluginList, err := registry.List()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err))
- return
- }
-
- // First, try to find by ID (preferred method)
- var plugin *plugins.Plugin
- for _, p := range pluginList {
- if p.ID == idOrName {
- plugin = &p
- break
- }
- }
-
- // Fallback to name for backward compatibility
- if plugin == nil {
- for _, p := range pluginList {
- if p.Name == idOrName {
- plugin = &p
- break
- }
- }
- }
-
- if plugin == nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("plugin not found: %s", idOrName))
- return
- }
-
- manager, err := plugins.NewManager()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err))
- return
- }
-
- if err := manager.Install(*plugin); err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to install plugin: %v", err))
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{
- Success: true,
- Message: fmt.Sprintf("plugin installed: %s", plugin.Name),
- })
-}
diff --git a/nix/inputs/dms-cli/internal/server/plugins/list.go b/nix/inputs/dms-cli/internal/server/plugins/list.go
deleted file mode 100644
index 4421608..0000000
--- a/nix/inputs/dms-cli/internal/server/plugins/list.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package plugins
-
-import (
- "fmt"
- "net"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/plugins"
- "github.com/AvengeMedia/danklinux/internal/server/models"
-)
-
-func HandleList(conn net.Conn, req models.Request) {
- registry, err := plugins.NewRegistry()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err))
- return
- }
-
- pluginList, err := registry.List()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err))
- return
- }
-
- manager, err := plugins.NewManager()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err))
- return
- }
-
- result := make([]PluginInfo, len(pluginList))
- for i, p := range pluginList {
- installed, _ := manager.IsInstalled(p)
- result[i] = PluginInfo{
- ID: p.ID,
- Name: p.Name,
- Category: p.Category,
- Author: p.Author,
- Description: p.Description,
- Repo: p.Repo,
- Path: p.Path,
- Capabilities: p.Capabilities,
- Compositors: p.Compositors,
- Dependencies: p.Dependencies,
- Installed: installed,
- FirstParty: strings.HasPrefix(p.Repo, "https://github.com/AvengeMedia"),
- }
- }
-
- models.Respond(conn, req.ID, result)
-}
diff --git a/nix/inputs/dms-cli/internal/server/plugins/list_installed.go b/nix/inputs/dms-cli/internal/server/plugins/list_installed.go
deleted file mode 100644
index dfb9211..0000000
--- a/nix/inputs/dms-cli/internal/server/plugins/list_installed.go
+++ /dev/null
@@ -1,76 +0,0 @@
-package plugins
-
-import (
- "fmt"
- "net"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/plugins"
- "github.com/AvengeMedia/danklinux/internal/server/models"
-)
-
-func HandleListInstalled(conn net.Conn, req models.Request) {
- manager, err := plugins.NewManager()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err))
- return
- }
-
- installedNames, err := manager.ListInstalled()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to list installed plugins: %v", err))
- return
- }
-
- registry, err := plugins.NewRegistry()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err))
- return
- }
-
- allPlugins, err := registry.List()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err))
- return
- }
-
- pluginMap := make(map[string]plugins.Plugin)
- for _, p := range allPlugins {
- pluginMap[p.ID] = p
- }
-
- result := make([]PluginInfo, 0, len(installedNames))
- for _, id := range installedNames {
- if plugin, ok := pluginMap[id]; ok {
- hasUpdate := false
- if hasUpdates, err := manager.HasUpdates(id, plugin); err == nil {
- hasUpdate = hasUpdates
- }
-
- result = append(result, PluginInfo{
- ID: plugin.ID,
- Name: plugin.Name,
- Category: plugin.Category,
- Author: plugin.Author,
- Description: plugin.Description,
- Repo: plugin.Repo,
- Path: plugin.Path,
- Capabilities: plugin.Capabilities,
- Compositors: plugin.Compositors,
- Dependencies: plugin.Dependencies,
- FirstParty: strings.HasPrefix(plugin.Repo, "https://github.com/AvengeMedia"),
- HasUpdate: hasUpdate,
- })
- } else {
- result = append(result, PluginInfo{
- ID: id,
- Name: id,
- Note: "not in registry",
- })
- }
- }
-
- SortPluginInfoByFirstParty(result)
-
- models.Respond(conn, req.ID, result)
-}
diff --git a/nix/inputs/dms-cli/internal/server/plugins/search.go b/nix/inputs/dms-cli/internal/server/plugins/search.go
deleted file mode 100644
index 2595f71..0000000
--- a/nix/inputs/dms-cli/internal/server/plugins/search.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package plugins
-
-import (
- "fmt"
- "net"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/plugins"
- "github.com/AvengeMedia/danklinux/internal/server/models"
-)
-
-func HandleSearch(conn net.Conn, req models.Request) {
- query, ok := req.Params["query"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'query' parameter")
- return
- }
-
- registry, err := plugins.NewRegistry()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err))
- return
- }
-
- pluginList, err := registry.List()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err))
- return
- }
-
- searchResults := plugins.FuzzySearch(query, pluginList)
-
- if category, ok := req.Params["category"].(string); ok && category != "" {
- searchResults = plugins.FilterByCategory(category, searchResults)
- }
-
- if compositor, ok := req.Params["compositor"].(string); ok && compositor != "" {
- searchResults = plugins.FilterByCompositor(compositor, searchResults)
- }
-
- if capability, ok := req.Params["capability"].(string); ok && capability != "" {
- searchResults = plugins.FilterByCapability(capability, searchResults)
- }
-
- searchResults = plugins.SortByFirstParty(searchResults)
-
- manager, err := plugins.NewManager()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err))
- return
- }
-
- result := make([]PluginInfo, len(searchResults))
- for i, p := range searchResults {
- installed, _ := manager.IsInstalled(p)
- result[i] = PluginInfo{
- ID: p.ID,
- Name: p.Name,
- Category: p.Category,
- Author: p.Author,
- Description: p.Description,
- Repo: p.Repo,
- Path: p.Path,
- Capabilities: p.Capabilities,
- Compositors: p.Compositors,
- Dependencies: p.Dependencies,
- Installed: installed,
- FirstParty: strings.HasPrefix(p.Repo, "https://github.com/AvengeMedia"),
- }
- }
-
- models.Respond(conn, req.ID, result)
-}
diff --git a/nix/inputs/dms-cli/internal/server/plugins/types.go b/nix/inputs/dms-cli/internal/server/plugins/types.go
deleted file mode 100644
index 232a258..0000000
--- a/nix/inputs/dms-cli/internal/server/plugins/types.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package plugins
-
-type PluginInfo struct {
- ID string `json:"id"`
- Name string `json:"name"`
- Category string `json:"category,omitempty"`
- Author string `json:"author,omitempty"`
- Description string `json:"description,omitempty"`
- Repo string `json:"repo,omitempty"`
- Path string `json:"path,omitempty"`
- Capabilities []string `json:"capabilities,omitempty"`
- Compositors []string `json:"compositors,omitempty"`
- Dependencies []string `json:"dependencies,omitempty"`
- Installed bool `json:"installed,omitempty"`
- FirstParty bool `json:"firstParty,omitempty"`
- Note string `json:"note,omitempty"`
- HasUpdate bool `json:"hasUpdate,omitempty"`
-}
-
-type SuccessResult struct {
- Success bool `json:"success"`
- Message string `json:"message"`
-}
diff --git a/nix/inputs/dms-cli/internal/server/plugins/uninstall.go b/nix/inputs/dms-cli/internal/server/plugins/uninstall.go
deleted file mode 100644
index 74d714a..0000000
--- a/nix/inputs/dms-cli/internal/server/plugins/uninstall.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package plugins
-
-import (
- "fmt"
- "net"
-
- "github.com/AvengeMedia/danklinux/internal/plugins"
- "github.com/AvengeMedia/danklinux/internal/server/models"
-)
-
-func HandleUninstall(conn net.Conn, req models.Request) {
- name, ok := req.Params["name"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'name' parameter")
- return
- }
-
- registry, err := plugins.NewRegistry()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err))
- return
- }
-
- pluginList, err := registry.List()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err))
- return
- }
-
- var plugin *plugins.Plugin
- for _, p := range pluginList {
- if p.Name == name {
- plugin = &p
- break
- }
- }
-
- if plugin == nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("plugin not found: %s", name))
- return
- }
-
- manager, err := plugins.NewManager()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err))
- return
- }
-
- installed, err := manager.IsInstalled(*plugin)
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to check if plugin is installed: %v", err))
- return
- }
-
- if !installed {
- models.RespondError(conn, req.ID, fmt.Sprintf("plugin not installed: %s", name))
- return
- }
-
- if err := manager.Uninstall(*plugin); err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to uninstall plugin: %v", err))
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{
- Success: true,
- Message: fmt.Sprintf("plugin uninstalled: %s", name),
- })
-}
diff --git a/nix/inputs/dms-cli/internal/server/plugins/update.go b/nix/inputs/dms-cli/internal/server/plugins/update.go
deleted file mode 100644
index 6560cb6..0000000
--- a/nix/inputs/dms-cli/internal/server/plugins/update.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package plugins
-
-import (
- "fmt"
- "net"
-
- "github.com/AvengeMedia/danklinux/internal/plugins"
- "github.com/AvengeMedia/danklinux/internal/server/models"
-)
-
-func HandleUpdate(conn net.Conn, req models.Request) {
- name, ok := req.Params["name"].(string)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'name' parameter")
- return
- }
-
- registry, err := plugins.NewRegistry()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err))
- return
- }
-
- pluginList, err := registry.List()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err))
- return
- }
-
- var plugin *plugins.Plugin
- for _, p := range pluginList {
- if p.Name == name {
- plugin = &p
- break
- }
- }
-
- if plugin == nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("plugin not found: %s", name))
- return
- }
-
- manager, err := plugins.NewManager()
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err))
- return
- }
-
- installed, err := manager.IsInstalled(*plugin)
- if err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to check if plugin is installed: %v", err))
- return
- }
-
- if !installed {
- models.RespondError(conn, req.ID, fmt.Sprintf("plugin not installed: %s", name))
- return
- }
-
- if err := manager.Update(*plugin); err != nil {
- models.RespondError(conn, req.ID, fmt.Sprintf("failed to update plugin: %v", err))
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{
- Success: true,
- Message: fmt.Sprintf("plugin updated: %s", name),
- })
-}
diff --git a/nix/inputs/dms-cli/internal/server/plugins/utils.go b/nix/inputs/dms-cli/internal/server/plugins/utils.go
deleted file mode 100644
index 8b89f44..0000000
--- a/nix/inputs/dms-cli/internal/server/plugins/utils.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package plugins
-
-import (
- "sort"
- "strings"
-)
-
-func SortPluginInfoByFirstParty(pluginInfos []PluginInfo) {
- sort.SliceStable(pluginInfos, func(i, j int) bool {
- isFirstPartyI := strings.HasPrefix(pluginInfos[i].Repo, "https://github.com/AvengeMedia")
- isFirstPartyJ := strings.HasPrefix(pluginInfos[j].Repo, "https://github.com/AvengeMedia")
- if isFirstPartyI != isFirstPartyJ {
- return isFirstPartyI
- }
- return false
- })
-}
diff --git a/nix/inputs/dms-cli/internal/server/router.go b/nix/inputs/dms-cli/internal/server/router.go
deleted file mode 100644
index 2c0c067..0000000
--- a/nix/inputs/dms-cli/internal/server/router.go
+++ /dev/null
@@ -1,149 +0,0 @@
-package server
-
-import (
- "fmt"
- "net"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/server/bluez"
- "github.com/AvengeMedia/danklinux/internal/server/brightness"
- "github.com/AvengeMedia/danklinux/internal/server/cups"
- "github.com/AvengeMedia/danklinux/internal/server/dwl"
- "github.com/AvengeMedia/danklinux/internal/server/freedesktop"
- "github.com/AvengeMedia/danklinux/internal/server/loginctl"
- "github.com/AvengeMedia/danklinux/internal/server/models"
- "github.com/AvengeMedia/danklinux/internal/server/network"
- serverPlugins "github.com/AvengeMedia/danklinux/internal/server/plugins"
- "github.com/AvengeMedia/danklinux/internal/server/wayland"
-)
-
-func RouteRequest(conn net.Conn, req models.Request) {
- if strings.HasPrefix(req.Method, "network.") {
- if networkManager == nil {
- models.RespondError(conn, req.ID, "network manager not initialized")
- return
- }
- netReq := network.Request{
- ID: req.ID,
- Method: req.Method,
- Params: req.Params,
- }
- network.HandleRequest(conn, netReq, networkManager)
- return
- }
-
- if strings.HasPrefix(req.Method, "plugins.") {
- serverPlugins.HandleRequest(conn, req)
- return
- }
-
- if strings.HasPrefix(req.Method, "loginctl.") {
- if loginctlManager == nil {
- models.RespondError(conn, req.ID, "loginctl manager not initialized")
- return
- }
- loginReq := loginctl.Request{
- ID: req.ID,
- Method: req.Method,
- Params: req.Params,
- }
- loginctl.HandleRequest(conn, loginReq, loginctlManager)
- return
- }
-
- if strings.HasPrefix(req.Method, "freedesktop.") {
- if freedesktopManager == nil {
- models.RespondError(conn, req.ID, "freedesktop manager not initialized")
- return
- }
- freedeskReq := freedesktop.Request{
- ID: req.ID,
- Method: req.Method,
- Params: req.Params,
- }
- freedesktop.HandleRequest(conn, freedeskReq, freedesktopManager)
- return
- }
-
- if strings.HasPrefix(req.Method, "wayland.") {
- if waylandManager == nil {
- models.RespondError(conn, req.ID, "wayland manager not initialized")
- return
- }
- waylandReq := wayland.Request{
- ID: req.ID,
- Method: req.Method,
- Params: req.Params,
- }
- wayland.HandleRequest(conn, waylandReq, waylandManager)
- return
- }
-
- if strings.HasPrefix(req.Method, "bluetooth.") {
- if bluezManager == nil {
- models.RespondError(conn, req.ID, "bluetooth manager not initialized")
- return
- }
- bluezReq := bluez.Request{
- ID: req.ID,
- Method: req.Method,
- Params: req.Params,
- }
- bluez.HandleRequest(conn, bluezReq, bluezManager)
- return
- }
-
- if strings.HasPrefix(req.Method, "cups.") {
- if cupsManager == nil {
- models.RespondError(conn, req.ID, "CUPS manager not initialized")
- return
- }
- cupsReq := cups.Request{
- ID: req.ID,
- Method: req.Method,
- Params: req.Params,
- }
- cups.HandleRequest(conn, cupsReq, cupsManager)
- return
- }
-
- if strings.HasPrefix(req.Method, "dwl.") {
- if dwlManager == nil {
- models.RespondError(conn, req.ID, "dwl manager not initialized")
- return
- }
- dwlReq := dwl.Request{
- ID: req.ID,
- Method: req.Method,
- Params: req.Params,
- }
- dwl.HandleRequest(conn, dwlReq, dwlManager)
- return
- }
-
- if strings.HasPrefix(req.Method, "brightness.") {
- if brightnessManager == nil {
- models.RespondError(conn, req.ID, "brightness manager not initialized")
- return
- }
- brightnessReq := brightness.Request{
- ID: req.ID,
- Method: req.Method,
- Params: req.Params,
- }
- brightness.HandleRequest(conn, brightnessReq, brightnessManager)
- return
- }
-
- switch req.Method {
- case "ping":
- models.Respond(conn, req.ID, "pong")
- case "getServerInfo":
- info := getServerInfo()
- models.Respond(conn, req.ID, info)
- case "subscribe":
- handleSubscribe(conn, req)
- default:
- models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method))
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/server.go b/nix/inputs/dms-cli/internal/server/server.go
deleted file mode 100644
index 307468b..0000000
--- a/nix/inputs/dms-cli/internal/server/server.go
+++ /dev/null
@@ -1,1050 +0,0 @@
-package server
-
-import (
- "bufio"
- "encoding/json"
- "fmt"
- "net"
- "os"
- "path/filepath"
- "strconv"
- "strings"
- "sync"
- "syscall"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/AvengeMedia/danklinux/internal/server/bluez"
- "github.com/AvengeMedia/danklinux/internal/server/brightness"
- "github.com/AvengeMedia/danklinux/internal/server/cups"
- "github.com/AvengeMedia/danklinux/internal/server/dwl"
- "github.com/AvengeMedia/danklinux/internal/server/freedesktop"
- "github.com/AvengeMedia/danklinux/internal/server/loginctl"
- "github.com/AvengeMedia/danklinux/internal/server/models"
- "github.com/AvengeMedia/danklinux/internal/server/network"
- "github.com/AvengeMedia/danklinux/internal/server/wayland"
- "github.com/AvengeMedia/danklinux/internal/server/wlcontext"
-)
-
-const APIVersion = 15
-
-type Capabilities struct {
- Capabilities []string `json:"capabilities"`
-}
-
-type ServerInfo struct {
- APIVersion int `json:"apiVersion"`
- Capabilities []string `json:"capabilities"`
-}
-
-type ServiceEvent struct {
- Service string `json:"service"`
- Data interface{} `json:"data"`
-}
-
-var networkManager *network.Manager
-var loginctlManager *loginctl.Manager
-var freedesktopManager *freedesktop.Manager
-var waylandManager *wayland.Manager
-var bluezManager *bluez.Manager
-var cupsManager *cups.Manager
-var dwlManager *dwl.Manager
-var brightnessManager *brightness.Manager
-var wlContext *wlcontext.SharedContext
-
-var capabilitySubscribers = make(map[string]chan ServerInfo)
-var capabilityMutex sync.RWMutex
-
-var cupsSubscribers = make(map[string]bool)
-var cupsSubscribersMutex sync.Mutex
-
-func getSocketDir() string {
- if runtime := os.Getenv("XDG_RUNTIME_DIR"); runtime != "" {
- return runtime
- }
-
- if os.Getuid() == 0 {
- if _, err := os.Stat("/run"); err == nil {
- return "/run/dankdots"
- }
- return "/var/run/dankdots"
- }
-
- return os.TempDir()
-}
-
-func GetSocketPath() string {
- return filepath.Join(getSocketDir(), fmt.Sprintf("danklinux-%d.sock", os.Getpid()))
-}
-
-func cleanupStaleSockets() {
- dir := getSocketDir()
- entries, err := os.ReadDir(dir)
- if err != nil {
- return
- }
-
- for _, entry := range entries {
- if !strings.HasPrefix(entry.Name(), "danklinux-") || !strings.HasSuffix(entry.Name(), ".sock") {
- continue
- }
-
- pidStr := strings.TrimPrefix(entry.Name(), "danklinux-")
- pidStr = strings.TrimSuffix(pidStr, ".sock")
- pid, err := strconv.Atoi(pidStr)
- if err != nil {
- continue
- }
-
- process, err := os.FindProcess(pid)
- if err != nil {
- socketPath := filepath.Join(dir, entry.Name())
- os.Remove(socketPath)
- log.Debugf("Removed stale socket: %s", socketPath)
- continue
- }
-
- err = process.Signal(syscall.Signal(0))
- if err != nil {
- socketPath := filepath.Join(dir, entry.Name())
- os.Remove(socketPath)
- log.Debugf("Removed stale socket: %s", socketPath)
- }
- }
-}
-
-func InitializeNetworkManager() error {
- manager, err := network.NewManager()
- if err != nil {
- log.Warnf("Failed to initialize network manager: %v", err)
- return err
- }
-
- networkManager = manager
-
- log.Info("Network manager initialized")
- return nil
-}
-
-func InitializeLoginctlManager() error {
- manager, err := loginctl.NewManager()
- if err != nil {
- log.Warnf("Failed to initialize loginctl manager: %v", err)
- return err
- }
-
- loginctlManager = manager
-
- log.Info("Loginctl manager initialized")
- return nil
-}
-
-func InitializeFreedeskManager() error {
- manager, err := freedesktop.NewManager()
- if err != nil {
- log.Warnf("Failed to initialize freedesktop manager: %v", err)
- return err
- }
-
- freedesktopManager = manager
-
- log.Info("Freedesktop manager initialized")
- return nil
-}
-
-func InitializeWaylandManager() error {
- log.Info("Attempting to initialize Wayland gamma control...")
-
- if wlContext == nil {
- ctx, err := wlcontext.New()
- if err != nil {
- log.Errorf("Failed to create shared Wayland context: %v", err)
- return err
- }
- wlContext = ctx
- }
-
- config := wayland.DefaultConfig()
- manager, err := wayland.NewManager(wlContext.Display(), config)
- if err != nil {
- log.Errorf("Failed to initialize wayland manager: %v", err)
- return err
- }
-
- waylandManager = manager
-
- log.Info("Wayland gamma control initialized successfully")
- return nil
-}
-
-func InitializeBluezManager() error {
- manager, err := bluez.NewManager()
- if err != nil {
- log.Warnf("Failed to initialize bluez manager: %v", err)
- return err
- }
-
- bluezManager = manager
-
- log.Info("Bluez manager initialized")
- return nil
-}
-
-func InitializeCupsManager() error {
- manager, err := cups.NewManager()
- if err != nil {
- log.Warnf("Failed to initialize cups manager: %v", err)
- return err
- }
-
- cupsManager = manager
-
- log.Info("CUPS manager initialized")
- return nil
-}
-
-func InitializeDwlManager() error {
- log.Info("Attempting to initialize DWL IPC...")
-
- if wlContext == nil {
- ctx, err := wlcontext.New()
- if err != nil {
- log.Errorf("Failed to create shared Wayland context: %v", err)
- return err
- }
- wlContext = ctx
- }
-
- manager, err := dwl.NewManager(wlContext.Display())
- if err != nil {
- log.Debug("Failed to initialize dwl manager: %v", err)
- return err
- }
-
- dwlManager = manager
-
- log.Info("DWL IPC initialized successfully")
- return nil
-}
-
-func InitializeBrightnessManager() error {
- manager, err := brightness.NewManager()
- if err != nil {
- log.Warnf("Failed to initialize brightness manager: %v", err)
- return err
- }
-
- brightnessManager = manager
-
- log.Info("Brightness manager initialized")
- return nil
-}
-
-func handleConnection(conn net.Conn) {
- defer conn.Close()
-
- caps := getCapabilities()
- capsData, _ := json.Marshal(caps)
- conn.Write(capsData)
- conn.Write([]byte("\n"))
-
- scanner := bufio.NewScanner(conn)
- for scanner.Scan() {
- line := scanner.Bytes()
-
- var req models.Request
- if err := json.Unmarshal(line, &req); err != nil {
- log.Warnf("handleConnection: Failed to unmarshal JSON: %v, line: %s", err, string(line))
- models.RespondError(conn, 0, "invalid json")
- continue
- }
-
- go RouteRequest(conn, req)
- }
-}
-
-func getCapabilities() Capabilities {
- caps := []string{"plugins"}
-
- if networkManager != nil {
- caps = append(caps, "network")
- }
-
- if loginctlManager != nil {
- caps = append(caps, "loginctl")
- }
-
- if freedesktopManager != nil {
- caps = append(caps, "freedesktop")
- }
-
- if waylandManager != nil {
- caps = append(caps, "gamma")
- }
-
- if bluezManager != nil {
- caps = append(caps, "bluetooth")
- }
-
- if cupsManager != nil {
- caps = append(caps, "cups")
- }
-
- if dwlManager != nil {
- caps = append(caps, "dwl")
- }
-
- if brightnessManager != nil {
- caps = append(caps, "brightness")
- }
-
- return Capabilities{Capabilities: caps}
-}
-
-func getServerInfo() ServerInfo {
- caps := []string{"plugins"}
-
- if networkManager != nil {
- caps = append(caps, "network")
- }
-
- if loginctlManager != nil {
- caps = append(caps, "loginctl")
- }
-
- if freedesktopManager != nil {
- caps = append(caps, "freedesktop")
- }
-
- if waylandManager != nil {
- caps = append(caps, "gamma")
- }
-
- if bluezManager != nil {
- caps = append(caps, "bluetooth")
- }
-
- if cupsManager != nil {
- caps = append(caps, "cups")
- }
-
- if dwlManager != nil {
- caps = append(caps, "dwl")
- }
-
- if brightnessManager != nil {
- caps = append(caps, "brightness")
- }
-
- return ServerInfo{
- APIVersion: APIVersion,
- Capabilities: caps,
- }
-}
-
-func notifyCapabilityChange() {
- capabilityMutex.RLock()
- defer capabilityMutex.RUnlock()
-
- info := getServerInfo()
- for _, ch := range capabilitySubscribers {
- select {
- case ch <- info:
- default:
- }
- }
-}
-
-func handleSubscribe(conn net.Conn, req models.Request) {
- clientID := fmt.Sprintf("meta-client-%p", conn)
-
- var services []string
- if servicesParam, ok := req.Params["services"].([]interface{}); ok {
- for _, s := range servicesParam {
- if str, ok := s.(string); ok {
- services = append(services, str)
- }
- }
- }
-
- if len(services) == 0 {
- services = []string{"all"}
- }
-
- subscribeAll := false
- for _, s := range services {
- if s == "all" {
- subscribeAll = true
- break
- }
- }
-
- var wg sync.WaitGroup
- eventChan := make(chan ServiceEvent, 256)
- stopChan := make(chan struct{})
-
- capChan := make(chan ServerInfo, 64)
- capabilityMutex.Lock()
- capabilitySubscribers[clientID+"-capabilities"] = capChan
- capabilityMutex.Unlock()
-
- wg.Add(1)
- go func() {
- defer wg.Done()
- defer func() {
- capabilityMutex.Lock()
- delete(capabilitySubscribers, clientID+"-capabilities")
- capabilityMutex.Unlock()
- }()
-
- for {
- select {
- case info, ok := <-capChan:
- if !ok {
- return
- }
- select {
- case eventChan <- ServiceEvent{Service: "server", Data: info}:
- case <-stopChan:
- return
- }
- case <-stopChan:
- return
- }
- }
- }()
-
- shouldSubscribe := func(service string) bool {
- if subscribeAll {
- return true
- }
- for _, s := range services {
- if s == service {
- return true
- }
- }
- return false
- }
-
- if shouldSubscribe("network") && networkManager != nil {
- wg.Add(1)
- netChan := networkManager.Subscribe(clientID + "-network")
- go func() {
- defer wg.Done()
- defer networkManager.Unsubscribe(clientID + "-network")
-
- initialState := networkManager.GetState()
- select {
- case eventChan <- ServiceEvent{Service: "network", Data: initialState}:
- case <-stopChan:
- return
- }
-
- for {
- select {
- case state, ok := <-netChan:
- if !ok {
- return
- }
- select {
- case eventChan <- ServiceEvent{Service: "network", Data: state}:
- case <-stopChan:
- return
- }
- case <-stopChan:
- return
- }
- }
- }()
- }
-
- if shouldSubscribe("network.credentials") && networkManager != nil {
- wg.Add(1)
- credChan := networkManager.SubscribeCredentials(clientID + "-credentials")
- go func() {
- defer wg.Done()
- defer networkManager.UnsubscribeCredentials(clientID + "-credentials")
-
- for {
- select {
- case prompt, ok := <-credChan:
- if !ok {
- return
- }
- select {
- case eventChan <- ServiceEvent{Service: "network.credentials", Data: prompt}:
- case <-stopChan:
- return
- }
- case <-stopChan:
- return
- }
- }
- }()
- }
-
- if shouldSubscribe("loginctl") && loginctlManager != nil {
- wg.Add(1)
- loginChan := loginctlManager.Subscribe(clientID + "-loginctl")
- go func() {
- defer wg.Done()
- defer loginctlManager.Unsubscribe(clientID + "-loginctl")
-
- initialState := loginctlManager.GetState()
- select {
- case eventChan <- ServiceEvent{Service: "loginctl", Data: initialState}:
- case <-stopChan:
- return
- }
-
- for {
- select {
- case state, ok := <-loginChan:
- if !ok {
- return
- }
- select {
- case eventChan <- ServiceEvent{Service: "loginctl", Data: state}:
- case <-stopChan:
- return
- }
- case <-stopChan:
- return
- }
- }
- }()
- }
-
- if shouldSubscribe("freedesktop") && freedesktopManager != nil {
- wg.Add(1)
- freedesktopChan := freedesktopManager.Subscribe(clientID + "-freedesktop")
- go func() {
- defer wg.Done()
- defer freedesktopManager.Unsubscribe(clientID + "-freedesktop")
-
- initialState := freedesktopManager.GetState()
- select {
- case eventChan <- ServiceEvent{Service: "freedesktop", Data: initialState}:
- case <-stopChan:
- return
- }
-
- for {
- select {
- case state, ok := <-freedesktopChan:
- if !ok {
- return
- }
- select {
- case eventChan <- ServiceEvent{Service: "freedesktop", Data: state}:
- case <-stopChan:
- return
- }
- case <-stopChan:
- return
- }
- }
- }()
- }
-
- if shouldSubscribe("gamma") && waylandManager != nil {
- wg.Add(1)
- waylandChan := waylandManager.Subscribe(clientID + "-gamma")
- go func() {
- defer wg.Done()
- defer waylandManager.Unsubscribe(clientID + "-gamma")
-
- initialState := waylandManager.GetState()
- select {
- case eventChan <- ServiceEvent{Service: "gamma", Data: initialState}:
- case <-stopChan:
- return
- }
-
- for {
- select {
- case state, ok := <-waylandChan:
- if !ok {
- return
- }
- select {
- case eventChan <- ServiceEvent{Service: "gamma", Data: state}:
- case <-stopChan:
- return
- }
- case <-stopChan:
- return
- }
- }
- }()
- }
-
- if shouldSubscribe("bluetooth") && bluezManager != nil {
- wg.Add(1)
- bluezChan := bluezManager.Subscribe(clientID + "-bluetooth")
- go func() {
- defer wg.Done()
- defer bluezManager.Unsubscribe(clientID + "-bluetooth")
-
- initialState := bluezManager.GetState()
- select {
- case eventChan <- ServiceEvent{Service: "bluetooth", Data: initialState}:
- case <-stopChan:
- return
- }
-
- for {
- select {
- case state, ok := <-bluezChan:
- if !ok {
- return
- }
- select {
- case eventChan <- ServiceEvent{Service: "bluetooth", Data: state}:
- case <-stopChan:
- return
- }
- case <-stopChan:
- return
- }
- }
- }()
- }
-
- if shouldSubscribe("bluetooth.pairing") && bluezManager != nil {
- wg.Add(1)
- pairingChan := bluezManager.SubscribePairing(clientID + "-pairing")
- go func() {
- defer wg.Done()
- defer bluezManager.UnsubscribePairing(clientID + "-pairing")
-
- for {
- select {
- case prompt, ok := <-pairingChan:
- if !ok {
- return
- }
- select {
- case eventChan <- ServiceEvent{Service: "bluetooth.pairing", Data: prompt}:
- case <-stopChan:
- return
- }
- case <-stopChan:
- return
- }
- }
- }()
- }
-
- if shouldSubscribe("cups") {
- cupsSubscribersMutex.Lock()
- wasEmpty := len(cupsSubscribers) == 0
- cupsSubscribers[clientID+"-cups"] = true
- cupsSubscribersMutex.Unlock()
-
- if wasEmpty {
- if err := InitializeCupsManager(); err != nil {
- log.Warnf("Failed to initialize CUPS manager for subscription: %v", err)
- } else {
- notifyCapabilityChange()
- }
- }
-
- if cupsManager != nil {
- wg.Add(1)
- cupsChan := cupsManager.Subscribe(clientID + "-cups")
- go func() {
- defer wg.Done()
- defer func() {
- cupsManager.Unsubscribe(clientID + "-cups")
-
- cupsSubscribersMutex.Lock()
- delete(cupsSubscribers, clientID+"-cups")
- isEmpty := len(cupsSubscribers) == 0
- cupsSubscribersMutex.Unlock()
-
- if isEmpty {
- log.Info("Last CUPS subscriber disconnected, shutting down CUPS manager")
- if cupsManager != nil {
- cupsManager.Close()
- cupsManager = nil
- notifyCapabilityChange()
- }
- }
- }()
-
- initialState := cupsManager.GetState()
- select {
- case eventChan <- ServiceEvent{Service: "cups", Data: initialState}:
- case <-stopChan:
- return
- }
-
- for {
- select {
- case state, ok := <-cupsChan:
- if !ok {
- return
- }
- select {
- case eventChan <- ServiceEvent{Service: "cups", Data: state}:
- case <-stopChan:
- return
- }
- case <-stopChan:
- return
- }
- }
- }()
- }
- }
-
- if shouldSubscribe("dwl") && dwlManager != nil {
- wg.Add(1)
- dwlChan := dwlManager.Subscribe(clientID + "-dwl")
- go func() {
- defer wg.Done()
- defer dwlManager.Unsubscribe(clientID + "-dwl")
-
- initialState := dwlManager.GetState()
- select {
- case eventChan <- ServiceEvent{Service: "dwl", Data: initialState}:
- case <-stopChan:
- return
- }
-
- for {
- select {
- case state, ok := <-dwlChan:
- if !ok {
- return
- }
- select {
- case eventChan <- ServiceEvent{Service: "dwl", Data: state}:
- case <-stopChan:
- return
- }
- case <-stopChan:
- return
- }
- }
- }()
- }
-
- if shouldSubscribe("brightness") && brightnessManager != nil {
- wg.Add(2)
- brightnessStateChan := brightnessManager.Subscribe(clientID + "-brightness-state")
- brightnessUpdateChan := brightnessManager.SubscribeUpdates(clientID + "-brightness-updates")
-
- go func() {
- defer wg.Done()
- defer brightnessManager.Unsubscribe(clientID + "-brightness-state")
-
- initialState := brightnessManager.GetState()
- select {
- case eventChan <- ServiceEvent{Service: "brightness", Data: initialState}:
- case <-stopChan:
- return
- }
-
- for {
- select {
- case state, ok := <-brightnessStateChan:
- if !ok {
- return
- }
- select {
- case eventChan <- ServiceEvent{Service: "brightness", Data: state}:
- case <-stopChan:
- return
- }
- case <-stopChan:
- return
- }
- }
- }()
-
- go func() {
- defer wg.Done()
- defer brightnessManager.UnsubscribeUpdates(clientID + "-brightness-updates")
-
- for {
- select {
- case update, ok := <-brightnessUpdateChan:
- if !ok {
- return
- }
- select {
- case eventChan <- ServiceEvent{Service: "brightness.update", Data: update}:
- case <-stopChan:
- return
- }
- case <-stopChan:
- return
- }
- }
- }()
- }
-
- go func() {
- wg.Wait()
- close(eventChan)
- }()
-
- info := getServerInfo()
- if err := json.NewEncoder(conn).Encode(models.Response[ServiceEvent]{
- ID: req.ID,
- Result: &ServiceEvent{Service: "server", Data: info},
- }); err != nil {
- close(stopChan)
- return
- }
-
- for event := range eventChan {
- if err := json.NewEncoder(conn).Encode(models.Response[ServiceEvent]{
- ID: req.ID,
- Result: &event,
- }); err != nil {
- close(stopChan)
- return
- }
- }
-}
-
-func cleanupManagers() {
- if networkManager != nil {
- networkManager.Close()
- }
- if loginctlManager != nil {
- loginctlManager.Close()
- }
- if freedesktopManager != nil {
- freedesktopManager.Close()
- }
- if waylandManager != nil {
- waylandManager.Close()
- }
- if bluezManager != nil {
- bluezManager.Close()
- }
- if cupsManager != nil {
- cupsManager.Close()
- }
- if dwlManager != nil {
- dwlManager.Close()
- }
- if brightnessManager != nil {
- brightnessManager.Close()
- }
- if wlContext != nil {
- wlContext.Close()
- }
-}
-
-func Start(printDocs bool) error {
- cleanupStaleSockets()
-
- socketPath := GetSocketPath()
- os.Remove(socketPath)
-
- listener, err := net.Listen("unix", socketPath)
- if err != nil {
- return err
- }
- defer listener.Close()
- defer cleanupManagers()
-
- log.Infof("DMS API Server listening on: %s", socketPath)
- log.Infof("API Version: %d", APIVersion)
- log.Info("Protocol: JSON over Unix socket")
- log.Info("Request format: {\"id\": , \"method\": \"...\", \"params\": {...}}")
- log.Info("Response format: {\"id\": , \"result\": {...}} or {\"id\": , \"error\": \"...\"}")
- log.Info("")
- if printDocs {
- log.Info("Available methods:")
- log.Info(" ping - Test connection")
- log.Info(" getServerInfo - Get server info (API version and capabilities)")
- log.Info(" subscribe - Subscribe to multiple services (params: services [default: all])")
- log.Info("Plugins:")
- log.Info(" plugins.list - List all plugins")
- log.Info(" plugins.listInstalled - List installed plugins")
- log.Info(" plugins.install - Install plugin (params: name)")
- log.Info(" plugins.uninstall - Uninstall plugin (params: name)")
- log.Info(" plugins.update - Update plugin (params: name)")
- log.Info(" plugins.search - Search plugins (params: query, category?, compositor?, capability?)")
- log.Info("Network:")
- log.Info(" network.getState - Get current network state")
- log.Info(" network.wifi.scan - Scan for WiFi networks")
- log.Info(" network.wifi.networks - Get WiFi network list")
- log.Info(" network.wifi.connect - Connect to WiFi (params: ssid, password?, username?)")
- log.Info(" network.wifi.disconnect - Disconnect WiFi")
- log.Info(" network.wifi.forget - Forget network (params: ssid)")
- log.Info(" network.wifi.toggle - Toggle WiFi radio")
- log.Info(" network.wifi.enable - Enable WiFi")
- log.Info(" network.wifi.disable - Disable WiFi")
- log.Info(" network.wifi.setAutoconnect - Set network autoconnect (params: ssid, autoconnect)")
- log.Info(" network.ethernet.connect - Connect Ethernet")
- log.Info(" network.ethernet.connect.config - Connect Ethernet to a specific configuration")
- log.Info(" network.ethernet.disconnect - Disconnect Ethernet")
- log.Info(" network.vpn.profiles - List VPN profiles")
- log.Info(" network.vpn.active - List active VPN connections")
- log.Info(" network.vpn.connect - Connect VPN (params: uuidOrName|name|uuid, singleActive?)")
- log.Info(" network.vpn.disconnect - Disconnect VPN (params: uuidOrName|name|uuid)")
- log.Info(" network.vpn.disconnectAll - Disconnect all VPNs")
- log.Info(" network.vpn.clearCredentials - Clear saved VPN credentials (params: uuidOrName|name|uuid)")
- log.Info(" network.preference.set - Set preference (params: preference [auto|wifi|ethernet])")
- log.Info(" network.info - Get network info (params: ssid)")
- log.Info(" network.credentials.submit - Submit credentials for prompt (params: token, secrets, save?)")
- log.Info(" network.credentials.cancel - Cancel credential prompt (params: token)")
- log.Info(" network.subscribe - Subscribe to network state changes (streaming)")
- log.Info("Loginctl:")
- log.Info(" loginctl.getState - Get current session state")
- log.Info(" loginctl.lock - Lock session")
- log.Info(" loginctl.unlock - Unlock session")
- log.Info(" loginctl.activate - Activate session")
- log.Info(" loginctl.setIdleHint - Set idle hint (params: idle)")
- log.Info(" loginctl.setLockBeforeSuspend - Set lock before suspend (params: enabled)")
- log.Info(" loginctl.setSleepInhibitorEnabled - Enable/disable sleep inhibitor (params: enabled)")
- log.Info(" loginctl.lockerReady - Signal locker UI is ready (releases sleep inhibitor)")
- log.Info(" loginctl.terminate - Terminate session")
- log.Info(" loginctl.subscribe - Subscribe to session state changes (streaming)")
- log.Info("Freedesktop:")
- log.Info(" freedesktop.getState - Get accounts & settings state")
- log.Info(" freedesktop.accounts.setIconFile - Set profile icon (params: path)")
- log.Info(" freedesktop.accounts.setRealName - Set real name (params: name)")
- log.Info(" freedesktop.accounts.setEmail - Set email (params: email)")
- log.Info(" freedesktop.accounts.setLanguage - Set language (params: language)")
- log.Info(" freedesktop.accounts.setLocation - Set location (params: location)")
- log.Info(" freedesktop.accounts.getUserIconFile - Get user icon (params: username)")
- log.Info(" freedesktop.settings.getColorScheme - Get color scheme")
- log.Info(" freedesktop.settings.setIconTheme - Set icon theme (params: iconTheme)")
- log.Info("Wayland:")
- log.Info(" wayland.gamma.getState - Get current gamma control state")
- log.Info(" wayland.gamma.setTemperature - Set temperature range (params: low, high)")
- log.Info(" wayland.gamma.setLocation - Set location (params: latitude, longitude)")
- log.Info(" wayland.gamma.setManualTimes - Set manual times (params: sunrise, sunset)")
- log.Info(" wayland.gamma.setGamma - Set gamma value (params: gamma)")
- log.Info(" wayland.gamma.setEnabled - Enable/disable gamma control (params: enabled)")
- log.Info(" wayland.gamma.subscribe - Subscribe to gamma state changes (streaming)")
- log.Info("Bluetooth:")
- log.Info(" bluetooth.getState - Get current bluetooth state")
- log.Info(" bluetooth.startDiscovery - Start device discovery")
- log.Info(" bluetooth.stopDiscovery - Stop device discovery")
- log.Info(" bluetooth.setPowered - Set adapter power state (params: powered)")
- log.Info(" bluetooth.pair - Pair with device (params: device)")
- log.Info(" bluetooth.connect - Connect to device (params: device)")
- log.Info(" bluetooth.disconnect - Disconnect from device (params: device)")
- log.Info(" bluetooth.remove - Remove/unpair device (params: device)")
- log.Info(" bluetooth.trust - Trust device (params: device)")
- log.Info(" bluetooth.untrust - Untrust device (params: device)")
- log.Info(" bluetooth.pairing.submit - Submit pairing response (params: token, secrets?, accept?)")
- log.Info(" bluetooth.pairing.cancel - Cancel pairing prompt (params: token)")
- log.Info(" bluetooth.subscribe - Subscribe to bluetooth state changes (streaming)")
- log.Info("CUPS:")
- log.Info(" cups.getPrinters - Get printers list")
- log.Info(" cups.getJobs - Get non-completed jobs list (params: printerName)")
- log.Info(" cups.pausePrinter - Pause printer (params: printerName)")
- log.Info(" cups.resumePrinter - Resume printer (params: printerName)")
- log.Info(" cups.cancelJob - Cancel job (params: printerName, jobID)")
- log.Info(" cups.purgeJobs - Cancel all jobs (params: printerName)")
- log.Info("DWL:")
- log.Info(" dwl.getState - Get current dwl state (tags, windows, layouts)")
- log.Info(" dwl.setTags - Set active tags (params: output, tagmask, toggleTagset)")
- log.Info(" dwl.setClientTags - Set focused client tags (params: output, andTags, xorTags)")
- log.Info(" dwl.setLayout - Set layout (params: output, index)")
- log.Info(" dwl.subscribe - Subscribe to dwl state changes (streaming)")
- log.Info("Brightness:")
- log.Info(" brightness.getState - Get current brightness state for all devices")
- log.Info(" brightness.setBrightness - Set device brightness (params: device, percent)")
- log.Info(" brightness.increment - Increment device brightness (params: device, step?)")
- log.Info(" brightness.decrement - Decrement device brightness (params: device, step?)")
- log.Info(" brightness.rescan - Rescan for brightness devices (e.g., after plugging in monitor)")
- log.Info(" brightness.subscribe - Subscribe to brightness state changes (streaming)")
- log.Info(" Subscription events:")
- log.Info(" - brightness : Full device list (on rescan, DDC discovery, device changes)")
- log.Info(" - brightness.update: Single device update (on brightness change for efficiency)")
- log.Info("")
- }
- log.Info("Initializing managers...")
- log.Info("")
-
- go func() {
- ticker := time.NewTicker(30 * time.Second)
- defer ticker.Stop()
-
- if err := InitializeNetworkManager(); err != nil {
- log.Warnf("Network manager unavailable: %v", err)
- } else {
- notifyCapabilityChange()
- return
- }
-
- for range ticker.C {
- if networkManager != nil {
- return
- }
- if err := InitializeNetworkManager(); err == nil {
- log.Info("Network manager initialized")
- notifyCapabilityChange()
- return
- }
- }
- }()
-
- go func() {
- if err := InitializeLoginctlManager(); err != nil {
- log.Warnf("Loginctl manager unavailable: %v", err)
- } else {
- notifyCapabilityChange()
- }
- }()
-
- go func() {
- if err := InitializeFreedeskManager(); err != nil {
- log.Warnf("Freedesktop manager unavailable: %v", err)
- } else if freedesktopManager != nil {
- freedesktopManager.NotifySubscribers()
- notifyCapabilityChange()
- }
- }()
-
- if err := InitializeWaylandManager(); err != nil {
- log.Warnf("Wayland manager unavailable: %v", err)
- }
-
- go func() {
- if err := InitializeBluezManager(); err != nil {
- log.Warnf("Bluez manager unavailable: %v", err)
- } else {
- notifyCapabilityChange()
- }
- }()
-
- if err := InitializeDwlManager(); err != nil {
- log.Debugf("DWL manager unavailable: %v", err)
- }
-
- go func() {
- if err := InitializeBrightnessManager(); err != nil {
- log.Warnf("Brightness manager unavailable: %v", err)
- } else {
- notifyCapabilityChange()
- }
- }()
-
- if wlContext != nil {
- wlContext.Start()
- log.Info("Wayland event dispatcher started")
- }
-
- log.Info("")
- log.Infof("Ready! Capabilities: %v", getCapabilities().Capabilities)
-
- for {
- conn, err := listener.Accept()
- if err != nil {
- return err
- }
- go handleConnection(conn)
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/server_test.go b/nix/inputs/dms-cli/internal/server/server_test.go
deleted file mode 100644
index c943c9e..0000000
--- a/nix/inputs/dms-cli/internal/server/server_test.go
+++ /dev/null
@@ -1,184 +0,0 @@
-package server
-
-import (
- "encoding/json"
- "fmt"
- "net"
- "os"
- "path/filepath"
- "testing"
-
- "github.com/AvengeMedia/danklinux/internal/server/models"
- "github.com/AvengeMedia/danklinux/internal/server/network"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestGetSocketDir(t *testing.T) {
- tests := []struct {
- name string
- xdgRuntimeDir string
- uid int
- expectedSubstr string
- }{
- {
- name: "uses XDG_RUNTIME_DIR when set",
- xdgRuntimeDir: "/run/user/1000",
- expectedSubstr: "/run/user/1000",
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if tt.xdgRuntimeDir != "" {
- t.Setenv("XDG_RUNTIME_DIR", tt.xdgRuntimeDir)
- }
-
- result := getSocketDir()
- assert.Contains(t, result, tt.expectedSubstr)
- })
- }
-}
-
-func TestGetSocketPath(t *testing.T) {
- path := GetSocketPath()
- assert.Contains(t, path, "danklinux-")
- assert.Contains(t, path, ".sock")
- assert.Contains(t, path, fmt.Sprintf("%d", os.Getpid()))
-}
-
-func TestGetCapabilities(t *testing.T) {
- originalNetworkManager := networkManager
- defer func() { networkManager = originalNetworkManager }()
-
- t.Run("capabilities without network manager", func(t *testing.T) {
- networkManager = nil
- caps := getCapabilities()
- assert.Contains(t, caps.Capabilities, "plugins")
- assert.NotContains(t, caps.Capabilities, "network")
- })
-
- t.Run("capabilities with network manager", func(t *testing.T) {
- networkManager = &network.Manager{}
- caps := getCapabilities()
- assert.Contains(t, caps.Capabilities, "plugins")
- assert.Contains(t, caps.Capabilities, "network")
- })
-}
-
-type mockConn struct {
- net.Conn
- written []byte
-}
-
-func (m *mockConn) Write(b []byte) (n int, err error) {
- m.written = append(m.written, b...)
- return len(b), nil
-}
-
-func (m *mockConn) Close() error {
- return nil
-}
-
-func TestRespondError(t *testing.T) {
- conn := &mockConn{}
- models.RespondError(conn, 123, "test error")
-
- var resp models.Response[any]
- err := json.Unmarshal(conn.written, &resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Equal(t, "test error", resp.Error)
- assert.Nil(t, resp.Result)
-}
-
-func TestRespond(t *testing.T) {
- conn := &mockConn{}
- result := map[string]string{"foo": "bar"}
- models.Respond(conn, 123, result)
-
- var resp models.Response[map[string]string]
- err := json.Unmarshal(conn.written, &resp)
- require.NoError(t, err)
-
- assert.Equal(t, 123, resp.ID)
- assert.Empty(t, resp.Error)
- require.NotNil(t, resp.Result)
- assert.Equal(t, "bar", (*resp.Result)["foo"])
-}
-
-func TestRequest_JSON(t *testing.T) {
- jsonStr := `{"id":123,"method":"test.method","params":{"key":"value"}}`
- var req models.Request
- err := json.Unmarshal([]byte(jsonStr), &req)
- require.NoError(t, err)
-
- assert.Equal(t, 123, req.ID)
- assert.Equal(t, "test.method", req.Method)
- assert.Equal(t, "value", req.Params["key"])
-}
-
-func TestResponse_JSON(t *testing.T) {
- t.Run("success response", func(t *testing.T) {
- result := "success"
- resp := models.Response[string]{
- ID: 123,
- Result: &result,
- }
-
- data, err := json.Marshal(resp)
- require.NoError(t, err)
-
- var decoded models.Response[string]
- err = json.Unmarshal(data, &decoded)
- require.NoError(t, err)
-
- assert.Equal(t, 123, decoded.ID)
- assert.Equal(t, "success", *decoded.Result)
- assert.Empty(t, decoded.Error)
- })
-
- t.Run("error response", func(t *testing.T) {
- resp := models.Response[any]{
- ID: 123,
- Error: "test error",
- }
-
- data, err := json.Marshal(resp)
- require.NoError(t, err)
-
- var decoded models.Response[any]
- err = json.Unmarshal(data, &decoded)
- require.NoError(t, err)
-
- assert.Equal(t, 123, decoded.ID)
- assert.Equal(t, "test error", decoded.Error)
- assert.Nil(t, decoded.Result)
- })
-}
-
-func TestCleanupStaleSockets(t *testing.T) {
- tempDir := t.TempDir()
- t.Setenv("XDG_RUNTIME_DIR", tempDir)
-
- // Create a socket file with a non-existent PID
- staleSocket := filepath.Join(tempDir, "danklinux-999999.sock")
- err := os.WriteFile(staleSocket, []byte{}, 0600)
- require.NoError(t, err)
-
- // Create a socket file with current PID (should not be deleted)
- activeSocket := filepath.Join(tempDir, fmt.Sprintf("danklinux-%d.sock", os.Getpid()))
- err = os.WriteFile(activeSocket, []byte{}, 0600)
- require.NoError(t, err)
-
- cleanupStaleSockets()
-
- // Stale socket should be removed
- _, err = os.Stat(staleSocket)
- assert.True(t, os.IsNotExist(err))
-
- // Active socket should still exist
- _, err = os.Stat(activeSocket)
- assert.NoError(t, err)
-}
diff --git a/nix/inputs/dms-cli/internal/server/wayland/gamma.go b/nix/inputs/dms-cli/internal/server/wayland/gamma.go
deleted file mode 100644
index 07d7795..0000000
--- a/nix/inputs/dms-cli/internal/server/wayland/gamma.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package wayland
-
-import (
- "math"
-
- "github.com/AvengeMedia/danklinux/internal/utils"
-)
-
-type GammaRamp struct {
- Red []uint16
- Green []uint16
- Blue []uint16
-}
-
-func GenerateGammaRamp(size uint32, temp int, gamma float64) GammaRamp {
- ramp := GammaRamp{
- Red: make([]uint16, size),
- Green: make([]uint16, size),
- Blue: make([]uint16, size),
- }
-
- for i := uint32(0); i < size; i++ {
- val := float64(i) / float64(size-1)
-
- valGamma := math.Pow(val, 1.0/gamma)
-
- r, g, b := temperatureToRGB(temp)
-
- ramp.Red[i] = uint16(utils.Clamp(valGamma*r*65535.0, 0, 65535))
- ramp.Green[i] = uint16(utils.Clamp(valGamma*g*65535.0, 0, 65535))
- ramp.Blue[i] = uint16(utils.Clamp(valGamma*b*65535.0, 0, 65535))
- }
-
- return ramp
-}
-
-func GenerateIdentityRamp(size uint32) GammaRamp {
- ramp := GammaRamp{
- Red: make([]uint16, size),
- Green: make([]uint16, size),
- Blue: make([]uint16, size),
- }
-
- for i := uint32(0); i < size; i++ {
- val := uint16((float64(i) / float64(size-1)) * 65535.0)
- ramp.Red[i] = val
- ramp.Green[i] = val
- ramp.Blue[i] = val
- }
-
- return ramp
-}
-
-func temperatureToRGB(temp int) (float64, float64, float64) {
- tempK := float64(temp) / 100.0
-
- var r, g, b float64
-
- if tempK <= 66 {
- r = 1.0
- } else {
- r = tempK - 60
- r = 329.698727446 * math.Pow(r, -0.1332047592)
- r = utils.Clamp(r, 0, 255) / 255.0
- }
-
- if tempK <= 66 {
- g = tempK
- g = 99.4708025861*math.Log(g) - 161.1195681661
- g = utils.Clamp(g, 0, 255) / 255.0
- } else {
- g = tempK - 60
- g = 288.1221695283 * math.Pow(g, -0.0755148492)
- g = utils.Clamp(g, 0, 255) / 255.0
- }
-
- if tempK >= 66 {
- b = 1.0
- } else if tempK <= 19 {
- b = 0.0
- } else {
- b = tempK - 10
- b = 138.5177312231*math.Log(b) - 305.0447927307
- b = utils.Clamp(b, 0, 255) / 255.0
- }
-
- return r, g, b
-}
diff --git a/nix/inputs/dms-cli/internal/server/wayland/gamma_test.go b/nix/inputs/dms-cli/internal/server/wayland/gamma_test.go
deleted file mode 100644
index 05f26e8..0000000
--- a/nix/inputs/dms-cli/internal/server/wayland/gamma_test.go
+++ /dev/null
@@ -1,120 +0,0 @@
-package wayland
-
-import (
- "testing"
-
- "github.com/AvengeMedia/danklinux/internal/utils"
-)
-
-func TestGenerateGammaRamp(t *testing.T) {
- tests := []struct {
- name string
- size uint32
- temp int
- gamma float64
- }{
- {"small_warm", 16, 6500, 1.0},
- {"small_cool", 16, 4000, 1.0},
- {"large_warm", 256, 6500, 1.0},
- {"large_cool", 256, 4000, 1.0},
- {"custom_gamma", 64, 5500, 1.2},
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- ramp := GenerateGammaRamp(tt.size, tt.temp, tt.gamma)
-
- if len(ramp.Red) != int(tt.size) {
- t.Errorf("expected %d red values, got %d", tt.size, len(ramp.Red))
- }
- if len(ramp.Green) != int(tt.size) {
- t.Errorf("expected %d green values, got %d", tt.size, len(ramp.Green))
- }
- if len(ramp.Blue) != int(tt.size) {
- t.Errorf("expected %d blue values, got %d", tt.size, len(ramp.Blue))
- }
-
- if ramp.Red[0] != 0 || ramp.Green[0] != 0 || ramp.Blue[0] != 0 {
- t.Errorf("first values should be 0, got R:%d G:%d B:%d",
- ramp.Red[0], ramp.Green[0], ramp.Blue[0])
- }
-
- lastIdx := tt.size - 1
- if ramp.Red[lastIdx] == 0 || ramp.Green[lastIdx] == 0 || ramp.Blue[lastIdx] == 0 {
- t.Errorf("last values should be non-zero, got R:%d G:%d B:%d",
- ramp.Red[lastIdx], ramp.Green[lastIdx], ramp.Blue[lastIdx])
- }
-
- for i := uint32(1); i < tt.size; i++ {
- if ramp.Red[i] < ramp.Red[i-1] {
- t.Errorf("red ramp not monotonic at index %d", i)
- }
- }
- })
- }
-}
-
-func TestTemperatureToRGB(t *testing.T) {
- tests := []struct {
- name string
- temp int
- }{
- {"very_warm", 6500},
- {"neutral", 5500},
- {"cool", 4000},
- {"very_cool", 3000},
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- r, g, b := temperatureToRGB(tt.temp)
-
- if r < 0 || r > 1 {
- t.Errorf("red out of range: %f", r)
- }
- if g < 0 || g > 1 {
- t.Errorf("green out of range: %f", g)
- }
- if b < 0 || b > 1 {
- t.Errorf("blue out of range: %f", b)
- }
- })
- }
-}
-
-func TestTemperatureProgression(t *testing.T) {
- temps := []int{3000, 4000, 5000, 6000, 6500}
-
- var prevBlue float64
- for i, temp := range temps {
- _, _, b := temperatureToRGB(temp)
- if i > 0 && b < prevBlue {
- t.Errorf("blue should increase with temperature, %d->%d: %f->%f",
- temps[i-1], temp, prevBlue, b)
- }
- prevBlue = b
- }
-}
-
-func TestClamp(t *testing.T) {
- tests := []struct {
- val float64
- min float64
- max float64
- expected float64
- }{
- {5, 0, 10, 5},
- {-5, 0, 10, 0},
- {15, 0, 10, 10},
- {0, 0, 10, 0},
- {10, 0, 10, 10},
- }
-
- for _, tt := range tests {
- result := utils.Clamp(tt.val, tt.min, tt.max)
- if result != tt.expected {
- t.Errorf("clamp(%f, %f, %f) = %f, want %f",
- tt.val, tt.min, tt.max, result, tt.expected)
- }
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/wayland/geolocation.go b/nix/inputs/dms-cli/internal/server/wayland/geolocation.go
deleted file mode 100644
index 43a986a..0000000
--- a/nix/inputs/dms-cli/internal/server/wayland/geolocation.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package wayland
-
-import (
- "encoding/json"
- "fmt"
- "io"
- "net/http"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/log"
-)
-
-type ipAPIResponse struct {
- Lat float64 `json:"lat"`
- Lon float64 `json:"lon"`
- City string `json:"city"`
-}
-
-func FetchIPLocation() (*float64, *float64, error) {
- client := &http.Client{
- Timeout: 10 * time.Second,
- }
-
- resp, err := client.Get("http://ip-api.com/json/")
- if err != nil {
- return nil, nil, fmt.Errorf("failed to fetch IP location: %w", err)
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return nil, nil, fmt.Errorf("ip-api.com returned status %d", resp.StatusCode)
- }
-
- body, err := io.ReadAll(resp.Body)
- if err != nil {
- return nil, nil, fmt.Errorf("failed to read response: %w", err)
- }
-
- var data ipAPIResponse
- if err := json.Unmarshal(body, &data); err != nil {
- return nil, nil, fmt.Errorf("failed to parse response: %w", err)
- }
-
- if data.Lat == 0 && data.Lon == 0 {
- return nil, nil, fmt.Errorf("missing location data in response")
- }
-
- log.Infof("Fetched IP-based location: %s (%.4f, %.4f)", data.City, data.Lat, data.Lon)
- return &data.Lat, &data.Lon, nil
-}
diff --git a/nix/inputs/dms-cli/internal/server/wayland/handlers.go b/nix/inputs/dms-cli/internal/server/wayland/handlers.go
deleted file mode 100644
index 8568af8..0000000
--- a/nix/inputs/dms-cli/internal/server/wayland/handlers.go
+++ /dev/null
@@ -1,205 +0,0 @@
-package wayland
-
-import (
- "encoding/json"
- "fmt"
- "net"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/server/models"
-)
-
-type Request struct {
- ID int `json:"id,omitempty"`
- Method string `json:"method"`
- Params map[string]interface{} `json:"params,omitempty"`
-}
-
-type SuccessResult struct {
- Success bool `json:"success"`
- Message string `json:"message"`
-}
-
-func HandleRequest(conn net.Conn, req Request, manager *Manager) {
- if manager == nil {
- models.RespondError(conn, req.ID, "wayland manager not initialized")
- return
- }
-
- switch req.Method {
- case "wayland.gamma.getState":
- handleGetState(conn, req, manager)
- case "wayland.gamma.setTemperature":
- handleSetTemperature(conn, req, manager)
- case "wayland.gamma.setLocation":
- handleSetLocation(conn, req, manager)
- case "wayland.gamma.setManualTimes":
- handleSetManualTimes(conn, req, manager)
- case "wayland.gamma.setUseIPLocation":
- handleSetUseIPLocation(conn, req, manager)
- case "wayland.gamma.setGamma":
- handleSetGamma(conn, req, manager)
- case "wayland.gamma.setEnabled":
- handleSetEnabled(conn, req, manager)
- case "wayland.gamma.subscribe":
- handleSubscribe(conn, req, manager)
- default:
- models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method))
- }
-}
-
-func handleGetState(conn net.Conn, req Request, manager *Manager) {
- state := manager.GetState()
- models.Respond(conn, req.ID, state)
-}
-
-func handleSetTemperature(conn net.Conn, req Request, manager *Manager) {
- var lowTemp, highTemp int
-
- if temp, ok := req.Params["temp"].(float64); ok {
- lowTemp = int(temp)
- highTemp = int(temp)
- } else {
- low, okLow := req.Params["low"].(float64)
- high, okHigh := req.Params["high"].(float64)
-
- if !okLow || !okHigh {
- models.RespondError(conn, req.ID, "missing temperature parameters (provide 'temp' or both 'low' and 'high')")
- return
- }
-
- lowTemp = int(low)
- highTemp = int(high)
- }
-
- if err := manager.SetTemperature(lowTemp, highTemp); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "temperature set"})
-}
-
-func handleSetLocation(conn net.Conn, req Request, manager *Manager) {
- lat, ok := req.Params["latitude"].(float64)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'latitude' parameter")
- return
- }
-
- lon, ok := req.Params["longitude"].(float64)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'longitude' parameter")
- return
- }
-
- if err := manager.SetLocation(lat, lon); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "location set"})
-}
-
-func handleSetManualTimes(conn net.Conn, req Request, manager *Manager) {
- sunriseParam := req.Params["sunrise"]
- sunsetParam := req.Params["sunset"]
-
- if sunriseParam == nil || sunsetParam == nil {
- manager.ClearManualTimes()
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "manual times cleared"})
- return
- }
-
- sunriseStr, ok := sunriseParam.(string)
- if !ok || sunriseStr == "" {
- manager.ClearManualTimes()
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "manual times cleared"})
- return
- }
-
- sunsetStr, ok := sunsetParam.(string)
- if !ok || sunsetStr == "" {
- manager.ClearManualTimes()
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "manual times cleared"})
- return
- }
-
- sunrise, err := time.Parse("15:04", sunriseStr)
- if err != nil {
- models.RespondError(conn, req.ID, "invalid sunrise format (use HH:MM)")
- return
- }
-
- sunset, err := time.Parse("15:04", sunsetStr)
- if err != nil {
- models.RespondError(conn, req.ID, "invalid sunset format (use HH:MM)")
- return
- }
-
- if err := manager.SetManualTimes(sunrise, sunset); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "manual times set"})
-}
-
-func handleSetUseIPLocation(conn net.Conn, req Request, manager *Manager) {
- use, ok := req.Params["use"].(bool)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'use' parameter")
- return
- }
-
- manager.SetUseIPLocation(use)
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "IP location preference set"})
-}
-
-func handleSetGamma(conn net.Conn, req Request, manager *Manager) {
- gamma, ok := req.Params["gamma"].(float64)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'gamma' parameter")
- return
- }
-
- if err := manager.SetGamma(gamma); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "gamma set"})
-}
-
-func handleSetEnabled(conn net.Conn, req Request, manager *Manager) {
- enabled, ok := req.Params["enabled"].(bool)
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'enabled' parameter")
- return
- }
-
- manager.SetEnabled(enabled)
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "enabled state set"})
-}
-
-func handleSubscribe(conn net.Conn, req Request, manager *Manager) {
- clientID := fmt.Sprintf("client-%p", conn)
- stateChan := manager.Subscribe(clientID)
- defer manager.Unsubscribe(clientID)
-
- initialState := manager.GetState()
- if err := json.NewEncoder(conn).Encode(models.Response[State]{
- ID: req.ID,
- Result: &initialState,
- }); err != nil {
- return
- }
-
- for state := range stateChan {
- if err := json.NewEncoder(conn).Encode(models.Response[State]{
- Result: &state,
- }); err != nil {
- return
- }
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/wayland/manager.go b/nix/inputs/dms-cli/internal/server/wayland/manager.go
deleted file mode 100644
index 5c2ffd9..0000000
--- a/nix/inputs/dms-cli/internal/server/wayland/manager.go
+++ /dev/null
@@ -1,1367 +0,0 @@
-package wayland
-
-import (
- "bytes"
- "encoding/binary"
- "fmt"
- "os"
- "syscall"
- "time"
-
- "github.com/godbus/dbus/v5"
- wlclient "github.com/yaslama/go-wayland/wayland/client"
- "golang.org/x/sys/unix"
-
- "github.com/AvengeMedia/danklinux/internal/errdefs"
- "github.com/AvengeMedia/danklinux/internal/log"
- "github.com/AvengeMedia/danklinux/internal/proto/wlr_gamma_control"
-)
-
-func NewManager(display *wlclient.Display, config Config) (*Manager, error) {
- if err := config.Validate(); err != nil {
- return nil, err
- }
-
- m := &Manager{
- config: config,
- display: display,
- outputs: make(map[uint32]*outputState),
- cmdq: make(chan cmd, 128),
- stopChan: make(chan struct{}),
- updateTrigger: make(chan struct{}, 1),
- subscribers: make(map[string]chan State),
- dirty: make(chan struct{}, 1),
- dbusSignal: make(chan *dbus.Signal, 16),
- transitionChan: make(chan int, 1),
- }
-
- if err := m.setupRegistry(); err != nil {
- return nil, err
- }
-
- // Setup D-Bus monitoring for suspend/resume events
- if err := m.setupDBusMonitor(); err != nil {
- log.Warnf("Failed to setup D-Bus monitoring for suspend/resume: %v", err)
- // Don't fail initialization if D-Bus setup fails, just continue without it
- }
-
- // Initialize currentTemp and targetTemp before starting any goroutines
- now := time.Now()
- initial := m.calculateTemperature(now)
- m.transitionMutex.Lock()
- m.currentTemp = initial
- m.targetTemp = initial
- m.transitionMutex.Unlock()
-
- m.alive = true
- m.updateState()
-
- m.notifierWg.Add(1)
- go m.notifier()
-
- m.wg.Add(1)
- go m.updateLoop()
-
- if m.dbusConn != nil {
- m.wg.Add(1)
- go m.dbusMonitor()
- }
-
- m.wg.Add(1)
- go m.waylandActor()
-
- m.wg.Add(1)
- go m.transitionWorker()
-
- if config.Enabled {
- m.post(func() {
- log.Info("Gamma control enabled at startup, initializing controls")
- gammaMgr := m.gammaControl.(*wlr_gamma_control.ZwlrGammaControlManagerV1)
- if err := func() error {
- var outputs []*wlclient.Output = m.availableOutputs
- return m.setupOutputControls(outputs, gammaMgr)
- }(); err != nil {
- log.Errorf("Failed to initialize gamma controls: %v", err)
- } else {
- m.controlsInitialized = true
- }
- })
- }
-
- return m, nil
-}
-
-func (m *Manager) post(fn func()) {
- select {
- case m.cmdq <- cmd{fn: fn}:
- default:
- log.Warn("Actor command queue full, dropping command")
- }
-}
-
-func (m *Manager) waylandActor() {
- defer m.wg.Done()
-
- for {
- select {
- case <-m.stopChan:
- return
- case c := <-m.cmdq:
- c.fn()
- }
- }
-}
-
-func (m *Manager) allOutputsReady() bool {
- m.outputsMutex.RLock()
- defer m.outputsMutex.RUnlock()
- if len(m.outputs) == 0 {
- return false
- }
- for _, o := range m.outputs {
- if o.rampSize == 0 || o.failed {
- return false
- }
- }
- return true
-}
-
-func (m *Manager) setupDBusMonitor() error {
- conn, err := dbus.ConnectSystemBus()
- if err != nil {
- return fmt.Errorf("failed to connect to system bus: %w", err)
- }
-
- // Subscribe to PrepareForSleep signal
- matchRule := "type='signal',interface='org.freedesktop.login1.Manager',member='PrepareForSleep',path='/org/freedesktop/login1'"
- if err := conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, matchRule).Err; err != nil {
- conn.Close()
- return fmt.Errorf("failed to add match rule: %w", err)
- }
-
- conn.Signal(m.dbusSignal)
- m.dbusConn = conn
-
- log.Info("D-Bus monitoring for suspend/resume events enabled")
- return nil
-}
-
-func (m *Manager) setupRegistry() error {
- log.Info("setupRegistry: starting registry setup")
- ctx := m.display.Context()
-
- registry, err := m.display.GetRegistry()
- if err != nil {
- return fmt.Errorf("failed to get registry: %w", err)
- }
- m.registry = registry
-
- outputs := make([]*wlclient.Output, 0)
- outputRegNames := make(map[uint32]uint32)
- outputNames := make(map[uint32]string)
- var gammaMgr *wlr_gamma_control.ZwlrGammaControlManagerV1
-
- registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) {
- switch e.Interface {
- case wlr_gamma_control.ZwlrGammaControlManagerV1InterfaceName:
- log.Infof("setupRegistry: found %s", wlr_gamma_control.ZwlrGammaControlManagerV1InterfaceName)
- manager := wlr_gamma_control.NewZwlrGammaControlManagerV1(ctx)
- version := e.Version
- if version > 1 {
- version = 1
- }
- if err := registry.Bind(e.Name, e.Interface, version, manager); err == nil {
- gammaMgr = manager
- log.Info("setupRegistry: gamma control manager bound successfully")
- } else {
- log.Errorf("setupRegistry: failed to bind gamma control: %v", err)
- }
- case "wl_output":
- log.Debugf("Global event: found wl_output (name=%d)", e.Name)
- output := wlclient.NewOutput(ctx)
- version := e.Version
- if version > 4 {
- version = 4
- }
- if err := registry.Bind(e.Name, e.Interface, version, output); err == nil {
- outputID := output.ID()
- log.Infof("Bound wl_output id=%d registry_name=%d", outputID, e.Name)
-
- output.SetNameHandler(func(ev wlclient.OutputNameEvent) {
- log.Infof("Output %d name: %s", outputID, ev.Name)
- outputNames[outputID] = ev.Name
- isVirtual := len(ev.Name) >= 9 && ev.Name[:9] == "HEADLESS-"
- if isVirtual {
- log.Infof("Output %d identified as virtual", outputID)
- }
- })
-
- if gammaMgr != nil {
- outputs = append(outputs, output)
- outputRegNames[outputID] = e.Name
- }
-
- m.outputsMutex.Lock()
- if m.outputRegNames != nil {
- m.outputRegNames[outputID] = e.Name
- }
- m.outputsMutex.Unlock()
-
- m.configMutex.RLock()
- enabled := m.config.Enabled
- m.configMutex.RUnlock()
-
- if enabled && m.controlsInitialized {
- m.post(func() {
- log.Infof("New output %d added, creating gamma control", outputID)
- if err := m.addOutputControl(output); err != nil {
- log.Errorf("Failed to add gamma control for new output %d: %v", outputID, err)
- }
- })
- } else if enabled && !m.controlsInitialized {
- m.post(func() {
- log.Infof("Output %d added after all were removed, creating gamma control", outputID)
- if err := m.addOutputControl(output); err != nil {
- log.Errorf("Failed to add gamma control for output %d: %v", outputID, err)
- } else {
- m.controlsInitialized = true
- }
- })
- }
- } else {
- log.Errorf("Failed to bind wl_output: %v", err)
- }
- }
- })
-
- registry.SetGlobalRemoveHandler(func(e wlclient.RegistryGlobalRemoveEvent) {
- m.post(func() {
- m.outputsMutex.Lock()
- defer m.outputsMutex.Unlock()
-
- for id, out := range m.outputs {
- if out.registryName == e.Name {
- log.Infof("Output %d (registry name %d) removed, destroying gamma control", id, e.Name)
- if out.gammaControl != nil {
- control := out.gammaControl.(*wlr_gamma_control.ZwlrGammaControlV1)
- control.Destroy()
- }
- delete(m.outputs, id)
-
- if len(m.outputs) == 0 {
- m.controlsInitialized = false
- log.Info("All outputs removed, controls no longer initialized")
- }
- return
- }
- }
- })
- })
-
- if err := m.display.Roundtrip(); err != nil {
- return fmt.Errorf("first roundtrip failed: %w", err)
- }
- if err := m.display.Roundtrip(); err != nil {
- return fmt.Errorf("second roundtrip failed: %w", err)
- }
-
- log.Infof("setupRegistry: discovered gamma_manager=%v, outputs=%d", gammaMgr != nil, len(outputs))
-
- if gammaMgr == nil {
- log.Error("setupRegistry: gamma control manager not found in registry")
- return errdefs.ErrNoGammaControl
- }
-
- if len(outputs) == 0 {
- log.Error("setupRegistry: no wl_output objects found")
- return fmt.Errorf("no outputs available")
- }
-
- physicalOutputs := make([]*wlclient.Output, 0)
- for _, output := range outputs {
- outputID := output.ID()
- name := outputNames[outputID]
- if name != "" && (len(name) >= 9 && name[:9] == "HEADLESS-") {
- log.Infof("Skipping virtual output %d (name=%s) for gamma control", outputID, name)
- continue
- }
- physicalOutputs = append(physicalOutputs, output)
- }
-
- log.Infof("setupRegistry: filtered %d physical outputs from %d total outputs", len(physicalOutputs), len(outputs))
-
- m.gammaControl = gammaMgr
- m.availableOutputs = physicalOutputs
- m.outputRegNames = outputRegNames
-
- log.Info("setupRegistry: completed successfully (gamma controls will be initialized when enabled)")
- return nil
-}
-
-func (m *Manager) setupOutputControls(outputs []*wlclient.Output, manager *wlr_gamma_control.ZwlrGammaControlManagerV1) error {
- log.Infof("setupOutputControls: creating gamma controls for %d outputs", len(outputs))
-
- for _, output := range outputs {
- control, err := manager.GetGammaControl(output)
- if err != nil {
- log.Warnf("Failed to get gamma control for output %d: %v", output.ID(), err)
- continue
- }
-
- outState := &outputState{
- id: output.ID(),
- registryName: m.outputRegNames[output.ID()],
- output: output,
- gammaControl: control,
- isVirtual: false,
- }
-
- func(state *outputState) {
- control.SetGammaSizeHandler(func(e wlr_gamma_control.ZwlrGammaControlV1GammaSizeEvent) {
- m.outputsMutex.Lock()
- if outState, exists := m.outputs[state.id]; exists {
- outState.rampSize = e.Size
- outState.failed = false
- outState.retryCount = 0
- log.Infof("Output %d gamma_size=%d", state.id, e.Size)
- }
- m.outputsMutex.Unlock()
-
- m.transitionMutex.RLock()
- currentTemp := m.currentTemp
- m.transitionMutex.RUnlock()
-
- m.post(func() {
- m.applyNowOnActor(currentTemp)
- })
- })
-
- control.SetFailedHandler(func(e wlr_gamma_control.ZwlrGammaControlV1FailedEvent) {
- m.outputsMutex.Lock()
- if outState, exists := m.outputs[state.id]; exists {
- outState.failed = true
- outState.rampSize = 0
- outState.retryCount++
- outState.lastFailTime = time.Now()
-
- retryCount := outState.retryCount
- if retryCount == 1 || retryCount%5 == 0 {
- log.Errorf("Gamma control failed for output %d (attempt %d)", state.id, retryCount)
- }
-
- backoff := time.Duration(300<= 9 && ev.Name[:9] == "HEADLESS-" {
- log.Infof("Detected virtual output %d (name=%s), marking for gamma control skip", outputID, ev.Name)
- outState.isVirtual = true
- outState.failed = true
- }
- }
- m.outputsMutex.Unlock()
- })
-
- gammaMgr := m.gammaControl.(*wlr_gamma_control.ZwlrGammaControlManagerV1)
-
- control, err := gammaMgr.GetGammaControl(output)
- if err != nil {
- return fmt.Errorf("failed to get gamma control: %w", err)
- }
-
- outState := &outputState{
- id: outputID,
- name: outputName,
- registryName: m.outputRegNames[outputID],
- output: output,
- gammaControl: control,
- isVirtual: false,
- }
-
- control.SetGammaSizeHandler(func(e wlr_gamma_control.ZwlrGammaControlV1GammaSizeEvent) {
- m.outputsMutex.Lock()
- if out, exists := m.outputs[outState.id]; exists {
- out.rampSize = e.Size
- out.failed = false
- out.retryCount = 0
- log.Infof("Output %d gamma_size=%d", outState.id, e.Size)
- }
- m.outputsMutex.Unlock()
-
- m.transitionMutex.RLock()
- currentTemp := m.currentTemp
- m.transitionMutex.RUnlock()
-
- m.post(func() {
- m.applyNowOnActor(currentTemp)
- })
- })
-
- control.SetFailedHandler(func(e wlr_gamma_control.ZwlrGammaControlV1FailedEvent) {
- m.outputsMutex.Lock()
- if out, exists := m.outputs[outState.id]; exists {
- out.failed = true
- out.rampSize = 0
- out.retryCount++
- out.lastFailTime = time.Now()
-
- retryCount := out.retryCount
- if retryCount == 1 || retryCount%5 == 0 {
- log.Errorf("Gamma control failed for output %d (attempt %d)", outState.id, retryCount)
- }
-
- backoff := time.Duration(300< %dK over %v", currentTemp, targetTemp, dur)
-
- for i := 0; i <= steps; i++ {
- select {
- case newTarget := <-m.transitionChan:
- m.transitionMutex.Lock()
- m.targetTemp = newTarget
- m.transitionMutex.Unlock()
- log.Debugf("Transition %dK -> %dK aborted (newer transition started)", currentTemp, targetTemp)
- break
- default:
- }
-
- m.transitionMutex.RLock()
- if m.targetTemp != targetTemp {
- m.transitionMutex.RUnlock()
- break
- }
- m.transitionMutex.RUnlock()
-
- progress := float64(i) / float64(steps)
- temp := currentTemp + int(float64(targetTemp-currentTemp)*progress)
-
- m.post(func() { m.applyNowOnActor(temp) })
-
- if i < steps {
- time.Sleep(stepDur)
- }
- }
-
- m.transitionMutex.RLock()
- finalTarget := m.targetTemp
- m.transitionMutex.RUnlock()
-
- if finalTarget == targetTemp {
- log.Debugf("Transition complete: now at %dK", targetTemp)
-
- m.configMutex.RLock()
- enabled := m.config.Enabled
- identityTemp := m.config.HighTemp
- m.configMutex.RUnlock()
-
- if !enabled && targetTemp == identityTemp && m.controlsInitialized {
- m.post(func() {
- log.Info("Destroying gamma controls after transition to identity")
- m.outputsMutex.Lock()
- for id, out := range m.outputs {
- if out.gammaControl != nil {
- control := out.gammaControl.(*wlr_gamma_control.ZwlrGammaControlV1)
- control.Destroy()
- log.Debugf("Destroyed gamma control for output %d", id)
- }
- }
- m.outputs = make(map[uint32]*outputState)
- m.controlsInitialized = false
- m.outputsMutex.Unlock()
-
- m.transitionMutex.Lock()
- m.currentTemp = identityTemp
- m.targetTemp = identityTemp
- m.transitionMutex.Unlock()
-
- if _, err := m.display.Sync(); err != nil {
- log.Warnf("Failed to sync Wayland display after destroying controls: %v", err)
- }
-
- log.Info("All gamma controls destroyed")
- })
- }
- }
- }
- }
-}
-
-func (m *Manager) recreateOutputControl(out *outputState) error {
- m.configMutex.RLock()
- enabled := m.config.Enabled
- m.configMutex.RUnlock()
-
- if !enabled || !m.controlsInitialized {
- return nil
- }
-
- m.outputsMutex.RLock()
- _, exists := m.outputs[out.id]
- m.outputsMutex.RUnlock()
-
- if !exists {
- return nil
- }
-
- if out.isVirtual {
- return nil
- }
-
- const maxRetries = 10
- if out.retryCount >= maxRetries {
- return nil
- }
-
- gammaMgr, ok := m.gammaControl.(*wlr_gamma_control.ZwlrGammaControlManagerV1)
- if !ok || gammaMgr == nil {
- return fmt.Errorf("gamma control manager not available")
- }
- control, err := gammaMgr.GetGammaControl(out.output)
- if err != nil {
- return fmt.Errorf("get gamma control: %w", err)
- }
-
- state := out
- control.SetGammaSizeHandler(func(e wlr_gamma_control.ZwlrGammaControlV1GammaSizeEvent) {
- m.outputsMutex.Lock()
- if outState, exists := m.outputs[state.id]; exists {
- outState.rampSize = e.Size
- outState.failed = false
- outState.retryCount = 0
- log.Infof("Output %d gamma_size=%d (recreated)", state.id, e.Size)
- }
- m.outputsMutex.Unlock()
-
- m.transitionMutex.RLock()
- currentTemp := m.currentTemp
- m.transitionMutex.RUnlock()
-
- m.post(func() {
- m.applyNowOnActor(currentTemp)
- })
- })
-
- control.SetFailedHandler(func(e wlr_gamma_control.ZwlrGammaControlV1FailedEvent) {
- m.outputsMutex.Lock()
- if outState, exists := m.outputs[state.id]; exists {
- outState.failed = true
- outState.rampSize = 0
- outState.retryCount++
- outState.lastFailTime = time.Now()
-
- retryCount := outState.retryCount
- if retryCount == 1 || retryCount%5 == 0 {
- log.Errorf("Gamma control failed for output %d (attempt %d)", state.id, retryCount)
- }
-
- backoff := time.Duration(300< 1 {
- return SunTimes{
- Sunrise: time.Date(year, month, day, 0, 0, 0, 0, time.UTC).In(loc),
- Sunset: time.Date(year, month, day, 0, 0, 0, 0, time.UTC).In(loc),
- }
- }
- if cosHourAngle < -1 {
- return SunTimes{
- Sunrise: time.Date(year, month, day, 0, 0, 0, 0, time.UTC).In(loc),
- Sunset: time.Date(year, month, day, 23, 59, 59, 0, time.UTC).In(loc),
- }
- }
-
- hourAngle := math.Acos(cosHourAngle) * radToDeg
-
- sunriseTime := solarNoon - hourAngle/15.0 - lon/15.0 - eqTime/60.0
- sunsetTime := solarNoon + hourAngle/15.0 - lon/15.0 - eqTime/60.0
-
- sunrise := timeOfDayToTime(sunriseTime, year, month, day, time.UTC).In(loc)
- sunset := timeOfDayToTime(sunsetTime, year, month, day, time.UTC).In(loc)
-
- return SunTimes{
- Sunrise: sunrise,
- Sunset: sunset,
- }
-}
-
-func timeOfDayToTime(hours float64, year int, month time.Month, day int, loc *time.Location) time.Time {
- h := int(hours)
- m := int((hours - float64(h)) * 60)
- s := int(((hours-float64(h))*60 - float64(m)) * 60)
-
- if h < 0 {
- h += 24
- day--
- }
- if h >= 24 {
- h -= 24
- day++
- }
-
- return time.Date(year, month, day, h, m, s, 0, loc)
-}
diff --git a/nix/inputs/dms-cli/internal/server/wayland/suncalc_test.go b/nix/inputs/dms-cli/internal/server/wayland/suncalc_test.go
deleted file mode 100644
index 0aaa535..0000000
--- a/nix/inputs/dms-cli/internal/server/wayland/suncalc_test.go
+++ /dev/null
@@ -1,378 +0,0 @@
-package wayland
-
-import (
- "math"
- "testing"
- "time"
-)
-
-func calculateTemperature(config Config, now time.Time) int {
- if !config.Enabled {
- return config.HighTemp
- }
-
- var sunrise, sunset time.Time
-
- if config.ManualSunrise != nil && config.ManualSunset != nil {
- year, month, day := now.Date()
- loc := now.Location()
-
- sunrise = time.Date(year, month, day,
- config.ManualSunrise.Hour(),
- config.ManualSunrise.Minute(),
- config.ManualSunrise.Second(), 0, loc)
- sunset = time.Date(year, month, day,
- config.ManualSunset.Hour(),
- config.ManualSunset.Minute(),
- config.ManualSunset.Second(), 0, loc)
-
- if sunset.Before(sunrise) {
- sunset = sunset.Add(24 * time.Hour)
- }
- } else if config.UseIPLocation {
- lat, lon, err := FetchIPLocation()
- if err != nil {
- return config.HighTemp
- }
- times := CalculateSunTimes(*lat, *lon, now)
- sunrise = times.Sunrise
- sunset = times.Sunset
- } else if config.Latitude != nil && config.Longitude != nil {
- times := CalculateSunTimes(*config.Latitude, *config.Longitude, now)
- sunrise = times.Sunrise
- sunset = times.Sunset
- } else {
- return config.HighTemp
- }
-
- if now.Before(sunrise) || now.After(sunset) {
- return config.LowTemp
- }
- return config.HighTemp
-}
-
-func calculateNextTransition(config Config, now time.Time) time.Time {
- if !config.Enabled {
- return now.Add(24 * time.Hour)
- }
-
- var sunrise, sunset time.Time
-
- if config.ManualSunrise != nil && config.ManualSunset != nil {
- year, month, day := now.Date()
- loc := now.Location()
-
- sunrise = time.Date(year, month, day,
- config.ManualSunrise.Hour(),
- config.ManualSunrise.Minute(),
- config.ManualSunrise.Second(), 0, loc)
- sunset = time.Date(year, month, day,
- config.ManualSunset.Hour(),
- config.ManualSunset.Minute(),
- config.ManualSunset.Second(), 0, loc)
-
- if sunset.Before(sunrise) {
- sunset = sunset.Add(24 * time.Hour)
- }
- } else if config.UseIPLocation {
- lat, lon, err := FetchIPLocation()
- if err != nil {
- return now.Add(24 * time.Hour)
- }
- times := CalculateSunTimes(*lat, *lon, now)
- sunrise = times.Sunrise
- sunset = times.Sunset
- } else if config.Latitude != nil && config.Longitude != nil {
- times := CalculateSunTimes(*config.Latitude, *config.Longitude, now)
- sunrise = times.Sunrise
- sunset = times.Sunset
- } else {
- return now.Add(24 * time.Hour)
- }
-
- if now.Before(sunrise) {
- return sunrise
- }
- if now.Before(sunset) {
- return sunset
- }
-
- if config.ManualSunrise != nil && config.ManualSunset != nil {
- year, month, day := now.Add(24 * time.Hour).Date()
- loc := now.Location()
- nextSunrise := time.Date(year, month, day,
- config.ManualSunrise.Hour(),
- config.ManualSunrise.Minute(),
- config.ManualSunrise.Second(), 0, loc)
- return nextSunrise
- }
-
- if config.UseIPLocation {
- lat, lon, err := FetchIPLocation()
- if err != nil {
- return now.Add(24 * time.Hour)
- }
- nextDayTimes := CalculateSunTimes(*lat, *lon, now.Add(24*time.Hour))
- return nextDayTimes.Sunrise
- }
-
- if config.Latitude != nil && config.Longitude != nil {
- nextDayTimes := CalculateSunTimes(*config.Latitude, *config.Longitude, now.Add(24*time.Hour))
- return nextDayTimes.Sunrise
- }
-
- return now.Add(24 * time.Hour)
-}
-
-func TestCalculateSunTimes(t *testing.T) {
- tests := []struct {
- name string
- lat float64
- lon float64
- date time.Time
- checkFunc func(*testing.T, SunTimes)
- }{
- {
- name: "new_york_summer",
- lat: 40.7128,
- lon: -74.0060,
- date: time.Date(2024, 6, 21, 12, 0, 0, 0, time.Local),
- checkFunc: func(t *testing.T, times SunTimes) {
- if times.Sunrise.Hour() < 4 || times.Sunrise.Hour() > 6 {
- t.Logf("sunrise: %v", times.Sunrise)
- }
- if times.Sunset.Hour() < 19 || times.Sunset.Hour() > 21 {
- t.Logf("sunset: %v", times.Sunset)
- }
- if !times.Sunset.After(times.Sunrise) {
- t.Error("sunset should be after sunrise")
- }
- },
- },
- {
- name: "london_winter",
- lat: 51.5074,
- lon: -0.1278,
- date: time.Date(2024, 12, 21, 12, 0, 0, 0, time.UTC),
- checkFunc: func(t *testing.T, times SunTimes) {
- if times.Sunrise.Hour() < 7 || times.Sunrise.Hour() > 9 {
- t.Errorf("unexpected sunrise hour: %d", times.Sunrise.Hour())
- }
- if times.Sunset.Hour() < 15 || times.Sunset.Hour() > 17 {
- t.Errorf("unexpected sunset hour: %d", times.Sunset.Hour())
- }
- },
- },
- {
- name: "equator_equinox",
- lat: 0.0,
- lon: 0.0,
- date: time.Date(2024, 3, 20, 12, 0, 0, 0, time.UTC),
- checkFunc: func(t *testing.T, times SunTimes) {
- if times.Sunrise.Hour() < 5 || times.Sunrise.Hour() > 7 {
- t.Errorf("unexpected sunrise hour: %d", times.Sunrise.Hour())
- }
- if times.Sunset.Hour() < 17 || times.Sunset.Hour() > 19 {
- t.Errorf("unexpected sunset hour: %d", times.Sunset.Hour())
- }
- },
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- times := CalculateSunTimes(tt.lat, tt.lon, tt.date)
- tt.checkFunc(t, times)
- })
- }
-}
-
-func TestCalculateTemperature(t *testing.T) {
- lat := 40.7128
- lon := -74.0060
- date := time.Date(2024, 6, 21, 0, 0, 0, 0, time.Local)
-
- config := Config{
- LowTemp: 4000,
- HighTemp: 6500,
- Latitude: &lat,
- Longitude: &lon,
- Enabled: true,
- }
-
- times := CalculateSunTimes(lat, lon, date)
-
- tests := []struct {
- name string
- timeFunc func() time.Time
- wantTemp int
- }{
- {
- name: "midnight",
- timeFunc: func() time.Time { return times.Sunrise.Add(-4 * time.Hour) },
- wantTemp: 4000,
- },
- {
- name: "sunrise",
- timeFunc: func() time.Time { return times.Sunrise },
- wantTemp: 6500,
- },
- {
- name: "noon",
- timeFunc: func() time.Time { return times.Sunrise.Add(6 * time.Hour) },
- wantTemp: 6500,
- },
- {
- name: "after_sunset_transition",
- timeFunc: func() time.Time { return times.Sunset.Add(2 * time.Hour) },
- wantTemp: 4000,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- temp := calculateTemperature(config, tt.timeFunc())
-
- if math.Abs(float64(temp-tt.wantTemp)) > 500 {
- t.Errorf("temperature = %d, want approximately %d", temp, tt.wantTemp)
- }
- })
- }
-}
-
-func TestCalculateTemperatureManualTimes(t *testing.T) {
- sunrise := time.Date(0, 1, 1, 6, 30, 0, 0, time.Local)
- sunset := time.Date(0, 1, 1, 18, 30, 0, 0, time.Local)
-
- config := Config{
- LowTemp: 4000,
- HighTemp: 6500,
- ManualSunrise: &sunrise,
- ManualSunset: &sunset,
- Enabled: true,
- }
-
- tests := []struct {
- name string
- time time.Time
- want int
- }{
- {"before_sunrise", time.Date(2024, 1, 1, 3, 0, 0, 0, time.Local), 4000},
- {"at_sunrise", time.Date(2024, 1, 1, 6, 30, 0, 0, time.Local), 6500},
- {"midday", time.Date(2024, 1, 1, 12, 0, 0, 0, time.Local), 6500},
- {"at_sunset", time.Date(2024, 1, 1, 18, 30, 0, 0, time.Local), 6500},
- {"after_sunset", time.Date(2024, 1, 1, 22, 0, 0, 0, time.Local), 4000},
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- temp := calculateTemperature(config, tt.time)
- if math.Abs(float64(temp-tt.want)) > 500 {
- t.Errorf("temperature = %d, want approximately %d", temp, tt.want)
- }
- })
- }
-}
-
-func TestCalculateTemperatureDisabled(t *testing.T) {
- lat := 40.7128
- lon := -74.0060
-
- config := Config{
- LowTemp: 4000,
- HighTemp: 6500,
- Latitude: &lat,
- Longitude: &lon,
- Enabled: false,
- }
-
- temp := calculateTemperature(config, time.Now())
- if temp != 6500 {
- t.Errorf("disabled should return high temp, got %d", temp)
- }
-}
-
-func TestCalculateNextTransition(t *testing.T) {
- lat := 40.7128
- lon := -74.0060
- date := time.Date(2024, 6, 21, 0, 0, 0, 0, time.Local)
-
- config := Config{
- LowTemp: 4000,
- HighTemp: 6500,
- Latitude: &lat,
- Longitude: &lon,
- Enabled: true,
- }
-
- times := CalculateSunTimes(lat, lon, date)
-
- tests := []struct {
- name string
- now time.Time
- checkFunc func(*testing.T, time.Time)
- }{
- {
- name: "before_sunrise",
- now: times.Sunrise.Add(-2 * time.Hour),
- checkFunc: func(t *testing.T, next time.Time) {
- if !next.Equal(times.Sunrise) && !next.After(times.Sunrise.Add(-1*time.Minute)) {
- t.Error("next transition should be at or near sunrise")
- }
- },
- },
- {
- name: "after_sunrise",
- now: times.Sunrise.Add(2 * time.Hour),
- checkFunc: func(t *testing.T, next time.Time) {
- if !next.After(times.Sunrise) {
- t.Error("next transition should be after sunrise")
- }
- },
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- next := calculateNextTransition(config, tt.now)
- tt.checkFunc(t, next)
- })
- }
-}
-
-func TestTimeOfDayToTime(t *testing.T) {
- tests := []struct {
- name string
- hours float64
- expected time.Time
- }{
- {
- name: "noon",
- hours: 12.0,
- expected: time.Date(2024, 6, 21, 12, 0, 0, 0, time.Local),
- },
- {
- name: "half_past",
- hours: 12.5,
- expected: time.Date(2024, 6, 21, 12, 30, 0, 0, time.Local),
- },
- {
- name: "early_morning",
- hours: 6.25,
- expected: time.Date(2024, 6, 21, 6, 15, 0, 0, time.Local),
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := timeOfDayToTime(tt.hours, 2024, 6, 21, time.Local)
-
- if result.Hour() != tt.expected.Hour() {
- t.Errorf("hour = %d, want %d", result.Hour(), tt.expected.Hour())
- }
- if result.Minute() != tt.expected.Minute() {
- t.Errorf("minute = %d, want %d", result.Minute(), tt.expected.Minute())
- }
- })
- }
-}
diff --git a/nix/inputs/dms-cli/internal/server/wayland/types.go b/nix/inputs/dms-cli/internal/server/wayland/types.go
deleted file mode 100644
index 02ccb07..0000000
--- a/nix/inputs/dms-cli/internal/server/wayland/types.go
+++ /dev/null
@@ -1,194 +0,0 @@
-package wayland
-
-import (
- "math"
- "sync"
- "time"
-
- "github.com/AvengeMedia/danklinux/internal/errdefs"
- "github.com/godbus/dbus/v5"
- wlclient "github.com/yaslama/go-wayland/wayland/client"
-)
-
-type Config struct {
- Outputs []string
- LowTemp int
- HighTemp int
- Latitude *float64
- Longitude *float64
- UseIPLocation bool
- ManualSunrise *time.Time
- ManualSunset *time.Time
- ManualDuration *time.Duration
- Gamma float64
- Enabled bool
-}
-
-type State struct {
- Config Config `json:"config"`
- CurrentTemp int `json:"currentTemp"`
- NextTransition time.Time `json:"nextTransition"`
- SunriseTime time.Time `json:"sunriseTime"`
- SunsetTime time.Time `json:"sunsetTime"`
- IsDay bool `json:"isDay"`
-}
-
-type cmd struct {
- fn func()
-}
-
-type Manager struct {
- config Config
- configMutex sync.RWMutex
- state *State
- stateMutex sync.RWMutex
-
- display *wlclient.Display
- registry *wlclient.Registry
- gammaControl interface{}
- availableOutputs []*wlclient.Output
- outputRegNames map[uint32]uint32
- outputs map[uint32]*outputState
- outputsMutex sync.RWMutex
- controlsInitialized bool
-
- cmdq chan cmd
- alive bool
-
- stopChan chan struct{}
- updateTrigger chan struct{}
- wg sync.WaitGroup
-
- currentTemp int
- targetTemp int
- transitionMutex sync.RWMutex
- transitionChan chan int
-
- cachedIPLat *float64
- cachedIPLon *float64
- locationMutex sync.RWMutex
-
- subscribers map[string]chan State
- subMutex sync.RWMutex
- dirty chan struct{}
- notifierWg sync.WaitGroup
- lastNotified *State
-
- dbusConn *dbus.Conn
- dbusSignal chan *dbus.Signal
-}
-
-type outputState struct {
- id uint32
- name string
- registryName uint32
- output *wlclient.Output
- gammaControl interface{}
- rampSize uint32
- failed bool
- isVirtual bool
- retryCount int
- lastFailTime time.Time
-}
-
-type SunTimes struct {
- Sunrise time.Time
- Sunset time.Time
-}
-
-func DefaultConfig() Config {
- return Config{
- Outputs: []string{},
- LowTemp: 4000,
- HighTemp: 6500,
- Gamma: 1.0,
- Enabled: false,
- }
-}
-
-func (c *Config) Validate() error {
- if c.LowTemp < 1000 || c.LowTemp > 10000 {
- return errdefs.ErrInvalidTemperature
- }
- if c.HighTemp < 1000 || c.HighTemp > 10000 {
- return errdefs.ErrInvalidTemperature
- }
- if c.LowTemp > c.HighTemp {
- return errdefs.ErrInvalidTemperature
- }
- if c.Gamma <= 0 || c.Gamma > 10 {
- return errdefs.ErrInvalidGamma
- }
- if c.Latitude != nil && (math.Abs(*c.Latitude) > 90) {
- return errdefs.ErrInvalidLocation
- }
- if c.Longitude != nil && (math.Abs(*c.Longitude) > 180) {
- return errdefs.ErrInvalidLocation
- }
- if (c.Latitude != nil) != (c.Longitude != nil) {
- return errdefs.ErrInvalidLocation
- }
- if (c.ManualSunrise != nil) != (c.ManualSunset != nil) {
- return errdefs.ErrInvalidManualTimes
- }
- return nil
-}
-
-func (m *Manager) GetState() State {
- m.stateMutex.RLock()
- defer m.stateMutex.RUnlock()
- if m.state == nil {
- return State{}
- }
- stateCopy := *m.state
- return stateCopy
-}
-
-func (m *Manager) Subscribe(id string) chan State {
- ch := make(chan State, 64)
- m.subMutex.Lock()
- m.subscribers[id] = ch
- m.subMutex.Unlock()
- return ch
-}
-
-func (m *Manager) Unsubscribe(id string) {
- m.subMutex.Lock()
- if ch, ok := m.subscribers[id]; ok {
- close(ch)
- delete(m.subscribers, id)
- }
- m.subMutex.Unlock()
-}
-
-func (m *Manager) notifySubscribers() {
- select {
- case m.dirty <- struct{}{}:
- default:
- }
-}
-
-func stateChanged(old, new *State) bool {
- if old == nil || new == nil {
- return true
- }
- if old.CurrentTemp != new.CurrentTemp {
- return true
- }
- if old.IsDay != new.IsDay {
- return true
- }
- if !old.NextTransition.Equal(new.NextTransition) {
- return true
- }
- if !old.SunriseTime.Equal(new.SunriseTime) {
- return true
- }
- if !old.SunsetTime.Equal(new.SunsetTime) {
- return true
- }
- if old.Config.Enabled != new.Config.Enabled {
- return true
- }
- return false
-}
diff --git a/nix/inputs/dms-cli/internal/server/wayland/types_test.go b/nix/inputs/dms-cli/internal/server/wayland/types_test.go
deleted file mode 100644
index f5bbb42..0000000
--- a/nix/inputs/dms-cli/internal/server/wayland/types_test.go
+++ /dev/null
@@ -1,330 +0,0 @@
-package wayland
-
-import (
- "testing"
- "time"
-)
-
-func TestConfigValidate(t *testing.T) {
- tests := []struct {
- name string
- config Config
- wantErr bool
- }{
- {
- name: "valid_default",
- config: DefaultConfig(),
- wantErr: false,
- },
- {
- name: "valid_with_location",
- config: Config{
- LowTemp: 4000,
- HighTemp: 6500,
- Latitude: floatPtr(40.7128),
- Longitude: floatPtr(-74.0060),
- Gamma: 1.0,
- Enabled: true,
- },
- wantErr: false,
- },
- {
- name: "valid_manual_times",
- config: Config{
- LowTemp: 4000,
- HighTemp: 6500,
- ManualSunrise: timePtr(time.Date(0, 1, 1, 6, 30, 0, 0, time.Local)),
- ManualSunset: timePtr(time.Date(0, 1, 1, 18, 30, 0, 0, time.Local)),
- Gamma: 1.0,
- Enabled: true,
- },
- wantErr: false,
- },
- {
- name: "invalid_low_temp_too_low",
- config: Config{
- LowTemp: 500,
- HighTemp: 6500,
- Gamma: 1.0,
- },
- wantErr: true,
- },
- {
- name: "invalid_low_temp_too_high",
- config: Config{
- LowTemp: 15000,
- HighTemp: 20000,
- Gamma: 1.0,
- },
- wantErr: true,
- },
- {
- name: "invalid_high_temp_too_low",
- config: Config{
- LowTemp: 4000,
- HighTemp: 500,
- Gamma: 1.0,
- },
- wantErr: true,
- },
- {
- name: "valid_temps_equal",
- config: Config{
- LowTemp: 5000,
- HighTemp: 5000,
- Gamma: 1.0,
- },
- wantErr: false,
- },
- {
- name: "invalid_temps_reversed",
- config: Config{
- LowTemp: 6500,
- HighTemp: 4000,
- Gamma: 1.0,
- },
- wantErr: true,
- },
- {
- name: "invalid_gamma_zero",
- config: Config{
- LowTemp: 4000,
- HighTemp: 6500,
- Gamma: 0,
- },
- wantErr: true,
- },
- {
- name: "invalid_gamma_negative",
- config: Config{
- LowTemp: 4000,
- HighTemp: 6500,
- Gamma: -1.0,
- },
- wantErr: true,
- },
- {
- name: "invalid_gamma_too_high",
- config: Config{
- LowTemp: 4000,
- HighTemp: 6500,
- Gamma: 15.0,
- },
- wantErr: true,
- },
- {
- name: "invalid_latitude_too_high",
- config: Config{
- LowTemp: 4000,
- HighTemp: 6500,
- Latitude: floatPtr(100),
- Longitude: floatPtr(0),
- Gamma: 1.0,
- },
- wantErr: true,
- },
- {
- name: "invalid_latitude_too_low",
- config: Config{
- LowTemp: 4000,
- HighTemp: 6500,
- Latitude: floatPtr(-100),
- Longitude: floatPtr(0),
- Gamma: 1.0,
- },
- wantErr: true,
- },
- {
- name: "invalid_longitude_too_high",
- config: Config{
- LowTemp: 4000,
- HighTemp: 6500,
- Latitude: floatPtr(40),
- Longitude: floatPtr(200),
- Gamma: 1.0,
- },
- wantErr: true,
- },
- {
- name: "invalid_longitude_too_low",
- config: Config{
- LowTemp: 4000,
- HighTemp: 6500,
- Latitude: floatPtr(40),
- Longitude: floatPtr(-200),
- Gamma: 1.0,
- },
- wantErr: true,
- },
- {
- name: "invalid_latitude_without_longitude",
- config: Config{
- LowTemp: 4000,
- HighTemp: 6500,
- Latitude: floatPtr(40),
- Gamma: 1.0,
- },
- wantErr: true,
- },
- {
- name: "invalid_longitude_without_latitude",
- config: Config{
- LowTemp: 4000,
- HighTemp: 6500,
- Longitude: floatPtr(-74),
- Gamma: 1.0,
- },
- wantErr: true,
- },
- {
- name: "invalid_sunrise_without_sunset",
- config: Config{
- LowTemp: 4000,
- HighTemp: 6500,
- ManualSunrise: timePtr(time.Date(0, 1, 1, 6, 30, 0, 0, time.Local)),
- Gamma: 1.0,
- },
- wantErr: true,
- },
- {
- name: "invalid_sunset_without_sunrise",
- config: Config{
- LowTemp: 4000,
- HighTemp: 6500,
- ManualSunset: timePtr(time.Date(0, 1, 1, 18, 30, 0, 0, time.Local)),
- Gamma: 1.0,
- },
- wantErr: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- err := tt.config.Validate()
- if (err != nil) != tt.wantErr {
- t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
- }
- })
- }
-}
-
-func TestDefaultConfig(t *testing.T) {
- config := DefaultConfig()
-
- if config.LowTemp != 4000 {
- t.Errorf("default low temp = %d, want 4000", config.LowTemp)
- }
- if config.HighTemp != 6500 {
- t.Errorf("default high temp = %d, want 6500", config.HighTemp)
- }
- if config.Gamma != 1.0 {
- t.Errorf("default gamma = %f, want 1.0", config.Gamma)
- }
- if config.Enabled {
- t.Error("default should be disabled")
- }
- if config.Latitude != nil {
- t.Error("default should not have latitude")
- }
- if config.Longitude != nil {
- t.Error("default should not have longitude")
- }
-}
-
-func TestStateChanged(t *testing.T) {
- baseState := &State{
- CurrentTemp: 5000,
- NextTransition: time.Now(),
- SunriseTime: time.Now().Add(6 * time.Hour),
- SunsetTime: time.Now().Add(18 * time.Hour),
- IsDay: true,
- Config: DefaultConfig(),
- }
-
- tests := []struct {
- name string
- old *State
- new *State
- wantChanged bool
- }{
- {
- name: "nil_old",
- old: nil,
- new: baseState,
- wantChanged: true,
- },
- {
- name: "nil_new",
- old: baseState,
- new: nil,
- wantChanged: true,
- },
- {
- name: "same_state",
- old: baseState,
- new: baseState,
- wantChanged: false,
- },
- {
- name: "temp_changed",
- old: baseState,
- new: &State{
- CurrentTemp: 6000,
- NextTransition: baseState.NextTransition,
- SunriseTime: baseState.SunriseTime,
- SunsetTime: baseState.SunsetTime,
- IsDay: baseState.IsDay,
- Config: baseState.Config,
- },
- wantChanged: true,
- },
- {
- name: "is_day_changed",
- old: baseState,
- new: &State{
- CurrentTemp: baseState.CurrentTemp,
- NextTransition: baseState.NextTransition,
- SunriseTime: baseState.SunriseTime,
- SunsetTime: baseState.SunsetTime,
- IsDay: false,
- Config: baseState.Config,
- },
- wantChanged: true,
- },
- {
- name: "enabled_changed",
- old: baseState,
- new: &State{
- CurrentTemp: baseState.CurrentTemp,
- NextTransition: baseState.NextTransition,
- SunriseTime: baseState.SunriseTime,
- SunsetTime: baseState.SunsetTime,
- IsDay: baseState.IsDay,
- Config: Config{
- LowTemp: 4000,
- HighTemp: 6500,
- Gamma: 1.0,
- Enabled: true,
- },
- },
- wantChanged: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- changed := stateChanged(tt.old, tt.new)
- if changed != tt.wantChanged {
- t.Errorf("stateChanged() = %v, want %v", changed, tt.wantChanged)
- }
- })
- }
-}
-
-func floatPtr(f float64) *float64 {
- return &f
-}
-
-func timePtr(t time.Time) *time.Time {
- return &t
-}
diff --git a/nix/inputs/dms-cli/internal/server/wlcontext/context.go b/nix/inputs/dms-cli/internal/server/wlcontext/context.go
deleted file mode 100644
index ea15973..0000000
--- a/nix/inputs/dms-cli/internal/server/wlcontext/context.go
+++ /dev/null
@@ -1,76 +0,0 @@
-package wlcontext
-
-import (
- "fmt"
- "sync"
-
- "github.com/AvengeMedia/danklinux/internal/errdefs"
- "github.com/AvengeMedia/danklinux/internal/log"
- wlclient "github.com/yaslama/go-wayland/wayland/client"
-)
-
-type SharedContext struct {
- display *wlclient.Display
- stopChan chan struct{}
- wg sync.WaitGroup
- mu sync.Mutex
- started bool
-}
-
-func New() (*SharedContext, error) {
- display, err := wlclient.Connect("")
- if err != nil {
- return nil, fmt.Errorf("%w: %v", errdefs.ErrNoWaylandDisplay, err)
- }
-
- sc := &SharedContext{
- display: display,
- stopChan: make(chan struct{}),
- started: false,
- }
-
- return sc, nil
-}
-
-func (sc *SharedContext) Start() {
- sc.mu.Lock()
- defer sc.mu.Unlock()
-
- if sc.started {
- return
- }
-
- sc.started = true
- sc.wg.Add(1)
- go sc.eventDispatcher()
-}
-
-func (sc *SharedContext) Display() *wlclient.Display {
- return sc.display
-}
-
-func (sc *SharedContext) eventDispatcher() {
- defer sc.wg.Done()
- ctx := sc.display.Context()
-
- for {
- select {
- case <-sc.stopChan:
- return
- default:
- if err := ctx.Dispatch(); err != nil {
- log.Errorf("Wayland connection error: %v", err)
- return
- }
- }
- }
-}
-
-func (sc *SharedContext) Close() {
- close(sc.stopChan)
- sc.wg.Wait()
-
- if sc.display != nil {
- sc.display.Context().Close()
- }
-}
diff --git a/nix/inputs/dms-cli/internal/tui/app.go b/nix/inputs/dms-cli/internal/tui/app.go
deleted file mode 100644
index a4a2d80..0000000
--- a/nix/inputs/dms-cli/internal/tui/app.go
+++ /dev/null
@@ -1,214 +0,0 @@
-package tui
-
-import (
- "github.com/AvengeMedia/danklinux/internal/deps"
- "github.com/AvengeMedia/danklinux/internal/distros"
- "github.com/charmbracelet/bubbles/spinner"
- "github.com/charmbracelet/bubbles/textinput"
- tea "github.com/charmbracelet/bubbletea"
-)
-
-type Model struct {
- version string
- state ApplicationState
-
- osInfo *distros.OSInfo
- dependencies []deps.Dependency
- err error
-
- spinner spinner.Model
- passwordInput textinput.Model
- width int
- height int
- isLoading bool
- styles Styles
-
- logMessages []string
- logChan chan string
- packageProgressChan chan packageInstallProgressMsg
- packageProgress packageInstallProgressMsg
- installationLogs []string
-
- selectedWM int
- selectedTerminal int
- selectedDep int
- selectedConfig int
- reinstallItems map[string]bool
- replaceConfigs map[string]bool
- sudoPassword string
- existingConfigs []ExistingConfigInfo
- fingerprintFailed bool
-}
-
-func NewModel(version string) Model {
- s := spinner.New()
- s.Spinner = spinner.Dot
-
- theme := TerminalTheme()
- styles := NewStyles(theme)
- s.Style = styles.SpinnerStyle
-
- pi := textinput.New()
- pi.Placeholder = "Enter sudo password"
- pi.EchoMode = textinput.EchoPassword
- pi.EchoCharacter = '•'
- pi.Focus()
-
- logChan := make(chan string, 1000)
- packageProgressChan := make(chan packageInstallProgressMsg, 100)
-
- return Model{
- version: version,
- state: StateWelcome,
- spinner: s,
- passwordInput: pi,
- isLoading: true,
- styles: styles,
-
- logMessages: []string{},
- logChan: logChan,
- packageProgressChan: packageProgressChan,
- packageProgress: packageInstallProgressMsg{
- progress: 0.0,
- step: "Initializing package installation",
- isComplete: false,
- },
- selectedWM: 0,
- selectedTerminal: 0, // Default to Ghostty
- selectedDep: 0,
- selectedConfig: 0,
- reinstallItems: make(map[string]bool),
- replaceConfigs: make(map[string]bool),
- installationLogs: []string{},
- }
-}
-
-func (m Model) Init() tea.Cmd {
- return tea.Batch(
- m.spinner.Tick,
- m.listenForLogs(),
- m.detectOS(),
- )
-}
-
-func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "ctrl+c":
- return m, tea.Quit
- }
- }
-
- if tickMsg, ok := msg.(spinner.TickMsg); ok {
- var cmd tea.Cmd
- m.spinner, cmd = m.spinner.Update(tickMsg)
- return m, tea.Batch(cmd, m.listenForLogs())
- }
-
- if sizeMsg, ok := msg.(tea.WindowSizeMsg); ok {
- m.width = sizeMsg.Width
- m.height = sizeMsg.Height
- }
-
- if logMsg, ok := msg.(logMsg); ok {
- m.logMessages = append(m.logMessages, logMsg.message)
- return m, m.listenForLogs()
- }
-
- switch m.state {
- case StateWelcome:
- return m.updateWelcomeState(msg)
- case StateSelectWindowManager:
- return m.updateSelectWindowManagerState(msg)
- case StateSelectTerminal:
- return m.updateSelectTerminalState(msg)
- case StateMissingWMInstructions:
- return m.updateMissingWMInstructionsState(msg)
- case StateDetectingDeps:
- return m.updateDetectingDepsState(msg)
- case StateDependencyReview:
- return m.updateDependencyReviewState(msg)
- case StateAuthMethodChoice:
- return m.updateAuthMethodChoiceState(msg)
- case StateFingerprintAuth:
- return m.updateFingerprintAuthState(msg)
- case StatePasswordPrompt:
- return m.updatePasswordPromptState(msg)
- case StateInstallingPackages:
- return m.updateInstallingPackagesState(msg)
- case StateConfigConfirmation:
- return m.updateConfigConfirmationState(msg)
- case StateDeployingConfigs:
- return m.updateDeployingConfigsState(msg)
- case StateInstallComplete:
- return m.updateInstallCompleteState(msg)
- case StateError:
- return m.updateErrorState(msg)
- default:
- return m, m.listenForLogs()
- }
-}
-
-func (m Model) View() string {
- switch m.state {
- case StateWelcome:
- return m.viewWelcome()
- case StateSelectWindowManager:
- return m.viewSelectWindowManager()
- case StateSelectTerminal:
- return m.viewSelectTerminal()
- case StateMissingWMInstructions:
- return m.viewMissingWMInstructions()
- case StateDetectingDeps:
- return m.viewDetectingDeps()
- case StateDependencyReview:
- return m.viewDependencyReview()
- case StateAuthMethodChoice:
- return m.viewAuthMethodChoice()
- case StateFingerprintAuth:
- return m.viewFingerprintAuth()
- case StatePasswordPrompt:
- return m.viewPasswordPrompt()
- case StateInstallingPackages:
- return m.viewInstallingPackages()
- case StateConfigConfirmation:
- return m.viewConfigConfirmation()
- case StateDeployingConfigs:
- return m.viewDeployingConfigs()
- case StateInstallComplete:
- return m.viewInstallComplete()
- case StateError:
- return m.viewError()
- default:
- return m.viewWelcome()
- }
-}
-
-func (m Model) listenForLogs() tea.Cmd {
- return func() tea.Msg {
- select {
- case msg, ok := <-m.logChan:
- if !ok {
- return nil
- }
- return logMsg{message: msg}
- default:
- return nil
- }
- }
-}
-
-func (m Model) detectOS() tea.Cmd {
- return func() tea.Msg {
- info, err := distros.GetOSInfo()
- osInfoMsg := &distros.OSInfo{}
- if info != nil {
- osInfoMsg.Distribution = info.Distribution
- osInfoMsg.Version = info.Version
- osInfoMsg.VersionID = info.VersionID
- osInfoMsg.PrettyName = info.PrettyName
- osInfoMsg.Architecture = info.Architecture
- }
- return osInfoCompleteMsg{info: osInfoMsg, err: err}
- }
-}
diff --git a/nix/inputs/dms-cli/internal/tui/banner.go b/nix/inputs/dms-cli/internal/tui/banner.go
deleted file mode 100644
index d0f625b..0000000
--- a/nix/inputs/dms-cli/internal/tui/banner.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package tui
-
-import "github.com/charmbracelet/lipgloss"
-
-func (m Model) renderBanner() string {
- logo := `
-██████╗ █████╗ ███╗ ██╗██╗ ██╗
-██╔══██╗██╔══██╗████╗ ██║██║ ██╔╝
-██║ ██║███████║██╔██╗ ██║█████╔╝
-██║ ██║██╔══██║██║╚██╗██║██╔═██╗
-██████╔╝██║ ██║██║ ╚████║██║ ██╗
-╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ `
-
- theme := TerminalTheme()
- style := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)).
- Bold(true).
- MarginBottom(1)
-
- return style.Render(logo)
-}
diff --git a/nix/inputs/dms-cli/internal/tui/messages.go b/nix/inputs/dms-cli/internal/tui/messages.go
deleted file mode 100644
index 3df9f1f..0000000
--- a/nix/inputs/dms-cli/internal/tui/messages.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package tui
-
-import (
- "github.com/AvengeMedia/danklinux/internal/deps"
- "github.com/AvengeMedia/danklinux/internal/distros"
-)
-
-type logMsg struct {
- message string
-}
-
-type osInfoCompleteMsg struct {
- info *distros.OSInfo
- err error
-}
-
-type depsDetectedMsg struct {
- deps []deps.Dependency
- err error
-}
-
-type packageInstallProgressMsg struct {
- progress float64
- step string
- isComplete bool
- needsSudo bool
- commandInfo string
- logOutput string
- error error
-}
-
-type packageProgressCompletedMsg struct{}
-
-type passwordValidMsg struct {
- password string
- valid bool
-}
-
-type delayCompleteMsg struct{}
diff --git a/nix/inputs/dms-cli/internal/tui/states.go b/nix/inputs/dms-cli/internal/tui/states.go
deleted file mode 100644
index a0bb5c2..0000000
--- a/nix/inputs/dms-cli/internal/tui/states.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package tui
-
-type ApplicationState int
-
-const (
- StateWelcome ApplicationState = iota
- StateSelectWindowManager
- StateSelectTerminal
- StateMissingWMInstructions
- StateDetectingDeps
- StateDependencyReview
- StateAuthMethodChoice
- StateFingerprintAuth
- StatePasswordPrompt
- StateInstallingPackages
- StateConfigConfirmation
- StateDeployingConfigs
- StateInstallComplete
- StateFinalComplete
- StateError
-)
diff --git a/nix/inputs/dms-cli/internal/tui/styles.go b/nix/inputs/dms-cli/internal/tui/styles.go
deleted file mode 100644
index 45a9dae..0000000
--- a/nix/inputs/dms-cli/internal/tui/styles.go
+++ /dev/null
@@ -1,124 +0,0 @@
-package tui
-
-import (
- "github.com/charmbracelet/bubbles/progress"
- "github.com/charmbracelet/lipgloss"
-)
-
-type AppTheme struct {
- Primary string
- Secondary string
- Accent string
- Text string
- Subtle string
- Error string
- Warning string
- Success string
- Background string
- Surface string
-}
-
-func TerminalTheme() AppTheme {
- return AppTheme{
- Primary: "6", // #625690 - purple
- Secondary: "5", // #36247a - dark purple
- Accent: "12", // #7060ac - light purple
- Text: "7", // #2e2e2e - dark gray
- Subtle: "8", // #4a4a4a - medium gray
- Error: "1", // #d83636 - red
- Warning: "3", // #ffff89 - yellow
- Success: "2", // #53e550 - green
- Background: "15", // #1a1a1a - near black
- Surface: "8", // #4a4a4a - medium gray
- }
-}
-
-func NewStyles(theme AppTheme) Styles {
- return Styles{
- Title: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)).
- Bold(true).
- MarginLeft(1).
- MarginBottom(1),
-
- Normal: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Text)),
-
- Bold: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Text)).
- Bold(true),
-
- Subtle: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Subtle)),
-
- Error: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Error)),
-
- Warning: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Warning)),
-
- StatusBar: lipgloss.NewStyle().
- Foreground(lipgloss.Color("#33275e")).
- Background(lipgloss.Color(theme.Primary)).
- Padding(0, 1),
-
- Key: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Accent)).
- Bold(true),
-
- SpinnerStyle: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)),
-
- Success: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Success)).
- Bold(true),
-
- HighlightButton: lipgloss.NewStyle().
- Foreground(lipgloss.Color("#33275e")).
- Background(lipgloss.Color(theme.Primary)).
- Padding(0, 2).
- Bold(true),
-
- SelectedOption: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Accent)).
- Bold(true),
-
- CodeBlock: lipgloss.NewStyle().
- Background(lipgloss.Color(theme.Surface)).
- Foreground(lipgloss.Color(theme.Text)).
- Padding(1, 2).
- MarginLeft(2),
- }
-}
-
-type Styles struct {
- Title lipgloss.Style
- Normal lipgloss.Style
- Bold lipgloss.Style
- Subtle lipgloss.Style
- Warning lipgloss.Style
- Error lipgloss.Style
- StatusBar lipgloss.Style
- Key lipgloss.Style
- SpinnerStyle lipgloss.Style
- Success lipgloss.Style
- HighlightButton lipgloss.Style
- SelectedOption lipgloss.Style
- CodeBlock lipgloss.Style
-}
-
-func (s Styles) NewThemedProgress(width int) progress.Model {
- theme := TerminalTheme()
- prog := progress.New(
- progress.WithGradient(theme.Secondary, theme.Primary),
- )
-
- prog.Width = width
- prog.ShowPercentage = true
- prog.PercentFormat = "%.0f%%"
- prog.PercentageStyle = lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Text)).
- Bold(true)
-
- return prog
-}
diff --git a/nix/inputs/dms-cli/internal/tui/views_config.go b/nix/inputs/dms-cli/internal/tui/views_config.go
deleted file mode 100644
index 5905a94..0000000
--- a/nix/inputs/dms-cli/internal/tui/views_config.go
+++ /dev/null
@@ -1,333 +0,0 @@
-package tui
-
-import (
- "context"
- "fmt"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/config"
- "github.com/AvengeMedia/danklinux/internal/deps"
- tea "github.com/charmbracelet/bubbletea"
-)
-
-type configDeploymentResult struct {
- results []config.DeploymentResult
- error error
-}
-
-type ExistingConfigInfo struct {
- ConfigType string
- Path string
- Exists bool
-}
-
-type configCheckResult struct {
- configs []ExistingConfigInfo
- error error
-}
-
-func (m Model) viewDeployingConfigs() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Deploying Configurations")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- spinner := m.spinner.View()
- status := m.styles.Normal.Render("Setting up configuration files...")
- b.WriteString(fmt.Sprintf("%s %s", spinner, status))
- b.WriteString("\n\n")
-
- // Show progress information
- info := m.styles.Subtle.Render("• Creating backups of existing configurations\n• Deploying optimized configurations\n• Detecting system paths")
- b.WriteString(info)
-
- // Show live log output if available
- if len(m.installationLogs) > 0 {
- b.WriteString("\n\n")
- logHeader := m.styles.Subtle.Render("Configuration Log:")
- b.WriteString(logHeader)
- b.WriteString("\n")
-
- // Show last few lines of logs
- maxLines := 5
- startIdx := 0
- if len(m.installationLogs) > maxLines {
- startIdx = len(m.installationLogs) - maxLines
- }
-
- for i := startIdx; i < len(m.installationLogs); i++ {
- if m.installationLogs[i] != "" {
- logLine := m.styles.Subtle.Render(" " + m.installationLogs[i])
- b.WriteString(logLine)
- b.WriteString("\n")
- }
- }
- }
-
- return b.String()
-}
-
-func (m Model) updateDeployingConfigsState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if result, ok := msg.(configDeploymentResult); ok {
- if result.error != nil {
- m.err = result.error
- m.state = StateError
- m.isLoading = false
- return m, nil
- }
-
- for _, deployResult := range result.results {
- if deployResult.Deployed {
- logMsg := fmt.Sprintf("✓ %s configuration deployed", deployResult.ConfigType)
- if deployResult.BackupPath != "" {
- logMsg += fmt.Sprintf(" (backup: %s)", deployResult.BackupPath)
- }
- m.installationLogs = append(m.installationLogs, logMsg)
- }
- }
-
- m.state = StateInstallComplete
- m.isLoading = false
- return m, nil
- }
-
- return m, m.listenForLogs()
-}
-
-func (m Model) deployConfigurations() tea.Cmd {
- return func() tea.Msg {
- // Determine the selected window manager
- var wm deps.WindowManager
- switch m.selectedWM {
- case 0:
- wm = deps.WindowManagerNiri
- case 1:
- wm = deps.WindowManagerHyprland
- default:
- wm = deps.WindowManagerNiri
- }
-
- // Determine the selected terminal
- var terminal deps.Terminal
- switch m.selectedTerminal {
- case 0:
- terminal = deps.TerminalGhostty
- case 1:
- terminal = deps.TerminalKitty
- default:
- terminal = deps.TerminalGhostty
- }
-
- deployer := config.NewConfigDeployer(m.logChan)
-
- results, err := deployer.DeployConfigurationsSelectiveWithReinstalls(context.Background(), wm, terminal, m.dependencies, m.replaceConfigs, m.reinstallItems)
-
- return configDeploymentResult{
- results: results,
- error: err,
- }
- }
-}
-
-func (m Model) viewConfigConfirmation() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Configuration Deployment")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- if len(m.existingConfigs) == 0 {
- // No existing configs, proceed directly
- info := m.styles.Normal.Render("No existing configurations found. Proceeding with deployment...")
- b.WriteString(info)
- return b.String()
- }
-
- // Show existing configurations with toggle options
- for i, configInfo := range m.existingConfigs {
- if configInfo.Exists {
- var status string
- var replaceMarker string
-
- shouldReplace := m.replaceConfigs[configInfo.ConfigType]
- if _, exists := m.replaceConfigs[configInfo.ConfigType]; !exists {
- shouldReplace = true
- m.replaceConfigs[configInfo.ConfigType] = true
- }
-
- if shouldReplace {
- replaceMarker = "🔄 "
- status = m.styles.Warning.Render("Will replace")
- } else {
- replaceMarker = "✓ "
- status = m.styles.Success.Render("Keep existing")
- }
-
- var line string
- if i == m.selectedConfig {
- line = fmt.Sprintf("▶ %s%-15s %s", replaceMarker, configInfo.ConfigType, status)
- line += fmt.Sprintf("\n %s", configInfo.Path)
- line = m.styles.SelectedOption.Render(line)
- } else {
- line = fmt.Sprintf(" %s%-15s %s", replaceMarker, configInfo.ConfigType, status)
- line += fmt.Sprintf("\n %s", configInfo.Path)
- line = m.styles.Normal.Render(line)
- }
-
- b.WriteString(line)
- b.WriteString("\n\n")
- }
- }
-
- backup := m.styles.Success.Render("✓ Replaced configurations will be backed up with timestamp")
- b.WriteString(backup)
- b.WriteString("\n\n")
-
- help := m.styles.Subtle.Render("↑/↓: Navigate, Space: Toggle replace/keep, Enter: Continue")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) updateConfigConfirmationState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if result, ok := msg.(configCheckResult); ok {
- if result.error != nil {
- m.err = result.error
- m.state = StateError
- return m, nil
- }
-
- m.existingConfigs = result.configs
-
- firstExistingSet := false
- for i, config := range result.configs {
- if config.Exists {
- m.replaceConfigs[config.ConfigType] = true
- if !firstExistingSet {
- m.selectedConfig = i
- firstExistingSet = true
- }
- }
- }
-
- hasExisting := false
- for _, config := range result.configs {
- if config.Exists {
- hasExisting = true
- break
- }
- }
-
- if !hasExisting {
- // No existing configs, proceed directly to deployment
- m.state = StateDeployingConfigs
- return m, m.deployConfigurations()
- }
-
- // Show confirmation view
- return m, nil
- }
-
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "up":
- if m.selectedConfig > 0 {
- for i := m.selectedConfig - 1; i >= 0; i-- {
- if m.existingConfigs[i].Exists {
- m.selectedConfig = i
- break
- }
- }
- }
- case "down":
- if m.selectedConfig < len(m.existingConfigs)-1 {
- for i := m.selectedConfig + 1; i < len(m.existingConfigs); i++ {
- if m.existingConfigs[i].Exists {
- m.selectedConfig = i
- break
- }
- }
- }
- case " ":
- if len(m.existingConfigs) > 0 && m.selectedConfig < len(m.existingConfigs) {
- configType := m.existingConfigs[m.selectedConfig].ConfigType
- if m.existingConfigs[m.selectedConfig].Exists {
- m.replaceConfigs[configType] = !m.replaceConfigs[configType]
- }
- }
- case "enter":
- m.state = StateDeployingConfigs
- return m, m.deployConfigurations()
- }
- }
-
- return m, nil
-}
-
-func (m Model) checkExistingConfigurations() tea.Cmd {
- return func() tea.Msg {
- var configs []ExistingConfigInfo
-
- if m.selectedWM == 0 {
- niriPath := filepath.Join(os.Getenv("HOME"), ".config", "niri", "config.kdl")
- niriExists := false
- if _, err := os.Stat(niriPath); err == nil {
- niriExists = true
- }
- configs = append(configs, ExistingConfigInfo{
- ConfigType: "Niri",
- Path: niriPath,
- Exists: niriExists,
- })
- } else {
- hyprlandPath := filepath.Join(os.Getenv("HOME"), ".config", "hypr", "hyprland.conf")
- hyprlandExists := false
- if _, err := os.Stat(hyprlandPath); err == nil {
- hyprlandExists = true
- }
- configs = append(configs, ExistingConfigInfo{
- ConfigType: "Hyprland",
- Path: hyprlandPath,
- Exists: hyprlandExists,
- })
- }
-
- if m.selectedTerminal == 0 {
- ghosttyPath := filepath.Join(os.Getenv("HOME"), ".config", "ghostty", "config")
- ghosttyExists := false
- if _, err := os.Stat(ghosttyPath); err == nil {
- ghosttyExists = true
- }
- configs = append(configs, ExistingConfigInfo{
- ConfigType: "Ghostty",
- Path: ghosttyPath,
- Exists: ghosttyExists,
- })
- } else {
- kittyPath := filepath.Join(os.Getenv("HOME"), ".config", "kitty", "kitty.conf")
- kittyExists := false
- if _, err := os.Stat(kittyPath); err == nil {
- kittyExists = true
- }
- configs = append(configs, ExistingConfigInfo{
- ConfigType: "Kitty",
- Path: kittyPath,
- Exists: kittyExists,
- })
- }
-
- return configCheckResult{
- configs: configs,
- error: nil,
- }
- }
-}
diff --git a/nix/inputs/dms-cli/internal/tui/views_dependencies.go b/nix/inputs/dms-cli/internal/tui/views_dependencies.go
deleted file mode 100644
index d92192c..0000000
--- a/nix/inputs/dms-cli/internal/tui/views_dependencies.go
+++ /dev/null
@@ -1,237 +0,0 @@
-package tui
-
-import (
- "context"
- "fmt"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
- "github.com/AvengeMedia/danklinux/internal/distros"
- tea "github.com/charmbracelet/bubbletea"
-)
-
-func (m Model) viewDetectingDeps() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Detecting Dependencies")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- spinner := m.spinner.View()
- status := m.styles.Normal.Render("Scanning system for existing packages and configurations...")
- b.WriteString(fmt.Sprintf("%s %s", spinner, status))
-
- return b.String()
-}
-
-func (m Model) viewDependencyReview() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Dependency Review")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- if len(m.dependencies) > 0 {
- for i, dep := range m.dependencies {
- var status string
- var reinstallMarker string
- var variantMarker string
-
- isDMS := dep.Name == "dms (DankMaterialShell)"
-
- if dep.CanToggle && dep.Variant == deps.VariantGit {
- variantMarker = "[git] "
- }
-
- if m.reinstallItems[dep.Name] {
- reinstallMarker = "🔄 "
- status = m.styles.Warning.Render("Will reinstall")
- } else if isDMS {
- reinstallMarker = "⚡ "
- switch dep.Status {
- case deps.StatusInstalled:
- status = m.styles.Success.Render("✓ Required (installed)")
- case deps.StatusMissing:
- status = m.styles.Warning.Render("○ Required (will install)")
- case deps.StatusNeedsUpdate:
- status = m.styles.Warning.Render("△ Required (needs update)")
- case deps.StatusNeedsReinstall:
- status = m.styles.Error.Render("! Required (needs reinstall)")
- }
- } else {
- switch dep.Status {
- case deps.StatusInstalled:
- status = m.styles.Success.Render("✓ Already Installed")
- case deps.StatusMissing:
- status = m.styles.Warning.Render("○ Will be installed")
- case deps.StatusNeedsUpdate:
- status = m.styles.Warning.Render("△ Needs update")
- case deps.StatusNeedsReinstall:
- status = m.styles.Error.Render("! Needs reinstall")
- }
- }
-
- var line string
- if i == m.selectedDep {
- line = fmt.Sprintf("▶ %s%s%-25s %s", reinstallMarker, variantMarker, dep.Name, status)
- if dep.Version != "" {
- line += fmt.Sprintf(" (%s)", dep.Version)
- }
- line = m.styles.SelectedOption.Render(line)
- } else {
- line = fmt.Sprintf(" %s%s%-25s %s", reinstallMarker, variantMarker, dep.Name, status)
- if dep.Version != "" {
- line += fmt.Sprintf(" (%s)", dep.Version)
- }
- line = m.styles.Normal.Render(line)
- }
-
- b.WriteString(line)
- b.WriteString("\n")
- }
- }
-
- b.WriteString("\n")
- help := m.styles.Subtle.Render("↑/↓: Navigate, Space: Toggle reinstall, G: Toggle stable/git, Enter: Continue")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) updateDetectingDepsState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if depsMsg, ok := msg.(depsDetectedMsg); ok {
- m.isLoading = false
- if depsMsg.err != nil {
- m.err = depsMsg.err
- m.state = StateError
- } else {
- m.dependencies = depsMsg.deps
- m.state = StateDependencyReview
- }
- return m, m.listenForLogs()
- }
- return m, m.listenForLogs()
-}
-
-func (m Model) updateDependencyReviewState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "up":
- if m.selectedDep > 0 {
- m.selectedDep--
- }
- case "down":
- if m.selectedDep < len(m.dependencies)-1 {
- m.selectedDep++
- }
- case " ":
- if len(m.dependencies) > 0 {
- depName := m.dependencies[m.selectedDep].Name
-
- if m.dependencies[m.selectedDep].Status == deps.StatusInstalled ||
- m.dependencies[m.selectedDep].Status == deps.StatusNeedsReinstall {
- m.reinstallItems[depName] = !m.reinstallItems[depName]
- }
- }
- case "g", "G":
- if len(m.dependencies) > 0 && m.dependencies[m.selectedDep].CanToggle {
- if m.dependencies[m.selectedDep].Variant == deps.VariantStable {
- m.dependencies[m.selectedDep].Variant = deps.VariantGit
- } else {
- m.dependencies[m.selectedDep].Variant = deps.VariantStable
- }
- }
- case "enter":
- // Check if fingerprint is enabled
- if checkFingerprintEnabled() {
- m.state = StateAuthMethodChoice
- m.selectedConfig = 0 // Default to fingerprint
- return m, nil
- } else {
- m.state = StatePasswordPrompt
- m.passwordInput.Focus()
- return m, nil
- }
- case "esc":
- m.state = StateSelectWindowManager
- return m, nil
- }
- }
- return m, m.listenForLogs()
-}
-
-func (m Model) installPackages() tea.Cmd {
- return func() tea.Msg {
- if m.osInfo == nil {
- return packageInstallProgressMsg{
- progress: 0.0,
- step: "Error: OS info not available",
- isComplete: true,
- }
- }
-
- installer, err := distros.NewPackageInstaller(m.osInfo.Distribution.ID, m.logChan)
- if err != nil {
- return packageInstallProgressMsg{
- progress: 0.0,
- step: fmt.Sprintf("Error: %s", err.Error()),
- isComplete: true,
- }
- }
-
- // Convert TUI selection to deps enum
- var wm deps.WindowManager
- if m.selectedWM == 0 {
- wm = deps.WindowManagerNiri
- } else {
- wm = deps.WindowManagerHyprland
- }
-
- installerProgressChan := make(chan distros.InstallProgressMsg, 100)
-
- go func() {
- defer close(installerProgressChan)
- err := installer.InstallPackages(context.Background(), m.dependencies, wm, m.sudoPassword, m.reinstallItems, installerProgressChan)
- if err != nil {
- installerProgressChan <- distros.InstallProgressMsg{
- Progress: 0.0,
- Step: fmt.Sprintf("Installation error: %s", err.Error()),
- IsComplete: true,
- Error: err,
- }
- }
- }()
-
- // Convert installer messages to TUI messages
- go func() {
- for msg := range installerProgressChan {
- tuiMsg := packageInstallProgressMsg{
- progress: msg.Progress,
- step: msg.Step,
- isComplete: msg.IsComplete,
- needsSudo: msg.NeedsSudo,
- commandInfo: msg.CommandInfo,
- logOutput: msg.LogOutput,
- error: msg.Error,
- }
- if msg.IsComplete {
- m.logChan <- fmt.Sprintf("[DEBUG] Sending completion signal: step=%s, progress=%.2f", msg.Step, msg.Progress)
- }
- m.packageProgressChan <- tuiMsg
- }
- m.logChan <- "[DEBUG] Installer channel closed"
- }()
-
- return packageInstallProgressMsg{
- progress: 0.05,
- step: "Starting installation...",
- isComplete: false,
- }
- }
-}
diff --git a/nix/inputs/dms-cli/internal/tui/views_install.go b/nix/inputs/dms-cli/internal/tui/views_install.go
deleted file mode 100644
index f3af334..0000000
--- a/nix/inputs/dms-cli/internal/tui/views_install.go
+++ /dev/null
@@ -1,265 +0,0 @@
-package tui
-
-import (
- "fmt"
- "strings"
-
- tea "github.com/charmbracelet/bubbletea"
-)
-
-// wrapText wraps text to the specified width
-func wrapText(text string, width int) string {
- if len(text) <= width {
- return text
- }
-
- var result strings.Builder
- words := strings.Fields(text)
- currentLine := ""
-
- for _, word := range words {
- if len(currentLine) == 0 {
- currentLine = word
- } else if len(currentLine)+1+len(word) <= width {
- currentLine += " " + word
- } else {
- result.WriteString(currentLine)
- result.WriteString("\n")
- currentLine = word
- }
- }
-
- if len(currentLine) > 0 {
- result.WriteString(currentLine)
- }
-
- return result.String()
-}
-
-func (m Model) viewInstallingPackages() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Installing Packages")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- if !m.packageProgress.isComplete {
- spinner := m.spinner.View()
- status := m.styles.Normal.Render(m.packageProgress.step)
- b.WriteString(fmt.Sprintf("%s %s", spinner, status))
- b.WriteString("\n\n")
-
- // Show progress bar
- progressBar := fmt.Sprintf("[%s%s] %.0f%%",
- strings.Repeat("█", int(m.packageProgress.progress*30)),
- strings.Repeat("░", 30-int(m.packageProgress.progress*30)),
- m.packageProgress.progress*100)
- b.WriteString(m.styles.Normal.Render(progressBar))
- b.WriteString("\n")
-
- // Show command info if available
- if m.packageProgress.commandInfo != "" {
- cmdInfo := m.styles.Subtle.Render("$ " + m.packageProgress.commandInfo)
- b.WriteString(cmdInfo)
- b.WriteString("\n")
- }
-
- // Show live log output
- if len(m.installationLogs) > 0 {
- b.WriteString("\n")
- logHeader := m.styles.Subtle.Render("Live Output:")
- b.WriteString(logHeader)
- b.WriteString("\n")
-
- // Show last few lines of accumulated logs
- maxLines := 8
- startIdx := 0
- if len(m.installationLogs) > maxLines {
- startIdx = len(m.installationLogs) - maxLines
- }
-
- for i := startIdx; i < len(m.installationLogs); i++ {
- if m.installationLogs[i] != "" {
- logLine := m.styles.Subtle.Render(" " + m.installationLogs[i])
- b.WriteString(logLine)
- b.WriteString("\n")
- }
- }
- }
-
- // Show error if any
- if m.packageProgress.error != nil {
- b.WriteString("\n")
- wrappedErrorMsg := wrapText("Error: "+m.packageProgress.error.Error(), 80)
- errorMsg := m.styles.Error.Render(wrappedErrorMsg)
- b.WriteString(errorMsg)
- }
-
- // Show sudo prompt if needed
- if m.packageProgress.needsSudo {
- sudoWarning := m.styles.Warning.Render("⚠ Using provided sudo password")
- b.WriteString(sudoWarning)
- }
- } else {
- if m.packageProgress.error != nil {
- wrappedFailedMsg := wrapText("✗ Installation failed: "+m.packageProgress.error.Error(), 80)
- errorMsg := m.styles.Error.Render(wrappedFailedMsg)
- b.WriteString(errorMsg)
- } else {
- success := m.styles.Success.Render("✓ Installation complete!")
- b.WriteString(success)
- }
- }
-
- return b.String()
-}
-
-func (m Model) viewInstallComplete() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Success.Render("Setup Complete!")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- success := m.styles.Success.Render("✓ All packages installed and configurations deployed.")
- b.WriteString(success)
- b.WriteString("\n\n")
-
- // Show what was accomplished
- accomplishments := []string{
- "• Window manager and dependencies installed",
- "• Terminal and development tools configured",
- "• Configuration files deployed with backups",
- "• System optimized for DankMaterialShell",
- }
-
- for _, item := range accomplishments {
- b.WriteString(m.styles.Subtle.Render(item))
- b.WriteString("\n")
- }
-
- b.WriteString("\n")
- info := m.styles.Normal.Render("Your system is ready! Log out and log back in to start using\nyour new desktop environment.\nIf you do not have a greeter, login with \"niri-session\" or \"Hyprland\" \n\nPress Enter to exit.")
- b.WriteString(info)
-
- return b.String()
-}
-
-func (m Model) viewError() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Error.Render("Installation Failed")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- if m.err != nil {
- wrappedError := wrapText("✗ "+m.err.Error(), 80)
- error := m.styles.Error.Render(wrappedError)
- b.WriteString(error)
- b.WriteString("\n\n")
- }
-
- // Show package progress error if available
- if m.packageProgress.error != nil {
- wrappedPackageError := wrapText("Package Installation Error: "+m.packageProgress.error.Error(), 80)
- packageError := m.styles.Error.Render(wrappedPackageError)
- b.WriteString(packageError)
- b.WriteString("\n\n")
- }
-
- // Show persistent installation logs
- if len(m.installationLogs) > 0 {
- logHeader := m.styles.Warning.Render("Installation Logs (last 15 lines):")
- b.WriteString(logHeader)
- b.WriteString("\n")
-
- maxLines := 15
- startIdx := 0
- if len(m.installationLogs) > maxLines {
- startIdx = len(m.installationLogs) - maxLines
- }
-
- for i := startIdx; i < len(m.installationLogs); i++ {
- if m.installationLogs[i] != "" {
- logLine := m.styles.Subtle.Render(" " + m.installationLogs[i])
- b.WriteString(logLine)
- b.WriteString("\n")
- }
- }
- b.WriteString("\n")
- }
-
- help := m.styles.Subtle.Render("Press Enter to exit")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) updateInstallingPackagesState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if progressMsg, ok := msg.(packageInstallProgressMsg); ok {
- m.packageProgress = progressMsg
-
- // Accumulate log output
- if progressMsg.logOutput != "" {
- m.installationLogs = append(m.installationLogs, progressMsg.logOutput)
- // Keep only last 50 lines to preserve more context for debugging
- if len(m.installationLogs) > 50 {
- m.installationLogs = m.installationLogs[len(m.installationLogs)-50:]
- }
- }
-
- if progressMsg.isComplete {
- if progressMsg.error != nil {
- m.state = StateError
- m.isLoading = false
- } else {
- m.installationLogs = []string{}
- m.state = StateConfigConfirmation
- m.isLoading = true
- return m, tea.Batch(m.spinner.Tick, m.checkExistingConfigurations())
- }
- }
- return m, m.listenForPackageProgress()
- }
- return m, m.listenForLogs()
-}
-
-func (m Model) updateInstallCompleteState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "enter":
- return m, tea.Quit
- }
- }
- return m, m.listenForLogs()
-}
-
-func (m Model) updateErrorState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "enter":
- return m, tea.Quit
- }
- }
- return m, m.listenForLogs()
-}
-
-func (m Model) listenForPackageProgress() tea.Cmd {
- return func() tea.Msg {
- msg, ok := <-m.packageProgressChan
- if !ok {
- return packageProgressCompletedMsg{}
- }
- // Always return the message, completion will be handled in updateInstallingPackagesState
- return msg
- }
-}
diff --git a/nix/inputs/dms-cli/internal/tui/views_nixos_wm.go b/nix/inputs/dms-cli/internal/tui/views_nixos_wm.go
deleted file mode 100644
index 16ecebd..0000000
--- a/nix/inputs/dms-cli/internal/tui/views_nixos_wm.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package tui
-
-import (
- "strings"
-
- tea "github.com/charmbracelet/bubbletea"
-)
-
-func (m Model) viewMissingWMInstructions() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n\n")
-
- // Determine which WM is missing
- wmName := "Niri"
- installCmd := `environment.systemPackages = with pkgs; [
- niri
-];`
- alternateCmd := `# Or enable the module if available:
-# programs.niri.enable = true;`
-
- if m.selectedWM == 1 {
- wmName = "Hyprland"
- installCmd = `programs.hyprland.enable = true;`
- alternateCmd = `# Or add to systemPackages:
-# environment.systemPackages = with pkgs; [
-# hyprland
-# ];`
- }
-
- // Title
- title := m.styles.Title.Render("⚠️ " + wmName + " Not Installed")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- // Explanation
- explanation := m.styles.Normal.Render(wmName + " needs to be installed system-wide on NixOS.")
- b.WriteString(explanation)
- b.WriteString("\n\n")
-
- // Instructions
- instructions := m.styles.Subtle.Render("To install " + wmName + ", add this to your /etc/nixos/configuration.nix:")
- b.WriteString(instructions)
- b.WriteString("\n\n")
-
- // Command box
- cmdBox := m.styles.CodeBlock.Render(installCmd)
- b.WriteString(cmdBox)
- b.WriteString("\n\n")
-
- // Alternate command
- altBox := m.styles.Subtle.Render(alternateCmd)
- b.WriteString(altBox)
- b.WriteString("\n\n")
-
- // Rebuild instruction
- rebuildInstruction := m.styles.Normal.Render("Then rebuild your system:")
- b.WriteString(rebuildInstruction)
- b.WriteString("\n")
-
- rebuildCmd := m.styles.CodeBlock.Render("sudo nixos-rebuild switch")
- b.WriteString(rebuildCmd)
- b.WriteString("\n\n")
-
- // Navigation help
- help := m.styles.Subtle.Render("Press Esc to go back and select a different window manager, or Ctrl+C to exit")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) updateMissingWMInstructionsState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "esc":
- // Go back to window manager selection
- m.state = StateSelectWindowManager
- return m, m.listenForLogs()
- case "ctrl+c":
- return m, tea.Quit
- }
- }
- return m, m.listenForLogs()
-}
diff --git a/nix/inputs/dms-cli/internal/tui/views_password.go b/nix/inputs/dms-cli/internal/tui/views_password.go
deleted file mode 100644
index 5f5c817..0000000
--- a/nix/inputs/dms-cli/internal/tui/views_password.go
+++ /dev/null
@@ -1,347 +0,0 @@
-package tui
-
-import (
- "context"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
- "time"
-
- tea "github.com/charmbracelet/bubbletea"
-)
-
-func (m Model) viewAuthMethodChoice() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Authentication Method")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- message := "Fingerprint authentication is available.\nHow would you like to authenticate?"
- b.WriteString(m.styles.Normal.Render(message))
- b.WriteString("\n\n")
-
- // Option 0: Fingerprint
- if m.selectedConfig == 0 {
- option := m.styles.SelectedOption.Render("▶ Use Fingerprint")
- b.WriteString(option)
- } else {
- option := m.styles.Normal.Render(" Use Fingerprint")
- b.WriteString(option)
- }
- b.WriteString("\n")
-
- // Option 1: Password
- if m.selectedConfig == 1 {
- option := m.styles.SelectedOption.Render("▶ Use Password")
- b.WriteString(option)
- } else {
- option := m.styles.Normal.Render(" Use Password")
- b.WriteString(option)
- }
- b.WriteString("\n\n")
-
- help := m.styles.Subtle.Render("↑/↓: Navigate, Enter: Select, Esc: Back")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) viewFingerprintAuth() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Fingerprint Authentication")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- if m.fingerprintFailed {
- errorMsg := m.styles.Error.Render("✗ Fingerprint authentication failed")
- b.WriteString(errorMsg)
- b.WriteString("\n")
- retryMsg := m.styles.Subtle.Render("Returning to authentication menu...")
- b.WriteString(retryMsg)
- } else {
- message := "Please place your finger on the fingerprint reader."
- b.WriteString(m.styles.Normal.Render(message))
- b.WriteString("\n\n")
-
- spinner := m.spinner.View()
- status := m.styles.Normal.Render("Waiting for fingerprint...")
- b.WriteString(fmt.Sprintf("%s %s", spinner, status))
- }
-
- return b.String()
-}
-
-func (m Model) viewPasswordPrompt() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Password Authentication")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- message := "Installation requires sudo privileges.\nPlease enter your password to continue:"
- b.WriteString(m.styles.Normal.Render(message))
- b.WriteString("\n\n")
-
- // Password input
- b.WriteString(m.passwordInput.View())
- b.WriteString("\n")
-
- // Show validation status
- if m.packageProgress.step == "Validating sudo password..." {
- spinner := m.spinner.View()
- status := m.styles.Normal.Render(m.packageProgress.step)
- b.WriteString(spinner + " " + status)
- b.WriteString("\n")
- } else if m.packageProgress.error != nil {
- errorMsg := m.styles.Error.Render("✗ " + m.packageProgress.error.Error() + ". Please try again.")
- b.WriteString(errorMsg)
- b.WriteString("\n")
- } else if m.packageProgress.step == "Password validation failed" {
- errorMsg := m.styles.Error.Render("✗ Incorrect password. Please try again.")
- b.WriteString(errorMsg)
- b.WriteString("\n")
- }
-
- b.WriteString("\n")
- help := m.styles.Subtle.Render("Enter: Continue, Esc: Back, Ctrl+C: Cancel")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) updateAuthMethodChoiceState(msg tea.Msg) (tea.Model, tea.Cmd) {
- m.fingerprintFailed = false
-
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "up":
- if m.selectedConfig > 0 {
- m.selectedConfig--
- }
- case "down":
- if m.selectedConfig < 1 {
- m.selectedConfig++
- }
- case "enter":
- if m.selectedConfig == 0 {
- m.state = StateFingerprintAuth
- m.isLoading = true
- return m, tea.Batch(m.spinner.Tick, m.tryFingerprint())
- } else {
- m.state = StatePasswordPrompt
- m.passwordInput.Focus()
- return m, nil
- }
- case "esc":
- m.state = StateDependencyReview
- return m, nil
- }
- }
- return m, nil
-}
-
-func (m Model) updateFingerprintAuthState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if validMsg, ok := msg.(passwordValidMsg); ok {
- if validMsg.valid {
- m.sudoPassword = ""
- m.packageProgress = packageInstallProgressMsg{}
- m.state = StateInstallingPackages
- m.isLoading = true
- return m, tea.Batch(m.spinner.Tick, m.installPackages())
- } else {
- m.fingerprintFailed = true
- return m, m.delayThenReturn()
- }
- }
-
- if _, ok := msg.(delayCompleteMsg); ok {
- m.fingerprintFailed = false
- m.selectedConfig = 0
- m.state = StateAuthMethodChoice
- return m, nil
- }
-
- return m, m.listenForLogs()
-}
-
-func (m Model) updatePasswordPromptState(msg tea.Msg) (tea.Model, tea.Cmd) {
- var cmd tea.Cmd
-
- if validMsg, ok := msg.(passwordValidMsg); ok {
- if validMsg.valid {
- // Password is valid, proceed with installation
- m.sudoPassword = validMsg.password
- m.passwordInput.SetValue("") // Clear password input
- // Clear any error state
- m.packageProgress = packageInstallProgressMsg{}
- m.state = StateInstallingPackages
- m.isLoading = true
- return m, tea.Batch(m.spinner.Tick, m.installPackages())
- } else {
- // Password is invalid, show error and stay on password prompt
- m.packageProgress = packageInstallProgressMsg{
- progress: 0.0,
- step: "Password validation failed",
- error: fmt.Errorf("incorrect password"),
- logOutput: "Authentication failed",
- }
- m.passwordInput.SetValue("")
- m.passwordInput.Focus()
- return m, nil
- }
- }
-
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "enter":
- // Don't allow multiple validation attempts while one is in progress
- if m.packageProgress.step == "Validating sudo password..." {
- return m, nil
- }
-
- // Validate password first
- password := m.passwordInput.Value()
- if password == "" {
- return m, nil // Don't proceed with empty password
- }
-
- // Clear any previous error and show validation in progress
- m.packageProgress = packageInstallProgressMsg{
- progress: 0.01,
- step: "Validating sudo password...",
- isComplete: false,
- logOutput: "Testing password with sudo -v",
- }
- return m, m.validatePassword(password)
- case "esc":
- // Go back to dependency review
- m.passwordInput.SetValue("")
- m.packageProgress = packageInstallProgressMsg{} // Clear any validation state
- m.state = StateDependencyReview
- return m, nil
- }
- }
-
- m.passwordInput, cmd = m.passwordInput.Update(msg)
- return m, cmd
-}
-
-func checkFingerprintEnabled() bool {
- ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
- defer cancel()
-
- // Check if pam_fprintd.so is in PAM config
- cmd := exec.CommandContext(ctx, "grep", "-q", "pam_fprintd.so", "/etc/pam.d/system-auth")
- if err := cmd.Run(); err != nil {
- return false
- }
-
- // Check if fprintd-list exists and user has enrolled fingerprints
- user := os.Getenv("USER")
- if user == "" {
- return false
- }
-
- listCmd := exec.CommandContext(ctx, "fprintd-list", user)
- output, err := listCmd.CombinedOutput()
- if err != nil {
- return false
- }
-
- // If output contains "finger:" or similar, fingerprints are enrolled
- return strings.Contains(string(output), "finger")
-}
-
-func checkSudoCached() bool {
- ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
- defer cancel()
-
- cmd := exec.CommandContext(ctx, "sudo", "-n", "true")
- err := cmd.Run()
- return err == nil
-}
-
-func (m Model) delayThenReturn() tea.Cmd {
- return func() tea.Msg {
- time.Sleep(2 * time.Second)
- return delayCompleteMsg{}
- }
-}
-
-func (m Model) tryFingerprint() tea.Cmd {
- return func() tea.Msg {
- clearCmd := exec.Command("sudo", "-k")
- clearCmd.Run()
-
- tmpDir := os.TempDir()
- askpassScript := filepath.Join(tmpDir, fmt.Sprintf("danklinux-fp-%d.sh", time.Now().UnixNano()))
-
- scriptContent := "#!/bin/sh\nexit 1\n"
- if err := os.WriteFile(askpassScript, []byte(scriptContent), 0700); err != nil {
- return passwordValidMsg{password: "", valid: false}
- }
- defer os.Remove(askpassScript)
-
- ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
- defer cancel()
-
- cmd := exec.CommandContext(ctx, "sudo", "-A", "-v")
- cmd.Env = append(os.Environ(), fmt.Sprintf("SUDO_ASKPASS=%s", askpassScript))
-
- err := cmd.Run()
-
- if err != nil {
- return passwordValidMsg{password: "", valid: false}
- }
-
- return passwordValidMsg{password: "", valid: true}
- }
-}
-
-func (m Model) validatePassword(password string) tea.Cmd {
- return func() tea.Msg {
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
- defer cancel()
-
- cmd := exec.CommandContext(ctx, "sudo", "-S", "-v")
-
- stdin, err := cmd.StdinPipe()
- if err != nil {
- return passwordValidMsg{password: "", valid: false}
- }
-
- if err := cmd.Start(); err != nil {
- return passwordValidMsg{password: "", valid: false}
- }
-
- _, err = fmt.Fprintf(stdin, "%s\n", password)
- stdin.Close()
- if err != nil {
- return passwordValidMsg{password: "", valid: false}
- }
-
- err = cmd.Wait()
-
- if err != nil {
- if ctx.Err() == context.DeadlineExceeded {
- return passwordValidMsg{password: "", valid: false}
- }
- return passwordValidMsg{password: "", valid: false}
- }
-
- return passwordValidMsg{password: password, valid: true}
- }
-}
diff --git a/nix/inputs/dms-cli/internal/tui/views_selection.go b/nix/inputs/dms-cli/internal/tui/views_selection.go
deleted file mode 100644
index 1f75df0..0000000
--- a/nix/inputs/dms-cli/internal/tui/views_selection.go
+++ /dev/null
@@ -1,216 +0,0 @@
-package tui
-
-import (
- "context"
- "fmt"
- "os/exec"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/deps"
- "github.com/AvengeMedia/danklinux/internal/distros"
- tea "github.com/charmbracelet/bubbletea"
-)
-
-func (m Model) viewSelectWindowManager() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Choose Window Manager")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- options := []struct {
- name string
- description string
- }{
- {"niri", "Scrollable-tiling Wayland compositor."},
- }
-
- if m.osInfo == nil || m.osInfo.Distribution.ID != "debian" {
- options = append(options, struct {
- name string
- description string
- }{"Hyprland", "Dynamic tiling Wayland compositor."})
- }
-
- for i, option := range options {
- if i == m.selectedWM {
- selected := m.styles.SelectedOption.Render("▶ " + option.name)
- b.WriteString(selected)
- b.WriteString("\n")
- desc := m.styles.Subtle.Render(" " + option.description)
- b.WriteString(desc)
- } else {
- normal := m.styles.Normal.Render(" " + option.name)
- b.WriteString(normal)
- b.WriteString("\n")
- desc := m.styles.Subtle.Render(" " + option.description)
- b.WriteString(desc)
- }
- b.WriteString("\n")
- if i < len(options)-1 {
- b.WriteString("\n")
- }
- }
-
- b.WriteString("\n")
- help := m.styles.Subtle.Render("Use ↑/↓ to navigate, Enter to select, Esc to go back")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) viewSelectTerminal() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Choose Terminal Emulator")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- options := []struct {
- name string
- description string
- }{
- {"ghostty", "A fast, native terminal emulator built in Zig."},
- {"kitty", "A feature-rich, customizable terminal emulator."},
- {"alacritty", "A simple terminal emulator."},
- }
-
- for i, option := range options {
- if i == m.selectedTerminal {
- selected := m.styles.SelectedOption.Render("▶ " + option.name)
- b.WriteString(selected)
- b.WriteString("\n")
- desc := m.styles.Subtle.Render(" " + option.description)
- b.WriteString(desc)
- } else {
- normal := m.styles.Normal.Render(" " + option.name)
- b.WriteString(normal)
- b.WriteString("\n")
- desc := m.styles.Subtle.Render(" " + option.description)
- b.WriteString(desc)
- }
- b.WriteString("\n")
- if i < len(options)-1 {
- b.WriteString("\n")
- }
- }
-
- b.WriteString("\n")
- help := m.styles.Subtle.Render("Use ↑/↓ to navigate, Enter to select, Esc to go back")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) updateSelectTerminalState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "up":
- if m.selectedTerminal > 0 {
- m.selectedTerminal--
- }
- case "down":
- if m.selectedTerminal < 2 {
- m.selectedTerminal++
- }
- case "enter":
- // On NixOS, check if the selected WM is actually installed
- if m.osInfo != nil && m.osInfo.Distribution.ID == "nixos" {
- var wmInstalled bool
- if m.selectedWM == 0 {
- wmInstalled = m.commandExists("niri")
- } else {
- wmInstalled = m.commandExists("hyprland") || m.commandExists("Hyprland")
- }
-
- if !wmInstalled {
- m.state = StateMissingWMInstructions
- return m, m.listenForLogs()
- }
- }
-
- m.state = StateDetectingDeps
- m.isLoading = true
- return m, tea.Batch(m.spinner.Tick, m.detectDependencies())
- case "esc":
- // Go back to window manager selection
- m.state = StateSelectWindowManager
- return m, m.listenForLogs()
- }
- }
- return m, m.listenForLogs()
-}
-
-func (m Model) updateSelectWindowManagerState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- maxWMIndex := 1
- if m.osInfo != nil && m.osInfo.Distribution.ID == "debian" {
- maxWMIndex = 0
- }
-
- switch keyMsg.String() {
- case "up":
- if m.selectedWM > 0 {
- m.selectedWM--
- }
- case "down":
- if m.selectedWM < maxWMIndex {
- m.selectedWM++
- }
- case "enter":
- m.state = StateSelectTerminal
- return m, m.listenForLogs()
- case "esc":
- // Go back to welcome screen
- m.state = StateWelcome
- return m, m.listenForLogs()
- }
- }
- return m, m.listenForLogs()
-}
-
-func (m Model) commandExists(cmd string) bool {
- _, err := exec.LookPath(cmd)
- return err == nil
-}
-
-func (m Model) detectDependencies() tea.Cmd {
- return func() tea.Msg {
- if m.osInfo == nil {
- return depsDetectedMsg{deps: nil, err: fmt.Errorf("OS info not available")}
- }
-
- detector, err := distros.NewDependencyDetector(m.osInfo.Distribution.ID, m.logChan)
- if err != nil {
- return depsDetectedMsg{deps: nil, err: err}
- }
-
- // Convert TUI selection to deps enum
- var wm deps.WindowManager
- if m.selectedWM == 0 {
- wm = deps.WindowManagerNiri // First option is Niri
- } else {
- wm = deps.WindowManagerHyprland // Second option is Hyprland
- }
-
- // Convert TUI terminal selection to deps enum
- var terminal deps.Terminal
- switch m.selectedTerminal {
- case 0:
- terminal = deps.TerminalGhostty
- case 1:
- terminal = deps.TerminalKitty
- default:
- terminal = deps.TerminalAlacritty
- }
-
- dependencies, err := detector.DetectDependenciesWithTerminal(context.Background(), wm, terminal)
- return depsDetectedMsg{deps: dependencies, err: err}
- }
-}
diff --git a/nix/inputs/dms-cli/internal/tui/views_welcome.go b/nix/inputs/dms-cli/internal/tui/views_welcome.go
deleted file mode 100644
index 549ea97..0000000
--- a/nix/inputs/dms-cli/internal/tui/views_welcome.go
+++ /dev/null
@@ -1,216 +0,0 @@
-package tui
-
-import (
- "fmt"
- "strings"
-
- "github.com/AvengeMedia/danklinux/internal/distros"
- tea "github.com/charmbracelet/bubbletea"
- "github.com/charmbracelet/lipgloss"
-)
-
-func (m Model) viewWelcome() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- theme := TerminalTheme()
-
- decorator := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Accent)).
- Render("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
-
- titleBox := lipgloss.NewStyle().
- Border(lipgloss.RoundedBorder()).
- BorderForeground(lipgloss.Color(theme.Primary)).
- Padding(0, 2).
- MarginBottom(1)
-
- titleText := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)).
- Bold(true).
- Render("dankinstall")
-
- versionTag := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Accent)).
- Italic(true).
- Render(" // Dank Linux Installer")
-
- subtitle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Subtle)).
- Italic(true).
- Render("Quickstart for a Dank™ Desktop")
-
- b.WriteString(decorator)
- b.WriteString("\n")
- b.WriteString(titleBox.Render(titleText + versionTag))
- b.WriteString("\n")
- b.WriteString(subtitle)
- b.WriteString("\n\n")
-
- if m.osInfo != nil {
- if distros.IsUnsupportedDistro(m.osInfo.Distribution.ID, m.osInfo.VersionID) {
- errorBox := lipgloss.NewStyle().
- Border(lipgloss.RoundedBorder()).
- BorderForeground(lipgloss.Color("#FF6B6B")).
- Padding(1, 2).
- MarginBottom(1)
-
- errorTitle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FF6B6B")).
- Bold(true).
- Render("⚠ UNSUPPORTED DISTRIBUTION")
-
- var errorMsg string
- switch m.osInfo.Distribution.ID {
- case "ubuntu":
- errorMsg = fmt.Sprintf("Ubuntu %s is not supported.\n\nOnly Ubuntu 25.04+ is supported.\n\nPlease upgrade to Ubuntu 25.04 or later.", m.osInfo.VersionID)
- case "debian":
- errorMsg = fmt.Sprintf("Debian %s is not supported.\n\nOnly Debian 13+ (Trixie) is supported.\n\nPlease upgrade to Debian 13 or later.", m.osInfo.VersionID)
- case "nixos":
- errorMsg = "NixOS is currently not supported, but there is a DankMaterialShell flake available."
- default:
- errorMsg = fmt.Sprintf("%s is not supported.\nFeel free to request on https://github.com/AvengeMedia/danklinux", m.osInfo.PrettyName)
- }
-
- errorMsgStyled := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Text)).
- Render(errorMsg)
-
- b.WriteString(errorBox.Render(errorTitle + "\n\n" + errorMsgStyled))
- b.WriteString("\n\n")
- } else {
- // System info box
- sysBox := lipgloss.NewStyle().
- Border(lipgloss.NormalBorder()).
- BorderForeground(lipgloss.Color(theme.Subtle)).
- Padding(0, 1).
- MarginBottom(1)
-
- // Style the distro name with its color
- distroStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(m.osInfo.Distribution.HexColorCode)).
- Bold(true)
- distroName := distroStyle.Render(m.osInfo.PrettyName)
-
- archStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Accent))
-
- sysInfo := fmt.Sprintf("System: %s / %s", distroName, archStyle.Render(m.osInfo.Architecture))
- b.WriteString(sysBox.Render(sysInfo))
- b.WriteString("\n")
-
- // Feature list with better styling
- featTitle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)).
- Bold(true).
- Underline(true).
- Render("WHAT YOU GET")
- b.WriteString(featTitle + "\n\n")
-
- features := []string{
- "[shell] dms (DankMaterialShell)",
- "[wm] niri or Hyprland",
- "[term] Ghostty, kitty, or Alacritty",
- "[style] All the themes, automatically.",
- "[config] DANK defaults - keybindings, rules, animations, etc.",
- }
-
- for i, feat := range features {
- prefix := feat[:9]
- content := feat[10:]
-
- prefixStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Accent)).
- Bold(true)
-
- contentStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Text))
-
- if i == len(features)-1 {
- contentStyle = contentStyle.Bold(true)
- }
-
- b.WriteString(fmt.Sprintf(" %s %s\n",
- prefixStyle.Render(prefix),
- contentStyle.Render(content)))
- }
-
- b.WriteString("\n")
-
- noteStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Subtle)).
- Italic(true)
- note := noteStyle.Render("* Existing configs can be replaced (and backed up) or preserved")
- b.WriteString(note)
- b.WriteString("\n")
-
- if m.osInfo.Distribution.ID == "gentoo" {
- gentooNote := noteStyle.Render("* Will set per-package USE flags and unmask testing packages as needed")
- b.WriteString(gentooNote)
- b.WriteString("\n")
- }
-
- b.WriteString("\n")
- }
-
- } else if m.isLoading {
- spinner := m.spinner.View()
- loading := m.styles.Normal.Render("Detecting system...")
- b.WriteString(fmt.Sprintf("%s %s\n\n", spinner, loading))
- }
-
- // Footer with better visual separation
- footerDivider := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Subtle)).
- Render("───────────────────────────────────────────────────────────")
- b.WriteString(footerDivider + "\n")
-
- if m.osInfo != nil {
- ctrlKey := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)).
- Bold(true).
- Render("Ctrl+C")
-
- if distros.IsUnsupportedDistro(m.osInfo.Distribution.ID, m.osInfo.VersionID) {
- b.WriteString(m.styles.Subtle.Render("Press ") + ctrlKey + m.styles.Subtle.Render(" to quit"))
- } else {
- enterKey := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)).
- Bold(true).
- Render("Enter")
-
- b.WriteString(m.styles.Subtle.Render("Press ") + enterKey + m.styles.Subtle.Render(" to choose window manager, ") + ctrlKey + m.styles.Subtle.Render(" to quit"))
- }
- } else {
- help := m.styles.Subtle.Render("Press Enter to continue, Ctrl+C to quit")
- b.WriteString(help)
- }
-
- return b.String()
-}
-
-func (m Model) updateWelcomeState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if completeMsg, ok := msg.(osInfoCompleteMsg); ok {
- m.isLoading = false
- if completeMsg.err != nil {
- m.err = completeMsg.err
- m.state = StateError
- } else {
- m.osInfo = completeMsg.info
- }
- return m, m.listenForLogs()
- }
-
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "enter":
- if m.osInfo != nil && !distros.IsUnsupportedDistro(m.osInfo.Distribution.ID, m.osInfo.VersionID) {
- m.state = StateSelectWindowManager
- return m, m.listenForLogs()
- }
- }
- }
- return m, m.listenForLogs()
-}
diff --git a/nix/inputs/dms-cli/internal/utils/math.go b/nix/inputs/dms-cli/internal/utils/math.go
deleted file mode 100644
index 408af9f..0000000
--- a/nix/inputs/dms-cli/internal/utils/math.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package utils
-
-import "golang.org/x/exp/constraints"
-
-func Clamp[T constraints.Ordered](val, min, max T) T {
- if val < min {
- return min
- }
- if val > max {
- return max
- }
- return val
-}
diff --git a/nix/inputs/dms-cli/internal/version/version.go b/nix/inputs/dms-cli/internal/version/version.go
deleted file mode 100644
index 831f1ff..0000000
--- a/nix/inputs/dms-cli/internal/version/version.go
+++ /dev/null
@@ -1,221 +0,0 @@
-package version
-
-import (
- "encoding/json"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
-)
-
-type VersionInfo struct {
- Current string
- Latest string
- IsGit bool
- IsBranch bool
- IsTag bool
- HasUpdate bool
-}
-
-func GetCurrentDMSVersion() (string, error) {
- homeDir, err := os.UserHomeDir()
- if err != nil {
- return "", fmt.Errorf("failed to get home directory: %w", err)
- }
-
- dmsPath := filepath.Join(homeDir, ".config", "quickshell", "dms")
- if _, err := os.Stat(dmsPath); os.IsNotExist(err) {
- return "", fmt.Errorf("DMS not installed")
- }
-
- originalDir, err := os.Getwd()
- if err != nil {
- return "", err
- }
- defer os.Chdir(originalDir)
-
- if err := os.Chdir(dmsPath); err != nil {
- return "", fmt.Errorf("failed to change to DMS directory: %w", err)
- }
-
- if _, err := os.Stat(filepath.Join(dmsPath, ".git")); err == nil {
- tagCmd := exec.Command("git", "describe", "--exact-match", "--tags", "HEAD")
- if tagOutput, err := tagCmd.Output(); err == nil {
- return strings.TrimSpace(string(tagOutput)), nil
- }
-
- branchCmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD")
- if branchOutput, err := branchCmd.Output(); err == nil {
- branch := strings.TrimSpace(string(branchOutput))
- revCmd := exec.Command("git", "rev-parse", "--short", "HEAD")
- if revOutput, err := revCmd.Output(); err == nil {
- rev := strings.TrimSpace(string(revOutput))
- return fmt.Sprintf("%s@%s", branch, rev), nil
- }
- return branch, nil
- }
- }
-
- cmd := exec.Command("dms", "--version")
- if output, err := cmd.Output(); err == nil {
- return strings.TrimSpace(string(output)), nil
- }
-
- return "unknown", nil
-}
-
-func GetLatestDMSVersion() (string, error) {
- homeDir, err := os.UserHomeDir()
- if err != nil {
- return "", fmt.Errorf("failed to get home directory: %w", err)
- }
-
- dmsPath := filepath.Join(homeDir, ".config", "quickshell", "dms")
-
- originalDir, err := os.Getwd()
- if err != nil {
- return "", err
- }
- defer os.Chdir(originalDir)
-
- if _, err := os.Stat(filepath.Join(dmsPath, ".git")); err == nil {
- if err := os.Chdir(dmsPath); err != nil {
- return "", fmt.Errorf("failed to change to DMS directory: %w", err)
- }
-
- currentRefCmd := exec.Command("git", "symbolic-ref", "-q", "HEAD")
- currentRefOutput, _ := currentRefCmd.Output()
- onBranch := len(currentRefOutput) > 0
-
- if !onBranch {
- tagCmd := exec.Command("git", "describe", "--exact-match", "--tags", "HEAD")
- if _, err := tagCmd.Output(); err == nil {
- // Add timeout to git fetch to prevent hanging
- fetchCmd := exec.Command("timeout", "5s", "git", "fetch", "origin", "--tags", "--quiet")
- fetchCmd.Run()
-
- latestTagCmd := exec.Command("git", "tag", "-l", "v0.1.*", "--sort=-version:refname")
- latestTagOutput, err := latestTagCmd.Output()
- if err != nil {
- return "", fmt.Errorf("failed to get latest tag: %w", err)
- }
-
- tags := strings.Split(strings.TrimSpace(string(latestTagOutput)), "\n")
- if len(tags) == 0 || tags[0] == "" {
- return "", fmt.Errorf("no v0.1.* tags found")
- }
- return tags[0], nil
- }
- } else {
- branchCmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD")
- branchOutput, err := branchCmd.Output()
- if err != nil {
- return "", fmt.Errorf("failed to get current branch: %w", err)
- }
- currentBranch := strings.TrimSpace(string(branchOutput))
-
- // Add timeout to git fetch to prevent hanging
- fetchCmd := exec.Command("timeout", "5s", "git", "fetch", "origin", currentBranch, "--quiet")
- fetchCmd.Run()
-
- remoteRevCmd := exec.Command("git", "rev-parse", "--short", fmt.Sprintf("origin/%s", currentBranch))
- remoteRevOutput, err := remoteRevCmd.Output()
- if err != nil {
- return "", fmt.Errorf("failed to get remote revision: %w", err)
- }
- remoteRev := strings.TrimSpace(string(remoteRevOutput))
- return fmt.Sprintf("%s@%s", currentBranch, remoteRev), nil
- }
- }
-
- // Add timeout to prevent hanging when GitHub is down
- cmd := exec.Command("curl", "-s", "--max-time", "5", "https://api.github.com/repos/AvengeMedia/danklinux/releases/latest")
- output, err := cmd.Output()
- if err != nil {
- return "", fmt.Errorf("failed to fetch latest release: %w", err)
- }
-
- var result struct {
- TagName string `json:"tag_name"`
- }
- if err := json.Unmarshal(output, &result); err != nil {
- for _, line := range strings.Split(string(output), "\n") {
- if strings.Contains(line, "\"tag_name\"") {
- parts := strings.Split(line, "\"")
- if len(parts) >= 4 {
- return parts[3], nil
- }
- }
- }
- return "", fmt.Errorf("failed to parse latest version: %w", err)
- }
-
- return result.TagName, nil
-}
-
-func GetDMSVersionInfo() (*VersionInfo, error) {
- current, err := GetCurrentDMSVersion()
- if err != nil {
- return nil, err
- }
-
- latest, err := GetLatestDMSVersion()
- if err != nil {
- return nil, fmt.Errorf("failed to get latest version: %w", err)
- }
-
- info := &VersionInfo{
- Current: current,
- Latest: latest,
- IsGit: strings.Contains(current, "@"),
- IsBranch: strings.Contains(current, "@"),
- IsTag: !strings.Contains(current, "@") && strings.HasPrefix(current, "v"),
- }
-
- if info.IsBranch {
- parts := strings.Split(current, "@")
- latestParts := strings.Split(latest, "@")
- if len(parts) == 2 && len(latestParts) == 2 {
- info.HasUpdate = parts[1] != latestParts[1]
- }
- } else if info.IsTag {
- info.HasUpdate = current != latest
- } else {
- info.HasUpdate = false
- }
-
- return info, nil
-}
-
-func CompareVersions(v1, v2 string) int {
- v1 = strings.TrimPrefix(v1, "v")
- v2 = strings.TrimPrefix(v2, "v")
-
- parts1 := strings.Split(v1, ".")
- parts2 := strings.Split(v2, ".")
-
- maxLen := len(parts1)
- if len(parts2) > maxLen {
- maxLen = len(parts2)
- }
-
- for i := 0; i < maxLen; i++ {
- var p1, p2 int
- if i < len(parts1) {
- fmt.Sscanf(parts1[i], "%d", &p1)
- }
- if i < len(parts2) {
- fmt.Sscanf(parts2[i], "%d", &p2)
- }
-
- if p1 < p2 {
- return -1
- }
- if p1 > p2 {
- return 1
- }
- }
-
- return 0
-}
diff --git a/nix/inputs/dms-cli/internal/version/version_test.go b/nix/inputs/dms-cli/internal/version/version_test.go
deleted file mode 100644
index 08b123a..0000000
--- a/nix/inputs/dms-cli/internal/version/version_test.go
+++ /dev/null
@@ -1,293 +0,0 @@
-package version
-
-import (
- "os"
- "os/exec"
- "path/filepath"
- "testing"
-)
-
-func TestCompareVersions(t *testing.T) {
- tests := []struct {
- v1 string
- v2 string
- expected int
- }{
- {"v0.1.0", "v0.1.0", 0},
- {"v0.1.0", "v0.1.1", -1},
- {"v0.1.1", "v0.1.0", 1},
- {"v0.1.10", "v0.1.2", 1},
- {"v0.2.0", "v0.1.9", 1},
- {"0.1.0", "0.1.0", 0},
- {"1.0.0", "v1.0.0", 0},
- {"v1.2.3", "v1.2.4", -1},
- {"v2.0.0", "v1.9.9", 1},
- }
-
- for _, tt := range tests {
- result := CompareVersions(tt.v1, tt.v2)
- if result != tt.expected {
- t.Errorf("CompareVersions(%q, %q) = %d; want %d", tt.v1, tt.v2, result, tt.expected)
- }
- }
-}
-
-func TestGetDMSVersionInfo_Structure(t *testing.T) {
- homeDir, err := os.UserHomeDir()
- if err != nil {
- t.Skip("Cannot get home directory")
- }
-
- dmsPath := filepath.Join(homeDir, ".config", "quickshell", "dms")
- if _, err := os.Stat(dmsPath); os.IsNotExist(err) {
- t.Skip("DMS not installed, skipping version info test")
- }
-
- info, err := GetDMSVersionInfo()
- if err != nil {
- t.Fatalf("GetDMSVersionInfo() failed: %v", err)
- }
-
- if info == nil {
- t.Fatal("GetDMSVersionInfo() returned nil")
- }
-
- if info.Current == "" {
- t.Error("Current version is empty")
- }
-
- if info.Latest == "" {
- t.Error("Latest version is empty")
- }
-
- t.Logf("Current: %s, Latest: %s, HasUpdate: %v", info.Current, info.Latest, info.HasUpdate)
-}
-
-func TestGetCurrentDMSVersion_NotInstalled(t *testing.T) {
- originalHome := os.Getenv("HOME")
- defer os.Setenv("HOME", originalHome)
-
- tempDir := t.TempDir()
- os.Setenv("HOME", tempDir)
-
- _, err := GetCurrentDMSVersion()
- if err == nil {
- t.Error("Expected error when DMS not installed, got nil")
- }
-}
-
-func TestGetCurrentDMSVersion_GitTag(t *testing.T) {
- if !commandExists("git") {
- t.Skip("git not available")
- }
-
- tempDir := t.TempDir()
- dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms")
- os.MkdirAll(dmsPath, 0755)
-
- originalHome := os.Getenv("HOME")
- defer os.Setenv("HOME", originalHome)
- os.Setenv("HOME", tempDir)
-
- exec.Command("git", "init", dmsPath).Run()
- exec.Command("git", "-C", dmsPath, "config", "user.email", "test@test.com").Run()
- exec.Command("git", "-C", dmsPath, "config", "user.name", "Test User").Run()
-
- testFile := filepath.Join(dmsPath, "test.txt")
- os.WriteFile(testFile, []byte("test"), 0644)
- exec.Command("git", "-C", dmsPath, "add", ".").Run()
- exec.Command("git", "-C", dmsPath, "commit", "-m", "initial").Run()
- exec.Command("git", "-C", dmsPath, "tag", "v0.1.0").Run()
-
- version, err := GetCurrentDMSVersion()
- if err != nil {
- t.Fatalf("GetCurrentDMSVersion() failed: %v", err)
- }
-
- if version != "v0.1.0" {
- t.Errorf("Expected version v0.1.0, got %s", version)
- }
-}
-
-func TestGetCurrentDMSVersion_GitBranch(t *testing.T) {
- if !commandExists("git") {
- t.Skip("git not available")
- }
-
- tempDir := t.TempDir()
- dmsPath := filepath.Join(tempDir, ".config", "quickshell", "dms")
- os.MkdirAll(dmsPath, 0755)
-
- originalHome := os.Getenv("HOME")
- defer os.Setenv("HOME", originalHome)
- os.Setenv("HOME", tempDir)
-
- exec.Command("git", "init", dmsPath).Run()
- exec.Command("git", "-C", dmsPath, "config", "user.email", "test@test.com").Run()
- exec.Command("git", "-C", dmsPath, "config", "user.name", "Test User").Run()
- exec.Command("git", "-C", dmsPath, "checkout", "-b", "master").Run()
-
- testFile := filepath.Join(dmsPath, "test.txt")
- os.WriteFile(testFile, []byte("test"), 0644)
- exec.Command("git", "-C", dmsPath, "add", ".").Run()
- exec.Command("git", "-C", dmsPath, "commit", "-m", "initial").Run()
-
- version, err := GetCurrentDMSVersion()
- if err != nil {
- t.Fatalf("GetCurrentDMSVersion() failed: %v", err)
- }
-
- if version == "" {
- t.Error("Expected non-empty version")
- }
-
- if len(version) < 7 {
- t.Errorf("Expected version with branch@commit format, got %s", version)
- }
-}
-
-func TestVersionInfo_IsGit(t *testing.T) {
- tests := []struct {
- current string
- isGit bool
- isBranch bool
- isTag bool
- }{
- {"v0.1.0", false, false, true},
- {"master@abc1234", true, true, false},
- {"dev@def5678", true, true, false},
- {"v0.2.0", false, false, true},
- {"unknown", false, false, false},
- }
-
- for _, tt := range tests {
- info := &VersionInfo{
- IsGit: tt.isGit,
- IsBranch: tt.isBranch,
- IsTag: tt.isTag,
- }
-
- actualIsGit := len(tt.current) > 0 && tt.current[0] != 'v' && tt.current != "unknown"
- actualIsBranch := len(tt.current) > 0 && tt.current[0] != 'v'
- actualIsTag := len(tt.current) > 0 && tt.current[0] == 'v'
-
- if tt.current == "unknown" {
- actualIsGit = false
- actualIsBranch = false
- actualIsTag = false
- }
-
- if info.IsGit != tt.isGit {
- t.Errorf("For %s: IsGit = %v; want %v", tt.current, info.IsGit, tt.isGit)
- }
- if info.IsBranch != tt.isBranch {
- t.Errorf("For %s: IsBranch = %v; want %v", tt.current, info.IsBranch, tt.isBranch)
- }
- if info.IsTag != tt.isTag {
- t.Errorf("For %s: IsTag = %v; want %v", tt.current, info.IsTag, tt.isTag)
- }
-
- _ = actualIsGit
- _ = actualIsBranch
- _ = actualIsTag
- }
-}
-
-func TestVersionInfo_HasUpdate_Branch(t *testing.T) {
- tests := []struct {
- current string
- latest string
- hasUpdate bool
- }{
- {"master@abc1234", "master@abc1234", false},
- {"master@abc1234", "master@def5678", true},
- {"dev@abc1234", "dev@abc1234", false},
- {"dev@old1234", "dev@new5678", true},
- }
-
- for _, tt := range tests {
- info := &VersionInfo{
- HasUpdate: tt.hasUpdate,
- }
-
- if info.HasUpdate != tt.hasUpdate {
- t.Errorf("For current=%s, latest=%s: HasUpdate = %v; want %v",
- tt.current, tt.latest, info.HasUpdate, tt.hasUpdate)
- }
- }
-}
-
-func TestVersionInfo_HasUpdate_Tag(t *testing.T) {
- tests := []struct {
- current string
- latest string
- hasUpdate bool
- }{
- {"v0.1.0", "v0.1.0", false},
- {"v0.1.0", "v0.1.1", true},
- {"v0.1.5", "v0.1.5", false},
- {"v0.1.9", "v0.2.0", true},
- }
-
- for _, tt := range tests {
- info := &VersionInfo{
- HasUpdate: tt.hasUpdate,
- }
-
- if info.HasUpdate != tt.hasUpdate {
- t.Errorf("For current=%s, latest=%s: HasUpdate = %v; want %v",
- tt.current, tt.latest, info.HasUpdate, tt.hasUpdate)
- }
- }
-}
-
-func commandExists(cmd string) bool {
- _, err := exec.LookPath(cmd)
- return err == nil
-}
-
-func TestGetLatestDMSVersion_FallbackParsing(t *testing.T) {
- jsonResponse := `{
- "tag_name": "v0.1.17",
- "name": "Release v0.1.17"
- }`
-
- lines := []string{
- ` "tag_name": "v0.1.17",`,
- ` "name": "Release v0.1.17"`,
- }
-
- for _, line := range lines {
- if len(line) > 0 && line[0:15] == ` "tag_name": "` {
- parts := []string{"", "", "", "v0.1.17"}
- version := parts[3]
- if version != "v0.1.17" {
- t.Errorf("Failed to parse version from line: %s", line)
- }
- }
- }
-
- _ = jsonResponse
-}
-
-func TestCompareVersions_EdgeCases(t *testing.T) {
- tests := []struct {
- v1 string
- v2 string
- expected int
- }{
- {"", "", 0},
- {"v1", "v1", 0},
- {"v1.0", "v1", 0},
- {"v1.0.0", "v1.0", 0},
- {"v1.0.1", "v1.0", 1},
- {"v1", "v1.0.1", -1},
- }
-
- for _, tt := range tests {
- result := CompareVersions(tt.v1, tt.v2)
- if result != tt.expected {
- t.Errorf("CompareVersions(%q, %q) = %d; want %d", tt.v1, tt.v2, result, tt.expected)
- }
- }
-}
diff --git a/nix/inputs/dms-cli/pkg/ipp/CREDITS.MD b/nix/inputs/dms-cli/pkg/ipp/CREDITS.MD
deleted file mode 100644
index b7d28cc..0000000
--- a/nix/inputs/dms-cli/pkg/ipp/CREDITS.MD
+++ /dev/null
@@ -1,5 +0,0 @@
-# Credits
-
-* Original socket adapter code is mostly taken from [korylprince/printer-manager-cups](https://github.com/korylprince/printer-manager-cups)
-([MIT](https://github.com/korylprince/printer-manager-cups/blob/v1.0.9/LICENSE) licensed):
-[conn.go](https://github.com/korylprince/printer-manager-cups/blob/v1.0.9/cups/conn.go)
diff --git a/nix/inputs/dms-cli/pkg/ipp/LICENSE b/nix/inputs/dms-cli/pkg/ipp/LICENSE
deleted file mode 100644
index 261eeb9..0000000
--- a/nix/inputs/dms-cli/pkg/ipp/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/nix/inputs/dms-cli/pkg/ipp/adapter-http.go b/nix/inputs/dms-cli/pkg/ipp/adapter-http.go
deleted file mode 100644
index 0862808..0000000
--- a/nix/inputs/dms-cli/pkg/ipp/adapter-http.go
+++ /dev/null
@@ -1,132 +0,0 @@
-package ipp
-
-import (
- "bytes"
- "crypto/tls"
- "fmt"
- "io"
- "net"
- "net/http"
- "strconv"
- "time"
-)
-
-type HttpAdapter struct {
- host string
- port int
- username string
- password string
- useTLS bool
- client *http.Client
-}
-
-func NewHttpAdapter(host string, port int, username, password string, useTLS bool) *HttpAdapter {
- httpClient := http.Client{
- Timeout: 0,
- Transport: &http.Transport{
- TLSClientConfig: &tls.Config{
- InsecureSkipVerify: true,
- },
- ResponseHeaderTimeout: 90 * time.Second,
- IdleConnTimeout: 120 * time.Second,
- },
- }
-
- return &HttpAdapter{
- host: host,
- port: port,
- username: username,
- password: password,
- useTLS: useTLS,
- client: &httpClient,
- }
-}
-
-func (h *HttpAdapter) SendRequest(url string, req *Request, additionalResponseData io.Writer) (*Response, error) {
- payload, err := req.Encode()
- if err != nil {
- return nil, err
- }
-
- size := len(payload)
- var body io.Reader
- if req.File != nil && req.FileSize != -1 {
- size += req.FileSize
- body = io.MultiReader(bytes.NewBuffer(payload), req.File)
- } else {
- body = bytes.NewBuffer(payload)
- }
-
- httpReq, err := http.NewRequest("POST", url, body)
- if err != nil {
- return nil, err
- }
-
- httpReq.Header.Set("Content-Length", strconv.Itoa(size))
- httpReq.Header.Set("Content-Type", ContentTypeIPP)
-
- if h.username != "" && h.password != "" {
- httpReq.SetBasicAuth(h.username, h.password)
- }
-
- httpResp, err := h.client.Do(httpReq)
- if err != nil {
- return nil, err
- }
- defer httpResp.Body.Close()
-
- if httpResp.StatusCode != 200 {
- return nil, HTTPError{
- Code: httpResp.StatusCode,
- }
- }
-
- // buffer response to avoid read issues
- buf := new(bytes.Buffer)
- if httpResp.ContentLength > 0 {
- buf.Grow(int(httpResp.ContentLength))
- }
- if _, err := io.Copy(buf, httpResp.Body); err != nil {
- return nil, fmt.Errorf("unable to buffer response: %w", err)
- }
-
- ippResp, err := NewResponseDecoder(buf).Decode(additionalResponseData)
- if err != nil {
- return nil, err
- }
-
- if err = ippResp.CheckForErrors(); err != nil {
- return nil, fmt.Errorf("received error IPP response: %w", err)
- }
-
- return ippResp, nil
-}
-
-func (h *HttpAdapter) GetHttpUri(namespace string, object interface{}) string {
- proto := "http"
- if h.useTLS {
- proto = "https"
- }
-
- uri := fmt.Sprintf("%s://%s:%d", proto, h.host, h.port)
-
- if namespace != "" {
- uri = fmt.Sprintf("%s/%s", uri, namespace)
- }
-
- if object != nil {
- uri = fmt.Sprintf("%s/%v", uri, object)
- }
-
- return uri
-}
-
-func (h *HttpAdapter) TestConnection() error {
- conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", h.host, h.port))
- if err != nil {
- return err
- }
- conn.Close()
-
- return nil
-}
diff --git a/nix/inputs/dms-cli/pkg/ipp/adapter.go b/nix/inputs/dms-cli/pkg/ipp/adapter.go
deleted file mode 100644
index 15ad2d0..0000000
--- a/nix/inputs/dms-cli/pkg/ipp/adapter.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package ipp
-
-import "io"
-
-type Adapter interface {
- SendRequest(url string, req *Request, additionalResponseData io.Writer) (*Response, error)
- GetHttpUri(namespace string, object interface{}) string
- TestConnection() error
-}
diff --git a/nix/inputs/dms-cli/pkg/ipp/attribute.go b/nix/inputs/dms-cli/pkg/ipp/attribute.go
deleted file mode 100644
index a9b4ba7..0000000
--- a/nix/inputs/dms-cli/pkg/ipp/attribute.go
+++ /dev/null
@@ -1,528 +0,0 @@
-package ipp
-
-import (
- "encoding/binary"
- "fmt"
- "io"
-)
-
-const (
- sizeInteger = int16(4)
- sizeBoolean = int16(1)
-)
-
-// AttributeEncoder encodes attribute to a io.Writer
-type AttributeEncoder struct {
- writer io.Writer
-}
-
-// NewAttributeEncoder returns a new encoder that writes to w
-func NewAttributeEncoder(w io.Writer) *AttributeEncoder {
- return &AttributeEncoder{w}
-}
-
-// Encode encodes a attribute and its value to a io.Writer
-// the tag is determined by the AttributeTagMapping map
-func (e *AttributeEncoder) Encode(attribute string, value interface{}) error {
- tag, ok := AttributeTagMapping[attribute]
- if !ok {
- return fmt.Errorf("cannot get tag of attribute %s", attribute)
- }
-
- switch v := value.(type) {
- case int:
- if tag != TagInteger && tag != TagEnum {
- return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
- }
-
- if err := e.encodeTag(tag); err != nil {
- return err
- }
-
- if err := e.encodeString(attribute); err != nil {
- return err
- }
-
- if err := e.encodeInteger(int32(v)); err != nil {
- return err
- }
- case int16:
- if tag != TagInteger && tag != TagEnum {
- return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
- }
-
- if err := e.encodeTag(tag); err != nil {
- return err
- }
-
- if err := e.encodeString(attribute); err != nil {
- return err
- }
-
- if err := e.encodeInteger(int32(v)); err != nil {
- return err
- }
- case int8:
- if tag != TagInteger && tag != TagEnum {
- return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
- }
-
- if err := e.encodeTag(tag); err != nil {
- return err
- }
-
- if err := e.encodeString(attribute); err != nil {
- return err
- }
-
- if err := e.encodeInteger(int32(v)); err != nil {
- return err
- }
- case int32:
- if tag != TagInteger && tag != TagEnum {
- return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
- }
-
- if err := e.encodeTag(tag); err != nil {
- return err
- }
-
- if err := e.encodeString(attribute); err != nil {
- return err
- }
-
- if err := e.encodeInteger(v); err != nil {
- return err
- }
- case int64:
- if tag != TagInteger && tag != TagEnum {
- return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
- }
-
- if err := e.encodeTag(tag); err != nil {
- return err
- }
-
- if err := e.encodeString(attribute); err != nil {
- return err
- }
-
- if err := e.encodeInteger(int32(v)); err != nil {
- return err
- }
- case []int:
- if tag != TagInteger && tag != TagEnum {
- return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
- }
-
- for index, val := range v {
- if err := e.encodeTag(tag); err != nil {
- return err
- }
-
- if index == 0 {
- if err := e.encodeString(attribute); err != nil {
- return err
- }
- } else {
- if err := e.writeNullByte(); err != nil {
- return err
- }
- }
-
- if err := e.encodeInteger(int32(val)); err != nil {
- return err
- }
- }
- case []int16:
- if tag != TagInteger && tag != TagEnum {
- return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
- }
-
- for index, val := range v {
- if err := e.encodeTag(tag); err != nil {
- return err
- }
-
- if index == 0 {
- if err := e.encodeString(attribute); err != nil {
- return err
- }
- } else {
- if err := e.writeNullByte(); err != nil {
- return err
- }
- }
-
- if err := e.encodeInteger(int32(val)); err != nil {
- return err
- }
- }
- case []int8:
- if tag != TagInteger && tag != TagEnum {
- return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
- }
-
- for index, val := range v {
- if err := e.encodeTag(tag); err != nil {
- return err
- }
-
- if index == 0 {
- if err := e.encodeString(attribute); err != nil {
- return err
- }
- } else {
- if err := e.writeNullByte(); err != nil {
- return err
- }
- }
-
- if err := e.encodeInteger(int32(val)); err != nil {
- return err
- }
- }
- case []int32:
- if tag != TagInteger && tag != TagEnum {
- return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
- }
-
- for index, val := range v {
- if err := e.encodeTag(tag); err != nil {
- return err
- }
-
- if index == 0 {
- if err := e.encodeString(attribute); err != nil {
- return err
- }
- } else {
- if err := e.writeNullByte(); err != nil {
- return err
- }
- }
-
- if err := e.encodeInteger(val); err != nil {
- return err
- }
- }
- case []int64:
- if tag != TagInteger && tag != TagEnum {
- return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
- }
-
- for index, val := range v {
- if err := e.encodeTag(tag); err != nil {
- return err
- }
-
- if index == 0 {
- if err := e.encodeString(attribute); err != nil {
- return err
- }
- } else {
- if err := e.writeNullByte(); err != nil {
- return err
- }
- }
-
- if err := e.encodeInteger(int32(val)); err != nil {
- return err
- }
- }
- case bool:
- if tag != TagBoolean {
- return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
- }
-
- if err := e.encodeTag(tag); err != nil {
- return err
- }
-
- if err := e.encodeString(attribute); err != nil {
- return err
- }
-
- if err := e.encodeBoolean(v); err != nil {
- return err
- }
- case []bool:
- if tag != TagBoolean {
- return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
- }
-
- for index, val := range v {
- if err := e.encodeTag(tag); err != nil {
- return err
- }
-
- if index == 0 {
- if err := e.encodeString(attribute); err != nil {
- return err
- }
- } else {
- if err := e.writeNullByte(); err != nil {
- return err
- }
- }
-
- if err := e.encodeBoolean(val); err != nil {
- return err
- }
- }
- case string:
- if err := e.encodeTag(tag); err != nil {
- return err
- }
-
- if err := e.encodeString(attribute); err != nil {
- return err
- }
-
- if err := e.encodeString(v); err != nil {
- return err
- }
- case []string:
- for index, val := range v {
- if err := e.encodeTag(tag); err != nil {
- return err
- }
-
- if index == 0 {
- if err := e.encodeString(attribute); err != nil {
- return err
- }
- } else {
- if err := e.writeNullByte(); err != nil {
- return err
- }
- }
-
- if err := e.encodeString(val); err != nil {
- return err
- }
- }
- default:
- return fmt.Errorf("type %T is not supported", value)
- }
-
- return nil
-}
-
-func (e *AttributeEncoder) encodeString(s string) error {
- if err := binary.Write(e.writer, binary.BigEndian, int16(len(s))); err != nil {
- return err
- }
-
- _, err := e.writer.Write([]byte(s))
- return err
-}
-
-func (e *AttributeEncoder) encodeInteger(i int32) error {
- if err := binary.Write(e.writer, binary.BigEndian, sizeInteger); err != nil {
- return err
- }
-
- return binary.Write(e.writer, binary.BigEndian, i)
-}
-
-func (e *AttributeEncoder) encodeBoolean(b bool) error {
- if err := binary.Write(e.writer, binary.BigEndian, sizeBoolean); err != nil {
- return err
- }
-
- return binary.Write(e.writer, binary.BigEndian, b)
-}
-
-func (e *AttributeEncoder) encodeTag(t int8) error {
- return binary.Write(e.writer, binary.BigEndian, t)
-}
-
-func (e *AttributeEncoder) writeNullByte() error {
- return binary.Write(e.writer, binary.BigEndian, int16(0))
-}
-
-// Attribute defines an ipp attribute
-type Attribute struct {
- Tag int8
- Name string
- Value interface{}
-}
-
-// Resolution defines the resolution attribute
-type Resolution struct {
- Height int32
- Width int32
- Depth int8
-}
-
-// AttributeDecoder reads and decodes ipp from an input stream
-type AttributeDecoder struct {
- reader io.Reader
-}
-
-// NewAttributeDecoder returns a new decoder that reads from r
-func NewAttributeDecoder(r io.Reader) *AttributeDecoder {
- return &AttributeDecoder{r}
-}
-
-// Decode reads the next ipp attribute into a attribute struct. the type is identified by a tag passed as an argument
-func (d *AttributeDecoder) Decode(tag int8) (*Attribute, error) {
- attr := Attribute{Tag: tag}
-
- name, err := d.decodeString()
- if err != nil {
- return nil, err
- }
- attr.Name = name
-
- switch attr.Tag {
- case TagEnum, TagInteger:
- val, err := d.decodeInteger()
- if err != nil {
- return nil, err
- }
- attr.Value = val
- case TagBoolean:
- val, err := d.decodeBool()
- if err != nil {
- return nil, err
- }
- attr.Value = val
- case TagDate:
- val, err := d.decodeDate()
- if err != nil {
- return nil, err
- }
- attr.Value = val
- case TagRange:
- val, err := d.decodeRange()
- if err != nil {
- return nil, err
- }
- attr.Value = val
- case TagResolution:
- val, err := d.decodeResolution()
- if err != nil {
- return nil, err
- }
- attr.Value = val
- default:
- val, err := d.decodeString()
- if err != nil {
- return nil, err
- }
- attr.Value = val
- }
-
- return &attr, nil
-}
-
-func (d *AttributeDecoder) decodeBool() (b bool, err error) {
- if _, err = d.readValueLength(); err != nil {
- return
- }
-
- if err = binary.Read(d.reader, binary.BigEndian, &b); err != nil {
- return
- }
-
- return
-}
-
-func (d *AttributeDecoder) decodeInteger() (i int, err error) {
- if _, err = d.readValueLength(); err != nil {
- return
- }
-
- var reti int32
- if err = binary.Read(d.reader, binary.BigEndian, &reti); err != nil {
- return
- }
-
- return int(reti), nil
-}
-
-func (d *AttributeDecoder) decodeString() (string, error) {
- length, err := d.readValueLength()
- if err != nil {
- return "", err
- }
-
- if length == 0 {
- return "", nil
- }
-
- bs := make([]byte, length)
- if _, err := d.reader.Read(bs); err != nil {
- return "", nil
- }
-
- return string(bs), nil
-}
-
-func (d *AttributeDecoder) decodeDate() ([]int, error) {
- length, err := d.readValueLength()
- if err != nil {
- return nil, err
- }
-
- is := make([]int, length)
- var ti int8
-
- for i := int16(0); i < length; i++ {
- if err = binary.Read(d.reader, binary.BigEndian, &ti); err != nil {
- return nil, err
- }
- is[i] = int(ti)
- }
-
- return is, nil
-}
-
-func (d *AttributeDecoder) decodeRange() ([]int32, error) {
- length, err := d.readValueLength()
- if err != nil {
- return nil, err
- }
-
- // initialize range element count (c) and range slice (r)
- c := length / 4
- r := make([]int32, c)
-
- for i := int16(0); i < c; i++ {
- var ti int32
- if err = binary.Read(d.reader, binary.BigEndian, &ti); err != nil {
- return nil, err
- }
- r[i] = ti
- }
-
- return r, nil
-}
-
-func (d *AttributeDecoder) decodeResolution() (res Resolution, err error) {
- _, err = d.readValueLength()
- if err != nil {
- return
- }
-
- if err = binary.Read(d.reader, binary.BigEndian, &res.Height); err != nil {
- return
- }
-
- if err = binary.Read(d.reader, binary.BigEndian, &res.Width); err != nil {
- return
- }
-
- if err = binary.Read(d.reader, binary.BigEndian, &res.Depth); err != nil {
- return
- }
-
- return
-}
-
-func (d *AttributeDecoder) readValueLength() (length int16, err error) {
- err = binary.Read(d.reader, binary.BigEndian, &length)
- return
-}
diff --git a/nix/inputs/dms-cli/pkg/ipp/constants.go b/nix/inputs/dms-cli/pkg/ipp/constants.go
deleted file mode 100644
index 5c91983..0000000
--- a/nix/inputs/dms-cli/pkg/ipp/constants.go
+++ /dev/null
@@ -1,449 +0,0 @@
-package ipp
-
-// ipp status codes
-const (
- StatusCupsInvalid int16 = -1
- StatusOk int16 = 0x0000
- StatusOkIgnoredOrSubstituted int16 = 0x0001
- StatusOkConflicting int16 = 0x0002
- StatusOkIgnoredSubscriptions int16 = 0x0003
- StatusOkIgnoredNotifications int16 = 0x0004
- StatusOkTooManyEvents int16 = 0x0005
- StatusOkButCancelSubscription int16 = 0x0006
- StatusOkEventsComplete int16 = 0x0007
- StatusRedirectionOtherSite int16 = 0x0200
- StatusCupsSeeOther int16 = 0x0280
- StatusErrorBadRequest int16 = 0x0400
- StatusErrorForbidden int16 = 0x0401
- StatusErrorNotAuthenticated int16 = 0x0402
- StatusErrorNotAuthorized int16 = 0x0403
- StatusErrorNotPossible int16 = 0x0404
- StatusErrorTimeout int16 = 0x0405
- StatusErrorNotFound int16 = 0x0406
- StatusErrorGone int16 = 0x0407
- StatusErrorRequestEntity int16 = 0x0408
- StatusErrorRequestValue int16 = 0x0409
- StatusErrorDocumentFormatNotSupported int16 = 0x040a
- StatusErrorAttributesOrValues int16 = 0x040b
- StatusErrorUriScheme int16 = 0x040c
- StatusErrorCharset int16 = 0x040d
- StatusErrorConflicting int16 = 0x040e
- StatusErrorCompressionError int16 = 0x040f
- StatusErrorDocumentFormatError int16 = 0x0410
- StatusErrorDocumentAccess int16 = 0x0411
- StatusErrorAttributesNotSettable int16 = 0x0412
- StatusErrorIgnoredAllSubscriptions int16 = 0x0413
- StatusErrorTooManySubscriptions int16 = 0x0414
- StatusErrorIgnoredAllNotifications int16 = 0x0415
- StatusErrorPrintSupportFileNotFound int16 = 0x0416
- StatusErrorDocumentPassword int16 = 0x0417
- StatusErrorDocumentPermission int16 = 0x0418
- StatusErrorDocumentSecurity int16 = 0x0419
- StatusErrorDocumentUnprintable int16 = 0x041a
- StatusErrorAccountInfoNeeded int16 = 0x041b
- StatusErrorAccountClosed int16 = 0x041c
- StatusErrorAccountLimitReached int16 = 0x041d
- StatusErrorAccountAuthorizationFailed int16 = 0x041e
- StatusErrorNotFetchable int16 = 0x041f
- StatusErrorCupsAccountInfoNeeded int16 = 0x049C
- StatusErrorCupsAccountClosed int16 = 0x049d
- StatusErrorCupsAccountLimitReached int16 = 0x049e
- StatusErrorCupsAccountAuthorizationFailed int16 = 0x049f
- StatusErrorInternal int16 = 0x0500
- StatusErrorOperationNotSupported int16 = 0x0501
- StatusErrorServiceUnavailable int16 = 0x0502
- StatusErrorVersionNotSupported int16 = 0x0503
- StatusErrorDevice int16 = 0x0504
- StatusErrorTemporary int16 = 0x0505
- StatusErrorNotAcceptingJobs int16 = 0x0506
- StatusErrorBusy int16 = 0x0507
- StatusErrorJobCanceled int16 = 0x0508
- StatusErrorMultipleJobsNotSupported int16 = 0x0509
- StatusErrorPrinterIsDeactivated int16 = 0x050a
- StatusErrorTooManyJobs int16 = 0x050b
- StatusErrorTooManyDocuments int16 = 0x050c
- StatusErrorCupsAuthenticationCanceled int16 = 0x1000
- StatusErrorCupsPki int16 = 0x1001
- StatusErrorCupsUpgradeRequired int16 = 0x1002
-)
-
-// ipp operations
-const (
- OperationCupsInvalid int16 = -0x0001
- OperationCupsNone int16 = 0x0000
- OperationPrintJob int16 = 0x0002
- OperationPrintUri int16 = 0x0003
- OperationValidateJob int16 = 0x0004
- OperationCreateJob int16 = 0x0005
- OperationSendDocument int16 = 0x0006
- OperationSendUri int16 = 0x0007
- OperationCancelJob int16 = 0x0008
- OperationGetJobAttributes int16 = 0x0009
- OperationGetJobs int16 = 0x000a
- OperationGetPrinterAttributes int16 = 0x000b
- OperationHoldJob int16 = 0x000c
- OperationReleaseJob int16 = 0x000d
- OperationRestartJob int16 = 0x000e
- OperationPausePrinter int16 = 0x0010
- OperationResumePrinter int16 = 0x0011
- OperationPurgeJobs int16 = 0x0012
- OperationSetPrinterAttributes int16 = 0x0013
- OperationSetJobAttributes int16 = 0x0014
- OperationGetPrinterSupportedValues int16 = 0x0015
- OperationCreatePrinterSubscriptions int16 = 0x0016
- OperationCreateJobSubscriptions int16 = 0x0017
- OperationGetSubscriptionAttributes int16 = 0x0018
- OperationGetSubscriptions int16 = 0x0019
- OperationRenewSubscription int16 = 0x001a
- OperationCancelSubscription int16 = 0x001b
- OperationGetNotifications int16 = 0x001c
- OperationSendNotifications int16 = 0x001d
- OperationGetResourceAttributes int16 = 0x001e
- OperationGetResourceData int16 = 0x001f
- OperationGetResources int16 = 0x0020
- OperationGetPrintSupportFiles int16 = 0x0021
- OperationEnablePrinter int16 = 0x0022
- OperationDisablePrinter int16 = 0x0023
- OperationPausePrinterAfterCurrentJob int16 = 0x0024
- OperationHoldNewJobs int16 = 0x0025
- OperationReleaseHeldNewJobs int16 = 0x0026
- OperationDeactivatePrinter int16 = 0x0027
- OperationActivatePrinter int16 = 0x0028
- OperationRestartPrinter int16 = 0x0029
- OperationShutdownPrinter int16 = 0x002a
- OperationStartupPrinter int16 = 0x002b
- OperationReprocessJob int16 = 0x002c
- OperationCancelCurrentJob int16 = 0x002d
- OperationSuspendCurrentJob int16 = 0x002e
- OperationResumeJob int16 = 0x002f
- OperationOperationPromoteJob int16 = 0x0030
- OperationScheduleJobAfter int16 = 0x0031
- OperationCancelDocument int16 = 0x0033
- OperationGetDocumentAttributes int16 = 0x0034
- OperationGetDocuments int16 = 0x0035
- OperationDeleteDocument int16 = 0x0036
- OperationSetDocumentAttributes int16 = 0x0037
- OperationCancelJobs int16 = 0x0038
- OperationCancelMyJobs int16 = 0x0039
- OperationResubmitJob int16 = 0x003a
- OperationCloseJob int16 = 0x003b
- OperationIdentifyPrinter int16 = 0x003c
- OperationValidateDocument int16 = 0x003d
- OperationAddDocumentImages int16 = 0x003e
- OperationAcknowledgeDocument int16 = 0x003f
- OperationAcknowledgeIdentifyPrinter int16 = 0x0040
- OperationAcknowledgeJob int16 = 0x0041
- OperationFetchDocument int16 = 0x0042
- OperationFetchJob int16 = 0x0043
- OperationGetOutputDeviceAttributes int16 = 0x0044
- OperationUpdateActiveJobs int16 = 0x0045
- OperationDeregisterOutputDevice int16 = 0x0046
- OperationUpdateDocumentStatus int16 = 0x0047
- OperationUpdateJobStatus int16 = 0x0048
- OperationUpdateOutputDeviceAttributes int16 = 0x0049
- OperationGetNextDocumentData int16 = 0x004a
- OperationAllocatePrinterResources int16 = 0x004b
- OperationCreatePrinter int16 = 0x004c
- OperationDeallocatePrinterResources int16 = 0x004d
- OperationDeletePrinter int16 = 0x004e
- OperationGetPrinters int16 = 0x004f
- OperationShutdownOnePrinter int16 = 0x0050
- OperationStartupOnePrinter int16 = 0x0051
- OperationCancelResource int16 = 0x0052
- OperationCreateResource int16 = 0x0053
- OperationInstallResource int16 = 0x0054
- OperationSendResourceData int16 = 0x0055
- OperationSetResourceAttributes int16 = 0x0056
- OperationCreateResourceSubscriptions int16 = 0x0057
- OperationCreateSystemSubscriptions int16 = 0x0058
- OperationDisableAllPrinters int16 = 0x0059
- OperationEnableAllPrinters int16 = 0x005a
- OperationGetSystemAttributes int16 = 0x005b
- OperationGetSystemSupportedValues int16 = 0x005c
- OperationPauseAllPrinters int16 = 0x005d
- OperationPauseAllPrintersAfterCurrentJob int16 = 0x005e
- OperationRegisterOutputDevice int16 = 0x005f
- OperationRestartSystem int16 = 0x0060
- OperationResumeAllPrinters int16 = 0x0061
- OperationSetSystemAttributes int16 = 0x0062
- OperationShutdownAllPrinter int16 = 0x0063
- OperationStartupAllPrinters int16 = 0x0064
- OperationPrivate int16 = 0x4000
- OperationCupsGetDefault int16 = 0x4001
- OperationCupsGetPrinters int16 = 0x4002
- OperationCupsAddModifyPrinter int16 = 0x4003
- OperationCupsDeletePrinter int16 = 0x4004
- OperationCupsGetClasses int16 = 0x4005
- OperationCupsAddModifyClass int16 = 0x4006
- OperationCupsDeleteClass int16 = 0x4007
- OperationCupsAcceptJobs int16 = 0x4008
- OperationCupsRejectJobs int16 = 0x4009
- OperationCupsSetDefault int16 = 0x400a
- OperationCupsGetDevices int16 = 0x400b
- OperationCupsGetPPDs int16 = 0x400c
- OperationCupsMoveJob int16 = 0x400d
- OperationCupsAuthenticateJob int16 = 0x400e
- OperationCupsGetPpd int16 = 0x400f
- OperationCupsGetDocument int16 = 0x4027
- OperationCupsCreateLocalPrinter int16 = 0x4028
-)
-
-// ipp tags
-const (
- TagCupsInvalid int8 = -1
- TagZero int8 = 0x00
- TagOperation int8 = 0x01
- TagJob int8 = 0x02
- TagEnd int8 = 0x03
- TagPrinter int8 = 0x04
- TagUnsupportedGroup int8 = 0x05
- TagSubscription int8 = 0x06
- TagEventNotification int8 = 0x07
- TagResource int8 = 0x08
- TagDocument int8 = 0x09
- TagSystem int8 = 0x0a
- TagUnsupportedValue int8 = 0x10
- TagDefault int8 = 0x11
- TagUnknown int8 = 0x12
- TagNoValue int8 = 0x13
- TagNotSettable int8 = 0x15
- TagDeleteAttr int8 = 0x16
- TagAdminDefine int8 = 0x17
- TagInteger int8 = 0x21
- TagBoolean int8 = 0x22
- TagEnum int8 = 0x23
- TagString int8 = 0x30
- TagDate int8 = 0x31
- TagResolution int8 = 0x32
- TagRange int8 = 0x33
- TagBeginCollection int8 = 0x34
- TagTextLang int8 = 0x35
- TagNameLang int8 = 0x36
- TagEndCollection int8 = 0x37
- TagText int8 = 0x41
- TagName int8 = 0x42
- TagReservedString int8 = 0x43
- TagKeyword int8 = 0x44
- TagUri int8 = 0x45
- TagUriScheme int8 = 0x46
- TagCharset int8 = 0x47
- TagLanguage int8 = 0x48
- TagMimeType int8 = 0x49
- TagMemberName int8 = 0x4a
- TagExtension int8 = 0x7f
-)
-
-// job states
-const (
- JobStatePending int8 = 0x03
- JobStateHeld int8 = 0x04
- JobStateProcessing int8 = 0x05
- JobStateStopped int8 = 0x06
- JobStateCanceled int8 = 0x07
- JobStateAborted int8 = 0x08
- JobStateCompleted int8 = 0x09
-)
-
-// document states
-const (
- DocumentStatePending int8 = 0x03
- DocumentStateProcessing int8 = 0x05
- DocumentStateCanceled int8 = 0x07
- DocumentStateAborted int8 = 0x08
- DocumentStateCompleted int8 = 0x08
-)
-
-// printer states
-const (
- PrinterStateIdle int8 = 0x0003
- PrinterStateProcessing int8 = 0x0004
- PrinterStateStopped int8 = 0x0005
-)
-
-// job state filter
-const (
- JobStateFilterNotCompleted = "not-completed"
- JobStateFilterCompleted = "completed"
- JobStateFilterAll = "all"
-)
-
-// error policies
-const (
- ErrorPolicyRetryJob = "retry-job"
- ErrorPolicyAbortJob = "abort-job"
- ErrorPolicyRetryCurrentJob = "retry-current-job"
- ErrorPolicyStopPrinter = "stop-printer"
-)
-
-// ipp defaults
-const (
- CharsetLanguage = "en-US"
- Charset = "utf-8"
- ProtocolVersionMajor = int8(2)
- ProtocolVersionMinor = int8(0)
-
- DefaultJobPriority = 50
-)
-
-// useful mime types for ipp
-const (
- MimeTypePostscript = "application/postscript"
- MimeTypeOctetStream = "application/octet-stream"
-)
-
-// ipp content types
-const (
- ContentTypeIPP = "application/ipp"
-)
-
-// known ipp attributes
-const (
- AttributeCopies = "copies"
- AttributeDocumentFormat = "document-format"
- AttributeDocumentName = "document-name"
- AttributeJobID = "job-id"
- AttributeJobName = "job-name"
- AttributeJobPriority = "job-priority"
- AttributeJobURI = "job-uri"
- AttributeLastDocument = "last-document"
- AttributeMyJobs = "my-jobs"
- AttributePPDName = "ppd-name"
- AttributePPDMakeAndModel = "ppd-make-and-model"
- AttributePrinterIsShared = "printer-is-shared"
- AttributePrinterIsTemporary = "printer-is-temporary"
- AttributePrinterURI = "printer-uri"
- AttributePurgeJobs = "purge-jobs"
- AttributeRequestedAttributes = "requested-attributes"
- AttributeRequestingUserName = "requesting-user-name"
- AttributeWhichJobs = "which-jobs"
- AttributeFirstJobID = "first-job-id"
- AttributeLimit = "limit"
- AttributeStatusMessage = "status-message"
- AttributeCharset = "attributes-charset"
- AttributeNaturalLanguage = "attributes-natural-language"
- AttributeDeviceURI = "device-uri"
- AttributeHoldJobUntil = "job-hold-until"
- AttributePrinterErrorPolicy = "printer-error-policy"
- AttributePrinterInfo = "printer-info"
- AttributePrinterLocation = "printer-location"
- AttributePrinterName = "printer-name"
- AttributePrinterStateReasons = "printer-state-reasons"
- AttributeJobPrinterURI = "job-printer-uri"
- AttributeMemberURIs = "member-uris"
- AttributeDocumentNumber = "document-number"
- AttributeDocumentState = "document-state"
- AttributeFinishings = "finishings"
- AttributeJobHoldUntil = "hold-job-until"
- AttributeJobSheets = "job-sheets"
- AttributeJobState = "job-state"
- AttributeJobStateReason = "job-state-reason"
- AttributeMedia = "media"
- AttributeSides = "sides"
- AttributeNumberUp = "number-up"
- AttributeOrientationRequested = "orientation-requested"
- AttributePrintQuality = "print-quality"
- AttributePrinterIsAcceptingJobs = "printer-is-accepting-jobs"
- AttributePrinterResolution = "printer-resolution"
- AttributePrinterState = "printer-state"
- AttributeMemberNames = "member-names"
- AttributePrinterType = "printer-type"
- AttributePrinterMakeAndModel = "printer-make-and-model"
- AttributePrinterStateMessage = "printer-state-message"
- AttributePrinterUriSupported = "printer-uri-supported"
- AttributeJobMediaProgress = "job-media-progress"
- AttributeJobKilobyteOctets = "job-k-octets"
- AttributeNumberOfDocuments = "number-of-documents"
- AttributeJobOriginatingUserName = "job-originating-user-name"
- AttributeOutputOrder = "outputorder"
- AttributeJobStateReasons = "job-state-reasons"
- AttributeJobStateMessage = "job-state-message"
- AttributeJobPrinterStateReasons = "job-printer-state-reasons"
- AttributeJobPrinterStateMessage = "job-printer-state-message"
- AttributeJobImpressionsCompleted = "job-impressions-completed"
- AttributePrintScaling = "print-scaling"
-)
-
-// Default attributes
-var (
- DefaultClassAttributes = []string{AttributePrinterName, AttributeMemberNames}
- DefaultPrinterAttributes = []string{
- AttributePrinterName, AttributePrinterType, AttributePrinterLocation, AttributePrinterInfo,
- AttributePrinterMakeAndModel, AttributePrinterState, AttributePrinterStateMessage, AttributePrinterStateReasons,
- AttributePrinterUriSupported, AttributeDeviceURI, AttributePrinterIsShared,
- }
- DefaultJobAttributes = []string{
- AttributeJobID, AttributeJobName, AttributePrinterURI, AttributeJobState, AttributeJobStateReason,
- AttributeJobHoldUntil, AttributeJobMediaProgress, AttributeJobKilobyteOctets, AttributeNumberOfDocuments, AttributeCopies,
- AttributeJobOriginatingUserName,
- }
-)
-
-// Attribute to tag mapping
-var (
- AttributeTagMapping = map[string]int8{
- AttributeCharset: TagCharset,
- AttributeNaturalLanguage: TagLanguage,
- AttributeCopies: TagInteger,
- AttributeDeviceURI: TagUri,
- AttributeDocumentFormat: TagMimeType,
- AttributeDocumentName: TagName,
- AttributeDocumentNumber: TagInteger,
- AttributeDocumentState: TagEnum,
- AttributeFinishings: TagEnum,
- AttributeJobHoldUntil: TagKeyword,
- AttributeHoldJobUntil: TagKeyword,
- AttributeJobID: TagInteger,
- AttributeJobName: TagName,
- AttributeJobPrinterURI: TagUri,
- AttributeJobPriority: TagInteger,
- AttributeJobSheets: TagName,
- AttributeJobState: TagEnum,
- AttributeJobStateReason: TagKeyword,
- AttributeJobURI: TagUri,
- AttributeLastDocument: TagBoolean,
- AttributeMedia: TagKeyword,
- AttributeSides: TagKeyword,
- AttributeMemberURIs: TagUri,
- AttributeMyJobs: TagBoolean,
- AttributeNumberUp: TagInteger,
- AttributeOrientationRequested: TagEnum,
- AttributePPDName: TagName,
- AttributePPDMakeAndModel: TagText,
- AttributeNumberOfDocuments: TagInteger,
- AttributePrintQuality: TagEnum,
- AttributePrinterErrorPolicy: TagName,
- AttributePrinterInfo: TagText,
- AttributePrinterIsAcceptingJobs: TagBoolean,
- AttributePrinterIsShared: TagBoolean,
- AttributePrinterIsTemporary: TagBoolean,
- AttributePrinterName: TagName,
- AttributePrinterLocation: TagText,
- AttributePrinterResolution: TagResolution,
- AttributePrinterState: TagEnum,
- AttributePrinterStateReasons: TagKeyword,
- AttributePrinterURI: TagUri,
- AttributePurgeJobs: TagBoolean,
- AttributeRequestedAttributes: TagKeyword,
- AttributeRequestingUserName: TagName,
- AttributeWhichJobs: TagKeyword,
- AttributeFirstJobID: TagInteger,
- AttributeStatusMessage: TagText,
- AttributeLimit: TagInteger,
- AttributeOutputOrder: TagName,
- AttributeJobStateReasons: TagString,
- AttributeJobStateMessage: TagString,
- AttributeJobPrinterStateReasons: TagString,
- AttributeJobPrinterStateMessage: TagString,
- AttributeJobImpressionsCompleted: TagInteger,
- AttributePrintScaling: TagKeyword,
- // IPP Subscription/Notification attributes (added for dankdots)
- "notify-events": TagKeyword,
- "notify-pull-method": TagKeyword,
- "notify-lease-duration": TagInteger,
- "notify-subscription-id": TagInteger,
- "notify-subscription-ids": TagInteger,
- "notify-sequence-numbers": TagInteger,
- "notify-wait": TagBoolean,
- "notify-recipient-uri": TagUri,
- }
-)
diff --git a/nix/inputs/dms-cli/pkg/ipp/cups-client.go b/nix/inputs/dms-cli/pkg/ipp/cups-client.go
deleted file mode 100644
index 9e2efc3..0000000
--- a/nix/inputs/dms-cli/pkg/ipp/cups-client.go
+++ /dev/null
@@ -1,322 +0,0 @@
-package ipp
-
-import (
- "bytes"
- "strings"
-)
-
-// CUPSClient implements a ipp client with specific cups operations
-type CUPSClient struct {
- *IPPClient
-}
-
-// NewCUPSClient creates a new cups ipp client (used HttpAdapter internally)
-func NewCUPSClient(host string, port int, username, password string, useTLS bool) *CUPSClient {
- ippClient := NewIPPClient(host, port, username, password, useTLS)
- return &CUPSClient{ippClient}
-}
-
-// NewCUPSClientWithAdapter creates a new cups ipp client with given Adapter
-func NewCUPSClientWithAdapter(username string, adapter Adapter) *CUPSClient {
- ippClient := NewIPPClientWithAdapter(username, adapter)
- return &CUPSClient{ippClient}
-}
-
-// GetDevices returns a map of device uris and printer attributes
-func (c *CUPSClient) GetDevices() (map[string]Attributes, error) {
- req := NewRequest(OperationCupsGetDevices, 1)
-
- resp, err := c.SendRequest(c.adapter.GetHttpUri("", nil), req, nil)
- if err != nil {
- return nil, err
- }
-
- printerNameMap := make(map[string]Attributes)
-
- for _, printerAttributes := range resp.PrinterAttributes {
- printerNameMap[printerAttributes[AttributeDeviceURI][0].Value.(string)] = printerAttributes
- }
-
- return printerNameMap, nil
-}
-
-// MoveJob moves a job to a other printer
-func (c *CUPSClient) MoveJob(jobID int, destPrinter string) error {
- req := NewRequest(OperationCupsMoveJob, 1)
- req.OperationAttributes[AttributeJobURI] = c.getJobUri(jobID)
- req.PrinterAttributes[AttributeJobPrinterURI] = c.getPrinterUri(destPrinter)
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("jobs", ""), req, nil)
- return err
-}
-
-// MoveAllJob moves all job from a printer to a other printer
-func (c *CUPSClient) MoveAllJob(srcPrinter, destPrinter string) error {
- req := NewRequest(OperationCupsMoveJob, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(srcPrinter)
- req.PrinterAttributes[AttributeJobPrinterURI] = c.getPrinterUri(destPrinter)
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("jobs", ""), req, nil)
- return err
-}
-
-// GetPPDs returns a map of ppd names and attributes
-func (c *CUPSClient) GetPPDs() (map[string]Attributes, error) {
- req := NewRequest(OperationCupsGetPPDs, 1)
-
- resp, err := c.SendRequest(c.adapter.GetHttpUri("", nil), req, nil)
- if err != nil {
- return nil, err
- }
-
- ppdNameMap := make(map[string]Attributes)
-
- for _, printerAttributes := range resp.PrinterAttributes {
- ppdNameMap[printerAttributes[AttributePPDName][0].Value.(string)] = printerAttributes
- }
-
- return ppdNameMap, nil
-}
-
-// AcceptJobs lets a printer accept jobs again
-func (c *CUPSClient) AcceptJobs(printer string) error {
- req := NewRequest(OperationCupsAcceptJobs, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// RejectJobs does not let a printer accept jobs
-func (c *CUPSClient) RejectJobs(printer string) error {
- req := NewRequest(OperationCupsRejectJobs, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// AddPrinterToClass adds a printer to a class, if the class does not exists it will be crated
-func (c *CUPSClient) AddPrinterToClass(class, printer string) error {
- attributes, err := c.GetPrinterAttributes(class, []string{AttributeMemberURIs})
- if err != nil && !IsNotExistsError(err) {
- return err
- }
-
- memberURIList := make([]string, 0)
-
- if !IsNotExistsError(err) {
- for _, member := range attributes[AttributeMemberURIs] {
- memberString := strings.Split(member.Value.(string), "/")
- printerName := memberString[len(memberString)-1]
-
- if printerName == printer {
- return nil
- }
-
- memberURIList = append(memberURIList, member.Value.(string))
- }
- }
-
- memberURIList = append(memberURIList, c.getPrinterUri(printer))
-
- req := NewRequest(OperationCupsAddModifyClass, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getClassUri(class)
- req.PrinterAttributes[AttributeMemberURIs] = memberURIList
-
- _, err = c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// DeletePrinterFromClass removes a printer from a class, if a class has no more printer it will be deleted
-func (c *CUPSClient) DeletePrinterFromClass(class, printer string) error {
- attributes, err := c.GetPrinterAttributes(class, []string{AttributeMemberURIs})
- if err != nil {
- return err
- }
-
- memberURIList := make([]string, 0)
-
- for _, member := range attributes[AttributeMemberURIs] {
- memberString := strings.Split(member.Value.(string), "/")
- printerName := memberString[len(memberString)-1]
-
- if printerName != printer {
- memberURIList = append(memberURIList, member.Value.(string))
- }
- }
-
- if len(memberURIList) == 0 {
- return c.DeleteClass(class)
- }
-
- req := NewRequest(OperationCupsAddModifyClass, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getClassUri(class)
- req.PrinterAttributes[AttributeMemberURIs] = memberURIList
-
- _, err = c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// DeleteClass deletes a class
-func (c *CUPSClient) DeleteClass(class string) error {
- req := NewRequest(OperationCupsDeleteClass, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getClassUri(class)
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// CreatePrinter creates a new printer
-func (c *CUPSClient) CreatePrinter(name, deviceURI, ppd string, shared bool, errorPolicy string, information, location string) error {
- req := NewRequest(OperationCupsAddModifyPrinter, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(name)
- req.OperationAttributes[AttributePPDName] = ppd
- req.OperationAttributes[AttributePrinterIsShared] = shared
- req.PrinterAttributes[AttributePrinterStateReasons] = "none"
- req.PrinterAttributes[AttributeDeviceURI] = deviceURI
- req.PrinterAttributes[AttributePrinterInfo] = information
- req.PrinterAttributes[AttributePrinterLocation] = location
- req.PrinterAttributes[AttributePrinterErrorPolicy] = errorPolicy
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// SetPrinterPPD sets the ppd for a printer
-func (c *CUPSClient) SetPrinterPPD(printer, ppd string) error {
- req := NewRequest(OperationCupsAddModifyPrinter, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
- req.OperationAttributes[AttributePPDName] = ppd
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// SetPrinterDeviceURI sets the device uri for a printer
-func (c *CUPSClient) SetPrinterDeviceURI(printer, deviceURI string) error {
- req := NewRequest(OperationCupsAddModifyPrinter, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
- req.PrinterAttributes[AttributeDeviceURI] = deviceURI
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// SetPrinterIsShared shares or unshares a printer in the network
-func (c *CUPSClient) SetPrinterIsShared(printer string, shared bool) error {
- req := NewRequest(OperationCupsAddModifyPrinter, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
- req.OperationAttributes[AttributePrinterIsShared] = shared
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// SetPrinterErrorPolicy sets the error policy for a printer
-func (c *CUPSClient) SetPrinterErrorPolicy(printer string, errorPolicy string) error {
- req := NewRequest(OperationCupsAddModifyPrinter, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
- req.PrinterAttributes[AttributePrinterErrorPolicy] = errorPolicy
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// SetPrinterInformation sets general printer information
-func (c *CUPSClient) SetPrinterInformation(printer, information string) error {
- req := NewRequest(OperationCupsAddModifyPrinter, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
- req.PrinterAttributes[AttributePrinterInfo] = information
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// SetPrinterLocation sets the printer location
-func (c *CUPSClient) SetPrinterLocation(printer, location string) error {
- req := NewRequest(OperationCupsAddModifyPrinter, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
- req.PrinterAttributes[AttributePrinterLocation] = location
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// DeletePrinter deletes a printer
-func (c *CUPSClient) DeletePrinter(printer string) error {
- req := NewRequest(OperationCupsDeletePrinter, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// GetPrinters returns a map of printer names and attributes
-func (c *CUPSClient) GetPrinters(attributes []string) (map[string]Attributes, error) {
- req := NewRequest(OperationCupsGetPrinters, 1)
-
- if attributes == nil {
- req.OperationAttributes[AttributeRequestedAttributes] = DefaultPrinterAttributes
- } else {
- req.OperationAttributes[AttributeRequestedAttributes] = append(attributes, AttributePrinterName)
- }
-
- resp, err := c.SendRequest(c.adapter.GetHttpUri("", nil), req, nil)
- if err != nil {
- return nil, err
- }
-
- printerNameMap := make(map[string]Attributes)
-
- for _, printerAttributes := range resp.PrinterAttributes {
- printerNameMap[printerAttributes[AttributePrinterName][0].Value.(string)] = printerAttributes
- }
-
- return printerNameMap, nil
-}
-
-// GetClasses returns a map of class names and attributes
-func (c *CUPSClient) GetClasses(attributes []string) (map[string]Attributes, error) {
- req := NewRequest(OperationCupsGetClasses, 1)
-
- if attributes == nil {
- req.OperationAttributes[AttributeRequestedAttributes] = DefaultClassAttributes
- } else {
- req.OperationAttributes[AttributeRequestedAttributes] = append(attributes, AttributePrinterName)
- }
-
- resp, err := c.SendRequest(c.adapter.GetHttpUri("", nil), req, nil)
- if err != nil {
- return nil, err
- }
-
- printerNameMap := make(map[string]Attributes)
-
- for _, printerAttributes := range resp.PrinterAttributes {
- printerNameMap[printerAttributes[AttributePrinterName][0].Value.(string)] = printerAttributes
- }
-
- return printerNameMap, nil
-}
-
-// PrintTestPage prints a test page of type application/vnd.cups-pdf-banner
-func (c *CUPSClient) PrintTestPage(printer string) (int, error) {
- testPage := new(bytes.Buffer)
- testPage.WriteString("#PDF-BANNER\n")
- testPage.WriteString("Template default-testpage.pdf\n")
- testPage.WriteString("Show printer-name printer-info printer-location printer-make-and-model printer-driver-name")
- testPage.WriteString("printer-driver-version paper-size imageable-area job-id options time-at-creation")
- testPage.WriteString("time-at-processing\n\n")
-
- return c.PrintDocuments([]Document{
- {
- Document: testPage,
- Name: "Test Page",
- Size: testPage.Len(),
- MimeType: MimeTypePostscript,
- },
- }, printer, map[string]interface{}{
- AttributeJobName: "Test Page",
- })
-}
diff --git a/nix/inputs/dms-cli/pkg/ipp/error.go b/nix/inputs/dms-cli/pkg/ipp/error.go
deleted file mode 100644
index e4edf5e..0000000
--- a/nix/inputs/dms-cli/pkg/ipp/error.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package ipp
-
-import "fmt"
-
-// IsNotExistsError checks a given error whether a printer or class does not exist
-func IsNotExistsError(err error) bool {
- if err == nil {
- return false
- }
-
- return err.Error() == "The printer or class does not exist."
-}
-
-// IPPError used for non ok ipp status codes
-type IPPError struct {
- Status int16
- Message string
-}
-
-func (e IPPError) Error() string {
- return fmt.Sprintf("ipp status: %d, message: %s", e.Status, e.Message)
-}
-
-// HTTPError used for non 200 http codes
-type HTTPError struct {
- Code int
-}
-
-func (e HTTPError) Error() string {
- return fmt.Sprintf("got http code %d", e.Code)
-}
diff --git a/nix/inputs/dms-cli/pkg/ipp/ipp-client.go b/nix/inputs/dms-cli/pkg/ipp/ipp-client.go
deleted file mode 100644
index 7a7cc53..0000000
--- a/nix/inputs/dms-cli/pkg/ipp/ipp-client.go
+++ /dev/null
@@ -1,329 +0,0 @@
-package ipp
-
-import (
- "errors"
- "fmt"
- "io"
- "os"
- "path"
-)
-
-// Document wraps an io.Reader with more information, needed for encoding
-type Document struct {
- Document io.Reader
- Size int
- Name string
- MimeType string
-}
-
-// IPPClient implements a generic ipp client
-type IPPClient struct {
- username string
- adapter Adapter
-}
-
-// NewIPPClient creates a new generic ipp client (used HttpAdapter internally)
-func NewIPPClient(host string, port int, username, password string, useTLS bool) *IPPClient {
- adapter := NewHttpAdapter(host, port, username, password, useTLS)
-
- return &IPPClient{
- username: username,
- adapter: adapter,
- }
-}
-
-// NewIPPClientWithAdapter creates a new generic ipp client with given Adapter
-func NewIPPClientWithAdapter(username string, adapter Adapter) *IPPClient {
- return &IPPClient{
- username: username,
- adapter: adapter,
- }
-}
-
-func (c *IPPClient) getPrinterUri(printer string) string {
- return fmt.Sprintf("ipp://localhost/printers/%s", printer)
-}
-
-func (c *IPPClient) getJobUri(jobID int) string {
- return fmt.Sprintf("ipp://localhost/jobs/%d", jobID)
-}
-
-func (c *IPPClient) getClassUri(printer string) string {
- return fmt.Sprintf("ipp://localhost/classes/%s", printer)
-}
-
-// SendRequest sends a request to a remote uri end returns the response
-func (c *IPPClient) SendRequest(url string, req *Request, additionalResponseData io.Writer) (*Response, error) {
- if _, ok := req.OperationAttributes[AttributeRequestingUserName]; !ok {
- req.OperationAttributes[AttributeRequestingUserName] = c.username
- }
-
- return c.adapter.SendRequest(url, req, additionalResponseData)
-}
-
-// PrintDocuments prints one or more documents using a Create-Job operation followed by one or more Send-Document operation(s). custom job settings can be specified via the jobAttributes parameter
-func (c *IPPClient) PrintDocuments(docs []Document, printer string, jobAttributes map[string]interface{}) (int, error) {
- printerURI := c.getPrinterUri(printer)
-
- req := NewRequest(OperationCreateJob, 1)
- req.OperationAttributes[AttributePrinterURI] = printerURI
- req.OperationAttributes[AttributeRequestingUserName] = c.username
-
- // set defaults for some attributes, may get overwritten
- req.OperationAttributes[AttributeJobName] = docs[0].Name
- req.OperationAttributes[AttributeCopies] = 1
- req.OperationAttributes[AttributeJobPriority] = DefaultJobPriority
-
- for key, value := range jobAttributes {
- req.JobAttributes[key] = value
- }
-
- resp, err := c.SendRequest(c.adapter.GetHttpUri("printers", printer), req, nil)
- if err != nil {
- return -1, err
- }
-
- if len(resp.JobAttributes) == 0 {
- return 0, errors.New("server doesn't returned a job id")
- }
-
- jobID := resp.JobAttributes[0][AttributeJobID][0].Value.(int)
-
- documentCount := len(docs) - 1
-
- for docID, doc := range docs {
- req = NewRequest(OperationSendDocument, 2)
- req.OperationAttributes[AttributePrinterURI] = printerURI
- req.OperationAttributes[AttributeRequestingUserName] = c.username
- req.OperationAttributes[AttributeJobID] = jobID
- req.OperationAttributes[AttributeDocumentName] = doc.Name
- req.OperationAttributes[AttributeDocumentFormat] = doc.MimeType
- req.OperationAttributes[AttributeLastDocument] = docID == documentCount
- req.File = doc.Document
- req.FileSize = doc.Size
-
- _, err = c.SendRequest(c.adapter.GetHttpUri("printers", printer), req, nil)
- if err != nil {
- return -1, err
- }
- }
-
- return jobID, nil
-}
-
-// PrintJob prints a document using a Print-Job operation. custom job settings can be specified via the jobAttributes parameter
-func (c *IPPClient) PrintJob(doc Document, printer string, jobAttributes map[string]interface{}) (int, error) {
- printerURI := c.getPrinterUri(printer)
-
- req := NewRequest(OperationPrintJob, 1)
- req.OperationAttributes[AttributePrinterURI] = printerURI
- req.OperationAttributes[AttributeRequestingUserName] = c.username
- req.OperationAttributes[AttributeJobName] = doc.Name
- req.OperationAttributes[AttributeDocumentFormat] = doc.MimeType
-
- // set defaults for some attributes, may get overwritten
- req.OperationAttributes[AttributeCopies] = 1
- req.OperationAttributes[AttributeJobPriority] = DefaultJobPriority
-
- for key, value := range jobAttributes {
- req.JobAttributes[key] = value
- }
-
- req.File = doc.Document
- req.FileSize = doc.Size
-
- resp, err := c.SendRequest(c.adapter.GetHttpUri("printers", printer), req, nil)
- if err != nil {
- return -1, err
- }
-
- if len(resp.JobAttributes) == 0 {
- return 0, errors.New("server doesn't returned a job id")
- }
-
- jobID := resp.JobAttributes[0][AttributeJobID][0].Value.(int)
-
- return jobID, nil
-}
-
-// PrintFile prints a local file on the file system. custom job settings can be specified via the jobAttributes parameter
-func (c *IPPClient) PrintFile(filePath, printer string, jobAttributes map[string]interface{}) (int, error) {
- fileStats, err := os.Stat(filePath)
- if os.IsNotExist(err) {
- return -1, err
- }
-
- fileName := path.Base(filePath)
-
- document, err := os.Open(filePath)
- if err != nil {
- return 0, err
- }
- defer document.Close()
-
- jobAttributes[AttributeJobName] = fileName
-
- return c.PrintDocuments([]Document{
- {
- Document: document,
- Name: fileName,
- Size: int(fileStats.Size()),
- MimeType: MimeTypeOctetStream,
- },
- }, printer, jobAttributes)
-}
-
-// GetPrinterAttributes returns the requested attributes for the specified printer, if attributes is nil the default attributes will be used
-func (c *IPPClient) GetPrinterAttributes(printer string, attributes []string) (Attributes, error) {
- req := NewRequest(OperationGetPrinterAttributes, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
- req.OperationAttributes[AttributeRequestingUserName] = c.username
-
- if attributes == nil {
- req.OperationAttributes[AttributeRequestedAttributes] = DefaultPrinterAttributes
- } else {
- req.OperationAttributes[AttributeRequestedAttributes] = attributes
- }
-
- resp, err := c.SendRequest(c.adapter.GetHttpUri("printers", printer), req, nil)
- if err != nil {
- return nil, err
- }
-
- if len(resp.PrinterAttributes) == 0 {
- return nil, errors.New("server doesn't return any printer attributes")
- }
-
- return resp.PrinterAttributes[0], nil
-}
-
-// ResumePrinter resumes a printer
-func (c *IPPClient) ResumePrinter(printer string) error {
- req := NewRequest(OperationResumePrinter, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// PausePrinter pauses a printer
-func (c *IPPClient) PausePrinter(printer string) error {
- req := NewRequest(OperationPausePrinter, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// GetJobAttributes returns the requested attributes for the specified job, if attributes is nil the default job will be used
-func (c *IPPClient) GetJobAttributes(jobID int, attributes []string) (Attributes, error) {
- req := NewRequest(OperationGetJobAttributes, 1)
- req.OperationAttributes[AttributeJobURI] = c.getJobUri(jobID)
-
- if attributes == nil {
- req.OperationAttributes[AttributeRequestedAttributes] = DefaultJobAttributes
- } else {
- req.OperationAttributes[AttributeRequestedAttributes] = attributes
- }
-
- resp, err := c.SendRequest(c.adapter.GetHttpUri("jobs", jobID), req, nil)
- if err != nil {
- return nil, err
- }
-
- if len(resp.JobAttributes) == 0 {
- return nil, errors.New("server doesn't return any job attributes")
- }
-
- return resp.JobAttributes[0], nil
-}
-
-// GetJobs returns jobs from a printer or class
-func (c *IPPClient) GetJobs(printer, class string, whichJobs string, myJobs bool, firstJobId, limit int, attributes []string) (map[int]Attributes, error) {
- req := NewRequest(OperationGetJobs, 1)
- req.OperationAttributes[AttributeWhichJobs] = whichJobs
- req.OperationAttributes[AttributeMyJobs] = myJobs
-
- if printer != "" {
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
- } else if class != "" {
- req.OperationAttributes[AttributePrinterURI] = c.getClassUri(printer)
- } else {
- req.OperationAttributes[AttributePrinterURI] = "ipp://localhost/"
- }
-
- if firstJobId > 0 {
- req.OperationAttributes[AttributeFirstJobID] = firstJobId
- }
-
- if limit > 0 {
- req.OperationAttributes[AttributeLimit] = limit
- }
-
- if myJobs {
- req.OperationAttributes[AttributeRequestingUserName] = c.username
- }
-
- if attributes == nil {
- req.OperationAttributes[AttributeRequestedAttributes] = DefaultJobAttributes
- } else {
- req.OperationAttributes[AttributeRequestedAttributes] = append(attributes, AttributeJobID)
- }
-
- resp, err := c.SendRequest(c.adapter.GetHttpUri("", nil), req, nil)
- if err != nil {
- return nil, err
- }
-
- jobIDMap := make(map[int]Attributes)
-
- for _, jobAttributes := range resp.JobAttributes {
- jobIDMap[jobAttributes[AttributeJobID][0].Value.(int)] = jobAttributes
- }
-
- return jobIDMap, nil
-}
-
-// CancelJob cancels a job. if purge is true, the job will also be removed
-func (c *IPPClient) CancelJob(jobID int, purge bool) error {
- req := NewRequest(OperationCancelJob, 1)
- req.OperationAttributes[AttributeJobURI] = c.getJobUri(jobID)
- req.OperationAttributes[AttributePurgeJobs] = purge
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("jobs", ""), req, nil)
- return err
-}
-
-// CancelAllJob cancels all jobs for a specified printer. if purge is true, the jobs will also be removed
-func (c *IPPClient) CancelAllJob(printer string, purge bool) error {
- req := NewRequest(OperationCancelJobs, 1)
- req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
- req.OperationAttributes[AttributePurgeJobs] = purge
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("admin", ""), req, nil)
- return err
-}
-
-// RestartJob restarts a job
-func (c *IPPClient) RestartJob(jobID int) error {
- req := NewRequest(OperationRestartJob, 1)
- req.OperationAttributes[AttributeJobURI] = c.getJobUri(jobID)
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("jobs", ""), req, nil)
- return err
-}
-
-// HoldJobUntil holds a job
-func (c *IPPClient) HoldJobUntil(jobID int, holdUntil string) error {
- req := NewRequest(OperationRestartJob, 1)
- req.OperationAttributes[AttributeJobURI] = c.getJobUri(jobID)
- req.JobAttributes[AttributeHoldJobUntil] = holdUntil
-
- _, err := c.SendRequest(c.adapter.GetHttpUri("jobs", ""), req, nil)
- return err
-}
-
-// TestConnection tests if a tcp connection to the remote server is possible
-func (c *IPPClient) TestConnection() error {
- return c.adapter.TestConnection()
-}
diff --git a/nix/inputs/dms-cli/pkg/ipp/request.go b/nix/inputs/dms-cli/pkg/ipp/request.go
deleted file mode 100644
index 0c29655..0000000
--- a/nix/inputs/dms-cli/pkg/ipp/request.go
+++ /dev/null
@@ -1,299 +0,0 @@
-package ipp
-
-import (
- "bytes"
- "encoding/binary"
- "io"
-)
-
-// Request defines a ipp request
-type Request struct {
- ProtocolVersionMajor int8
- ProtocolVersionMinor int8
-
- Operation int16
- RequestId int32
-
- OperationAttributes map[string]interface{}
- JobAttributes map[string]interface{}
- PrinterAttributes map[string]interface{}
- SubscriptionAttributes map[string]interface{} // Added for subscription operations
-
- File io.Reader
- FileSize int
-}
-
-// NewRequest creates a new ipp request
-func NewRequest(op int16, reqID int32) *Request {
- return &Request{
- ProtocolVersionMajor: ProtocolVersionMajor,
- ProtocolVersionMinor: ProtocolVersionMinor,
- Operation: op,
- RequestId: reqID,
- OperationAttributes: make(map[string]interface{}),
- JobAttributes: make(map[string]interface{}),
- PrinterAttributes: make(map[string]interface{}),
- SubscriptionAttributes: make(map[string]interface{}),
- File: nil,
- FileSize: -1,
- }
-}
-
-// Encode encodes the request to a byte slice
-func (r *Request) Encode() ([]byte, error) {
- buf := new(bytes.Buffer)
- enc := NewAttributeEncoder(buf)
-
- if err := binary.Write(buf, binary.BigEndian, r.ProtocolVersionMajor); err != nil {
- return nil, err
- }
-
- if err := binary.Write(buf, binary.BigEndian, r.ProtocolVersionMinor); err != nil {
- return nil, err
- }
-
- if err := binary.Write(buf, binary.BigEndian, r.Operation); err != nil {
- return nil, err
- }
-
- if err := binary.Write(buf, binary.BigEndian, r.RequestId); err != nil {
- return nil, err
- }
-
- if err := binary.Write(buf, binary.BigEndian, TagOperation); err != nil {
- return nil, err
- }
-
- if r.OperationAttributes == nil {
- r.OperationAttributes = make(map[string]interface{}, 2)
- }
-
- if _, found := r.OperationAttributes[AttributeCharset]; !found {
- r.OperationAttributes[AttributeCharset] = Charset
- }
-
- if _, found := r.OperationAttributes[AttributeNaturalLanguage]; !found {
- r.OperationAttributes[AttributeNaturalLanguage] = CharsetLanguage
- }
-
- if err := r.encodeOperationAttributes(enc); err != nil {
- return nil, err
- }
-
- if len(r.JobAttributes) > 0 {
- if err := binary.Write(buf, binary.BigEndian, TagJob); err != nil {
- return nil, err
- }
- for attr, value := range r.JobAttributes {
- if err := enc.Encode(attr, value); err != nil {
- return nil, err
- }
- }
- }
-
- if len(r.PrinterAttributes) > 0 {
- if err := binary.Write(buf, binary.BigEndian, TagPrinter); err != nil {
- return nil, err
- }
- for attr, value := range r.PrinterAttributes {
- if err := enc.Encode(attr, value); err != nil {
- return nil, err
- }
- }
- }
-
- if len(r.SubscriptionAttributes) > 0 {
- if err := binary.Write(buf, binary.BigEndian, TagSubscription); err != nil {
- return nil, err
- }
- if err := r.encodeSubscriptionAttributes(enc); err != nil {
- return nil, err
- }
- }
-
- if err := binary.Write(buf, binary.BigEndian, TagEnd); err != nil {
- return nil, err
- }
-
- return buf.Bytes(), nil
-}
-
-func (r *Request) encodeOperationAttributes(enc *AttributeEncoder) error {
- ordered := []string{
- AttributeCharset,
- AttributeNaturalLanguage,
- AttributePrinterURI,
- AttributeJobID,
- }
-
- for _, attr := range ordered {
- if value, ok := r.OperationAttributes[attr]; ok {
- delete(r.OperationAttributes, attr)
- if err := enc.Encode(attr, value); err != nil {
- return err
- }
- }
- }
-
- for attr, value := range r.OperationAttributes {
- if err := enc.Encode(attr, value); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func (r *Request) encodeSubscriptionAttributes(enc *AttributeEncoder) error {
- // Encode subscription attributes in proper order
- // notify-pull-method and notify-lease-duration must come before notify-events
- ordered := []string{
- "notify-pull-method",
- "notify-lease-duration",
- "notify-events",
- }
-
- for _, attr := range ordered {
- if value, ok := r.SubscriptionAttributes[attr]; ok {
- delete(r.SubscriptionAttributes, attr)
- if err := enc.Encode(attr, value); err != nil {
- return err
- }
- }
- }
-
- // Encode any remaining subscription attributes
- for attr, value := range r.SubscriptionAttributes {
- if err := enc.Encode(attr, value); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-// RequestDecoder reads and decodes a request from a stream
-type RequestDecoder struct {
- reader io.Reader
-}
-
-// NewRequestDecoder returns a new decoder that reads from r
-func NewRequestDecoder(r io.Reader) *RequestDecoder {
- return &RequestDecoder{
- reader: r,
- }
-}
-
-// Decode decodes a ipp request into a request struct. additional data will be written to an io.Writer if data is not nil
-func (d *RequestDecoder) Decode(data io.Writer) (*Request, error) {
- req := new(Request)
-
- if err := binary.Read(d.reader, binary.BigEndian, &req.ProtocolVersionMajor); err != nil {
- return nil, err
- }
-
- if err := binary.Read(d.reader, binary.BigEndian, &req.ProtocolVersionMinor); err != nil {
- return nil, err
- }
-
- if err := binary.Read(d.reader, binary.BigEndian, &req.Operation); err != nil {
- return nil, err
- }
-
- if err := binary.Read(d.reader, binary.BigEndian, &req.RequestId); err != nil {
- return nil, err
- }
-
- startByteSlice := make([]byte, 1)
-
- tag := TagCupsInvalid
- previousAttributeName := ""
- tagSet := false
-
- attribDecoder := NewAttributeDecoder(d.reader)
-
- // decode attribute buffer
- for {
- if _, err := d.reader.Read(startByteSlice); err != nil {
- // when we read from a stream, we may get an EOF if we want to read the end tag
- // all data should be read and we can ignore the error
- if err == io.EOF {
- break
- }
- return nil, err
- }
-
- startByte := int8(startByteSlice[0])
-
- // check if attributes are completed
- if startByte == TagEnd {
- break
- }
-
- if startByte == TagOperation {
- if req.OperationAttributes == nil {
- req.OperationAttributes = make(map[string]interface{})
- }
-
- tag = TagOperation
- tagSet = true
-
- }
-
- if startByte == TagJob {
- if req.JobAttributes == nil {
- req.JobAttributes = make(map[string]interface{})
- }
- tag = TagJob
- tagSet = true
- }
-
- if startByte == TagPrinter {
- if req.PrinterAttributes == nil {
- req.PrinterAttributes = make(map[string]interface{})
- }
- tag = TagPrinter
- tagSet = true
- }
-
- if tagSet {
- if _, err := d.reader.Read(startByteSlice); err != nil {
- return nil, err
- }
- startByte = int8(startByteSlice[0])
- }
-
- attrib, err := attribDecoder.Decode(startByte)
- if err != nil {
- return nil, err
- }
-
- if attrib.Name != "" {
- appendAttributeToRequest(req, tag, attrib.Name, attrib.Value)
- previousAttributeName = attrib.Name
- } else {
- appendAttributeToRequest(req, tag, previousAttributeName, attrib.Value)
- }
-
- tagSet = false
- }
-
- if data != nil {
- if _, err := io.Copy(data, d.reader); err != nil {
- return nil, err
- }
- }
-
- return req, nil
-}
-
-func appendAttributeToRequest(req *Request, tag int8, name string, value interface{}) {
- switch tag {
- case TagOperation:
- req.OperationAttributes[name] = value
- case TagPrinter:
- req.PrinterAttributes[name] = value
- case TagJob:
- req.JobAttributes[name] = value
- }
-}
diff --git a/nix/inputs/dms-cli/pkg/ipp/response.go b/nix/inputs/dms-cli/pkg/ipp/response.go
deleted file mode 100644
index 73e3566..0000000
--- a/nix/inputs/dms-cli/pkg/ipp/response.go
+++ /dev/null
@@ -1,383 +0,0 @@
-package ipp
-
-import (
- "bytes"
- "encoding/binary"
- "io"
-)
-
-// Attributes is a wrapper for a set of attributes
-type Attributes map[string][]Attribute
-
-// Response defines a ipp response
-type Response struct {
- ProtocolVersionMajor int8
- ProtocolVersionMinor int8
-
- StatusCode int16
- RequestId int32
-
- OperationAttributes Attributes
- PrinterAttributes []Attributes
- JobAttributes []Attributes
- SubscriptionAttributes []Attributes // Added for subscription responses
-}
-
-// CheckForErrors checks the status code and returns a error if it is not zero. it also returns the status message if provided by the server
-func (r *Response) CheckForErrors() error {
- if r.StatusCode != StatusOk {
- err := IPPError{
- Status: r.StatusCode,
- Message: "no status message returned",
- }
-
- if len(r.OperationAttributes["status-message"]) > 0 {
- err.Message = r.OperationAttributes["status-message"][0].Value.(string)
- }
-
- return err
- }
-
- return nil
-}
-
-// NewResponse creates a new ipp response
-func NewResponse(statusCode int16, reqID int32) *Response {
- return &Response{
- ProtocolVersionMajor: ProtocolVersionMajor,
- ProtocolVersionMinor: ProtocolVersionMinor,
- StatusCode: statusCode,
- RequestId: reqID,
- OperationAttributes: make(Attributes),
- PrinterAttributes: make([]Attributes, 0),
- JobAttributes: make([]Attributes, 0),
- }
-}
-
-// Encode encodes the response to a byte slice
-func (r *Response) Encode() ([]byte, error) {
- buf := new(bytes.Buffer)
- enc := NewAttributeEncoder(buf)
-
- if err := binary.Write(buf, binary.BigEndian, r.ProtocolVersionMajor); err != nil {
- return nil, err
- }
-
- if err := binary.Write(buf, binary.BigEndian, r.ProtocolVersionMinor); err != nil {
- return nil, err
- }
-
- if err := binary.Write(buf, binary.BigEndian, r.StatusCode); err != nil {
- return nil, err
- }
-
- if err := binary.Write(buf, binary.BigEndian, r.RequestId); err != nil {
- return nil, err
- }
-
- if err := binary.Write(buf, binary.BigEndian, TagOperation); err != nil {
- return nil, err
- }
-
- if r.OperationAttributes == nil {
- r.OperationAttributes = make(Attributes, 0)
- }
-
- if _, found := r.OperationAttributes[AttributeCharset]; !found {
- r.OperationAttributes[AttributeCharset] = []Attribute{
- {
- Value: Charset,
- },
- }
- }
-
- if _, found := r.OperationAttributes[AttributeNaturalLanguage]; !found {
- r.OperationAttributes[AttributeNaturalLanguage] = []Attribute{
- {
- Value: CharsetLanguage,
- },
- }
- }
-
- if err := r.encodeOperationAttributes(enc); err != nil {
- return nil, err
- }
-
- if len(r.PrinterAttributes) > 0 {
- for _, printerAttr := range r.PrinterAttributes {
- if err := binary.Write(buf, binary.BigEndian, TagPrinter); err != nil {
- return nil, err
- }
-
- for name, attr := range printerAttr {
- if len(attr) == 0 {
- continue
- }
-
- values := make([]interface{}, len(attr))
- for i, v := range attr {
- values[i] = v.Value
- }
-
- if len(values) == 1 {
- if err := enc.Encode(name, values[0]); err != nil {
- return nil, err
- }
- } else {
- if err := enc.Encode(name, values); err != nil {
- return nil, err
- }
- }
- }
- }
- }
-
- if len(r.JobAttributes) > 0 {
- for _, jobAttr := range r.JobAttributes {
- if err := binary.Write(buf, binary.BigEndian, TagJob); err != nil {
- return nil, err
- }
-
- for name, attr := range jobAttr {
- if len(attr) == 0 {
- continue
- }
-
- values := make([]interface{}, len(attr))
- for i, v := range attr {
- values[i] = v.Value
- }
-
- if len(values) == 1 {
- if err := enc.Encode(name, values[0]); err != nil {
- return nil, err
- }
- } else {
- if err := enc.Encode(name, values); err != nil {
- return nil, err
- }
- }
- }
- }
- }
-
- if err := binary.Write(buf, binary.BigEndian, TagEnd); err != nil {
- return nil, err
- }
-
- return buf.Bytes(), nil
-}
-
-func (r *Response) encodeOperationAttributes(enc *AttributeEncoder) error {
- ordered := []string{
- AttributeCharset,
- AttributeNaturalLanguage,
- AttributePrinterURI,
- AttributeJobID,
- }
-
- for _, name := range ordered {
- if attr, ok := r.OperationAttributes[name]; ok {
- delete(r.OperationAttributes, name)
- if err := encodeOperationAttribute(enc, name, attr); err != nil {
- return err
- }
- }
- }
-
- for name, attr := range r.OperationAttributes {
- if err := encodeOperationAttribute(enc, name, attr); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func encodeOperationAttribute(enc *AttributeEncoder, name string, attr []Attribute) error {
- if len(attr) == 0 {
- return nil
- }
-
- values := make([]interface{}, len(attr))
- for i, v := range attr {
- values[i] = v.Value
- }
-
- if len(values) == 1 {
- return enc.Encode(name, values[0])
- }
-
- return enc.Encode(name, values)
-}
-
-// ResponseDecoder reads and decodes a response from a stream
-type ResponseDecoder struct {
- reader io.Reader
-}
-
-// NewResponseDecoder returns a new decoder that reads from r
-func NewResponseDecoder(r io.Reader) *ResponseDecoder {
- return &ResponseDecoder{
- reader: r,
- }
-}
-
-// Decode decodes a ipp response into a response struct. additional data will be written to an io.Writer if data is not nil
-func (d *ResponseDecoder) Decode(data io.Writer) (*Response, error) {
- /*
- 1 byte: Protocol Major Version - b
- 1 byte: Protocol Minor Version - b
- 2 byte: Status ID - h
- 4 byte: Request ID - i
- 1 byte: Operation Attribute Byte (\0x01)
- N times: Attributes
- 1 byte: Attribute End Byte (\0x03)
- */
-
- resp := new(Response)
-
- // wrap the reader so we have more functionality
- // reader := bufio.NewReader(d.reader)
-
- if err := binary.Read(d.reader, binary.BigEndian, &resp.ProtocolVersionMajor); err != nil {
- return nil, err
- }
-
- if err := binary.Read(d.reader, binary.BigEndian, &resp.ProtocolVersionMinor); err != nil {
- return nil, err
- }
-
- if err := binary.Read(d.reader, binary.BigEndian, &resp.StatusCode); err != nil {
- return nil, err
- }
-
- if err := binary.Read(d.reader, binary.BigEndian, &resp.RequestId); err != nil {
- return nil, err
- }
-
- startByteSlice := make([]byte, 1)
-
- tag := TagCupsInvalid
- previousAttributeName := ""
- tempAttributes := make(Attributes)
- tagSet := false
-
- attribDecoder := NewAttributeDecoder(d.reader)
-
- // decode attribute buffer
- for {
- if _, err := d.reader.Read(startByteSlice); err != nil {
- // when we read from a stream, we may get an EOF if we want to read the end tag
- // all data should be read and we can ignore the error
- if err == io.EOF {
- break
- }
- return nil, err
- }
-
- startByte := int8(startByteSlice[0])
-
- // check if attributes are completed
- if startByte == TagEnd {
- break
- }
-
- if startByte == TagOperation {
- if len(tempAttributes) > 0 && tag != TagCupsInvalid {
- appendAttributeToResponse(resp, tag, tempAttributes)
- tempAttributes = make(Attributes)
- }
-
- tag = TagOperation
- tagSet = true
- }
-
- if startByte == TagJob {
- if len(tempAttributes) > 0 && tag != TagCupsInvalid {
- appendAttributeToResponse(resp, tag, tempAttributes)
- tempAttributes = make(Attributes)
- }
-
- tag = TagJob
- tagSet = true
- }
-
- if startByte == TagPrinter {
- if len(tempAttributes) > 0 && tag != TagCupsInvalid {
- appendAttributeToResponse(resp, tag, tempAttributes)
- tempAttributes = make(Attributes)
- }
-
- tag = TagPrinter
- tagSet = true
- }
-
- if startByte == TagSubscription {
- if len(tempAttributes) > 0 && tag != TagCupsInvalid {
- appendAttributeToResponse(resp, tag, tempAttributes)
- tempAttributes = make(Attributes)
- }
-
- tag = TagSubscription
- tagSet = true
- }
-
- if startByte == TagEventNotification {
- if len(tempAttributes) > 0 && tag != TagCupsInvalid {
- appendAttributeToResponse(resp, tag, tempAttributes)
- tempAttributes = make(Attributes)
- }
-
- tag = TagEventNotification
- tagSet = true
- }
-
- if tagSet {
- if _, err := d.reader.Read(startByteSlice); err != nil {
- return nil, err
- }
- startByte = int8(startByteSlice[0])
- }
-
- attrib, err := attribDecoder.Decode(startByte)
- if err != nil {
- return nil, err
- }
-
- if attrib.Name != "" {
- tempAttributes[attrib.Name] = append(tempAttributes[attrib.Name], *attrib)
- previousAttributeName = attrib.Name
- } else {
- tempAttributes[previousAttributeName] = append(tempAttributes[previousAttributeName], *attrib)
- }
-
- tagSet = false
- }
-
- if len(tempAttributes) > 0 && tag != TagCupsInvalid {
- appendAttributeToResponse(resp, tag, tempAttributes)
- }
-
- if data != nil {
- if _, err := io.Copy(data, d.reader); err != nil {
- return nil, err
- }
- }
-
- return resp, nil
-}
-
-func appendAttributeToResponse(resp *Response, tag int8, attr map[string][]Attribute) {
- switch tag {
- case TagOperation:
- resp.OperationAttributes = attr
- case TagPrinter:
- resp.PrinterAttributes = append(resp.PrinterAttributes, attr)
- case TagJob:
- resp.JobAttributes = append(resp.JobAttributes, attr)
- case TagSubscription, TagEventNotification:
- // Both subscription and event notification attributes go to SubscriptionAttributes
- resp.SubscriptionAttributes = append(resp.SubscriptionAttributes, attr)
- }
-}
diff --git a/nix/inputs/dms-cli/pkg/ipp/utils.go b/nix/inputs/dms-cli/pkg/ipp/utils.go
deleted file mode 100644
index 62689a3..0000000
--- a/nix/inputs/dms-cli/pkg/ipp/utils.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package ipp
-
-import (
- "fmt"
- "os"
- "path"
-)
-
-// ParseControlFile reads and decodes a cups control file into a response
-func ParseControlFile(jobID int, spoolDirectory string) (*Response, error) {
- if spoolDirectory == "" {
- spoolDirectory = "/var/spool/cups"
- }
-
- controlFilePath := path.Join(spoolDirectory, fmt.Sprintf("c%d", jobID))
-
- if _, err := os.Stat(controlFilePath); err != nil {
- return nil, err
- }
-
- controlFile, err := os.Open(controlFilePath)
- if err != nil {
- return nil, err
- }
- defer controlFile.Close()
-
- return NewResponseDecoder(controlFile).Decode(nil)
-}
diff --git a/pkgs/nix-benchmark/nix/package.nix b/pkgs/nix-benchmark/nix/package.nix
index a4570c3..ffa6d8a 100644
--- a/pkgs/nix-benchmark/nix/package.nix
+++ b/pkgs/nix-benchmark/nix/package.nix
@@ -28,6 +28,7 @@ stdenvNoCC.mkDerivation {
nixVersions.nix_2_32
nixVersions.git
lixPackageSets.lix_2_93.lix
+ lixPackageSets.lix_2_94.lix
lixPackageSets.git.lix
]);
diff --git a/pkgs/nix-benchmark/src/nix-benchmark.sh b/pkgs/nix-benchmark/src/nix-benchmark.sh
index de1b2c3..f8fad1e 100755
--- a/pkgs/nix-benchmark/src/nix-benchmark.sh
+++ b/pkgs/nix-benchmark/src/nix-benchmark.sh
@@ -21,10 +21,6 @@ showUsage() {
origArgs=("$@")
nixBins=(@nixBins@)
-# We use both `pipe-operator` and `pipe-operators` because Lix decided to be
-# quirky and remove the 's' from the name, whilst every other Nix version still
-# uses 'operators'. Extremly irritating change on Lix's end.
-nixEvalArgs="eval --option eval-cache false --option extra-experimental-features 'pipe-operator pipe-operators' --raw"
flakeRef=
while [ "$#" -gt 0 ]; do
@@ -56,11 +52,29 @@ fi
benchmarkNixEval() {
local nixBinary="$1"
+ local nixEvalArgs="eval --raw --option 'eval-cache' 'false' --option 'extra-experimental-features'"
local name="$($nixBinary --version 2> /dev/null | head -n1)"
+
+ # Both Nix and Lix support the pipe (`|>`) operator through an optional
+ # experimental feature toggle. However, they both use different names for
+ # the feature. Lix uses 'pipe-operator', whilst Nix uses 'pipe-operators'.
+ #
+ # Lix's reasoning is that their implementation of the operator differs from
+ # official Nix, and as a result should be disambiguated. In practice I have
+ # not actually seen much of a difference, but I'll take their word for it.
+ #
+ # In order to respect this difference, I append to the experimental feature
+ # depending on which version of Nix is being used for benchmarking.
+ if [[ "$name" == "nix (Lix, like Nix)"* ]]; then
+ nixEvalArgs="$nixEvalArgs 'pipe-operator'"
+ else
+ nixEvalArgs="$nixEvalArgs 'pipe-operators'"
+ fi
+
local cmd="$nixBinary $nixEvalArgs '$flakeRef.drvPath'"
- hyperfine --warmup 5 --runs 20 --command-name "$name" "$cmd"
+ hyperfine --warmup 4 --runs 8 --command-name "$name" "$cmd"
}
for bin in "${nixBins[@]}"; do
diff --git a/users/frontear/home/desktops/niri/default.nix b/users/frontear/home/desktops/niri/default.nix
index 7e213d2..b53e2e5 100644
--- a/users/frontear/home/desktops/niri/default.nix
+++ b/users/frontear/home/desktops/niri/default.nix
@@ -26,6 +26,12 @@ in {
repeat-rate 25
}
+ mouse {
+ accel-profile "flat"
+ // scroll-button 274 // found with `libinput debug-events`
+ // scroll-method "on-button-down"
+ }
+
touchpad {
accel-profile "adaptive"
click-method "clickfinger"
diff --git a/users/frontear/nixos/default.nix b/users/frontear/nixos/default.nix
index 5229319..1afd6fb 100644
--- a/users/frontear/nixos/default.nix
+++ b/users/frontear/nixos/default.nix
@@ -16,5 +16,10 @@
extraGroups = [ "wheel" ] ++
(lib.optional config.networking.networkmanager.enable "networkmanager");
};
+
+ # Allow my user to control the OpenRazer daemon.
+ hardware.openrazer.users = [
+ "frontear"
+ ];
};
}
\ No newline at end of file