]>
Commit | Line | Data |
---|---|---|
24fd1fe6 IB |
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 | , doRemoveVendor ? true | |
67 | , ...}@args: | |
68 | ||
69 | let | |
70 | reconstructInstalled = writeTextFile { | |
71 | name = "reconstructinstalled.php"; | |
72 | executable = true; | |
73 | text = '' | |
74 | #! ${php}/bin/php | |
75 | <?php | |
76 | if(file_exists($argv[1])) | |
77 | { | |
78 | $composerLockStr = file_get_contents($argv[1]); | |
79 | ||
80 | if($composerLockStr === false) | |
81 | { | |
82 | fwrite(STDERR, "Cannot open composer.lock contents\n"); | |
83 | exit(1); | |
84 | } | |
85 | else | |
86 | { | |
87 | $config = json_decode($composerLockStr, true); | |
88 | ||
89 | if(array_key_exists("packages", $config)) | |
90 | $allPackages = $config["packages"]; | |
91 | else | |
92 | $allPackages = array(); | |
93 | ||
94 | ${stdenv.lib.optionalString (!noDev) '' | |
95 | if(array_key_exists("packages-dev", $config)) | |
96 | $allPackages = array_merge($allPackages, $config["packages-dev"]); | |
97 | ''} | |
98 | ||
99 | $packagesStr = json_encode($allPackages, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); | |
100 | print($packagesStr); | |
101 | } | |
102 | } | |
103 | else | |
104 | print("[]"); | |
105 | ?> | |
106 | ''; | |
107 | }; | |
108 | ||
109 | constructBin = writeTextFile { | |
110 | name = "constructbin.php"; | |
111 | executable = true; | |
112 | text = '' | |
113 | #! ${php}/bin/php | |
114 | <?php | |
115 | $composerJSONStr = file_get_contents($argv[1]); | |
116 | ||
117 | if($composerJSONStr === false) | |
118 | { | |
119 | fwrite(STDERR, "Cannot open composer.json contents\n"); | |
120 | exit(1); | |
121 | } | |
122 | else | |
123 | { | |
124 | $config = json_decode($composerJSONStr, true); | |
125 | ||
126 | if(array_key_exists("bin-dir", $config)) | |
127 | $binDir = $config["bin-dir"]; | |
128 | else | |
129 | $binDir = "bin"; | |
130 | ||
131 | if(array_key_exists("bin", $config)) | |
132 | { | |
133 | if(!file_exists("vendor/".$binDir)) | |
134 | mkdir("vendor/".$binDir); | |
135 | ||
136 | foreach($config["bin"] as $bin) | |
137 | symlink("../../".$bin, "vendor/".$binDir."/".basename($bin)); | |
138 | } | |
139 | } | |
140 | ?> | |
141 | ''; | |
142 | }; | |
143 | ||
144 | bundleDependencies = dependencies: | |
145 | stdenv.lib.concatMapStrings (dependencyName: | |
146 | let | |
147 | dependency = dependencies.${dependencyName}; | |
148 | in | |
149 | '' | |
150 | ${if dependency.targetDir == "" then '' | |
151 | vendorDir="$(dirname ${dependencyName})" | |
152 | mkdir -p "$vendorDir" | |
153 | ${if symlinkDependencies then | |
154 | ''ln -s "${dependency.src}" "$vendorDir/$(basename "${dependencyName}")"'' | |
155 | else | |
156 | ''cp -a "${dependency.src}" "$vendorDir/$(basename "${dependencyName}")"'' | |
157 | }${if dependency.needsModifyRights or false then "\n" + '' | |
158 | chmod -R u+rwx "$vendorDir/$(basename "${dependencyName}")" | |
159 | '' else ""} | |
160 | '' else '' | |
161 | namespaceDir="${dependencyName}/$(dirname "${dependency.targetDir}")" | |
162 | mkdir -p "$namespaceDir" | |
163 | ${if symlinkDependencies then | |
164 | ''ln -s "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"'' | |
165 | else | |
166 | ''cp -a "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"'' | |
167 | }${if dependency.needsModifyRights or false then "\n" + '' | |
168 | chmod -R u+rwx "$namespaceDir/$(basename "${dependency.targetDir}")" | |
169 | '' else ""} | |
170 | ''} | |
171 | '') (builtins.attrNames dependencies); | |
172 | ||
173 | extraArgs = removeAttrs args [ "name" "packages" "devPackages" "buildInputs" ]; | |
174 | in | |
175 | stdenv.mkDerivation ({ | |
176 | name = "composer-${name}"; | |
177 | buildInputs = [ php composer ] ++ buildInputs; | |
178 | ||
179 | inherit unpackPhase buildPhase; | |
180 | ||
181 | installPhase = '' | |
182 | ${if executable then '' | |
183 | mkdir -p $out/share/php | |
184 | cp -a $src $out/share/php/$name | |
185 | chmod -R u+w $out/share/php/$name | |
186 | cd $out/share/php/$name | |
187 | '' else '' | |
188 | cp -a $src $out | |
189 | chmod -R u+w $out | |
190 | cd $out | |
191 | ''} | |
192 | ||
193 | # Execute pre install hook | |
194 | runHook preInstall | |
195 | ||
196 | # Remove unwanted files | |
197 | rm -f *.nix | |
198 | ||
199 | export HOME=$TMPDIR | |
200 | ||
201 | ${if doRemoveVendor then '' | |
202 | # Remove the provided vendor folder if it exists | |
203 | rm -Rf vendor | |
204 | '' else ""} | |
205 | # If there is no composer.lock file, compose a dummy file. | |
206 | # Otherwise, composer attempts to download the package.json file from | |
207 | # the registry which we do not want. | |
208 | if [ ! -f composer.lock ] | |
209 | then | |
210 | cat > composer.lock <<EOF | |
211 | { | |
212 | "packages": [] | |
213 | } | |
214 | EOF | |
215 | fi | |
216 | ||
217 | # Reconstruct the installed.json file from the lock file | |
218 | mkdir -p vendor/composer | |
219 | ${reconstructInstalled} composer.lock > vendor/composer/installed.json | |
220 | ||
221 | # Copy or symlink the provided dependencies | |
222 | cd vendor | |
223 | ${bundleDependencies packages} | |
224 | ${stdenv.lib.optionalString (!noDev) (bundleDependencies devPackages)} | |
225 | cd .. | |
226 | ||
227 | # Reconstruct autoload scripts | |
228 | # We use the optimize feature because Nix packages cannot change after they have been built | |
229 | # Using the dynamic loader for a Nix package is useless since there is nothing to dynamically reload. | |
230 | composer dump-autoload --optimize ${stdenv.lib.optionalString noDev "--no-dev"} | |
231 | ||
232 | # Run the install step as a validation to confirm that everything works out as expected | |
233 | composer install --optimize-autoloader ${stdenv.lib.optionalString noDev "--no-dev"} | |
234 | ||
235 | ${stdenv.lib.optionalString executable '' | |
236 | # Reconstruct the bin/ folder if we deploy an executable project | |
237 | ${constructBin} composer.json | |
238 | ln -s $(pwd)/vendor/bin $out/bin | |
239 | ''} | |
240 | ||
241 | ${stdenv.lib.optionalString (!symlinkDependencies) '' | |
242 | # Patch the shebangs if possible | |
243 | if [ -d $(pwd)/vendor/bin ] | |
244 | then | |
245 | # Look for all executables in bin/ | |
246 | for i in $(pwd)/vendor/bin/* | |
247 | do | |
248 | # Look for their location | |
249 | realFile=$(readlink -f "$i") | |
250 | ||
251 | # Restore write permissions | |
252 | chmod u+wx "$(dirname "$realFile")" | |
253 | chmod u+w "$realFile" | |
254 | ||
255 | # Patch shebang | |
256 | sed -e "s|#!/usr/bin/php|#!${php}/bin/php|" \ | |
257 | -e "s|#!/usr/bin/env php|#!${php}/bin/php|" \ | |
258 | "$realFile" > tmp | |
259 | mv tmp "$realFile" | |
260 | chmod u+x "$realFile" | |
261 | done | |
262 | fi | |
263 | ''} | |
264 | ||
265 | if [ "$removeComposerArtifacts" = "1" ] | |
266 | then | |
267 | # Remove composer stuff | |
268 | rm -f composer.json composer.lock | |
269 | fi | |
270 | ||
271 | # Execute post install hook | |
272 | runHook postInstall | |
273 | ''; | |
274 | } // extraArgs); | |
275 | in | |
276 | { | |
277 | composer = stdenv.lib.makeOverridable composer; | |
278 | buildZipPackage = stdenv.lib.makeOverridable buildZipPackage; | |
279 | buildPackage = stdenv.lib.makeOverridable buildPackage; | |
280 | } |