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

[FEATURE]: Add package for Nix/NixOS #4935

Open
sagikazarmark opened this issue Aug 10, 2023 · 20 comments
Open

[FEATURE]: Add package for Nix/NixOS #4935

sagikazarmark opened this issue Aug 10, 2023 · 20 comments

Comments

@sagikazarmark
Copy link

Feature Request

Background / Motivation

I use Nix as my package manager for macOS and Linux.

What should the user be able to do?

Install garden using Nix.

Why do they want to do this? What problem does it solve?

Nix is particularly useful in creating portable development environments. Since garden is often used for development, integrating it into such environments is crucial.

Suggested Implementation(s)

Create a Nix package.

How important is this feature for you/your team?

🌵 Not having this feature makes using Garden painful

Additional information

There is already a closed issue asking for a Nix package: #2785

I decided to open a new issue, because I'd be happy to do the work, but I'd need some assistance because I'm not intimately familiar how Node CLIs are packaged (particularly garden seems to require some additional files for it to run).

What I need to be able to create a Nix package:

  • a build command that creates a script/artifact I can run
  • list of additional files required for said artifact

I tried following the contributing guide, but it's not obvious what the output of yarn build is.

Any assistance would be greatly appreciated.

Thanks!

@sagikazarmark
Copy link
Author

Here is an initial version using the binary distribution for now: https://github.com/sagikazarmark/nix-garden

@stefreak
Copy link
Member

@sagikazarmark Cool, thank you for working on this!

In our contributing guide we have a section about how to build the release binaries and docker containers.

In NixOS you use glibc by default, right?

Basically we need the built pkg vercel nodejs binary, and a "static" directory (that needs to be initialized as a git repository unfortunately right now).

See also the debian Dockerfile: https://github.com/garden-io/garden/blob/main/support/buster.Dockerfile#L47C2-L47C2
The build context root for that Dockerfile dist/linux-amd64 (This directory exists after running yarn dist)

Happy to help if you run into problems.

@stefreak
Copy link
Member

stefreak commented Aug 11, 2023

Unfortunately we have no official ARM binaries yet, which should be straightforward to change nowadays but we are tracking a separate issue for that: #1547

@sagikazarmark
Copy link
Author

sagikazarmark commented Aug 11, 2023

@stefreak thanks for getting back to me.

As far as I understand the value behind building the vercel pkg binaries is to distribute garden as a single executable. I'm not sure the Nix package needs that as Nix is perfectly capable of installing Node as a dependency as well.

The repo I linked above already uses the binary distribution which is a good start IMO, but I'd like to play a bit with skipping the final vercel build and just use ... the artifact that comes before that. A script file? Not sure yet.

In NixOS you use glibc by default, right?

Yep

Basically we need the built pkg vercel nodejs binary, and a "static" directory (that needs to be initialized as a git repository unfortunately right now).

One problem I already have (with the binary distributed version) is this:

Unexpected Git error occurred while running 'git status' from path "/nix/store/hlg35xcp6aihwazrcvy5s8b9b63hm0bh-garden-0.13.10/static". Exit code: 128. Error message: fatal: detected dubious ownership in repository at '/nix/store/hlg35xcp6aih
wazrcvy5s8b9b63hm0bh-garden-0.13.10/static'
To add an exception for this directory, call:

        git config --global --add safe.directory /nix/store/hlg35xcp6aihwazrcvy5s8b9b63hm0bh-garden-0.13.10/static


Command "git status" failed with code 128:

   fatal: detected dubious ownership in repository at '/nix/store/hlg35xcp6aihwazrcvy5s8b9b63hm0bh-garden-0.13.10/static'
To add an exception for this directory, call:

        git config --global --add safe.directory /nix/store/hlg35xcp6aihwazrcvy5s8b9b63hm0bh-garden-0.13.10/static

Nix puts all packages in a so-called "Nix store" (basically /nix in the filesystem) and makes them read-only and owned by root, to make sure no accidental modifications happen.

I'll take a look at the links you've provided and come back if I have any questions. Thanks!

@stefreak
Copy link
Member

@sagikazarmark then it might be possible that #4047 has to be finished first, where we get rid of the requirement that the static directory is a git repository.

@sagikazarmark
Copy link
Author

@stefreak I managed to work around the problem for now: https://github.com/sagikazarmark/nix-garden/blob/main/flake.nix#L93-L98

The binary distribution seems to be working for the moment, so I'll test it in the next couple weeks and then submit it to the official Nix repository.

I'll keep working on the vercel-less version in the meantime.

@worldofgeese
Copy link
Contributor

worldofgeese commented Aug 14, 2023

@sagikazarmark as a user of Nix and Guix this is something I've wanted for a long time (I created an issue in nixpkgs but never got around to filling).

Since I use Guix System on my personal laptop, I created a Guix package for garden over the weekend. ldd shows missing libraries on the raw garden binary:

