Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setup hook to make Exec= paths absolute in desktop files #68035

Open
wants to merge 7 commits into
base: master
from

Conversation

@symphorien
Copy link
Contributor

symphorien commented Sep 3, 2019

Motivation for this change

Using sed to replace a path in a desktop file with an absolute one is a common idiom in nixpkgs: https://search.nix.gsc.io/?q=(sed%7Csubstitute).*desktop&i=nope&files=&repos= has about 150 matches.

This setup hook automates this in a similar fashion as patchShebangs. A selection of derivations are converted to using this setup hook both to test and illustrate its usage.

(the deepin changes were tested the last revision of nixpkgs where it builds)

The setup hook is designed to be able to handle several Exec= lines in a single desktop file, and handle both existing and inexsting (think /usr/bin), absolute and relative paths. It will bail out if the Exec= line is quoted because I am unable to implement this in bash, and I found no perl or python library which can both read and write properly quoted argv arrays in desktop files.

Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nix-review --run "nix-review wip"
  • Determined the impact on package closure size (by running nix path-info -S before and after)
  • Fits CONTRIBUTING.md.
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested execution of all binary files (usually in ./result/bin/)
  • Ensured that relevant documentation is up to date
symphorien added 2 commits Sep 3, 2019
this setup hook rewrites Exec= to an absolute path in desktop entries,
like what patchShebangs does to scripts.
@exi
exi approved these changes Sep 4, 2019
fi;
done
if [[ -z $success ]]; then
echo "Warning: $desktopFile has Exec=$execname which is not found in $dirs or is not executable.";

This comment has been minimized.

Copy link
@ttuegel

ttuegel Sep 4, 2019

Member

I would prefer that this be an error instead of a warning if the $execname is not found. The warning is too easy to miss.

This comment has been minimized.

Copy link
@symphorien

symphorien Sep 4, 2019

Author Contributor

done

@ofborg ofborg bot requested review from exi and ttuegel Sep 4, 2019
@jtojnar

This comment has been minimized.

Copy link
Contributor

jtojnar commented Sep 4, 2019

GLib has a keyfile parser but it is not very Pythonic:

#!/usr/bin/env nix-shell
#!nix-shell -p python3.pkgs.pygobject3 -p glib -i python3
import gi
gi.require_version('GLib', '2.0')

import argparse
import sys

from gi.repository import GLib
from pathlib import Path

PATH_KEYS = [
GLib.KEY_FILE_DESKTOP_KEY_EXEC,
GLib.KEY_FILE_DESKTOP_KEY_TRY_EXEC,
]

def absolutize(value, bindir):
	executable = bindir / Path(value).name
	if executable.is_file():
		return executable
	else:
		raise FileNotFoundError(f'{executable} does not exist')


if __name__ == '__main__':
	parser = argparse.ArgumentParser(description='Absolutize desktop files')
	parser.add_argument('prefix', help='Path where to base applicationsdir and bindir on')
	args = parser.parse_args()

	applicationsdir = Path(args.prefix, 'share', 'applications')
	bindir = Path(args.prefix, 'bin')
	for desktop_path in applicationsdir.iterdir():
		print(f'Patching {desktop_path}', file=sys.stderr)
		if desktop_path.suffix == '.desktop':
			desktop = GLib.KeyFile()
			desktop.load_from_file(desktop_path.as_posix(), GLib.KeyFileFlags.KEEP_TRANSLATIONS | GLib.KeyFileFlags.KEEP_COMMENTS)
			groups, _len = desktop.get_groups()
			for group in groups:
				for key in PATH_KEYS:
					try:
						value = desktop.get_string(group, key)
						if value:
							# TODO: parse the Exec lines according to https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s07.html
							print(f'\tReplacing [{group}]{key}={value}', file=sys.stderr)
							executable, rest = value.split(' ', 1)
							if '"' in executable:
								print(f'\t\tSkipping executable containing quotes', file=sys.stderr)
							else:
								new_value = f'{absolutize(executable, bindir)} {rest}'
								desktop.set_string(group, key, new_value)
					except GLib.Error as e:
						if not e.code == GLib.KeyFileError.KEY_NOT_FOUND:
							raise e
			desktop.save_to_file(desktop_path.as_posix())
@exi
exi approved these changes Sep 5, 2019
continue;;
*)
# we look in $out/bin and buildInputs
dirs="${!outputBin}/bin:$HOST_PATH";

