NixOS / nix

Nix, the purely functional package manager
https://nixos.org/
GNU Lesser General Public License v2.1
12.96k stars 1.54k forks source link

Optional Mac-friendly functionality for `nix-env` #1278

Open copumpkin opened 7 years ago

copumpkin commented 7 years ago

This is just an idea, but I'm trying to think of how I'd want .app files to be managed by Nix, and I think this is it:

  1. Mac derivations contain by convention something like $out/Applications/MyApp.app
  2. Just the way nix-env manages ~/.nix-profile on all systems, on Darwin it should be somewhat aware of ~/Applications
  3. On macOS, every time it updates the user's profile, it looks for Applications in the profile's symlink tree, finds all top-level .app files (really folders) in there, and creates/updates macOS alias files for them in ~/Applications. These need to be macOS aliases because Spotlight (the macOS indexing system) doesn't index symlinks. I'm unsure if the aliases need to point to the underlying nix store paths or if they can point to the symlinks in the user's profile. This isn't ideal because it hurts the atomicity of environment updates a bit, but I don't think it'll be terrible

Any thoughts? It's not beautiful in part because ~/Applications doesn't "belong" to Nix (so other things could be in it), and in part because we can't use symlinks, but I think it would work quite nicely for a lot of things.

I see this as an alternate proposal to https://github.com/NixOS/nix/issues/956, which wants to completely own ~/Applications and assumes symlinks.

@edolstra @LnL7 @acowley @shlevy @domenkozar @mpscholten @matthewbauer

copumpkin commented 7 years ago

I think @matthewbauer's post-create-profile-hook would handle this sort of thing. I struggle to think of other uses for it than this (perhaps Windows?) but the more generic method might be good.

LnL7 commented 7 years ago

Related https://github.com/LnL7/nix-darwin/issues/11.

shlevy commented 7 years ago

I think this is probably the right thing, though it's awful :tongue:

matthewbauer commented 7 years ago

I don't think there should be any more Mac-specific features in Nix than is absolutely necessary.

What I like about a post-create-profile-hook is that it could be used in other cases, although you're right it's not exactly clear where is could be used. I suppose in non-NixOS Linux environments it could setup links in ~/.local/share/applications and some other things to make app "visible" by the DE (perhaps that's useful in NixOS as well).

Some important questions about this though:

copumpkin commented 7 years ago

Well, what I'm proposing wouldn't happen per-derivation. It'd be a post-buildEnv action, and would consume the output of buildEnv. Either as a generic hook or as a Mac-specific thing. I don't see any reason to make it more general than that, or to have to think about propagation and all that jazz. Propagation gets ugly due to the difficulty of defining what it means to be an input (buildInputs vs. string dependencies, etc.), and I'd rather just avoid it all.

I'd rather just make a "symlink tree" (alias tree) of the contents of the environment's Applications folder in whichever structure the individual derivations specify. So if Qt has $out/Applications/Foo/Util.app, you end up with an alias to that in a folder under ~/Applications

matthewbauer commented 7 years ago

Ok, that would definitely be simpler. Another thing to think about: how to go about cleaning up old ~symlinks~ aliases when a new profile is created. Can we just delete everything in ~/Applications/ that is a ~symlink~ alias? What if I have a ~symlink~ alias that I don't want deleted? Maybe it even points to a path in /nix/store/.../Applications/....

Related is whether the ~symlink~ alias should go from ~/Applications/... to ~/.nix-profile/Applications/... or just directly to /nix/store/.../Applications/....

copumpkin commented 7 years ago

@matthewbauer it should know the previous generation and the current generation and be able to figure out which aliases it should be getting rid of/changing/adding. The second point is what I didn't know in my original proposal, and also keep in mind that it can't be a symlink, but rather must be a Mac alias.

shlevy commented 7 years ago

We may want to do something like the /etc/static thing NixOS does to make it a little bit closer to atomic.

matthewbauer commented 7 years ago

also keep in mind that it can't be a symlink, but rather must be a Mac alias.

Interesting, the only way to make these from a CLI seems to be osxutils? Somebody should get that in Nixpkgs😈...

matthewbauer commented 7 years ago

If there's interest in post-create-profile-hook, I can try to type up an RFC over the weekend and put it on NixOS/rfcs.

therealpxc commented 7 years ago

We could get font installation through Nix to work right on macOS this way, too, I think. :-)

alyssais commented 6 years ago

Is it enough to just tell LaunchServices about the application with lsregister, rather than symlinking them?

copumpkin commented 6 years ago

@alyssais how do you mean? The main thing I was trying to address is that spotlight and spotlight-based tools (e.g., Alfred) for launching apps don't pick up symlinks, so even though we could symlink stuff to ~/Applications, they wouldn't be very user-friendly. Are you suggesting to put "fake" shim .apps into ~/Applications that then call the real ones in the nix store?

eqyiel commented 4 years ago

@copumpkin FYI

I realised the same thing (that spotlight and spotlight-based tools like Aflred) don't follow symlinks and did something like this using macOS Alias files (bookmark88 format).

This is not a general solution but you may be interested how I did it: https://github.com/eqyiel/dotfiles/blob/5fbad92e52a636bc85f10f06e7c0766009358038/nix/.config/nixpkgs/darwin/modules/link-apps/default.nix#L3-L35

And the swift code to create an alias file: https://github.com/eqyiel/dotfiles/blob/5fbad92e52a636bc85f10f06e7c0766009358038/nix/.config/nixpkgs/darwin/modules/link-apps/create-macos-alias.swift

(Copying here for posterity because I set that repo to private)

#!/usr/bin/env swift

// Create an alias file ("bookmark88" format).  Note that although Finder treats
// this like a symlink, it is different.
//
// Equivalent to:
// osascript -e "tell application "Finder" to make new alias at POSIX file \"${dest}\" to POSIX file \"${src}\""

import Foundation

var src: String?
var dest: String?

if CommandLine.argc < 3 {
    print("Expected two arguments: src and dest.")
    exit(1)
} else {
    src = CommandLine.arguments[1]
    dest = CommandLine.arguments[2]
}

let url = URL(fileURLWithPath: src!)
let aliasUrl = URL(fileURLWithPath: dest!)

do {
    let data = try url.bookmarkData(options: .suitableForBookmarkFile, includingResourceValuesForKeys: nil, relativeTo: nil)
    try URL.writeBookmarkData(data, to: aliasUrl)
} catch {
    print("Unexpected error: \(error).")
    exit(1)
}
stale[bot] commented 3 years ago

I marked this as stale due to inactivity. → More info