TagStudioDev / TagStudio

A User-Focused Photo & File Management System
https://docs.tagstud.io/
GNU General Public License v3.0
5.26k stars 375 forks source link

Support `nix run` #200

Open Arya-Elfren opened 6 months ago

Arya-Elfren commented 6 months ago

Allow people to run nix run github:TagStudioDev/TagStudio to build and run the app.

Familex commented 2 months ago

Can be done with poetry2nix if #368 gets merged (nix run requires apps.<system>.default)

zierf commented 2 months ago

I have a nearly complete flake.nix for this in my poetry2nix Branch. The flake has a devShell providing poetry (and also qtcreator, mypy, ruff as before).

It would also solve #415 and #422.

415: Application Icon, Name and global menu ![Screenshot_20240901_155513](https://github.com/user-attachments/assets/635f292f-126f-4121-ada3-a68ca14e9436)
422 Pin to panel ![Screenshot_20240901_165559](https://github.com/user-attachments/assets/665ce5cb-3629-4090-ae95-d6002f367f39)

Please note that the icon and application name only appear if the application has been installed into the system. A .desktop file is then available, which will also be used when starting from the devShell. The same applies to pinning to a panel.

I think nix run only works with apps.${system}.default when you are in the flake itself. Otherwise, after installation, I get an error message like:

       error: A definition for option `environment.systemPackages."[definition 1-entry 3]"' is not of type `package'. Definition values:
       - In `/nix/store/ajvaxx5hvdhcdr3r9f0wpww61b05x9i2-source/configuration.nix':
           {
             program = "/nix/store/6srq67rl2fnawd9q4ikm6npqgx8nbg17-python3.12-tagstudio-9.3.2/bin/tagstudio";
             type = "app";
           }

When providing a derivation with packages.${system}.default, it can also simply be started directly from the system with tagstudio.


The only remaining problem is that I have to add python312.pkgs.pyside6 as an extra dependency. Due to this additional dependency, the execution at least works in the devShell itself with nix run etc.

However, if you install the Flake into the system, you get this error:

Traceback (most recent call last):
  File "/nix/store/lkih98vq66kb3cfw3j961bln7wd30843-python3.12-tagstudio-9.3.2/bin/..tagstudio-wrapped-wrapped", line 6, in <module>
    from tagstudio.tag_studio import main
  File "/nix/store/lkih98vq66kb3cfw3j961bln7wd30843-python3.12-tagstudio-9.3.2/lib/python3.12/site-packages/tagstudio/tag_studio.py", line 8, in <module>
    from src.cli.ts_cli import CliDriver  # type: ignore
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/nix/store/lkih98vq66kb3cfw3j961bln7wd30843-python3.12-tagstudio-9.3.2/lib/python3.12/site-packages/tagstudio/src/cli/ts_cli.py", line 32, in <module>
    from src.qt.helpers.file_opener import open_file
  File "/nix/store/lkih98vq66kb3cfw3j961bln7wd30843-python3.12-tagstudio-9.3.2/lib/python3.12/site-packages/tagstudio/src/qt/helpers/file_opener.py", line 13, in <module>
    from PySide6.QtWidgets import QLabel
ModuleNotFoundError: No module named 'PySide6.QtWidgets'

The installed application can still be used with tagstudio in an open devShell. So I think it must have something to do with the environment.

It would of course be better to be able to do without python312.pkgs.pyside6 completely, so that PySide6 could be managed entirely via Poetry and pinned to other versions that do not have to be compatible with the Nix package.

So if anyone finds a simple solution for this, let me know.


The following commands are available to start the application from the devShell:

zierf commented 2 months ago

I got it working now. It can be executed directly with nix run from GitHub and could also be installed as a flake directly into the system.


Runnable from devShell:


Installable in a System Flake:

flake.nix

{
  description = "System Flake";

  inputs = {
    # ...
    nix-tagstudio = {
      url = "github:zierf/TagStudio/poetry2nix";
      #inputs.nixpkgs.follows = "nixpkgs";
    };
  };
  outputs = { self, nixpkgs, nixpkgs-stable, home-manager, nixos-hardware, ... } @inputs:

  # ...
}

configuration.nix

{ pkgs, pkgs-stable, inputs, ... }:

# ...

environment.systemPackages = with pkgs; [
  inputs.nix-tagstudio.packages."${pkgs.system}".tagstudio
  # ...
];

# ...

Possibly a working template for the handle github:TagStudioDev/TagStudio in the future. At least it would resolve #415 and #422 and this issue.


I have kept the dependency list small so that end users are not dragging in too many different packages with their own dependency tree. Apart from Poetry2Nix there are no dependencies that would fundamentally break the flake if they stopped working.

I have also kept the dependencies pinned with the flake.lock so that the build remains as reproducible as possible. If desired, a user could always activate inputs.nixpkgs.follows = "nixpkgs"; to build the flake with their own nixpkgs from their own system, but with the risk that the build will no longer be as reproducible.


The poetry2nix Issue #1191 has at least shown a possible override that uses the working PySide6 package from nixpkgs. It's not perfect, but it seems that the standard override of poetry2nix now needs a subsequent correction.

overrides = defaultPoetryOverrides.${system}.extend (final: prev: {
  # Overrides for PySide6
  pyside6 = final.pkgs.python312.pkgs.pyside6;
  #shiboken6 = final.pkgs.python3.pkgs.shiboken6;
});

While experimenting around, I also built a kind of minimal example for a flake with usable PySide6.

It's called poetry2nix_pyside6, if anyone is interested. It was quite a journey to gather all the necessary information, especially since everything is so scattered.

Maybe the example project will be useful again for a better overlay that doesn't need the PySide6 package from the nixpkgs. But at the moment I don't know what that should look like.

Familex commented 2 months ago

@zierf works for me, good job.

Are those 4GiB of dependencies really necessary?

image

zierf commented 2 months ago

Thanks for testing, your feedback has a valid point! These are most likely the known working nixpkgs for a successful build.

You can find out more about the structure of the inputs using the command nix flake info on any Flake. It shows that poetry2nix in this iteration has not used the same nixpkgs as the Flake for TagStudio.


The following declaration would have allowed to use the existing nixpkgs during installation via the system Flake. It lets poetry2nix and TagStudio adapt to the existing packages. However, there is a risk that the build will fail with nixpkgs that don't quite fit.

poetry2nix = {
  url = "github:nix-community/poetry2nix";
  inputs.nixpkgs.follows = "nixpkgs";
};

nix-tagstudio = {
  url = "github:zierf/TagStudio/poetry2nix";
  inputs.nixpkgs.follows = "nixpkgs";
  inputs.poetry2nix.follows = "poetry2nix";
};

Here is a bit more information about this topic and how it works: Recommendations for use of flakes’ input-follows

However, this is still very cumbersome and ugly, especially when using a lot of imported flakes. You would have to check all the dependencies of the packages and (if necessary) manually import them again so that they follow your own nixpkgs, only to then finally put them back into the package you actually wanted in the first place.


I have now made another change so that everything in the flake follows the nixpkgs specified in the inputs at top of the file. Since poetry2nix is the only significant dependency, it now follows the pinned packages.

After making a change to the Flake, you can immediately see whether poetry2nix can still produce a successful build with the locked nixpkgs. The main thing is that the Flake is consistent in itself at the end.

However, at the top level I will not be adding a follows directive to the nixpkgs. The lockfile should always allow you to reproduce a working build at any time.


After my last change, you can now manually override the package pinning at any time in the parent importing flake with only one inputs.nixpkgs.follows.

nix-tagstudio = {
  url = "github:zierf/TagStudio/poetry2nix";
  inputs.nixpkgs.follows = "nixpkgs";
};

Don't forget to run nix flake lock --update-input nix-tagstudio on your Flake system if the package was already installed and stored in your own lockfile.

Can't wait for Poetry #368 to be merged.

Familex commented 2 months ago

@zierf I've built with and without follows.

Here is my nixos diffs: without follows, with follows.

Still 1GiB of space... It looks like qt.full accounts for most of the size. I'm also confused about the xorg dependency (I'm under wayland).

zierf commented 2 months ago

Removing qt6.full broke video playback. I think qt6.qtmultimedia as a replacement should suffice.

I use Wayland myself, but xorg.libXrandr enabled us to play video at all.

Apart from that, we should not forget that TagStudio could potentially be run in XWayland at any time. (QT_QPA_PLATFORM=xcb nix run and QT_QPA_PLATFORM=xcb poetry run tagstudio)

Due to the override of PySide6 from the Nix packages, most of the previously explicitly listed dependencies no longer seem to be necessary, at least for nix run. Until then, they usually had a reason to be listed and I hadn't even included some dependencies used in the previous Flake, which was a conversion from the original change.

I still think that the optimal solution would be having proper overrides, but I don't know what they are missing.

The qt6.qtmultimedia could probably be part of the override then and no longer needed in the buildInputs. I have reduced the list of the remaining dependencies a bit and moved them directly to the devShell so that poetry run tagstudio remains functional.

Familex commented 2 months ago

@zierf nice! now diff looks resonable: only qt and python.

Sigmanificient commented 2 months ago

I already have a working derivation that depends on the poetry branch, since 23/08

zierf commented 2 months ago

@zierf nice! now diff looks resonable: only qt and python.

Great, I'm glad it's in usable condition now!

I made a small correction for the devShell only containing Poetry, adjusted a few things for the .desktop file and added a meta attribute. But no significant changes to the underlying program.

Maybe at some point I'll move parts of the flake into an extra default.nix and shell.nix. This should cover most build workflows under Nix and follow the way official nixpkgs are build.

What I would really like to see is an updated version of the official PySide6-Overrides in poetry2nix. It would round things off, but doesn't stop us from having a working flake.

I already have a working derivation that depends on the poetry branch, since 23/08

Not sure exactly what this is supposed to tell us without further references or explanations.