1{ lib, gemConfig, ... }:
2
3let
4 inherit (lib)
5 attrValues
6 concatMap
7 converge
8 filterAttrs
9 getAttrs
10 intersectLists
11 ;
12
13in
14rec {
15 bundlerFiles =
16 {
17 gemfile ? null,
18 lockfile ? null,
19 gemset ? null,
20 gemdir ? null,
21 ...
22 }:
23 {
24 inherit gemdir;
25
26 gemfile =
27 if gemfile == null then
28 assert gemdir != null;
29 gemdir + "/Gemfile"
30 else
31 gemfile;
32
33 lockfile =
34 if lockfile == null then
35 assert gemdir != null;
36 gemdir + "/Gemfile.lock"
37 else
38 lockfile;
39
40 gemset =
41 if gemset == null then
42 assert gemdir != null;
43 gemdir + "/gemset.nix"
44 else
45 gemset;
46 };
47
48 filterGemset =
49 { ruby, groups, ... }:
50 gemset:
51 let
52 platformGems = filterAttrs (_: platformMatches ruby) gemset;
53 directlyMatchingGems = filterAttrs (_: groupMatches groups) platformGems;
54
55 expandDependencies =
56 gems:
57 let
58 depNames = concatMap (gem: gem.dependencies or [ ]) (attrValues gems);
59 deps = getAttrs depNames platformGems;
60 in
61 gems // deps;
62 in
63 converge expandDependencies directlyMatchingGems;
64
65 platformMatches =
66 { rubyEngine, version, ... }:
67 attrs:
68 (
69 !(attrs ? platforms)
70 || builtins.length attrs.platforms == 0
71 || builtins.any (
72 platform:
73 platform.engine == rubyEngine && (!(platform ? version) || platform.version == version.majMin)
74 ) attrs.platforms
75 );
76
77 groupMatches =
78 groups: attrs:
79 groups == null
80 || !(attrs ? groups)
81 || (intersectLists (groups ++ [ "default" ]) attrs.groups) != [ ];
82
83 applyGemConfigs =
84 attrs: (if gemConfig ? ${attrs.gemName} then attrs // gemConfig.${attrs.gemName} attrs else attrs);
85
86 genStubsScript =
87 {
88 lib,
89 runCommand,
90 ruby,
91 confFiles,
92 bundler,
93 groups,
94 binPaths,
95 ...
96 }:
97 let
98 genStubsScript =
99 runCommand "gen-bin-stubs"
100 {
101 strictDeps = true;
102 nativeBuildInputs = [ ruby ];
103 }
104 ''
105 cp ${./gen-bin-stubs.rb} $out
106 chmod +x $out
107 patchShebangs --build $out
108 '';
109 in
110 ''
111 ${genStubsScript} \
112 "${ruby}/bin/ruby" \
113 "${confFiles}/Gemfile" \
114 "$out/${ruby.gemPath}" \
115 "${bundler}/${ruby.gemPath}/gems/bundler-${bundler.version}" \
116 ${lib.escapeShellArg binPaths} \
117 ${lib.escapeShellArg groups}
118 '';
119
120 pathDerivation =
121 {
122 gemName,
123 version,
124 path,
125 ...
126 }:
127 let
128 res = {
129 type = "derivation";
130 bundledByPath = true;
131 name = gemName;
132 version = version;
133 outPath = "${path}";
134 outputs = [ "out" ];
135 out = res;
136 outputName = "out";
137 suffix = version;
138 gemType = "path";
139 };
140 in
141 res;
142
143 composeGemAttrs =
144 ruby: gems: name: attrs:
145 (
146 (removeAttrs attrs [ "platforms" ])
147 // {
148 inherit ruby;
149 inherit (attrs.source) type;
150 source = removeAttrs attrs.source [ "type" ];
151 gemName = name;
152 gemPath = map (gemName: gems.${gemName}) (attrs.dependencies or [ ]);
153 }
154 );
155}