Skip to content

Commit 16eaf16

Browse files
committed
add patches attribute for pins
1 parent 03268a3 commit 16eaf16

5 files changed

Lines changed: 111 additions & 25 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
- Pins now optionally take a patches attribute and apply them using pkgs.applyPatches
6+
57
## 0.5.0
68

79
- **[Breaking] Support for the "Lockable HTTP Tarball Protocol" has been removed.**

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Simple and convenient dependency pinning for Nix
2525
- Unlike tracking a channel from its git branch, this gives you access to the `programs.sqlite` database
2626
- Can also track Nix channel artifacts like live isos
2727
- Track PyPi packages
28+
- Patch pins with pkgs.applyPatches
2829

2930
## Getting Started
3031

@@ -438,6 +439,26 @@ in
438439
sources.mySource { inherit pkgs; }
439440
```
440441

442+
### Applying patches to pins
443+
444+
Since there's no Nix builtin for applying patches, we need to rely on nixpkgs.
445+
Then you can pass patches as a list of patch files.
446+
447+
```nix
448+
let
449+
sources = import ./npins;
450+
bootstrapPkgs = import sources.nixpkgs { };
451+
patchedNixpkgs = sources.nixpkgs {
452+
pkgs = bootstrapPkgs;
453+
patches = [ ./my_nixpkgs.patch ];
454+
};
455+
pkgs = import patchedNixpkgs {};
456+
in pkgs.hello
457+
```
458+
459+
The unpatched version is exposed as nixpkgs.unpatchedPath, while outPath is overridden with the patched version.
460+
You can also use something like `lib.mapAttrs` together with `builtins.readDir` to apply patches dynamically. :)
461+
441462
### Running the latest unreleased `npins`
442463

443464
The recommended way is to use our packaging [in the repository](./npins.nix) by pinning npins itself with npins:

README.md.in

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Simple and convenient dependency pinning for Nix
2525
- Unlike tracking a channel from its git branch, this gives you access to the `programs.sqlite` database
2626
- Can also track Nix channel artifacts like live isos
2727
- Track PyPi packages
28+
- Patch pins with pkgs.applyPatches
2829

2930
## Getting Started
3031

@@ -260,6 +261,26 @@ in
260261
sources.mySource { inherit pkgs; }
261262
```
262263

264+
### Applying patches to pins
265+
266+
Since there's no Nix builtin for applying patches, we need to rely on nixpkgs.
267+
Then you can pass patches as a list of patch files.
268+
269+
```nix
270+
let
271+
sources = import ./npins;
272+
bootstrapPkgs = import sources.nixpkgs { };
273+
patchedNixpkgs = sources.nixpkgs {
274+
pkgs = bootstrapPkgs;
275+
patches = [ ./my_nixpkgs.patch ];
276+
};
277+
pkgs = import patchedNixpkgs {};
278+
in pkgs.hello
279+
```
280+
281+
The unpatched version is exposed as nixpkgs.unpatchedPath, while outPath is overridden with the patched version.
282+
You can also use something like `lib.mapAttrs` together with `builtins.readDir` to apply patches dynamically. :)
283+
263284
### Running the latest unreleased `npins`
264285

265286
The recommended way is to use our packaging [in the repository](./npins.nix) by pinning npins itself with npins:

libnpins/src/default.nix

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,26 @@ let
3838
let
3939
envVarName = "NPINS_OVERRIDE_${saneName}";
4040
saneName = stringAsChars (c: if (builtins.match "[a-zA-Z0-9]" c) == null then "_" else c) name;
41-
ersatz = builtins.getEnv envVarName;
41+
replacement = builtins.getEnv envVarName;
4242
in
43-
if ersatz == "" then
43+
if replacement == "" then
4444
path
4545
else
4646
# this turns the string into an actual Nix path (for both absolute and
4747
# relative paths)
48-
builtins.trace "Overriding path of \"${name}\" with \"${ersatz}\" due to set \"${envVarName}\"" (
49-
if builtins.substring 0 1 ersatz == "/" then
50-
/. + ersatz
51-
else
52-
/. + builtins.getEnv "PWD" + "/${ersatz}"
53-
);
48+
builtins.trace "Overriding path of \"${name}\" with \"${replacement}\" due to set \"${envVarName}\""
49+
(
50+
if builtins.substring 0 1 replacement == "/" then
51+
/. + replacement
52+
else
53+
/. + builtins.getEnv "PWD" + "/${replacement}"
54+
);
5455

