lol
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

yarn2nix: init at 0.1.0 (#35340)

authored by

Michael Fellinger and committed by zimbatm.tngl.sh 3b769eaf 0883e1c3

+444
+144
pkgs/development/tools/yarn2nix/bin/yarn2nix.js
··· 1 + #!/usr/bin/env node 2 + "use strict"; 3 + 4 + const crypto = require('crypto'); 5 + const fs = require("fs"); 6 + const https = require("https"); 7 + const path = require("path"); 8 + const util = require("util"); 9 + 10 + const lockfile = require("@yarnpkg/lockfile") 11 + const docopt = require("docopt").docopt; 12 + 13 + //////////////////////////////////////////////////////////////////////////////// 14 + 15 + const USAGE = ` 16 + Usage: yarn2nix [options] 17 + 18 + Options: 19 + -h --help Shows this help. 20 + --no-nix Hide the nix output 21 + --no-patch Don't patch the lockfile if hashes are missing 22 + --lockfile=FILE Specify path to the lockfile [default: ./yarn.lock]. 23 + ` 24 + 25 + const HEAD = ` 26 + {fetchurl, linkFarm}: rec { 27 + offline_cache = linkFarm "offline" packages; 28 + packages = [ 29 + `.trim(); 30 + 31 + //////////////////////////////////////////////////////////////////////////////// 32 + 33 + function generateNix(lockedDependencies) { 34 + let found = {}; 35 + 36 + console.log(HEAD) 37 + 38 + for (var depRange in lockedDependencies) { 39 + let dep = lockedDependencies[depRange]; 40 + 41 + let depRangeParts = depRange.split('@'); 42 + let [url, sha1] = dep["resolved"].split("#"); 43 + let file_name = path.basename(url) 44 + 45 + if (found.hasOwnProperty(file_name)) { 46 + continue; 47 + } else { 48 + found[file_name] = null; 49 + } 50 + 51 + 52 + console.log(` 53 + { 54 + name = "${file_name}"; 55 + path = fetchurl { 56 + name = "${file_name}"; 57 + url = "${url}"; 58 + sha1 = "${sha1}"; 59 + }; 60 + }`) 61 + } 62 + 63 + console.log(" ];") 64 + console.log("}") 65 + } 66 + 67 + 68 + function getSha1(url) { 69 + return new Promise((resolve, reject) => { 70 + https.get(url, (res) => { 71 + const { statusCode } = res; 72 + const hash = crypto.createHash('sha1'); 73 + if (statusCode !== 200) { 74 + const err = new Error('Request Failed.\n' + 75 + `Status Code: ${statusCode}`); 76 + // consume response data to free up memory 77 + res.resume(); 78 + reject(err); 79 + } 80 + 81 + res.on('data', (chunk) => { hash.update(chunk); }); 82 + res.on('end', () => { resolve(hash.digest('hex')) }); 83 + res.on('error', reject); 84 + }); 85 + }); 86 + }; 87 + 88 + function updateResolvedSha1(pkg) { 89 + // local dependency 90 + if (!pkg.resolved) { return Promise.resolve(); } 91 + let [url, sha1] = pkg.resolved.split("#", 2) 92 + if (!sha1) { 93 + return new Promise((resolve, reject) => { 94 + getSha1(url).then(sha1 => { 95 + pkg.resolved = `${url}#${sha1}`; 96 + resolve(); 97 + }).catch(reject); 98 + }); 99 + } else { 100 + // nothing to do 101 + return Promise.resolve(); 102 + }; 103 + } 104 + 105 + function values(obj) { 106 + var entries = []; 107 + for (let key in obj) { 108 + entries.push(obj[key]); 109 + } 110 + return entries; 111 + } 112 + 113 + //////////////////////////////////////////////////////////////////////////////// 114 + // Main 115 + //////////////////////////////////////////////////////////////////////////////// 116 + 117 + var options = docopt(USAGE); 118 + 119 + let data = fs.readFileSync(options['--lockfile'], 'utf8') 120 + let json = lockfile.parse(data) 121 + if (json.type != "success") { 122 + throw new Error("yarn.lock parse error") 123 + } 124 + 125 + // Check fore missing hashes in the yarn.lock and patch if necessary 126 + var pkgs = values(json.object); 127 + Promise.all(pkgs.map(updateResolvedSha1)).then(() => { 128 + let newData = lockfile.stringify(json.object); 129 + 130 + if (newData != data) { 131 + console.error("found changes in the lockfile", options["--lockfile"]); 132 + 133 + if (options["--no-patch"]) { 134 + console.error("...aborting"); 135 + process.exit(1); 136 + } 137 + 138 + fs.writeFileSync(options['--lockfile'], newData); 139 + } 140 + 141 + if (!options['--no-nix']) { 142 + generateNix(json.object); 143 + } 144 + })
+199
pkgs/development/tools/yarn2nix/default.nix
··· 1 + { stdenv, lib, fetchurl, linkFarm, runCommand, nodejs, yarn }: 2 + 3 + let 4 + unlessNull = item: alt: 5 + if item == null then alt else item; 6 + 7 + yarn2nix = mkYarnPackage { 8 + src = ./.; 9 + yarnNix = ./yarn.nix; 10 + 11 + passthru = { 12 + inherit 13 + defaultYarnFlags 14 + linkNodeModulesHook 15 + mkYarnModules 16 + mkYarnNix 17 + mkYarnPackage 18 + # Export yarn again to make it easier to find out which yarn was used. 19 + yarn 20 + ; 21 + }; 22 + 23 + meta = with lib; { 24 + description = "generate nix expressions from a yarn.lock file"; 25 + homepage = "https://github.com/moretea/yarn2nix"; 26 + license = licenses.gpl3; 27 + maintainers = with maintainers; [ manveru zimbatm ]; 28 + }; 29 + }; 30 + 31 + # Generates the yarn.nix from the yarn.lock file 32 + mkYarnNix = yarnLock: 33 + runCommand "yarn.nix" {} 34 + "${yarn2nix}/bin/yarn2nix --lockfile ${yarnLock} --no-patch > $out"; 35 + 36 + # Loads the generated offline cache. This will be used by yarn as 37 + # the package source. 38 + importOfflineCache = yarnNix: 39 + let 40 + pkg = import yarnNix { inherit fetchurl linkFarm; }; 41 + in 42 + pkg.offline_cache; 43 + 44 + defaultYarnFlags = [ 45 + "--offline" 46 + "--frozen-lockfile" 47 + "--ignore-engines" 48 + "--ignore-scripts" 49 + ]; 50 + 51 + mkYarnModules = { 52 + name, 53 + packageJSON, 54 + yarnLock, 55 + yarnNix ? mkYarnNix yarnLock, 56 + yarnFlags ? defaultYarnFlags, 57 + pkgConfig ? {}, 58 + preBuild ? "", 59 + }: 60 + let 61 + offlineCache = importOfflineCache yarnNix; 62 + extraBuildInputs = (lib.flatten (builtins.map (key: 63 + pkgConfig.${key} . buildInputs or [] 64 + ) (builtins.attrNames pkgConfig))); 65 + postInstall = (builtins.map (key: 66 + if (pkgConfig.${key} ? postInstall) then 67 + '' 68 + for f in $(find -L -path '*/node_modules/${key}' -type d); do 69 + (cd "$f" && (${pkgConfig.${key}.postInstall})) 70 + done 71 + '' 72 + else 73 + "" 74 + ) (builtins.attrNames pkgConfig)); 75 + in 76 + stdenv.mkDerivation { 77 + inherit name preBuild; 78 + phases = ["configurePhase" "buildPhase"]; 79 + buildInputs = [ yarn nodejs ] ++ extraBuildInputs; 80 + 81 + configurePhase = '' 82 + # Yarn writes cache directories etc to $HOME. 83 + export HOME=$PWD/yarn_home 84 + ''; 85 + 86 + buildPhase = '' 87 + runHook preBuild 88 + 89 + cp ${packageJSON} ./package.json 90 + cp ${yarnLock} ./yarn.lock 91 + chmod +w ./yarn.lock 92 + 93 + yarn config --offline set yarn-offline-mirror ${offlineCache} 94 + 95 + # Do not look up in the registry, but in the offline cache. 96 + # TODO: Ask upstream to fix this mess. 97 + sed -i -E 's|^(\s*resolved\s*")https?://.*/|\1|' yarn.lock 98 + yarn install ${lib.escapeShellArgs yarnFlags} 99 + 100 + ${lib.concatStringsSep "\n" postInstall} 101 + 102 + mkdir $out 103 + mv node_modules $out/ 104 + patchShebangs $out 105 + ''; 106 + }; 107 + 108 + # This can be used as a shellHook in mkYarnPackage. It brings the built node_modules into 109 + # the shell-hook environment. 110 + linkNodeModulesHook = '' 111 + if [[ -d node_modules || -L node_modules ]]; then 112 + echo "./node_modules is present. Replacing." 113 + rm -rf node_modules 114 + fi 115 + 116 + ln -s "$node_modules" node_modules 117 + ''; 118 + 119 + mkYarnPackage = { 120 + name ? null, 121 + src, 122 + packageJSON ? src + "/package.json", 123 + yarnLock ? src + "/yarn.lock", 124 + yarnNix ? mkYarnNix yarnLock, 125 + yarnFlags ? defaultYarnFlags, 126 + yarnPreBuild ? "", 127 + pkgConfig ? {}, 128 + extraBuildInputs ? [], 129 + publishBinsFor ? null, 130 + ... 131 + }@attrs: 132 + let 133 + package = lib.importJSON packageJSON; 134 + pname = package.name; 135 + version = package.version; 136 + deps = mkYarnModules { 137 + name = "${pname}-modules-${version}"; 138 + preBuild = yarnPreBuild; 139 + inherit packageJSON yarnLock yarnNix yarnFlags pkgConfig; 140 + }; 141 + publishBinsFor_ = unlessNull publishBinsFor [pname]; 142 + in stdenv.mkDerivation (builtins.removeAttrs attrs ["pkgConfig"] // { 143 + inherit src; 144 + 145 + name = unlessNull name "${pname}-${version}"; 146 + 147 + buildInputs = [ yarn nodejs ] ++ extraBuildInputs; 148 + 149 + node_modules = deps + "/node_modules"; 150 + 151 + configurePhase = attrs.configurePhase or '' 152 + runHook preConfigure 153 + 154 + if [ -d npm-packages-offline-cache ]; then 155 + echo "npm-pacakges-offline-cache dir present. Removing." 156 + rm -rf npm-packages-offline-cache 157 + fi 158 + 159 + if [[ -d node_modules || -L node_modules ]]; then 160 + echo "./node_modules is present. Removing." 161 + rm -rf node_modules 162 + fi 163 + 164 + mkdir -p node_modules 165 + ln -s $node_modules/* node_modules/ 166 + ln -s $node_modules/.bin node_modules/ 167 + 168 + if [ -d node_modules/${pname} ]; then 169 + echo "Error! There is already an ${pname} package in the top level node_modules dir!" 170 + exit 1 171 + fi 172 + 173 + runHook postConfigure 174 + ''; 175 + 176 + # Replace this phase on frontend packages where only the generated 177 + # files are an interesting output. 178 + installPhase = attrs.installPhase or '' 179 + runHook preInstall 180 + 181 + mkdir -p $out 182 + cp -r node_modules $out/node_modules 183 + cp -r . $out/node_modules/${pname} 184 + rm -rf $out/node_modules/${pname}/node_modules 185 + 186 + mkdir $out/bin 187 + node ${./fixup_bin.js} $out ${lib.concatStringsSep " " publishBinsFor_} 188 + 189 + runHook postInstall 190 + ''; 191 + 192 + passthru = { 193 + inherit package deps; 194 + } // (attrs.passthru or {}); 195 + 196 + # TODO: populate meta automatically 197 + }); 198 + in 199 + yarn2nix
+45
pkgs/development/tools/yarn2nix/fixup_bin.js
··· 1 + #!/usr/bin/env node 2 + "use strict"; 3 + 4 + /* Usage: 5 + * node fixup_bin.js <output_dir> [<bin_pkg_1>, <bin_pkg_2> ... ] 6 + */ 7 + 8 + const fs = require("fs"); 9 + const path = require("path"); 10 + 11 + const output = process.argv[2]; 12 + const packages_to_publish_bin = process.argv.slice(3); 13 + const derivation_bin_path = output + "/bin"; 14 + 15 + function processPackage(name) { 16 + console.log("Processing ", name); 17 + const package_path = output + "/node_modules/" + name; 18 + const package_json_path = package_path + "/package.json"; 19 + const package_json = JSON.parse(fs.readFileSync(package_json_path)); 20 + 21 + if (!package_json.bin) { 22 + console.log("No binaries provided"); 23 + return; 24 + } 25 + 26 + // There are two alternative syntaxes for `bin` 27 + // a) just a plain string, in which case the name of the package is the name of the binary. 28 + // b) an object, where key is the name of the eventual binary, and the value the path to that binary. 29 + if (typeof package_json.bin == "string") { 30 + let bin_name = package_json.bin; 31 + package_json.bin = { }; 32 + package_json.bin[package_json.name] = bin_name; 33 + } 34 + 35 + for (let binName in package_json.bin) { 36 + const bin_path = package_json.bin[binName]; 37 + const full_bin_path = path.normalize(package_path + "/" + bin_path); 38 + fs.symlinkSync(full_bin_path, derivation_bin_path + "/"+ binName); 39 + console.log("Linked", binName); 40 + } 41 + } 42 + 43 + packages_to_publish_bin.forEach((pkg) => { 44 + processPackage(pkg); 45 + });
+19
pkgs/development/tools/yarn2nix/package.json
··· 1 + { 2 + "name": "yarn2nix", 3 + "version": "1.0.0", 4 + "description": "Convert packages.json and yarn.lock into a Nix expression that downloads all the dependencies", 5 + "main": "index.js", 6 + "repository": ".", 7 + "author": "Maarten Hoogendoorn <maarten@moretea.nl>", 8 + "license": "MIT", 9 + "scripts": { 10 + "yarn2nix": "bin/yarn2nix.js" 11 + }, 12 + "bin": { 13 + "yarn2nix": "bin/yarn2nix.js" 14 + }, 15 + "dependencies": { 16 + "@yarnpkg/lockfile": "^1.0.0", 17 + "docopt": "^0.6.2" 18 + } 19 + }
+11
pkgs/development/tools/yarn2nix/yarn.lock
··· 1 + # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 + # yarn lockfile v1 3 + 4 + 5 + "@yarnpkg/lockfile@^1.0.0": 6 + version "1.0.0" 7 + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.0.0.tgz#33d1dbb659a23b81f87f048762b35a446172add3" 8 + 9 + docopt@^0.6.2: 10 + version "0.6.2" 11 + resolved "https://registry.yarnpkg.com/docopt/-/docopt-0.6.2.tgz#b28e9e2220da5ec49f7ea5bb24a47787405eeb11"
+23
pkgs/development/tools/yarn2nix/yarn.nix
··· 1 + {fetchurl, linkFarm}: rec { 2 + offline_cache = linkFarm "offline" packages; 3 + packages = [ 4 + 5 + { 6 + name = "lockfile-1.0.0.tgz"; 7 + path = fetchurl { 8 + name = "lockfile-1.0.0.tgz"; 9 + url = "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.0.0.tgz"; 10 + sha1 = "33d1dbb659a23b81f87f048762b35a446172add3"; 11 + }; 12 + } 13 + 14 + { 15 + name = "docopt-0.6.2.tgz"; 16 + path = fetchurl { 17 + name = "docopt-0.6.2.tgz"; 18 + url = "https://registry.yarnpkg.com/docopt/-/docopt-0.6.2.tgz"; 19 + sha1 = "b28e9e2220da5ec49f7ea5bb24a47787405eeb11"; 20 + }; 21 + } 22 + ]; 23 + }
+3
pkgs/top-level/all-packages.nix
··· 5603 5603 5604 5604 yarn = callPackage ../development/tools/yarn { }; 5605 5605 5606 + yarn2nix = callPackage ../development/tools/yarn2nix { }; 5607 + inherit (yarn2nix) mkYarnPackage; 5608 + 5606 5609 yasr = callPackage ../applications/audio/yasr { }; 5607 5610 5608 5611 yank = callPackage ../tools/misc/yank { };