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

Optional Mac-friendly functionality for nix-env #1278

Open
copumpkin opened this issue Mar 16, 2017 · 15 comments
Open

Optional Mac-friendly functionality for nix-env #1278

copumpkin opened this issue Mar 16, 2017 · 15 comments
Assignees
Labels
feature Feature request or proposal macos Nix on macOS, aka OS X, aka darwin

Comments

@copumpkin
Copy link
Member

copumpkin commented Mar 16, 2017

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 #956, which wants to completely own ~/Applications and assumes symlinks.

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

@copumpkin
Copy link
Member Author

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
Copy link
Member

LnL7 commented Mar 16, 2017

Related LnL7/nix-darwin#11.

@shlevy
Copy link
Member

shlevy commented Mar 16, 2017

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

@matthewbauer
Copy link
Member

matthewbauer commented Mar 16, 2017

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:

  • Should the hook be specified for the derivation or globally for all derivations?
    • In other words, would the hook run every time a new profile is created or just when a derivation has the post-create-profile-hook attribute set?
    • For the latter, we would want to start differentiating between "apps" and non-"apps" in nixpkgs. I've thought this could be useful for a while, but it would be a big change. Each derivation would use something like stdenv.mkApplication, stdenv.mkFont, stdenv.mkLibrary, etc.
  • Should this hook "propagate" to buildInputs or propagatedBuildInputs as well?
    • For instance, user installs an app that depends on Qt, but Qt provides a couple of .app's in /nix/store/.../Applications. Do we want those apps to appear in the user's ~/Applications folder?

@copumpkin
Copy link
Member Author

copumpkin commented Mar 16, 2017

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
Copy link
Member

matthewbauer commented Mar 16, 2017

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
Copy link
Member Author

@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
Copy link
Member

shlevy commented Mar 16, 2017

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

@matthewbauer
Copy link
Member

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
Copy link
Member

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
Copy link

therealpxc commented Jun 30, 2017

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

@alyssais
Copy link
Member

alyssais commented Aug 2, 2018

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

@copumpkin
Copy link
Member Author

copumpkin commented Aug 2, 2018

@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
Copy link

eqyiel commented May 26, 2020

@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
Copy link

stale bot commented Feb 13, 2021

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

@stale stale bot added the stale label Feb 13, 2021
@fricklerhandwerk fricklerhandwerk added feature Feature request or proposal macos Nix on macOS, aka OS X, aka darwin labels Sep 12, 2022
@stale stale bot removed stale labels Sep 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Feature request or proposal macos Nix on macOS, aka OS X, aka darwin
Projects
None yet
Development

No branches or pull requests

9 participants