ldd garden 
	linux-vdso.so.1 (0x00007ffcbbfe9000)
	libdl.so.2 => /gnu/store/ip9mj1pwymxi1yq32zbhwp3n3bycy6yi-glibc-2.35/lib/libdl.so.2 (0x00007fd2f5496000)
	libstdc++.so.6 => not found
	libm.so.6 => /gnu/store/ip9mj1pwymxi1yq32zbhwp3n3bycy6yi-glibc-2.35/lib/libm.so.6 (0x00007fd2f53b9000)
	libgcc_s.so.1 => not found
	libpthread.so.0 => /gnu/store/ip9mj1pwymxi1yq32zbhwp3n3bycy6yi-glibc-2.35/lib/libpthread.so.0 (0x00007fd2f53b4000)
	libc.so.6 => /gnu/store/ip9mj1pwymxi1yq32zbhwp3n3bycy6yi-glibc-2.35/lib/libc.so.6 (0x00007fd2f51b6000)
	/lib64/ld-linux-x86-64.so.2 => /gnu/store/ip9mj1pwymxi1yq32zbhwp3n3bycy6yi-glibc-2.35/lib/ld-linux-x86-64.so.2 (0x00007fd2f549d000)

My Guix package definition is unfinished because patchelf-ing in these library paths changes the binary size, which Pkg has an issue with because it uses hardcoded offsets. As far as I can tell the solution is to manually bodge the PAYLOAD_POSITION and PRELUDE_POSITION as this packager did in 2018.

I've noticed you don't use patchelf. I'm confused why your flake works for you because as I understand NixOS suffers from the same issue as Guix System in needing to patch the RPATH and dynamic linker of most binaries to work with these distros. How have you avoided it?

In any case, thanks for your efforts to package garden for Nix! This will open up our tool to be used across a broader range of non-FHS compliant distros and by macOS users that don't want to deal with Homebrew (far and away the worst package manager I've ever used).

@sagikazarmark
Copy link
Author

@worldofgeese I only used the package on macOS so far, so that might answer why it works.

The garden binary itself is packaged using vercel/pkg which I think we should be able to omit (that could also make packaging easier).

@worldofgeese
Copy link
Contributor

worldofgeese commented Aug 16, 2023

@sagikazarmark I spoke with @TimBeyer to understand our binary build process a little more: yarn build and yarn dist call out to https://github.com/garden-io/garden/blob/main/cli/src/build-pkg.ts. Tim tells me it'd be non-trivial to duplicate what build-pkg.ts does for another packager. However, we did arrive at some promising possibilities!

  1. yarn install is not an alias but a standard yarn command and installs all dependencies into the local node_modules folder. If we pull in yarn as an explicit dependency we can use this in our package definitions to make an FHS-independent package that runs on NixOS and Guix System.
  2. We used to publish garden to NPM but stopped. If we began publishing to NPM again, we could just install garden as an NPM package within our build environments.

There are performance penalties to using Pkg in the resulting binary so it may be we see performance improvements by pursuing either of these alternatives in our own definitions.

@sagikazarmark
Copy link
Author

@worldofgeese these are great news! I could see either of these happening.

  1. maybe slightly easier from a Nix/Guix perspective, but puts more requirements on garden. 1. is a bit more work on the Nix side, but makes less assumptions about packaging.

I believe we should pursue both (given publishing on NPM is something you can/want to do), but for the long term, option 1 is probably a better solution.

There are performance penalties to using Pkg in the resulting binary so it may be we see performance improvements by pursuing either of these alternatives in our own definitions.

I definitely see that penalty on macOS (especially due to the Rosetta requirement).

@TimBeyer
Copy link
Contributor

I definitely see that penalty on macOS (especially due to the Rosetta requirement).

We just published a release with native ARM binaries for macOS which has much improved performance over the version running via Rosetta. There's still a small overhead for running in pkg but overall it's a much better experience.
I recommend you try it out!

@sagikazarmark
Copy link
Author

@TimBeyer thanks! I upgraded to the new version: sagikazarmark/nix-garden@8d05717

It is indeed somewhat better.

Looking at the latest release note I noticed there is a self-update option. @worldofgeese I think it would be nice if we could disable it somehow in the nix packaged version.

@worldofgeese
Copy link
Contributor

worldofgeese commented Aug 17, 2023

@sagikazarmark I'm working on this after work hours so I won't be the fastest person in the world but I made some good progress today! I found a yarn package definition for Guix (make sure it's 1.* because we're not compatible with 2), built it, opened a shell into its definition (guix shell -f yarn.scm), cloned the garden repo, ran yarn build && yarn install (you need to build to get some of the dependencies like open-tracing) then ran cli/bin/garden and... it works! Or at least the CLI shows me a list of arguments: so far so good.

Next steps will be to compose these steps into a definition, which I've already started on.

@sagikazarmark
Copy link
Author

