Getting started to build a go project

Here is an attempt to get started with to build a go project.
While I got it working it feels rough around the edges:

$ mkdir app && cd app
$ nix flake init -t github:nix-community/gomod2nix#app
$ nix develop
$ gomod2nix generate

$ nix run
error: unable to execute '/nix/store/1362dp94w76q433jhcmcn0249qd0lah7-myapp-0.1/bin/myapp': No such file or directory

$ nix-build
/nix/store/2rjfh44xk68zzzd8szacpapgmnz2bdh4-myapp-0.1/bin/gomod2nix-template 

After changing the go.mod file so it

cat go.mod 
module example.com/myapp

go 1.17

matches the default.nix

buildGoApplication {
  pname = "myapp";
  version = "0.1";
  pwd = ./.;
  src = ./.;
  modules = ./gomod2nix.toml;
}

and now it builds and runs OK with nix run

$ nix run
Hello flake

Is this the right way to approach this?

I am almost there. I managed to install the go project as flake.

GitHub - tcurdt/release-go

But I am still struggling with a couple of things.

installing as a service

I am trying to expose the service but obviously I am still not exposing it the right way.

Because when I am trying to enable it,

    {
      services.release-go = {
        enable = true;
      };
    }

it fails to build.

error: The option `services.release-go' does not exist.

why for each system?

Since nix is source based, why iterated though the systems with flake-utils.lib.eachDefaultSystem?

Flakes have per-system attributes (typically package related) which are usually depend upon something platform specific (e.g. something could be x86_64-linux only and cannot be built/used on darwin’s) and system-independent outputs (modules). See output schema in wiki for more details.

In your flake you are declaring the nixosModules output as a per system attribute by defining it inside the call to flake-utils.lib.eachDefaultSystem. One way to make it system-independent with flake-utils is to merge it to the result of eachDefaultSystem call:

# ...
(flake-utils.lib.eachDefaultSystem (system:
{
  pkgs = { /* ... */ };
})
//
{
  nixosModules.default = import ./myCustomModule.nix;
}

One important thing to keep in mind is that modules take pkgs as an argument, so when you use pkgs.myCustomPackage in your module – myCustomPackage needs to be a part of the pkgs.

With flakes one pattern is to make the myCustomModule take the flake itself as the outer parameter, like so:

# flake.nix
outputs = { self, /* the rest of the params */ }:
# ...
{
  nixosModules.default = import ./myCustomModule.nix { inherit self; };
}

# myCustomModule.nix
self:
{ pkgs, lib, config, ... }:
let
  thisFlakePackages' = self.packages.${pkgs.system};
in
{
  options.services.myService.package = thisFlakePackages'.default;
}

IMO when it comes to patterns like this one, flake.parts offer a more concise way to write this with flakes.

OK, I see that per-system attributes might be needed for some packages.
And I will have a look at “flake.parts”.
Thanks for the pointer. I will give that a try.

But I don’t think the problem I am describing (providing a service configuration)
is related to the general pattern, is it?

What I have:

# flake.nix
outputs = { self, nixpkgs, flake-utils, gomod2nix }:
# ...
nixosModules.default = (import ./services.nix);
# services.nix
{ config, lib, pkgs, ... }:
with lib;
let
#  ...
in
{
  options.services.release-go = {
  ...
  };

What you are showing is the assignment of the package - not the systemd services configuration that I am struggling with.

Or do I misunderstand something?

I am trying to expose the service but obviously I am still not exposing it the right way

Your nixcfg repo does not really pass the module from release-go flake to the machine’s configuration.

To fix this:

  1. Make the nixosModules.default system-independent (merge the result or use flake.parts). Glancing at the repo, I think you’ve done this already.

  2. Fix the way you are passing flake’s package to its module (e.g. through the outer argument in my previous post). Without this step pkgs.relase-go will not exist and this line will produce an error.

  3. Import the release-go flake’s module in your nixcfg. (this is actually the reason for “no such option” error)

    Since you’re passing inputs to the utm.nix, you could try this:

    modules = [
      # ...
      inputs.release-go.nixosModules.default
    ]
    

    and comment out release-go here.

As an example for something very similar – there’s xremap flake. It has a perSystem package which gets pulled into a nixosModule. Might not be the best example because of repo-specific machinery but it’s the one I have at hand :slight_smile: .

Alternatively there’s rust-web-server template with a bit more boilerplate directly in the flake file

After a lot pulling hairs and help on matrix, I just got it working.
I pretty much ran into everything you mentioned :slight_smile:

Thanks for the examples. I will compare and learn.