This comment has been minimized.

Copy link
@matthewbauer
@symphorien

This comment has been minimized.

Copy link
Contributor Author

symphorien commented Sep 6, 2019

About writing the setup hook in python: I have the secret hope that if this setup hook proves useful, it may become part of stdenv, like patchShebangs. If this is the case, writing it in bash is a plus.
I would have gone the python way if there was a compelling feature, like a python module to escape/unescape Exec= lines. There is none (pyxdg is just useless), so I would prefer bash. (I also considered perl, but https://metacpan.org/pod/File::DesktopEntry can only read but not write argv arrays as Exec= value).

@worldofpeace

This comment has been minimized.

Copy link
Member

worldofpeace commented Sep 11, 2019

Could we get a more specific name than desktopFileHook? With that name I can't really tell that it patches all desktop files to have absolute paths for Exec.

Could we also document the hook?

@lheckemann lheckemann added this to the 20.03 milestone Sep 12, 2019
@symphorien

This comment has been minimized.

Copy link
Contributor Author

symphorien commented Sep 13, 2019

Would patchDesktopFileExec be a better name?
I will write documentation once we settle on this question.

@worldofpeace

This comment has been minimized.

Copy link
Member

worldofpeace commented Sep 13, 2019

patchDesktopFileExec sounds fine.

@ofborg ofborg bot requested a review from exi Sep 17, 2019
@symphorien symphorien force-pushed the symphorien:desktopFileHook branch 2 times, most recently from afa2b52 to 82acf6c Sep 17, 2019
@symphorien

This comment has been minimized.

Copy link
Contributor Author

symphorien commented Sep 17, 2019

I renamed the hook and added some documentation.
Unfortunately I could not compile the documentation: the makefile in doc/ just explodes:

Full error
$  make
(cd doc-support; nix-build)
trace: `mkStrict' is obsolete; use `mkOverride 0' instead.
trace: `lib.nixpkgsVersion` is deprecated, use `lib.version` instead!
trace: Warning: `showVal` is deprecated and will be removed in the next release, please use `traceSeqN`
trace: lib.zip is deprecated, use lib.zipAttrsWith instead
/nix/store/ji86grg1g6pa9gk9i9vzkn2ii9dz4jb6-doc-support
make: Dépendance circulaire manual-full.xml <- manual-full.xml abandonnée.
xmllint --nonet --xinclude --noxincludenode manual.xml --output manual-full.xml
introduction.chapter.xml:1: parser error : Document is empty

^
manual.xml:8: element include: XInclude error : could not load introduction.chapter.xml, and no fallback was found
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.concatStrings.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.concatMapStrings.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.concatImapStrings.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.intersperse.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.concatStringsSep.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.concatMapStringsSep.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.concatImapStringsSep.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.makeSearchPath.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.makeSearchPathOutput.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.makeLibraryPath.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.makeBinPath.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.optionalString.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.hasPrefix.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.hasSuffix.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.hasInfix.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.stringToCharacters.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.stringAsChars.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.escape.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.escapeShellArg.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.escapeShellArgs.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.escapeNixString.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.toLower.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.toUpper.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.addContextFrom.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.splitString.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.removePrefix.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.removeSuffix.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.versionOlder.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.versionAtLeast.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.getVersion.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.nameFromURL.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.enableFeature.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.enableFeatureAs.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.withFeature.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.withFeatureAs.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.fixedWidthString.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.fixedWidthNumber.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.isCoercibleToString.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.isStorePath.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.toInt.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.readPathsFromFile.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.strings.fileContents.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.id.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.const.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.concat.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.or.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.and.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.bitAnd.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.bitOr.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.bitXor.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.bitNot.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.boolToString.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.mergeAttrs.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.flip.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.mapNullable.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.version.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.release.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.codeName.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.versionSuffix.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.revisionWithDefault.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.inNixShell.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.min.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.max.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.mod.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.compare.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.splitByAndCompare.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.importJSON.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.setFunctionArgs.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.functionArgs.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.trivial.isFunction.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.singleton.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.foldr.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.fold.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.foldl.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.foldl-prime.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.imap0.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.imap1.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.concatMap.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.flatten.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.remove.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.findSingle.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.findFirst.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.any.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.all.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.count.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.optional.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.optionals.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.toList.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.range.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.partition.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.groupBy-prime.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.zipListsWith.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.zipLists.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.reverseList.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.listDfs.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.toposort.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.sort.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.compareLists.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.naturalSort.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.take.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.drop.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.sublist.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.last.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.init.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.crossLists.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.unique.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.intersectLists.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.subtractLists.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.lists.mutuallyExclusive.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.debug.traceIf.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.debug.traceValFn.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.debug.traceVal.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.debug.traceSeq.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.debug.traceSeqN.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.debug.traceValSeqFn.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.debug.traceValSeq.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.debug.traceValSeqNFn.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.debug.traceValSeqN.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.debug.runTests.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.debug.testAllTrue.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.options.isOption.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.options.mkOption.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.options.mkEnableOption.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.options.mkSinkUndeclaredOptions.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.options.mergeEqualOption.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.options.getValues.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.options.getFiles.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.options.scrubOptionValue.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.options.literalExample.xml"
warning: failed to load external entity "functions/library/generated/overrides/lib.options.showOption.xml"
languages-frameworks/android.section.xml:1: parser error : Document is empty

^
languages-frameworks/index.xml:13: element include: XInclude error : could not load languages-frameworks/android.section.xml, and no fallback was found
languages-frameworks/haskell.section.xml:1: parser error : Document is empty

^
languages-frameworks/index.xml:18: element include: XInclude error : could not load languages-frameworks/haskell.section.xml, and no fallback was found
languages-frameworks/idris.section.xml:1: parser error : Document is empty

^
languages-frameworks/index.xml:19: element include: XInclude error : could not load languages-frameworks/idris.section.xml, and no fallback was found
languages-frameworks/ios.section.xml:1: parser error : Document is empty

^
languages-frameworks/index.xml:20: element include: XInclude error : could not load languages-frameworks/ios.section.xml, and no fallback was found
languages-frameworks/node.section.xml:1: parser error : Document is empty

^
languages-frameworks/index.xml:23: element include: XInclude error : could not load languages-frameworks/node.section.xml, and no fallback was found
languages-frameworks/python.section.xml:1: parser error : Document is empty

^
languages-frameworks/index.xml:26: element include: XInclude error : could not load languages-frameworks/python.section.xml, and no fallback was found
languages-frameworks/r.section.xml:1: parser error : Document is empty

^
languages-frameworks/index.xml:28: element include: XInclude error : could not load languages-frameworks/r.section.xml, and no fallback was found
languages-frameworks/rust.section.xml:1: parser error : Document is empty

^
languages-frameworks/index.xml:30: element include: XInclude error : could not load languages-frameworks/rust.section.xml, and no fallback was found
languages-frameworks/titanium.section.xml:1: parser error : Document is empty

^
languages-frameworks/index.xml:32: element include: XInclude error : could not load languages-frameworks/titanium.section.xml, and no fallback was found
languages-frameworks/vim.section.xml:1: parser error : Document is empty

^
languages-frameworks/index.xml:33: element include: XInclude error : could not load languages-frameworks/vim.section.xml, and no fallback was found
languages-frameworks/emscripten.section.xml:1: parser error : Document is empty

^
languages-frameworks/index.xml:34: element include: XInclude error : could not load languages-frameworks/emscripten.section.xml, and no fallback was found
make: *** [Makefile:75: manual-full.xml] Error 1
@symphorien symphorien force-pushed the symphorien:desktopFileHook branch from 82acf6c to dfb22e6 Sep 17, 2019
@symphorien

This comment has been minimized.

Copy link
Contributor Author

symphorien commented Sep 17, 2019

I needed to run make clean for the manual build to succeed. Thanks to @jtojnar for the hint.

@worldofpeace

This comment has been minimized.

Copy link
Member

worldofpeace commented Sep 17, 2019

Guess this could fix #53111 if we used it widely.

@jtojnar

This comment has been minimized.

Copy link
Contributor

jtojnar commented Sep 18, 2019

Why do we even do this in the first place? The /bin directory is more likely to be linked to the profile (and thus PATH) than /share/applications (to XDG_DATA_DIRS). I can understand this for XDG Autostart desktop files, which might Exec things in libexec but for app launchers, I do not see the point. In fact, it may be even harmful for some launchers.

@symphorien

This comment has been minimized.

Copy link
Contributor Author

symphorien commented Sep 19, 2019

Why do we even do this in the first place?

My initial motivation was to remove the root cause of PRs like #66721

... harmful for some launchers.

That's unfortunate. It may be better to drop this PR then. What do you think ?

@worldofpeace

This comment has been minimized.

Copy link
Member

worldofpeace commented Sep 19, 2019

I believe that's just a bug in whiskermenu @symphorien, which isn't even a part of the xfce defaults.
I still think this change is ok.

@jtojnar

This comment has been minimized.

Copy link
Contributor

jtojnar commented Sep 19, 2019

The issue is not endemic to Whiskermenu. Pretty much any launcher that copies desktop files is affected.

I think a setup hook making conversion the other way around (from absolute path to basename, if is under /bin) would be still useful.

@worldofpeace

This comment has been minimized.

Copy link
Member

worldofpeace commented Sep 19, 2019

For things in share/applications I'd like something that can fix #53111, so absolute paths won't be avoided in certain cases. How about we have best of both in one hook? Default autoPatchDesktopFiles can fixup things in share/applications basenamed but make things in etc/xdg absolute. And we can have two functions so people can make them absolute or basenamed manually?

@jtojnar

This comment has been minimized.

Copy link
Contributor

jtojnar commented Sep 19, 2019

Sounds good.

@matthewbauer

This comment has been minimized.

Copy link
Member

matthewbauer commented Sep 23, 2019

I just noticed this open issue and wonder if it is still relevant:

#11471

Perhaps we shouldn't use absolute paths in desktop files?

@worldofpeace

This comment has been minimized.

Copy link
Member

worldofpeace commented Sep 23, 2019

See #68035 (comment) @matthewbauer.
We converged on not making them absolute by default, but the hook can still have that function.

I'd still like to make them absolute in environments that don't copy desktop files.

@symphorien

This comment has been minimized.

Copy link
Contributor Author

symphorien commented Dec 14, 2019

Here is a new attempt based on a slightly different principle.

Exec=/usr/bin/klystrack

is translated to

Exec=/bin/sh -c "x='klystrack'; if test -x '/nix/store/5dpaj5kh7qyjxs0z1r8212f7hf35b5nd-klystrack-1.7.6/bin/klystrack'; then x='/nix/store/5dpaj5kh7qyjxs0z1r8212f7hf35b5nd-klystrack-1.7.6/bin/klystrack'; fi; exec \$x \"\$@\"" "klystrack"

In other words:

  • if the store path is still there, the absolute path is used
  • if the desktop file has been copied by a desktop environment, and then the store path garbage collected, the desktop file falls back to $PATH.

This should solve the problem of #68035 (comment)

Tested on a few examples with xdg-open and thunar on xfce. Validated a few examples with desktop-file-validate. Therefore the quoting should be right.

This should apply equally well to autostart file, I think.
Also, it only depends on the POSIX semantics of /bin/sh so it should be as portable as possible.

If there is interest, I will fix the doc and solve the merge conflict.

@worldofpeace

This comment has been minimized.

Copy link
Member

worldofpeace commented Dec 15, 2019

@symphorien It's a nice trick for compatibility with programs that copy things into local dirs.
I don't have any real problems with it, it's just if the hook's use proliferates this will be a known convention in NixOS. Would this be done to desktop files that already have an absolute path? For example, there's projects that use meson to get absolute paths in the desktop file, so they will already be hardcoded in the nix store. But unknown to us, it will break for these menus that copy desktop items.

I don't expect to apply this treewide, just to work nicely in a case like that. Don't want to push the label on this PR.

@worldofpeace

This comment has been minimized.

Copy link
Member

worldofpeace commented Dec 15, 2019

@jtojnar I realized desktop-file-utils has desktop-file-edit.

desktop-file-edit --set-key=Exec --set-value=\"$exec %U\" $file

But it depends on glib, and this is just bash. So I guess @symphorien should still prefer this.

@symphorien

This comment has been minimized.

Copy link
Contributor Author

symphorien commented Dec 15, 2019

Yes the hook rewrites already absolute paths. But of course, this PR will only enable this behavior for derivations which opt in.

if the hook's use proliferates this will be a known convention in NixOS.

What do you mean ?

Regarding desktop-file-edit, nice finding ! Unfortunately, it does not handle several keys (see spectacle's desktop file) nor quoting, so there is little value in using it imo.

and rewrite documentation instead of fixing the merge conflict
@symphorien

This comment has been minimized.

Copy link
Contributor Author

symphorien commented Jan 3, 2020

I solved the merged conflict and updated documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

8 participants
You can’t perform that action at this time.