From 1932c72becb2c16cf5563eda9b18b88d06db9940 Mon Sep 17 00:00:00 2001 From: cwyc Date: Wed, 19 Aug 2020 20:50:29 -0400 Subject: [PATCH 1/2] xdg-desktop-entries: add module rebase --- .github/CODEOWNERS | 5 + modules/misc/xdg-desktop-entries.nix | 152 ++++++++++++++++++ modules/modules.nix | 1 + tests/modules/misc/xdg/default.nix | 1 + tests/modules/misc/xdg/desktop-entries.nix | 53 ++++++ .../misc/xdg/desktop-full-expected.desktop | 14 ++ .../misc/xdg/desktop-min-expected.desktop | 6 + 7 files changed, 232 insertions(+) create mode 100644 modules/misc/xdg-desktop-entries.nix create mode 100644 tests/modules/misc/xdg/desktop-entries.nix create mode 100644 tests/modules/misc/xdg/desktop-full-expected.desktop create mode 100644 tests/modules/misc/xdg/desktop-min-expected.desktop diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d8640934de4a..2b3a9a5d5d0f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -37,6 +37,11 @@ /modules/misc/xdg-system-dirs.nix @tadfisher /tests/modules/misc/xdg/system-dirs.nix @tadfisher +/modules/misc/xdg-desktop-entries.nix @cwyc +/tests/modules/misc/xdg/desktop-entries.nix @cwyc +/tests/modules/misc/xdg/desktop-full-expected.desktop @cwyc +/tests/modules/misc/xdg/desktop-min-expected.desktop @cwyc + /modules/programs/aria2.nix @JustinLovinger /modules/programs/autojump.nix @evanjs diff --git a/modules/misc/xdg-desktop-entries.nix b/modules/misc/xdg-desktop-entries.nix new file mode 100644 index 000000000000..4853a34c5738 --- /dev/null +++ b/modules/misc/xdg-desktop-entries.nix @@ -0,0 +1,152 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + desktopEntry = { + options = { + # Since this module uses the nixpkgs/pkgs/build-support/make-desktopitem function, + # our options and defaults follow its parameters, with the following exceptions: + + # `desktopName` on makeDesktopItem is controlled by `name`. + # This is what we'd commonly consider the name of the application. + # `name` on makeDesktopItem is controlled by this module's key in the attrset. + # This is the file's filename excluding ".desktop". + + # `extraEntries` on makeDesktopItem is controlled by `extraConfig` + # to match what's commonly used by other home manager modules. + + # `terminal` and `startupNotify` on makeDesktopItem ask for "true" or "false" strings, + # for usability's sake we ask for a boolean. + + # `mimeType` and `categories` on makeDesktopItem ask for a string in the format "one;two;three;", + # for the same reason we ask for a list of strings. + + # `fileValidation` isn't exposed for simplicity's sake + + # Descriptions are taken from the desktop entry spec: + # https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#recognized-keys + + type = mkOption { + description = "The type of the desktop entry."; + default = "Application"; + type = types.enum [ "Application" "Link" "Directory" ]; + }; + + exec = mkOption { + description = "Program to execute, possibly with arguments."; + type = types.str; + }; + + icon = mkOption { + description = "Icon to display in file manager, menus, etc."; + type = types.nullOr types.str; + default = null; + }; + + comment = mkOption { + description = "Tooltip for the entry."; + type = types.nullOr types.str; + default = null; + }; + + terminal = mkOption { + description = "Whether the program runs in a terminal window."; + type = types.bool; + default = false; + }; + + name = mkOption { + description = "Specific name of the application."; + type = types.str; + }; + + genericName = mkOption { + description = "Generic name of the application."; + type = types.nullOr types.str; + default = null; + }; + + mimeType = mkOption { + description = "The MIME type(s) supported by this application."; + type = types.nullOr (types.listOf types.str); + default = null; + }; + + categories = mkOption { + description = + "Categories in which the entry should be shown in a menu."; + type = types.nullOr (types.listOf types.str); + default = null; + }; + + startupNotify = mkOption { + description = '' + If true, it is KNOWN that the application will send a "remove" + message when started with the DESKTOP_STARTUP_ID + environment variable set. If false, it is KNOWN that the application + does not work with startup notification at all.''; + type = types.nullOr types.bool; + default = null; + }; + + extraConfig = mkOption { + description = "Extra lines to add to the desktop file."; + type = types.nullOr types.lines; + default = null; + }; + }; + }; + + #formatting helpers + ifNotNull = a: a': if a == null then null else a'; + stringBool = bool: if bool then "true" else "false"; + semicolonList = list: + (concatStringsSep ";" list) + ";"; # requires trailing semicolon + + #passing config options to makeDesktopItem in expected format + makeFile = name: config: + pkgs.makeDesktopItem { + name = name; + type = config.type; + exec = config.exec; + icon = config.icon; + comment = config.comment; + terminal = ifNotNull config.terminal (stringBool config.terminal); + desktopName = config.name; + genericName = config.genericName; + mimeType = ifNotNull config.mimeType (semicolonList config.mimeType); + categories = + ifNotNull config.categories (semicolonList config.categories); + startupNotify = + ifNotNull config.startupNotify (stringBool config.startupNotify); + extraEntries = config.extraConfig; + }; +in { + meta.maintainers = with maintainers; [ cwyc ]; + + options.xdg.desktopEntries = mkOption { + description = '' + Desktop Entries allow applications to be shown in your desktop environment's app launcher. + You can define entries for programs without entries or override existing entries. + See for more information on options. + ''; + default = { }; + type = types.attrsOf (types.submodule desktopEntry); + example = { + firefox = { + name = "Firefox"; + genericName = "Web Browser"; + exec = "firefox %U"; + terminal = false; + categories = [ "Application" "Network" "WebBrowser" ]; + mimeType = [ "text/html" "text/xml" ]; + }; + }; + }; + + config.home.packages = mkIf (config.xdg.desktopEntries != { }) + (map hiPrio # we need hiPrio to override existing entries + (attrsets.mapAttrsToList makeFile config.xdg.desktopEntries)); + +} diff --git a/modules/modules.nix b/modules/modules.nix index e7f4c1b63db0..c0dd457c7ff7 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -41,6 +41,7 @@ let (loadModule ./misc/version.nix { }) (loadModule ./misc/vte.nix { }) (loadModule ./misc/xdg-system-dirs.nix { condition = hostPlatform.isLinux; }) + (loadModule ./misc/xdg-desktop-entries.nix { condition = hostPlatform.isLinux; }) (loadModule ./misc/xdg-mime.nix { condition = hostPlatform.isLinux; }) (loadModule ./misc/xdg-mime-apps.nix { condition = hostPlatform.isLinux; }) (loadModule ./misc/xdg-user-dirs.nix { condition = hostPlatform.isLinux; }) diff --git a/tests/modules/misc/xdg/default.nix b/tests/modules/misc/xdg/default.nix index 45610154c3e5..b637cd1bf5a3 100644 --- a/tests/modules/misc/xdg/default.nix +++ b/tests/modules/misc/xdg/default.nix @@ -2,4 +2,5 @@ xdg-mime-apps-basics = ./mime-apps-basics.nix; xdg-file-attr-names = ./file-attr-names.nix; xdg-system-dirs = ./system-dirs.nix; + xdg-desktop-entries = ./desktop-entries.nix; } diff --git a/tests/modules/misc/xdg/desktop-entries.nix b/tests/modules/misc/xdg/desktop-entries.nix new file mode 100644 index 000000000000..5f4783ed47b6 --- /dev/null +++ b/tests/modules/misc/xdg/desktop-entries.nix @@ -0,0 +1,53 @@ +{ config, lib, pkgs, ... }: + +with lib; + +{ + config = { + xdg.desktopEntries = { + full = { # full definition + type = "Application"; + exec = "test --option"; + icon = "test"; + comment = "My Application"; + terminal = true; + name = "Test"; + genericName = "Web Browser"; + mimeType = [ "text/html" "text/xml" ]; + categories = [ "Application" "Network" "WebBrowser" ]; + startupNotify = false; + extraConfig = '' + NoDisplay=false + DBusActivatable=false + ''; + }; + min = { # minimal definition + exec = "test --option"; + name = "Test"; + }; + }; + + #testing that preexisting entries in the store are overridden + home.packages = [ + (pkgs.makeDesktopItem { + name = "full"; + desktopName = "We don't want this"; + exec = "no"; + }) + (pkgs.makeDesktopItem { + name = "min"; + desktopName = "We don't want this"; + exec = "no"; + }) + ]; + + nmt.script = '' + assertFileExists home-path/share/applications/full.desktop + assertFileExists home-path/share/applications/min.desktop + assertFileContent home-path/share/applications/full.desktop \ + ${./desktop-full-expected.desktop} + assertFileContent home-path/share/applications/min.desktop \ + ${./desktop-min-expected.desktop} + ''; + }; +} diff --git a/tests/modules/misc/xdg/desktop-full-expected.desktop b/tests/modules/misc/xdg/desktop-full-expected.desktop new file mode 100644 index 000000000000..2998fb64e729 --- /dev/null +++ b/tests/modules/misc/xdg/desktop-full-expected.desktop @@ -0,0 +1,14 @@ +[Desktop Entry] +Type=Application +Exec=test --option +Terminal=true +Name=Test +Icon=test +Comment=My Application +GenericName=Web Browser +MimeType=text/html;text/xml; +Categories=Application;Network;WebBrowser; +StartupNotify=false +NoDisplay=false +DBusActivatable=false + diff --git a/tests/modules/misc/xdg/desktop-min-expected.desktop b/tests/modules/misc/xdg/desktop-min-expected.desktop new file mode 100644 index 000000000000..745492e4f5a7 --- /dev/null +++ b/tests/modules/misc/xdg/desktop-min-expected.desktop @@ -0,0 +1,6 @@ +[Desktop Entry] +Type=Application +Exec=test --option +Terminal=false +Name=Test + From fc023b469a7bab0755983ea663c7986f5af5f5d5 Mon Sep 17 00:00:00 2001 From: --get <--show> Date: Fri, 23 Oct 2020 22:36:02 -0400 Subject: [PATCH 2/2] xdg-desktop-entries: adapt to changes in makeDesktopItem This package depends on the makeDesktopItem function in nixpkgs, which recently changed its syntax: https://github.com/NixOS/nixpkgs/pull/91790 This commit makes the module compatible with the new syntax. It also exposes the fileValidation option in makeDesktopItem. --- modules/misc/xdg-desktop-entries.nix | 64 +++++++++++++------ tests/modules/misc/xdg/desktop-entries.nix | 11 +++- .../misc/xdg/desktop-full-expected.desktop | 18 +++--- .../misc/xdg/desktop-min-expected.desktop | 5 +- 4 files changed, 65 insertions(+), 33 deletions(-) diff --git a/modules/misc/xdg-desktop-entries.nix b/modules/misc/xdg-desktop-entries.nix index 4853a34c5738..382d6c2b56eb 100644 --- a/modules/misc/xdg-desktop-entries.nix +++ b/modules/misc/xdg-desktop-entries.nix @@ -13,17 +13,16 @@ let # `name` on makeDesktopItem is controlled by this module's key in the attrset. # This is the file's filename excluding ".desktop". - # `extraEntries` on makeDesktopItem is controlled by `extraConfig` + # `extraEntries` on makeDesktopItem is controlled by `extraConfig`, + # and `extraDesktopEntries` by `settings`, # to match what's commonly used by other home manager modules. - # `terminal` and `startupNotify` on makeDesktopItem ask for "true" or "false" strings, + # `startupNotify` on makeDesktopItem asks for "true" or "false" strings, # for usability's sake we ask for a boolean. # `mimeType` and `categories` on makeDesktopItem ask for a string in the format "one;two;three;", # for the same reason we ask for a list of strings. - # `fileValidation` isn't exposed for simplicity's sake - # Descriptions are taken from the desktop entry spec: # https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#recognized-keys @@ -91,9 +90,33 @@ let }; extraConfig = mkOption { - description = "Extra lines to add to the desktop file."; - type = types.nullOr types.lines; - default = null; + description = '' + Extra configuration. Will be appended to the end of the file and + may thus contain extra sections. + ''; + type = types.lines; + default = ""; + }; + + settings = mkOption { + type = types.attrsOf types.string; + description = '' + Extra key-value pairs to add to the [Desktop Entry] section. + This may override other values. + ''; + default = { }; + example = literalExample '' + { + Keywords = "calc;math"; + DBusActivatable = "false"; + } + ''; + }; + + fileValidation = mkOption { + type = types.bool; + description = "Whether to validate the generated desktop file."; + default = true; }; }; }; @@ -104,7 +127,7 @@ let semicolonList = list: (concatStringsSep ";" list) + ";"; # requires trailing semicolon - #passing config options to makeDesktopItem in expected format + #passes config options to makeDesktopItem in expected format makeFile = name: config: pkgs.makeDesktopItem { name = name; @@ -112,7 +135,7 @@ let exec = config.exec; icon = config.icon; comment = config.comment; - terminal = ifNotNull config.terminal (stringBool config.terminal); + terminal = config.terminal; desktopName = config.name; genericName = config.genericName; mimeType = ifNotNull config.mimeType (semicolonList config.mimeType); @@ -121,6 +144,7 @@ let startupNotify = ifNotNull config.startupNotify (stringBool config.startupNotify); extraEntries = config.extraConfig; + extraDesktopEntries = config.settings; }; in { meta.maintainers = with maintainers; [ cwyc ]; @@ -133,16 +157,18 @@ in { ''; default = { }; type = types.attrsOf (types.submodule desktopEntry); - example = { - firefox = { - name = "Firefox"; - genericName = "Web Browser"; - exec = "firefox %U"; - terminal = false; - categories = [ "Application" "Network" "WebBrowser" ]; - mimeType = [ "text/html" "text/xml" ]; - }; - }; + example = literalExample '' + { + firefox = { + name = "Firefox"; + genericName = "Web Browser"; + exec = "firefox %U"; + terminal = false; + categories = [ "Application" "Network" "WebBrowser" ]; + mimeType = [ "text/html" "text/xml" ]; + }; + } + ''; }; config.home.packages = mkIf (config.xdg.desktopEntries != { }) diff --git a/tests/modules/misc/xdg/desktop-entries.nix b/tests/modules/misc/xdg/desktop-entries.nix index 5f4783ed47b6..098aa7eeede5 100644 --- a/tests/modules/misc/xdg/desktop-entries.nix +++ b/tests/modules/misc/xdg/desktop-entries.nix @@ -14,12 +14,17 @@ with lib; name = "Test"; genericName = "Web Browser"; mimeType = [ "text/html" "text/xml" ]; - categories = [ "Application" "Network" "WebBrowser" ]; + categories = [ "Network" "WebBrowser" ]; startupNotify = false; extraConfig = '' - NoDisplay=false - DBusActivatable=false + [X-ExtraSection] + Exec=foo -o ''; + settings = { + Keywords = "calc;math"; + DBusActivatable = "false"; + }; + fileValidation = true; }; min = { # minimal definition exec = "test --option"; diff --git a/tests/modules/misc/xdg/desktop-full-expected.desktop b/tests/modules/misc/xdg/desktop-full-expected.desktop index 2998fb64e729..fd5ace1b9263 100644 --- a/tests/modules/misc/xdg/desktop-full-expected.desktop +++ b/tests/modules/misc/xdg/desktop-full-expected.desktop @@ -1,14 +1,16 @@ [Desktop Entry] -Type=Application -Exec=test --option -Terminal=true -Name=Test -Icon=test +Categories=Network;WebBrowser; Comment=My Application +DBusActivatable=false +Exec=test --option GenericName=Web Browser +Icon=test +Keywords=calc;math MimeType=text/html;text/xml; -Categories=Application;Network;WebBrowser; +Name=Test StartupNotify=false -NoDisplay=false -DBusActivatable=false +Terminal=true +Type=Application +[X-ExtraSection] +Exec=foo -o diff --git a/tests/modules/misc/xdg/desktop-min-expected.desktop b/tests/modules/misc/xdg/desktop-min-expected.desktop index 745492e4f5a7..9475024ae992 100644 --- a/tests/modules/misc/xdg/desktop-min-expected.desktop +++ b/tests/modules/misc/xdg/desktop-min-expected.desktop @@ -1,6 +1,5 @@ [Desktop Entry] -Type=Application Exec=test --option -Terminal=false Name=Test - +Terminal=false +Type=Application