How can you set a default option to a program

Hi,

I was hoping that someone could help me with a problem that I am having.

I would like to be able to set a default option to a program so that I do not need to type it in each time. As an example I would like to run the command qbittorrent and have it execute qbittorrent --profile=/dir/to/profile. However I cannot figure out how to do this.

An obvious solution would be to set up an alias to do this. But I set all of my alias’ in one module and I would prefer to have a solution which applies this in my qbittorrent module.

I also thought about using pkgs.writeShellScriptBin but this does not seem to work (I think that the Shell script cannot have the same name as the application) as in this example.

let 
  qbittorrent = pkgs.writeShellScriptBin "qbittorrent" '' 
qbittorrent --config=/path/to/dir
''
in
{
  environment.systemPackages = [
    pkgs.qbittorrent
    qbittorrent
  ];
}

The only other solution that I can think of is to use a separate name for the shell script (like bittorrent) but I would prefer to no do this.

Can anyone else suggest a different solution?

Thanks

Why not just set an alias in the qbittorrent module then? NixOS will merge all the modules together in the end, it’d work fine.

It can, as long as it precedes the other package in $PATH. That said, if you really want to go that route I’d say the best way is this:

{ pkgs, lib, ...}: {
  environment.systemPackages = let
    # `buildEnv` avoids the overhead of rebuilding you get
    # with an override + `wrapProgram`
    customizedQbittorrent = pkgs.buildEnv {
      ignoreCollisions = true;
      paths = [
        # Order is important, the `ignoreCollisions` will make the
        # package further down take precedence - or was it the
        # other way around?
        pkgs.qbittorrent
        # You can peobably use `runCommand` + `wrapProgram`
        # for slightly cleaner results and an actual binary output
        (pkgs.writeShellScriptBin "qbittorrent" "${pkgs.qbittorrent} --config=/path/to/dir")
      ];
    };
  in [
    customQbittorrent
  ];
}

Still, I’d just set it up with an alias, personally. That, or read the qbittorrent docs to see if it supports a standard path or an environment variable.

I usually like to use makeWrapper in a symlinkJoin to append arguments to applications.

{
  lib,
  symlinkJoin,
  makeWrapper,

  qbittorrent,
}:
symlinkJoin {
  name = lib.getName qbittorrent;
  paths = [
    qbittorrent
  ];

  nativeBuildInputs = [
    makeWrapper
  ];

  postBuild = ''
    wrapProgram $out/bin/qbittorrent \
      --arguments here
  '';
}

Thank you for this solution,

I was able to get it to work and it taught me some new things about Nixos that I did not know. However I have a few questions.

About symlinkJoin; I was reading about this and it seems like its purpose is to place multiple packages into a single store path. But in your solution you only have the one qbittorrent package. I was wondering why you didnt just override the postBuild of the qbittorrent derivation alone (I only believe this is possible and did not test it myself (it is late for me now)). Is the reason because with this method Nixos will opt to use the cached binary instead of rebuilding from the source (which is what i understand would happen if you modified the ~binary~ (EDIT - I meant derivation))?

About wrapProgram; When you said --arguments here I was getting an error but eventually found that --add-flags ARG worked. However to figure this out I had to look into the shell scrip to understand each of the individual makeWrapperArgs. In the Nixos manual there is only mention and examples of makeWrapperArgs. Honestly I found that shell script to be a lot more useful and was surprised that it was not in the official doucmentation. I am curious where do you look for the details on makeWrapperArgs (I am more curious about this because I feel like there is other documentation that i am missing).

How do you evaluate this derivation in your configuration; For me I am just including this in my configurations environment.systemPackages. Besides that I am only really aware of nix-build to evaluate dervications. Im just curious if you evaluate it elsewhere or if it is just normal to place into systemPackages.

Thankyou

If you change the postBuild of the original package, you change the build script and therefore nix considers the package changed. It therefore misses the cache and you need to compile the full package locally.

You could do it, but it makes all your updates insanely slow just to change a CLI flag. This is why I use buildEnv, too, both basically do the same thing. Pick your favorite way to place a subtly different binary in /bin.

By reading the script, like you did. Sadly the nixpkgs codebase has a huge documentation indexing problem, especially for the various build hooks.

I’ve started using noogle for actual nix functions, but it can’t index build hook docs. You just have to get proficient with grep (or rg) when working with nixpkgs.

That’s how it’s done, just refer to the package where it ends up being used. Nix is a lazy language.

You can use nix-build to test it, if you want. Place the package definition in a separate file and then import it into environment.systemPackages instead.

You can also make your own package set and introduce it into _module.args, either through flakes’ specialArgs or a simple import in your configuration.nix. This becomes useful as you write more downstream packages.

Bingo, that’s exactly why I used symlinkJoin.

Unfortunately, same place as you. I usually go into the shell script and read its documentation because there’s pretty much no good documentation on this particular program anywhere else in the official docs.

That’s the standard. Sometimes I might put it into the .package option of a module instead, but otherwise it just goes straight into the aforementioned environment.systemPackages (or users.users.my-user.packages).