diff options
Diffstat (limited to 'virtual/modules/websites/commons/composer-env.nix')
-rw-r--r-- | virtual/modules/websites/commons/composer-env.nix | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/virtual/modules/websites/commons/composer-env.nix b/virtual/modules/websites/commons/composer-env.nix new file mode 100644 index 0000000..123d5fa --- /dev/null +++ b/virtual/modules/websites/commons/composer-env.nix | |||
@@ -0,0 +1,274 @@ | |||
1 | # This file originates from composer2nix | ||
2 | |||
3 | { stdenv, writeTextFile, fetchurl, php, unzip }: | ||
4 | |||
5 | let | ||
6 | composer = stdenv.mkDerivation { | ||
7 | name = "composer-1.8.0"; | ||
8 | src = fetchurl { | ||
9 | url = https://github.com/composer/composer/releases/download/1.8.0/composer.phar; | ||
10 | sha256 = "19pg9ip2mpyf5cyq34fld7qwl77mshqw3c4nif7sxmpnar6sh089"; | ||
11 | }; | ||
12 | buildInputs = [ php ]; | ||
13 | |||
14 | # We must wrap the composer.phar because of the impure shebang. | ||
15 | # We cannot use patchShebangs because the executable verifies its own integrity and will detect that somebody has tampered with it. | ||
16 | |||
17 | buildCommand = '' | ||
18 | # Copy phar file | ||
19 | mkdir -p $out/share/php | ||
20 | cp $src $out/share/php/composer.phar | ||
21 | chmod 755 $out/share/php/composer.phar | ||
22 | |||
23 | # Create wrapper executable | ||
24 | mkdir -p $out/bin | ||
25 | cat > $out/bin/composer <<EOF | ||
26 | #! ${stdenv.shell} -e | ||
27 | exec ${php}/bin/php $out/share/php/composer.phar "\$@" | ||
28 | EOF | ||
29 | chmod +x $out/bin/composer | ||
30 | ''; | ||
31 | meta = { | ||
32 | description = "Dependency Manager for PHP"; | ||
33 | #license = stdenv.licenses.mit; | ||
34 | maintainers = [ stdenv.lib.maintainers.sander ]; | ||
35 | platforms = stdenv.lib.platforms.unix; | ||
36 | }; | ||
37 | }; | ||
38 | |||
39 | buildZipPackage = { name, src }: | ||
40 | stdenv.mkDerivation { | ||
41 | inherit name src; | ||
42 | buildInputs = [ unzip ]; | ||
43 | buildCommand = '' | ||
44 | unzip $src | ||
45 | baseDir=$(find . -type d -mindepth 1 -maxdepth 1) | ||
46 | cd $baseDir | ||
47 | mkdir -p $out | ||
48 | mv * $out | ||
49 | ''; | ||
50 | }; | ||
51 | |||
52 | buildPackage = | ||
53 | { name | ||
54 | , src | ||
55 | , packages ? {} | ||
56 | , devPackages ? {} | ||
57 | , buildInputs ? [] | ||
58 | , symlinkDependencies ? false | ||
59 | , executable ? false | ||
60 | , removeComposerArtifacts ? false | ||
61 | , postInstall ? "" | ||
62 | , preInstall ? "" | ||
63 | , noDev ? false | ||
64 | , unpackPhase ? "true" | ||
65 | , buildPhase ? "true" | ||
66 | , ...}@args: | ||
67 | |||
68 | let | ||
69 | reconstructInstalled = writeTextFile { | ||
70 | name = "reconstructinstalled.php"; | ||
71 | executable = true; | ||
72 | text = '' | ||
73 | #! ${php}/bin/php | ||
74 | <?php | ||
75 | if(file_exists($argv[1])) | ||
76 | { | ||
77 | $composerLockStr = file_get_contents($argv[1]); | ||
78 | |||
79 | if($composerLockStr === false) | ||
80 | { | ||
81 | fwrite(STDERR, "Cannot open composer.lock contents\n"); | ||
82 | exit(1); | ||
83 | } | ||
84 | else | ||
85 | { | ||
86 | $config = json_decode($composerLockStr, true); | ||
87 | |||
88 | if(array_key_exists("packages", $config)) | ||
89 | $allPackages = $config["packages"]; | ||
90 | else | ||
91 | $allPackages = array(); | ||
92 | |||
93 | ${stdenv.lib.optionalString (!noDev) '' | ||
94 | if(array_key_exists("packages-dev", $config)) | ||
95 | $allPackages = array_merge($allPackages, $config["packages-dev"]); | ||
96 | ''} | ||
97 | |||
98 | $packagesStr = json_encode($allPackages, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); | ||
99 | print($packagesStr); | ||
100 | } | ||
101 | } | ||
102 | else | ||
103 | print("[]"); | ||
104 | ?> | ||
105 | ''; | ||
106 | }; | ||
107 | |||
108 | constructBin = writeTextFile { | ||
109 | name = "constructbin.php"; | ||
110 | executable = true; | ||
111 | text = '' | ||
112 | #! ${php}/bin/php | ||
113 | <?php | ||
114 | $composerJSONStr = file_get_contents($argv[1]); | ||
115 | |||
116 | if($composerJSONStr === false) | ||
117 | { | ||
118 | fwrite(STDERR, "Cannot open composer.json contents\n"); | ||
119 | exit(1); | ||
120 | } | ||
121 | else | ||
122 | { | ||
123 | $config = json_decode($composerJSONStr, true); | ||
124 | |||
125 | if(array_key_exists("bin-dir", $config)) | ||
126 | $binDir = $config["bin-dir"]; | ||
127 | else | ||
128 | $binDir = "bin"; | ||
129 | |||
130 | if(array_key_exists("bin", $config)) | ||
131 | { | ||
132 | if(!file_exists("vendor/".$binDir)) | ||
133 | mkdir("vendor/".$binDir); | ||
134 | |||
135 | foreach($config["bin"] as $bin) | ||
136 | symlink("../../".$bin, "vendor/".$binDir."/".basename($bin)); | ||
137 | } | ||
138 | } | ||
139 | ?> | ||
140 | ''; | ||
141 | }; | ||
142 | |||
143 | bundleDependencies = dependencies: | ||
144 | stdenv.lib.concatMapStrings (dependencyName: | ||
145 | let | ||
146 | dependency = dependencies.${dependencyName}; | ||
147 | in | ||
148 | '' | ||
149 | ${if dependency.targetDir == "" then '' | ||
150 | vendorDir="$(dirname ${dependencyName})" | ||
151 | mkdir -p "$vendorDir" | ||
152 | ${if symlinkDependencies then | ||
153 | ''ln -s "${dependency.src}" "$vendorDir/$(basename "${dependencyName}")"'' | ||
154 | else | ||
155 | ''cp -av "${dependency.src}" "$vendorDir/$(basename "${dependencyName}")"'' | ||
156 | } | ||
157 | '' else '' | ||
158 | namespaceDir="${dependencyName}/$(dirname "${dependency.targetDir}")" | ||
159 | mkdir -p "$namespaceDir" | ||
160 | ${if symlinkDependencies then | ||
161 | ''ln -s "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"'' | ||
162 | else | ||
163 | ''cp -av "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"'' | ||
164 | } | ||
165 | ''} | ||
166 | '') (builtins.attrNames dependencies); | ||
167 | |||
168 | extraArgs = removeAttrs args [ "name" "packages" "devPackages" "buildInputs" ]; | ||
169 | in | ||
170 | stdenv.mkDerivation ({ | ||
171 | name = "composer-${name}"; | ||
172 | buildInputs = [ php composer ] ++ buildInputs; | ||
173 | |||
174 | inherit unpackPhase buildPhase; | ||
175 | |||
176 | installPhase = '' | ||
177 | ${if executable then '' | ||
178 | mkdir -p $out/share/php | ||
179 | cp -av $src $out/share/php/$name | ||
180 | chmod -R u+w $out/share/php/$name | ||
181 | cd $out/share/php/$name | ||
182 | '' else '' | ||
183 | cp -av $src $out | ||
184 | chmod -R u+w $out | ||
185 | cd $out | ||
186 | ''} | ||
187 | |||
188 | # Execute pre install hook | ||
189 | runHook preInstall | ||
190 | |||
191 | # Remove unwanted files | ||
192 | rm -f *.nix | ||
193 | |||
194 | export HOME=$TMPDIR | ||
195 | |||
196 | # Remove the provided vendor folder if it exists | ||
197 | rm -Rf vendor | ||
198 | |||
199 | # If there is no composer.lock file, compose a dummy file. | ||
200 | # Otherwise, composer attempts to download the package.json file from | ||
201 | # the registry which we do not want. | ||
202 | if [ ! -f composer.lock ] | ||
203 | then | ||
204 | cat > composer.lock <<EOF | ||
205 | { | ||
206 | "packages": [] | ||
207 | } | ||
208 | EOF | ||
209 | fi | ||
210 | |||
211 | # Reconstruct the installed.json file from the lock file | ||
212 | mkdir -p vendor/composer | ||
213 | ${reconstructInstalled} composer.lock > vendor/composer/installed.json | ||
214 | |||
215 | # Copy or symlink the provided dependencies | ||
216 | cd vendor | ||
217 | ${bundleDependencies packages} | ||
218 | ${stdenv.lib.optionalString (!noDev) (bundleDependencies devPackages)} | ||
219 | cd .. | ||
220 | |||
221 | # Reconstruct autoload scripts | ||
222 | # We use the optimize feature because Nix packages cannot change after they have been built | ||
223 | # Using the dynamic loader for a Nix package is useless since there is nothing to dynamically reload. | ||
224 | composer dump-autoload --optimize ${stdenv.lib.optionalString noDev "--no-dev"} | ||
225 | |||
226 | # Run the install step as a validation to confirm that everything works out as expected | ||
227 | composer install --optimize-autoloader ${stdenv.lib.optionalString noDev "--no-dev"} | ||
228 | |||
229 | ${stdenv.lib.optionalString executable '' | ||
230 | # Reconstruct the bin/ folder if we deploy an executable project | ||
231 | ${constructBin} composer.json | ||
232 | ln -s $(pwd)/vendor/bin $out/bin | ||
233 | ''} | ||
234 | |||
235 | ${stdenv.lib.optionalString (!symlinkDependencies) '' | ||
236 | # Patch the shebangs if possible | ||
237 | if [ -d $(pwd)/vendor/bin ] | ||
238 | then | ||
239 | # Look for all executables in bin/ | ||
240 | for i in $(pwd)/vendor/bin/* | ||
241 | do | ||
242 | # Look for their location | ||
243 | realFile=$(readlink -f "$i") | ||
244 | |||
245 | # Restore write permissions | ||
246 | chmod u+wx "$(dirname "$realFile")" | ||
247 | chmod u+w "$realFile" | ||
248 | |||
249 | # Patch shebang | ||
250 | sed -e "s|#!/usr/bin/php|#!${php}/bin/php|" \ | ||
251 | -e "s|#!/usr/bin/env php|#!${php}/bin/php|" \ | ||
252 | "$realFile" > tmp | ||
253 | mv tmp "$realFile" | ||
254 | chmod u+x "$realFile" | ||
255 | done | ||
256 | fi | ||
257 | ''} | ||
258 | |||
259 | if [ "$removeComposerArtifacts" = "1" ] | ||
260 | then | ||
261 | # Remove composer stuff | ||
262 | rm -f composer.json composer.lock | ||
263 | fi | ||
264 | |||
265 | # Execute post install hook | ||
266 | runHook postInstall | ||
267 | ''; | ||
268 | } // extraArgs); | ||
269 | in | ||
270 | { | ||
271 | composer = stdenv.lib.makeOverridable composer; | ||
272 | buildZipPackage = stdenv.lib.makeOverridable buildZipPackage; | ||
273 | buildPackage = stdenv.lib.makeOverridable buildPackage; | ||
274 | } | ||