@worldofgeese I also started to work on a definition here: sagikazarmark/nix-garden@b621f9f

Unfortunately, yarn build fails with the following error:

[1/0/3 built, 0.0 MiB DL] building garden (configurePhase): configuringdirenv: ([/nix/store/2fq15zs5fq3ag5ynfxxaa3nw6ys0z6i9-direnv-2.32.3/bin/direnv export zsh]) is taking a while to execute. Use CTRL-C to give up.
error: builder for '/nix/store/fs4p6223viqjdcgkh1cillma9jw61k2y-garden.drv' failed with exit code 1;
       last 10 log lines:
       > core ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄  $ ./scripts/run-script.ts clean && find . -name ".garden" -type d -prune -exec rm -rf '{}' '+'
       > core ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄  SyntaxError: Unexpected token  in JSON at position 0
       > core ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄  error Command failed with exit code 1.
       > core ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄  info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
       > 
       > clean script in package @garden-io/core failed with code 1
       > error Command failed with exit code 1.
       > info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
       > error Command failed with exit code 1.
       > info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
       For full logs, run 'nix log /nix/store/fs4p6223viqjdcgkh1cillma9jw61k2y-garden.drv'.

Unfortunately, it doesn't tell more about what the problem is.

It could be some automagic, that mkYarnPackage does (I noticed for example that garden utilizes workspaces), but I haven't been able to figure out the problem so far.

I have two suggestions for making progress at this point:

  1. Submit a PR with my binary based definition so that we can get garden in nixpkgs. I know such PRs have been accepted in the past.
  2. Let's join forces and work on a common repo (I'm happy to add you to mine, but I'm okay with working on whatever repo (eg. under garden) as well).

I understand the time constraints, so I think it makes sense to not duplicate efforts.

What do you think?

@worldofgeese
Copy link
Contributor

worldofgeese commented Aug 30, 2023

@sagikazarmark I built a garden Guix package definition that uses yarn to build but ran into the wrinkle that Guix build environments are not network-capable.

Looking at your Nix package and based on mkYarnPackage's Nix definition it looks like it takes a version argument. Could you try and pass any version of yarn version 1 to it? garden will only build with v1.

In any case, based on our shared difficulties, I suggest creating an NPM package of garden, then using Nix and Guix's native Node build methods to source it. I was going to try to yarn publish to my own NPM namespace now and see if that works and if not, investigate what we'd need to get a functional NPM package. To that end, @stefreak indicated the static directory and the nodejs options that we need to control may be tricky to solve for. Once they are, it should be trivial to package for Nix and Guix.

Happy to work on any common repo with the objective of getting these accepted into their respective homes (Nixpkgs and nonguix)!

@sagikazarmark
Copy link
Author

@worldofgeese great news!

Since the binary distribution works rather well at the moment, I think it makes sense to wait for an NPM package instead of struggling to come up with a build definition (that may never work).

One thing that doesn't work with the NPM definition is disabling self-update though (which is a bit unfortunate, but not the end of the world).

@stefreak
Copy link
Member

@sagikazarmark your original approach should work fine, can you maybe dig deeper into why clean fails with that JSON error?

run-script.ts clean basically runs yarn clean in every single package directory. To do that, it reads the definition of the clean task from the package.json.

The output contains the log line clean script in package @garden-io/core failed with code 1 which suggests that it tried to read the package.json In core/.

Does the core/package.json contain a weird character at the beginning of the file? Can you share with us the output of hexdump -C core/package.json?

@worldofgeese
Copy link
Contributor

worldofgeese commented Sep 13, 2023

@stefreak @sagikazarmark I have a PR I'm hoping to get up end of day today that adds an NPM package to simplify this process. You can already try it with npx @worldofgeese/cli. I will write back here when it's up for review.

I've tested with my own projects and it works great for all commands I've tested. In fact, it is significantly faster in all operations.

EDIT: it's up without any context. I will add more details later tonight or by the morning.

@stefreak
Copy link
Member

We re-did how we build Garden and implemented a new binary shipping mechanism (garden-sea)

We now implement some environment variables in this wrapper binary: https://github.com/garden-io/garden/blob/main/garden-sea/src/node.rs#L43C12-L43C12
Namely GARDEN_MAX_SEMI_SPACE_SIZE, GARDEN_MAX_OLD_SPACE_SIZE, and GARDEN_SEA_UV_USE_IO_URING.

We also updated Node.js to 21.1 in the mean time. Should we try again with the npm run dist approach (https://docs.garden.io/v/edge-release/contributing-to-garden/developing-garden#release-binaries-and-docker-containers) or do we need to go down the NPM package path? With the NPM package we'd have less control over NodeJS versions and these kind of low level NodeJS settings.

@stefreak
Copy link
Member

If we want to go down the NPM package path, #4477 is resolved now so the NPM PR is unblocked and we can continue working on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants