makeFromDesktopEntry()

Hello,

For awhile I’ve been using a quick function I’ve made (in the same vein as nixpkgs own makeDesktopEntry), just thought I’d post in here in the event the larger community may benefit from it. In essence, this function creates a derivation which instantiates to a desktop file which has been based on another (with some key=value modifications made to specific sections). I use this primarily to create “override” entries (where all I want is a few small modifications to an already existing desktop file).

e.g.

makeFromDesktopEntry = (import ./src {inherit pkgs;});

makeFromDesktopEntry {
   from = pkgs.firefox;
   name = "firefox";
   mods = {
      "[Desktop Entry]" = {
         "Icon" = "web-browser";
         "GenericName" = "Internet Web Browser";
      };
     "[Desktop Action new-private-window]" = {
         "Name" = "New not-so-private Window";
      };
   };
}

# Which creates /nix/store/<hash-entry>/share/applications/firefox.desktop
# Which in turn contains the default firefox desktop entry text but with the above keys changed

*This function doesn’t have the same strong typing as makeDesktopEntry (to lazy to implement it) so besides structures all data types are strings.

Source:

{ pkgs, ... }:

let
   mkSectionKeys = section:
      builtins.attrValues (builtins.mapAttrs (key: value:
         "${key}=${value}") section);
   mkSectionsMods = entry:
      ((builtins.concatStringsSep "\n" (builtins.concatLists (
         builtins.attrValues (builtins.mapAttrs (section: mod:
            [section] ++ (mkSectionKeys mod)) entry)))) + "\n");

   mkFromDesktopEntry = {
        from
      , name
      , mods
      , rename ? name
   }: pkgs.runCommandLocal "from-${rename}-desktop" {} ''
      input_file="${from}/share/applications/${name}.desktop"
      output_file="$out/share/applications/${rename}.desktop"

      if [ ! -e "$input_file" ]; then
         echo "Error: File '$input_File' doesn't exist" 
         exit 1
      fi

      mkdir -p "$out/share/applications/"
      awk -v "mods=${mkSectionsMods mods}" '
         BEGIN{
            FS = "=";
            n_sections = 0;
            n_changes = 0;
            n_lines = split(mods, lines, "\n");

            for (i = 1; i <= n_lines; i++) {
               if (match(lines[i], "^\\[[[:print:]]+\\]$")) {
                  n_sections++;
                  sections[n_sections] = i;
               }
            }
         } {
            swapped = 0;

            if (match($0, "^[[:space:]]*\\[[[:print:]]+\\][[:space:]]*$")) {
               while (n_changes > 0) {
                  if (changes[n_changes]) {
                     print(changes[n_changes]);
                  }
                  n_changes--;
               }

               print("")
               for (i = 1; i <= n_sections; i++) {
                  section = lines[sections[i]];
                  gsub(/[\\.^$(){}\[\]|*+?]/, "\\\\&", section);
                  if (match($0, "^[[:space:]]*" section "[[:space:]]*$")) {
                     start = (sections[i] + 1);
                     if (n_sections == i) {
                        end = n_lines;
                     } else {
                        end = (sections[i + 1] - 1);
                     }

                     for (n = start; n <= end; n++) {
                        if (lines[n] != "") {
                           n_changes++;
                           changes[n_changes] = lines[n];
                        }
                     }
                     break;
                  }
               }
            } else {
               for (i = 1; i <= n_changes; i++) {
                  if (split(changes[i], key) >= 2) {
                     if (match($1, "^[[:space:]]*" key[1] "[[:space:]]*$")) {
                        print changes[i];
                        changes[i] = "";
                        swapped = 1;
                        break;
                     }
                  }
               }
            }

            if ((!swapped) && $0) {
               print($0)
            }
         } END{
            while (n_changes > 0) {
               if (changes[n_changes]) {
                  print(changes[n_changes]);
               }
               n_changes--;
            }
         }' "$input_file" > "$output_file"
   '';
in mkFromDesktopEntry

Thanks,

2 Likes