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

Allow patching dependency sources #151

Merged
merged 5 commits into from
Jun 9, 2022

Conversation

infinisil
Copy link
Contributor

Adds support for patching dependency sources with patches and postPatch derivation attributes. This is a bit hacky, as patching any files requires recalculating the integrity value, which needs to be done at build-time. But it works, and I made sure to make the code resilient and commented.

This is a solution for #110, as this allows doing patchShebangs on individual packages. npmlock2nix could also provide a predefined list of patches for individual packages for convenience in the future.

Copy link
Collaborator

@andir andir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few comments that I had while going through the first couple of changes.

internal.nix Outdated
@@ -76,20 +76,42 @@ rec {
inherit rev ref;
allRefs = true;
};

# If sourceMods.${name} is set, call it with some information about this
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we give strong gurantees what "some information" are going to be? It would be good to pick something that we can document somewhere. Having to guess or debug your way there wouldn't be the best experience.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the API.md I at documented it as only a version attribute for now, leaving the possibility for more in the future open. The version however is a bit ambiguous, because for github: dependencies it could be a git hash or any other git reference. Maybe it would be better to let users distinguish between github: and url sources, e.g. by setting sourceType = "github" / "url"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this a bit, now these attributes are passed:

  • version for HTTP tarball sources
  • github = { org, repo, rev, ref } for GitHub sources

Considering that sources for a specific package should typically all be of the same source type, this should also work fairly well.

I also thought a lot about providing a proper version in the GitHub case:

  • It's possible to get the version at build time via the .version field in the package.json file. This would be a uniform way of getting a correct version
  • However we lose the ability to decide on which patches to include at eval time
  • In order to still be able to limit patches to specific versions, it would be best to have some way of specifying NPM version ranges for each patch and calling runtime checks to figure out whether to include them.
  • I deemed this approach too complicated though, because it would have to involve coming up with our own custom scheme of declaring patches and patch commands, entirely separately from the current nixpkgs way.
  • The version and github based version decisions should be good enough for most use cases for now.

internal.nix Outdated

# If sourceMods.${name} is set, call it with some information about this
# source for it to make a decision about when to do modifications
mods = lib.optionalAttrs (sourceOptions ? sourceMods.${name})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you call it mods (sourceMods) but it actually is extra attributes (attrs) in the packTgz invocation. Can we agree on one way to call these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I called it sourceAttrs now, also relating to the thoughts in #151 (comment)

inherit src;
nativeBuildInputs = attrs.nativeBuildInputs or [ ] ++ [
# Allows patchShebangs in postPatch to patch shebangs to nodejs
nodejs
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might not be required if patchShebangs isn't called at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit annoying to include the correct version of nodejs, and considering that it's always a dependency anyways, and that many scripts would use node as an executable, I think it makes sense to provide this as a default


# Patching shebangs
node-pre-gyp = _: {
postPatch = "patchShebangs bin";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The interface here is a very leaky abstraction. We just plug some additional variables into the runCommand but only some will ever actually have an impact. I'd rather prefer an interface that isn't passing everything through from the user but defines a stricter interface.

The alternative is to provide an overrideAttrs interface here instead.

I prefer the first approach as it comes with a more limited set of features that we have to take care of.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. I think we can limit this to only patches and postPatch for now, but it could be extended with support for other attributes in the future (for now other attributes should give an error)

Copy link
Contributor Author

@infinisil infinisil Mar 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After another thought, I think it's probably better to just support all attributes, both to keep it simpler, but also because people might have different needs. Notably there's also prePatch, you can add dependencies in buildInputs as needed by patchShebangs, you may want to set NIX_DEBUG for debugging, you may want to set sourceRoot to only get a subdirectory, you may want to set dontUnpack to preserve the original .tgz and patch that with tar directly, you may want to set environment variables.

I pushed support for this in this PR now, along with documentation for it

@infinisil infinisil force-pushed the source-options branch 2 times, most recently from 4b3a198 to a236825 Compare March 17, 2022 16:28
@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/tweag-nix-dev-update-26/18252/1

API.md Outdated
@@ -114,3 +115,32 @@ npmlock2nix.build {
};
}
```

### Source derivation attributes
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This addition seems sound. I just worry a bit about supporting this as an interface. Users should/will experience breakage over time as this is a very broad interface that we can't by no means keep stable/guarantee.

Copy link
Contributor Author

@infinisil infinisil Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #151 (comment), do you think it would be fine with to have it be like this considering the arguments there?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the appeal and I can see why it might be used. I just don't want to advertise it as the go-to solution. We should do most if not all things for the users instead of exposing these broad interfaces...

I'll give it a bit of though.

internal.nix Outdated
# of entries, where each entry contains a JSON object path of the
# integrity field and the corresponding resolved file path, separated
# by a tab, ready for shell consumption
jqFindNullIntegrity = ''
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have to do that during build time? Can't we have nix do this for us? I'd rather not depend on yet another DSL for this. Especially since I am not using jq very often and at some point changes to this will have to be made.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah that's a good point, this part could be done by Nix at eval time, I'll give that a go

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed a commit to do this with Nix instead. Also rebased this PR on top of master.

This allows more flexibility for the future, such as support for:
- Source patches
- Fetch authentication
Can be used to patchShebangs for specific packages, which with NPM
version 7.0 can't be done globally for all packages anymore

Could also be a replacement for preInstallLinks
@andir
Copy link
Collaborator

andir commented Apr 6, 2022

Thank you for the updates you provided. I'll try to get through them some afternoon this week.

API.md Outdated
# sourceInfo either contains:
# - A version attribute
# - A github = { org, repo, rev, ref } attribute for GitHub sources
package-name = sourceInfo: {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The more I think about this the interface should be:


sourceOverrides = {
   package-name = sourceInfo: drv: drv.overrideAttrs (_:{  }); 
}

As that is the standard way of doing overrides within nixpkgs. This also doesn't expose some half-baked custom solution but rather whatever the typical nix developer is already familiar with. IIRC poetry2nix does it very similar.

@andir
Copy link
Collaborator

andir commented Apr 12, 2022

Besides the override interface this looks fine and I'd accept it. @infinisil can you make that change?

@infinisil
Copy link
Contributor Author

@andir Changed the interface according to your suggestion.

While I think there's some redundancy to it (because it's probably always going to be a .overrideAttrs, and the old argument isn't really needed), I think the benefit of familiarity is beneficial enough. Also the implementation becomes a bit nicer.

@infinisil infinisil mentioned this pull request Apr 26, 2022
9 tasks
@infinisil
Copy link
Contributor Author

(ping, does this look good?)

@andir andir merged commit 5c4f247 into nix-community:master Jun 9, 2022
@infinisil infinisil deleted the source-options branch October 3, 2022 23:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants