]>
Commit | Line | Data |
---|---|---|
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 | }${if dependency.needsModifyRights or false then "\n" + '' | |
157 | chmod -R u+rwx "$vendorDir/$(basename "${dependencyName}")" | |
158 | '' else ""} | |
159 | '' else '' | |
160 | namespaceDir="${dependencyName}/$(dirname "${dependency.targetDir}")" | |
161 | mkdir -p "$namespaceDir" | |
162 | ${if symlinkDependencies then | |
163 | ''ln -s "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"'' | |
164 | else | |
165 | ''cp -av "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"'' | |
166 | }${if dependency.needsModifyRights or false then "\n" + '' | |
167 | chmod -R u+rwx "$namespaceDir/$(basename "${dependency.targetDir}")" | |
168 | '' else ""} | |
169 | ''} | |
170 | '') (builtins.attrNames dependencies); | |
171 | ||
172 | extraArgs = removeAttrs args [ "name" "packages" "devPackages" "buildInputs" ]; | |
173 | in | |
174 | stdenv.mkDerivation ({ | |
175 | name = "composer-${name}"; | |
176 | buildInputs = [ php composer ] ++ buildInputs; | |
177 | ||
178 | inherit unpackPhase buildPhase; | |
179 | ||
180 | installPhase = '' | |
181 | ${if executable then '' | |
182 | mkdir -p $out/share/php | |
183 | cp -av $src $out/share/php/$name | |
184 | chmod -R u+w $out/share/php/$name | |
185 | cd $out/share/php/$name | |
186 | '' else '' | |
187 | cp -av $src $out | |
188 | chmod -R u+w $out | |
189 | cd $out | |
190 | ''} | |
191 | ||
192 | # Execute pre install hook | |
193 | runHook preInstall | |
194 | ||
195 | # Remove unwanted files | |
196 | rm -f *.nix | |
197 | ||
198 | export HOME=$TMPDIR | |
199 | ||
200 | # Remove the provided vendor folder if it exists | |
201 | rm -Rf vendor | |
202 | ||
203 | # If there is no composer.lock file, compose a dummy file. | |
204 | # Otherwise, composer attempts to download the package.json file from | |
205 | # the registry which we do not want. | |
206 | if [ ! -f composer.lock ] | |
207 | then | |
208 | cat > composer.lock <<EOF | |
209 | { | |
210 | "packages": [] | |
211 | } | |
212 | EOF | |
213 | fi | |
214 | ||
215 | # Reconstruct the installed.json file from the lock file | |
216 | mkdir -p vendor/composer | |
217 | ${reconstructInstalled} composer.lock > vendor/composer/installed.json | |
218 | ||
219 | # Copy or symlink the provided dependencies | |
220 | cd vendor | |
221 | ${bundleDependencies packages} | |
222 | ${stdenv.lib.optionalString (!noDev) (bundleDependencies devPackages)} | |
223 | cd .. | |
224 | ||
225 | # Reconstruct autoload scripts | |
226 | # We use the optimize feature because Nix packages cannot change after they have been built | |
227 | # Using the dynamic loader for a Nix package is useless since there is nothing to dynamically reload. | |
228 | composer dump-autoload --optimize ${stdenv.lib.optionalString noDev "--no-dev"} | |
229 | ||
230 | # Run the install step as a validation to confirm that everything works out as expected | |
231 | composer install --optimize-autoloader ${stdenv.lib.optionalString noDev "--no-dev"} | |
232 | ||
233 | ${stdenv.lib.optionalString executable '' | |
234 | # Reconstruct the bin/ folder if we deploy an executable project | |
235 | ${constructBin} composer.json | |
236 | ln -s $(pwd)/vendor/bin $out/bin | |
237 | ''} | |
238 | ||
239 | ${stdenv.lib.optionalString (!symlinkDependencies) '' | |
240 | # Patch the shebangs if possible | |
241 | if [ -d $(pwd)/vendor/bin ] | |
242 | then | |
243 | # Look for all executables in bin/ | |
244 | for i in $(pwd)/vendor/bin/* | |
245 | do | |
246 | # Look for their location | |
247 | realFile=$(readlink -f "$i") | |
248 | ||
249 | # Restore write permissions | |
250 | chmod u+wx "$(dirname "$realFile")" | |
251 | chmod u+w "$realFile" | |
252 | ||
253 | # Patch shebang | |
254 | sed -e "s|#!/usr/bin/php|#!${php}/bin/php|" \ | |
255 | -e "s|#!/usr/bin/env php|#!${php}/bin/php|" \ | |
256 | "$realFile" > tmp | |
257 | mv tmp "$realFile" | |
258 | chmod u+x "$realFile" | |
259 | done | |
260 | fi | |
261 | ''} | |
262 | ||
263 | if [ "$removeComposerArtifacts" = "1" ] | |
264 | then | |
265 | # Remove composer stuff | |
266 | rm -f composer.json composer.lock | |
267 | fi | |
268 | ||
269 | # Execute post install hook | |
270 | runHook postInstall | |
271 | ''; | |
272 | } // extraArgs); | |
273 | in | |
274 | { | |
275 | composer = stdenv.lib.makeOverridable composer; | |
276 | buildZipPackage = stdenv.lib.makeOverridable buildZipPackage; | |
277 | buildPackage = stdenv.lib.makeOverridable buildPackage; | |
278 | } |