Open tmillr opened 7 months ago
Agreed. I especially tried to use writeShellScriptBin
as the launchd.user.agents.<name>.command
instead of just using launchd.user.agents.<name>.script
hoping that it would use the script directly, but alas I only see sh
.
Bump
This is pretty critical imo, having a bunch of anon launch items is not cool and makes me want to immediately revert this installation and wipe out LaunchDaemons
~ ❯ ls /Library/LaunchAgents
org.gpgtools.Libmacgpg.xpc.plist org.gpgtools.macgpg2.shutdown-gpg-agent.plist
org.gpgtools.macgpg2.fix.plist org.gpgtools.updater.plist
~ ❯ ls /Library/LaunchDaemons
com.docker.socket.plist
com.docker.vmnetd.plist
com.nordvpn.macos.helper.plist
org.nixos.activate-system.plist
org.nixos.darwin-store.plist
org.nixos.nix-daemon.plist
org.nixos.nix-gc.plist
systems.determinate.nix-installer.nix-hook.plist
I understand that the sh
display can be solved by wrapping stuff in a bundle, but it seems tricky to make that work without adding a dependency on the Nix store. We would need logic to manually manage those files. This would also want solving upstream in the Nix installers too.
If you want to work on it we’d review PRs to handle this.
I understand that the
sh
display can be solved by wrapping stuff in a bundle, but it seems tricky to make that work without adding a dependency on the Nix store. We would need logic to manually manage those files. This would also want solving upstream in the Nix installers too.If you want to work on it we’d review PRs to handle this.
I can take a look, seems like the core issue is like you described
the .plist is running an arbitrary command instead of a binary
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>
<key>Label</key>
<string>org.nixos.activate-system</string>
<key>ProgramArguments</key>
<array>
<string>/bin/sh</string>
<string>-c</string>
<string>exec /nix/store/sc025m1df2knrv1b0hagzmg42lcsjs0b-activate-system-start</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
what I can't seem to figure out is why I have 6 entries in login items and only 5 nixos daemons
the .plist is running an arbitrary command instead of a binary
Yes, we can’t really fix that. But we can wrap the shell script inside a bundle that will at least show up with a useful description. It’s just that it means managing files outside the Nix store, which is always a pain.
I’m guessing the sixth entry is one of the non‐Nix daemons, but I don’t know.
the .plist is running an arbitrary command instead of a binary
Yes, we can’t really fix that. But we can wrap the shell script inside a bundle that will at least show up with a useful description. It’s just that it means managing files outside the Nix store, which is always a pain.
I’m guessing the sixth entry is one of the non‐Nix daemons, but I don’t know.
Sixth entry might come from https://github.com/dustinlyons/nixos-config which I based my config off of.
Something along these lines?
#!/bin/sh
ID="$1"
BASE_PATH="/nix/store"
# Create the full path by appending the ID to the base path
ACTIVATION_COMMAND="${BASE_PATH}/${ID}-activate-system-start"
exec "$ACTIVATION_COMMAND"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>
<key>Label</key>
<string>org.nixos.activate-system</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/nixos-store-activate-system-start</string>
<string>sc025m1df2knrv1b0hagzmg42lcsjs0b</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
I think we would prefer to make a bundle per daemon, so that we can give them human‐readable descriptions.
I can test this out locally, but personally I wouldn't trust myself to push any of this upstream, still pretty new to nixos
from a maintainers perspective what is the biggest technical hurdle preventing this?
managing these bundles outside of nix?
Someone has to do the work and someone else has to check that it’ll work correctly and not break things :)
There’s no inherent obstacle, as far as I know, we just have limited maintainer resources. Generally any time we have to manage a file that isn’t just a symlink into /nix/store
it’s a bit of a pain. Probably what we’d want to do is make a /Library/Application Support/Nix
or something to contain bundles containing the shell scripts, use rsync
during activation to synchronize that with the system generation being activated, and make the LaunchDaemons
and LaunchAgents
point to there. But this hasn’t been a priority for me and I haven’t had time to look into how using bundles for this works, so it just hasn’t happened so far.
Someone has to do the work and someone else has to check that it’ll work correctly and not break things :)
There’s no inherent obstacle, as far as I know, we just have limited maintainer resources. Generally any time we have to manage a file that isn’t just a symlink into
/nix/store
it’s a bit of a pain. Probably what we’d want to do is make a/Library/Application Support/Nix
or something to contain bundles containing the shell scripts, usersync
during activation to synchronize that with the system generation being activated, and make theLaunchDaemons
andLaunchAgents
point to there. But this hasn’t been a priority for me and I haven’t had time to look into how using bundles for this works, so it just hasn’t happened so far.
Ok, I'll take a crack at the bundling, I've worked on that kind of thing before.
Once I get something local running well I'll update this issue and we can figure out how to get it upstream.
I'm not sure how to keep it in sync with nix, which is what you mentioned, but I should be able to get something working for my current generation.
Here's a little workaround I used for one of my own/custom agents:
{
launchd = {
user.agents =
{}
// (let
name = "clean-nvim-cache";
in {
${name} = {
serviceConfig = {
Program = "${writeShellApplication {
inherit name;
runtimeInputs = [findutils neovim];
text = ''
cache_path="$(
command nvim -es -i NONE 2>&1 <<< '1verbose lua print(vim.loader.path)'
)"
command find \
"$cache_path" \
-mindepth 1 \
-atime +49 \
-delete
'';
}}/bin/${name}";
RunAtLoad = false;
LowPriorityIO = true;
ProcessType = "Background";
StartCalendarInterval = [
{
Day = 1;
Hour = 1;
Minute = 22;
}
];
};
};
});
};
}
which results in:
But I think it'd be nice if:
It does say unidentified developer
, but this is better than before. And now when I click the info icon it takes me to the shell script/wrapper (which I can directly open via Finder
and view the commands being run), as opposed to getting the sh
binary every time, which is another improvement.
What would be the point of using an app bundle? So that the script is signed and/or becomes identified developer
?
Here's a little workaround I used for one of my own/custom agents:
{ launchd = { user.agents = {} // (let name = "clean-nvim-cache"; in { ${name} = { serviceConfig = { Program = "${writeShellApplication { inherit name; runtimeInputs = [findutils neovim]; text = '' cache_path="$( command nvim -es -i NONE 2>&1 <<< '1verbose lua print(vim.loader.path)' )" command find \ "$cache_path" \ -mindepth 1 \ -atime +49 \ -delete ''; }}/bin/${name}"; RunAtLoad = false; LowPriorityIO = true; ProcessType = "Background"; StartCalendarInterval = [ { Day = 1; Hour = 1; Minute = 22; } ]; }; }; }); }; }
which results in:
But I think it'd be nice if:
- The builtin non-binary agents did something like this by default
- It did it for custom/user-added agents as well (or there was a utility function? idk)
It does say
unidentified developer
, but this is better than before. And now when I click the info icon it takes me to the shell script/wrapper (which I can directly open viaFinder
and view the commands being run), as opposed to getting thesh
binary every time, which is another improvement.What would be the point of using an app bundle? So that the script is signed and/or becomes
identified developer
?
this is great, thanks for sharing
yeah the primary reason to bundle is to sign it and distribute it through the installer
I don’t know if signing is on the cards but associated bundles mean we could do things like icons etc. rather than just jamming everything into the name of a script file that shows up with a Terminal icon.
The writeShellApplication
solution doesn’t work because it races the mount of the Nix store when encryption is enabled; it would prevent us from using wait4path
etc.
This isn't a bug nor anything super important, but it would be nicer if agents and daemons were wrapped into appropriately named files/executables. With the current setup (i.e. just using
sh
inProgramArguments
), you end up with something like this in the System Settings > Login Items pane:and furthermore, clicking on the info icon takes you to the sh executable (which isn't very useful: this tells me nothing about which executables/commands are actually invoked and it's hard to determine which is which).
To remedy this, it would probably be necessary to wrap most of the existing agents with perhaps the exception of executables which are already self-explanatory (e.g.
gpg-connect-agent
). It seems macOS just uses the name/path of the executable here (ignoring the name of the plist, the label defined within the plist, as well as any shebangs the executable file might have).