5556
mkSource =
5657
name: spec:
5758
{
5859
pkgs ? null,
60+
patches ? [ ],
5961
}:
6062
assert spec ? type;
6163
let
@@ -98,22 +100,34 @@ let
98100
};
99101

100102
path =
101-
if spec.type == "Git" then
102-
mkGitSource fetchers spec
103-
else if spec.type == "GitRelease" then
104-
mkGitSource fetchers spec
105-
else if spec.type == "PyPi" then
106-
mkPyPiSource fetchers spec
107-
else if spec.type == "Channel" then
108-
mkChannelSource fetchers spec
109-
else if spec.type == "Url" || spec.type == "MutableUrl" then
110-
mkUrlSource fetchers spec
111-
else if spec.type == "Container" then
112-
mkContainerSource pkgs spec
103+
{
104+
"Git" = mkGitSource fetchers spec;
105+
"GitRelease" = mkGitSource fetchers spec;
106+
"PyPi" = mkPyPiSource fetchers spec;
107+
"Channel" = mkChannelSource fetchers spec;
108+
"Url" = mkUrlSource fetchers spec;
109+
"MutableUrl" = mkUrlSource fetchers spec;
110+
"Container" = mkContainerSource pkgs spec;
111+
}
112+
.${spec.type} or (builtins.throw "Unknown source type ${spec.type}");
113+
114+
overridePath = mayOverride name path;
115+
patchedPath =
116+
if patches == [ ] then
117+
overridePath
118+
else if pkgs != null then
119+
pkgs.applyPatches {
120+
inherit name patches;
121+
src = overridePath;
122+
}
113123
else
114-
builtins.throw "Unknown source type ${spec.type}";
124+
builtins.throw "${name}: pkgs is required to apply patches";
115125
in
116-
spec // { outPath = mayOverride name path; };
126+
spec
127+
// {
128+
outPath = patchedPath;
129+
unpatchedPath = overridePath;
130+
};
117131

118132
mkGitSource =
119133
{

test.nix

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -874,7 +874,7 @@ in
874874
'';
875875
};
876876

877-
gitDependencyOverride = mkGitTest rec {
877+
gitDependencyOverride = mkGitTest {
878878
name = "git-dependency-override";
879879
repositories."foo" = gitRepo;
880880
commands = ''
@@ -891,7 +891,7 @@ in
891891
};
892892

893893
# https://github.com/andir/npins/issues/75
894-
regression_issue75 = mkGitTest rec {
894+
regression_issue75 = mkGitTest {
895895
name = "regression-issue-75";
896896
repositories."foo" = gitRepo;
897897
commands = ''
@@ -902,7 +902,7 @@ in
902902
'';
903903
};
904904

905-
getPath = mkGitTest rec {
905+
getPath = mkGitTest {
906906
name = "get-path";
907907
repositories."foo" = gitRepo;
908908
commands = ''
@@ -914,4 +914,32 @@ in
914914
eq "$(nix-instantiate --eval npins -A foo.outPath)" "\"$(npins get-path foo)\""
915915
'';
916916
};
917+
applyPatch =
918+
let
919+
patchFile = pkgs.writeText "my.patch" ''
920+
diff --git a/test.txt b/test.txt
921+
index e69de29..980a0d5 100644
922+
--- a/test.txt
923+
+++ b/test.txt
924+
@@ -0,0 +1 @@
925+
+Hello World!
926+
'';
927+
in
928+
mkGitTest {
929+
name = "apply-patch";
930+
repositories."foo" = gitRepo;
931+
commands = ''
932+
npins init --bare
933+
npins add git http://localhost:8000/foo -b test-branch
934+
npins show
935+
set +x
936+
937+
RESULT=$(nix-instantiate --eval --json --strict --expr 'let pkgs = import ${pins.nixpkgs} {}; pins = import ./npins; foo = pins.foo { inherit pkgs; patches = [ ${patchFile} ]; }; in { patchedPath = foo.outPath; unpatchedPath = foo.unpatchedPath; }')
938+
939+
OUTPATH=$(echo "$RESULT" | ${pkgs.jq}/bin/jq -r .patchedPath)
940+
UNPATCHEDPATH=$(echo "$RESULT" | ${pkgs.jq}/bin/jq -r .unpatchedPath)
941+
942+
neq $OUTPATH $UNPATCHEDPATH
943+
'';
944+
};
917945
}

0 commit comments

Comments
 (0)