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

applications are only linked for system packages, not user packages #139

Open
BrianHicks opened this issue May 5, 2019 · 26 comments
Open

Comments

@BrianHicks
Copy link

When I do this:

{ users.users.brianhicks.packages = [ pkgs.emacsMacport ]; }

I expect Emacs.app to be available somewhere—maybe in ~/Applications/Nix Apps. But it's not! However, if I do this:

{ environment.systemPackages = [ pkgs.emacsMacport ]; }

Then ~/Applications/Nix Apps/Emacs.app gets created.

This is important to me because I manage my packages through home-manager, where I create a big ol' bundle of emacs packages all together. I'd rather not have to move all that configuration out of home-manager just to use graphical Emacs!

According to @rvolosatovs in nix-community/home-manager#702 (comment), it's because these lines specifically (and only) include the system packages:

system.build.applications = pkgs.buildEnv {
name = "system-applications";
paths = config.environment.systemPackages;
pathsToLink = "/Applications";
};

@BrianHicks
Copy link
Author

@LnL7 I don't have a great idea of how hard this would be to fix. Do you think it would be something someone newish (read: me) could take on? Would a patch for this behavior be welcome?

@LnL7
Copy link
Owner

LnL7 commented May 15, 2019

The main problem is that there's no link between the user running darwin-rebuild and users entries. It's probably better to link per user applications instead and move system packages to /Applications.

@BrianHicks
Copy link
Author

I'm having some trouble understanding what you're saying about the running user. Why does this matter? Shouldn't stuff end up in /$USER_HOME/Applications regardless of who is running it?

Regardless, is that a change you're open to? I'm happy to look into it but I would rather not waste everyone's time by making something that would be doomed before I started 😁

@BrianHicks
Copy link
Author

OK, I've taken more time to think about it today, and just want to check my understanding. I think we'd need to:

  1. change https://github.com/LnL7/nix-darwin/blob/3ba909eb2dd3ddd893604f83048fa76cc2e47e74/modules/system/applications.nix to symlink into /Applications/Nix Apps instead of ~/Applications or ~/Applications/Nix Apps.
  2. Figure out some way of removing the old symlinks in ~.
  3. add similar app linking logic in https://github.com/LnL7/nix-darwin/blob/3ba909eb2dd3ddd893604f83048fa76cc2e47e74/modules/users/default.nix somewhere. This would put applications in users.<user?>.packages in ~/Applications or ~/Applications/Nix Apps like the system packages are now.

The first seems pretty approachable; I'm sure I could handle it. But I'm not sure if the second or third even make sense. @LnL7, what do you think? Would that be a good way to move forward on this?

(to be clear, if it's "yes" I plan to make PRs to do this!)

@LnL7
Copy link
Owner

LnL7 commented Jul 18, 2019

Yeah that's what I was suggesting.

@BrianHicks
Copy link
Author

BrianHicks commented Jul 18, 2019 via email

@jsravn
Copy link

jsravn commented Jul 23, 2020

For future reference, you can override the applications link like:

system.build.applications = pkgs.lib.mkForce (pkgs.buildEnv {
  name = "applications";
  paths = config.environment.systemPackages ++ config.home-manager.users.myusername.home.packages;
  pathsToLink = "/Applications";
});

It'd be nice if it was a config option though to avoid the mkForce.

@purcell
Copy link
Contributor

purcell commented Jul 23, 2020

@jsravn Nice, thanks for sharing that. It's a shame the larger change to place system-wide app links under /Applications and per-user app links under ~/Applications didn't end up getting seen through, because it feels like the ideal outcome.

@jsravn
Copy link

jsravn commented Jul 24, 2020

Seems like spotlight struggles to index the links in ~/Applications however. I'm pretty sure it worked for me at one point but it's not working anymore. Any ideas?

@jsravn
Copy link

jsravn commented Jul 24, 2020

I modified the activation script to create aliases which get picked up by spotlight.

    system.activationScripts.applications.text = pkgs.lib.mkForce (''
      echo "setting up ~/Applications/NixApps..."
      mkdir -p ~/Applications
      rm -rf ~/Applications/NixApps
      mkdir -p ~/Applications/NixApps
      chown myusername ~/Applications/NixApps
      find ${config.system.build.applications}/Applications -maxdepth 1 -type l | while read f; do
        echo "Linking $f"
        src=$(/usr/bin/stat -f%Y $f)
        osascript -e "tell app \"Finder\" to make alias file at POSIX file \"/Users/myusername/Applications/NixApps/\" to POSIX file \"$src\"";
      done
    '');

It can probably be made a bit nicer but it works.

@purcell
Copy link
Contributor

purcell commented Jul 30, 2020

@jsravn I found that some alias files were ending up with different names over time, e.g. with numeric suffixes. Making the name of the alias file explicit as follows seems to help:

  system.activationScripts.applications.text = pkgs.lib.mkForce (''
      echo "setting up ~/Applications/Nix..."
      rm -rf ~/Applications/Nix
      mkdir -p ~/Applications/Nix
      chown ${me} ~/Applications/Nix
      find ${config.system.build.applications}/Applications -maxdepth 1 -type l | while read f; do
        src="$(/usr/bin/stat -f%Y $f)"
        appname="$(basename $src)"
        osascript -e "tell app \"Finder\" to make alias file at POSIX file \"/Users/${me}/Applications/Nix/\" to POSIX file \"$src\" with properties {name: \"$appname\"}";
    done
  '');

(Note that ${me} is just a local attribute with my username.)

@jsravn
Copy link

jsravn commented Aug 25, 2020

Nice one! @LnL7 would you accept a PR with this change?

@LnL7
Copy link
Owner

LnL7 commented Aug 26, 2020

Relying on applescript seems pretty undesirable to me, especially for headless usecases. But should be pretty easy to create an alias using CoreFoundation if there's no binary that create one on the system already.

@akoppela
Copy link

Hello. I’ve encountered this issue today. At the moment I’ve applied a fix from above. I’d like to fix it permanently though. I’ll continue Brian’s PR unless you have time to fix it @LnL7. What are your thoughts?

@andreykaipov
Copy link

So on Catalina, I tried the above suggestions of using aliases created through AppleScript instead of symlinks, but Spotlight still couldn't find the apps Nix installed into ~/Applications. I even tried creating the symlinks and aliases in /Applications, but still nothing. So now I'm just copying the entire app directory over! Wasteful but at least it shows up in Spotlight!

  system.activationScripts.applications.text = pkgs.lib.mkForce (''
    rm -rf ~/Applications/Nix\ Apps
    mkdir -p ~/Applications/Nix\ Apps
    for app in $(find ${config.system.build.applications}/Applications -maxdepth 1 -type l); do
      src="$(/usr/bin/stat -f%Y "$app")"
      cp -r "$src" ~/Applications/Nix\ Apps
    done
  '');

@kaii-zen
Copy link

Copying (or moving?) the entire app to /Applications is actually the approach taken by brew cask. I suspect there's a good reason for that so I do the same as you do in my nix-darwin config.

@wangkev
Copy link

wangkev commented Dec 26, 2020

Copying the applications solved the issue for me too. I added the -L flag to follow symlinks too (this helped copy the alacritty app properly, for example).

@0ihsan
Copy link

0ihsan commented Dec 27, 2020

So now I'm just copying the entire app directory over!

@andreykaipov @wangkev
If you comment out the program to uninstall, and run nix-collect-garbage is the copied app directory will be removed or not?

I don't want leave garbage files/links/directories after uninstalling them.

@andreykaipov
Copy link

@ihsanturk If I understand the question correctly - the copied apps aren't removed even when you uninstall Nix because Nix doesn't know what directories you create in your custom activation script, so you don't have to worry about commenting them out in your config before running garbage collection. As part of my uninstall script I have to manually remove the created directory.

Also I've since changed the above script to compare the hashes of <app>/Contents/MacOS to prevent unnecessary copying. It makes for a rather large snippet, but you can view it here.

@akoppela
Copy link

@ihsanturk Yes. the app will be removed. It's in the script.

system.activationScripts.applications.text = pkgs.lib.mkForce (''
  rm -rf ~/Applications/Nix\ Apps
  mkdir -p ~/Applications/Nix\ Apps
  for app in $(find ${config.system.build.applications}/Applications -maxdepth 1 -type l); do
    src="$(/usr/bin/stat -f%Y "$app")"
    cp -r "$src" ~/Applications/Nix\ Apps
  done
'');

The script starts with rm -rf ~/Applications/Nix\ Apps which removes all previously copied apps. Then later in the script it copies new list of apps.

@0ihsan
Copy link

0ihsan commented Dec 29, 2020

Thanks!
Those were my two wishes:

... compare the hashes of /Contents/MacOS to prevent unnecessary copying.

The script starts with rm -rf ~/Applications/Nix\ Apps which removes all previously copied apps.

Now I will integrate them. I hope these will be solved more generally by Nix itself.

neic added a commit to neic/dotfiles that referenced this issue Jan 30, 2021
Nix-darwin does not seem mature for .apps. This is especially fustrating:
LnL7/nix-darwin#139

Reverts 4bba196
@kubukoz
Copy link

kubukoz commented Feb 6, 2021

I really don't understand why nix-darwin puts anything in the home directory. These are system packages, shouldn't they go to /Applications? I would assume ~/Applications would be used by home-manager, but apparently it can't (on mac) because of the conflict.

@sei40kr
Copy link

sei40kr commented Oct 27, 2021

@akoppela
Thank you!

↓ FYI I improved your snippet by resolving the symlinks in bulk, and using APFS's copy-on-write.

  system.activationScripts.applications.text = let
    env = pkgs.buildEnv {
      name = "system-applications";
      paths = config.environment.systemPackages;
      pathsToLink = "/Applications";
    };
  in mkForce ''
    # Set up applications.
    echo "setting up ~/Applications..." >&2

    rm -rf ~/Applications/Nix\ Apps
    mkdir -p ~/Applications/Nix\ Apps

    find ${env}/Applications -maxdepth 1 -type l -exec readlink '{}' + |
        while read src; do
          /bin/cp -cr "$src" ~/Applications/Nix\ Apps
        done
  '';

Sciencentistguy added a commit to Sciencentistguy/nixfiles that referenced this issue Jun 24, 2022
@IvarWithoutBones
Copy link

Folders symlinked to ~/Applications do not show up in spotlight, and copying them seems like a waste of disk space. Not to mention that it can take a while too if you have a lot of packages. I found a workaround using APFS aliases, those show up in spotlight and barely take any disk space.

This is my activation script:

  # Nix-darwin does not link installed applications to the user environment. This means apps will not show up
  # in spotlight, and when launched through the dock they come with a terminal window. This is a workaround.
  # Upstream issue: https://github.com/LnL7/nix-darwin/issues/214
  system.activationScripts.applications.text = lib.mkForce ''
    echo "setting up ~/Applications..." >&2
    applications="$HOME/Applications"
    nix_apps="$applications/Nix Apps"

    # Needs to be writable by the user so that home-manager can symlink into it
    if ! test -d "$applications"; then
        mkdir -p "$applications"
        chown ${username}: "$applications"
        chmod u+w "$applications"
    fi

    # Delete the directory to remove old links
    rm -rf "$nix_apps"
    mkdir -p "$nix_apps"
    find ${config.system.build.applications}/Applications -maxdepth 1 -type l -exec readlink '{}' + |
        while read src; do
            # Spotlight does not recognize symlinks, it will ignore directory we link to the applications folder.
            # It does understand MacOS aliases though, a unique filesystem feature. Sadly they cannot be created
            # from bash (as far as I know), so we use the oh-so-great Apple Script instead.
            /usr/bin/osascript -e "
                set fileToAlias to POSIX file \"$src\" 
                set applicationsFolder to POSIX file \"$nix_apps\"
                tell application \"Finder\"
                    make alias file to fileToAlias at applicationsFolder
                    # This renames the alias; 'mpv.app alias' -> 'mpv.app'
                    set name of result to \"$(rev <<< "$src" | cut -d'/' -f1 | rev)\"
                end tell
            " 1>/dev/null
        done
  '';

I have done something similar for home-manager, which integrates with this just fine.

Commit from my dotfiles: IvarWithoutBones/dotfiles@0b3faad

@lishaduck
Copy link

lishaduck commented Nov 28, 2024

I'm upgrading nix for the first time in a few months and @IvarWithoutBones's workaround errors now. I guess nix is running shellcheck somewhere/somehow?
Anyhow, making the suggested fix seemed to worked for me: swap while read src; do with while read -r src; do to handle paths with backslashes.

@Samasaur1
Copy link
Contributor

Yes, as of #1139 nix-darwin activation scripts are shellchecked

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

No branches or pull requests