How to properly package a executable file

I want to package flatpak-compose for nixpkgs, right now I have:

{
  stdenv,
  fetchzip
}:

stdenv.mkDerivation rec {
  pname = "flatpak-compose";
  version = "0.4.0";
  
  src = fetchzip {
    url = "https://github.com/faan11/${pname}/releases/download/${version}/flatpak-compose-linux-amd64.zip";
    hash = "sha256-GMwx1f6Ivpl0b3br2fXu/EQDsUioPq2AJEdvuc/mj+k=";
  };

  installPhase = ''
    mkdir -p $out/bin
    cp flatpak-compose-linux-amd64 $out/bin
    runHook postInstall
  '';
}

}

This is one of my first attempts of packaging something for nix, so I have a feeling this could be way better. I also would like to know, how would I add this package to nixpkgs or make it so I can add flatpak-compose to my flake

You’re packaging the binary, the better way would would be to build it from source.
Since it is written in Go that should be fairly easy to do.

You can look at the Go section in the Nixpkgs manual and search in the Nixpkgs repository for examples.

This is a Go application I packaged, it might not be the best example however as it is only the second package I added and I have never written a line of Go:

1 Like

This could be a possibility too, although I always have wondered if a rebuild my system will it build this package again or will it only do the latter if the version has been changed?

It will behave like any other Nix package.
Unless you don’t change the related Nix code or the source it won’t have to rebuild it.
If you garbage collect it then you will have to rebuild it again, however this won’t happen if it is part of your NixOS configuration.

If you add it to the Nixpkgs repository you get the nice benefit that it gets built for you and the update bot takes care of tracking the updates.

Thanks for all the info, what is the process of adding for example my package to nixpkgs? I have skimmed the docs and it seems like a lot of work

I generated a new .nix file with nix-init, nix-init is so promising!:

{
  lib,
  buildGoModule,
  fetchFromGitHub,
}:

buildGoModule rec {
  pname = "flatpak-compose";
  version = "0.4.0";

  src = fetchFromGitHub {
    owner = "faan11";
    repo = "flatpak-compose";
    rev = version;
    hash = "sha256-BpsEelrtb5yWRiP70/wIsrYWS2aFl6tUFbQ8ChTrj+s=";
  };

  vendorHash = "sha256-1TyFfRL6HTOa+M4CEcHeiReRcPlPNKMneq2AVXS0kX0=";

  ldflags = [ "-s" "-w" ];

  meta = {
    description = "Define your flatpak applications and permissions";
    homepage = "https://github.com/faan11/flatpak-compose";
    license = lib.licenses.mit;
    maintainers = with lib.maintainers; [ ];
    mainProgram = "flatpak-compose";
  };
}

This is the PR I created for my first package.
It is actually not that much work.

I will do this in the future thanks for clearing so much up! Before I mark your answer as solution (thanks again) I am wondering if my nix file could be improved since its generated by nix-init

I personally would remove the rec and the with, it would then look more like this: nixpkgs/pkgs/by-name/st/stu/package.nix at e2605d0744c2417b09f8bf850dfca42fcf537d34 ¡ NixOS/nixpkgs ¡ GitHub

If you’re contributing this to nixpkgs, there’s nothing objective to improve here other than maybe using refs/tags/${version} (although I believe another arg was added to fetchFromGitHub which avoids that boilerplate, even), and of course the meta.maintainers should be set to yourself and/or someone else willing.

If I remove rec pname and version cant be used in other values, and my .nix file has no with? I might be misunderstanding your answer

They’re saying to use let instead of rec, which is not going provide any benefit here.

Ahh ok, I have though of it I like rec more

What are the cons of this?

remove the rec and the with

The rec keyword allows recursive attribute sets, meaning attributes can reference each other within the same set. While this is convenient, it can lead to problems:

  • Implicit dependencies: When using rec, dependencies between attributes makes the code less clear and can introduce infinite recursion.
  • Performance overhead: Recursive attribute sets require additional computation to resolve interdependent references via fixpoint iteration.

The with keyword brings all attributes from an attribute set into the current scope:

  • Name collisions: Introduces risk of unintentional name shadowing and conflicts
  • Reduces code readability: Makes it unclear where specific attributes are coming from
  • No static analysis: The ambiguity caused by with makes static analysis very difficult

Especially nested with can be hard to read.

Without both, it might look like:

{
  lib,
  buildGoModule,
  fetchFromGitHub,
}: let
  pname = "flatpak-compose";
  version = "0.4.0";
  owner = "faan11";
  repo = "flatpak-compose";
in buildGoModule {
  inherit pname version;

  src = fetchFromGitHub {
    inherit owner repo;
    rev = "refs/tags/${version}";
    hash = "sha256-BpsEelrtb5yWRiP70/wIsrYWS2aFl6tUFbQ8ChTrj+s=";
  };

  vendorHash = "sha256-1TyFfRL6HTOa+M4CEcHeiReRcPlPNKMneq2AVXS0kX0=";

  ldflags = [ "-s" "-w" ];

  meta = {
    description = "Define your flatpak applications and permissions";
    homepage = "https://github.com/${owner}/${repo}";
    license = lib.licenses.mit;
    maintainers = [ lib.maintainers.you ];
    mainProgram = "flatpak-compose";
  };
}

Here, inherit pname; is just syntax sugar for pname = pname; which is allowed when you don’t use rec (since otherwise that’s an infinite recursion right there).

1 Like

It is more explicit which makes it easier to see what’s going on which I like.
But as I said I’m no expert and I probably prefer certain crutches to help me understand code which others would not use anymore.

Thanks for all the help! I will figure discuss with faan11 if he wants to be maintainer and make a pull request, this is what I ended with:

{
  lib,
  buildGoModule,
  fetchFromGitHub,
}:
let 
  pname = "flatpak-compose";
  version = "0.4.0";
  owner = "faan11";
  repo = "flatpak-compose"; 
in

buildGoModule rec {
  inherit pname version

  src = fetchFromGitHub {
    inherit owner repo;
    rev = "refs/tags/${version}";
    hash = "sha256-BpsEelrtb5yWRiP70/wIsrYWS2aFl6tUFbQ8ChTrj+s=";
  };

  vendorHash = "sha256-1TyFfRL6HTOa+M4CEcHeiReRcPlPNKMneq2AVXS0kX0=";

  ldflags = [ "-s" "-w" ];

  meta = {
    description = "Define your flatpak applications and permissions";
    homepage = "https://github.com/${owner}/${repo}";
    license = lib.licenses.mit;
    maintainers = with lib.maintainers; [ ];
    mainProgram = "flatpak-compose";
  };
}
1 Like

I built it as test, and the resulting bin file is named ‘cmd’, is this a issue? The file name should just be flatpak-compose; do I add a mv command to extraInstallCommands or something

In their GitHub action faan11 use the -o option when building the package.

Maybe you can use it somehow with buildGoModule as well or maybe the name should be already present in the source.
For this I don’t know enough about Go.

Same here, fortunately he uses NixOs so he might know