Browse Source

merge openwrt and nixpkgs vis, add arch support

master
Milan Pässler 11 months ago
parent
commit
21b2bbef11
11 changed files with 390 additions and 474 deletions
  1. +5
    -3
      client/index.html
  2. +6
    -9
      client/package.json
  3. +46
    -25
      client/src/index.js
  4. +52
    -365
      client/yarn.lock
  5. +77
    -0
      server/archlinux.js
  6. +10
    -0
      server/error.js
  7. +29
    -70
      server/index.js
  8. +96
    -0
      server/nixpkgs.js
  9. +61
    -0
      server/openwrt.js
  10. +3
    -2
      server/package.json
  11. +5
    -0
      server/yarn.lock

+ 5
- 3
client/index.html View File

@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html lang="de">
<head>
<title>nixpkgs reference viewer</title>
<title>package dependency viewer</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<meta name="theme-color" content="#ffffff">
@@ -10,11 +10,13 @@
<body>
<canvas id="canvas"></canvas>
<form id="inputs">
<input type="text" id="derivation">
<select id="backend">
</select>
<input type="text" id="name">
<input type="submit" id="go" value="Go">
<p class="hidden" id="queued">Queued: <span id="queued-count"></span></p>
</form>
<noscript>JavaScript is required to use nixpkgs reference viewer</noscript>
<noscript>JavaScript is required to use package dependency viewer</noscript>
</body>
<script type="module" src="main.min.js"></script>
</html>

+ 6
- 9
client/package.json View File

@@ -1,20 +1,17 @@
{
"name": "nixpkgs-vis-client",
"version": "1.0.0",
"name": "pkgvis-client",
"version": "1.1.0",
"license": "AGPL-3.0",
"author": "Milan Pässler",
"dependencies": {
"@types/d3-force": "^1.1.1",
"d3-force": "^1.1.2"
"d3-force": "^1.2.1"
},
"scripts": {
"build": "node_modules/.bin/rollup -c"
},
"devDependencies": {
"rollup": "^1.4.0",
"rollup-plugin-node-resolve": "^4.0.1",
"rollup-plugin-terser": "^4.0.4",
"rollup-plugin-typescript2": "^0.19.3",
"typescript": "^3.3.3333"
"rollup": "^1.10.0",
"rollup-plugin-node-resolve": "^4.2.3",
"rollup-plugin-terser": "^4.0.4"
}
}

+ 46
- 25
client/src/index.js View File

@@ -1,5 +1,7 @@
import * as d3Force from 'd3-force';

const apiUri = "/api";

const dpr = window.devicePixelRatio || 1;

const view = {
@@ -14,7 +16,7 @@ const view = {
dragStartOffsetX: 0,
dragStartOffsetY: 0,
pinchStartDistance: 0,
pinchStartScale: 0
pinchStartScale: 0,
};

const graph = {
@@ -24,7 +26,7 @@ const graph = {
let queued = 0;
let queryNum = 0;
let simulation = d3Force.forceSimulation();
let linkForce = d3Force.forceLink([]).id(d => String(d.hash));
let linkForce = d3Force.forceLink([]).id(d => String(d.id));
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

@@ -82,21 +84,21 @@ function updateQueued(newQueued) {
}
}

function addNode(node) {
if (!graph.nodes[node.hash]) {
graph.nodes[node.hash] = node;
node.references.forEach(async (link) => {
function addNode(backend, node) {
if (!graph.nodes[node.id]) {
node.weight = Math.min(50, 5 + (node.size / 5000000) || 0);
graph.nodes[node.id] = node;
node.deps.forEach(async (link) => {
let neighbour;
try {
neighbour = await fetchNode("hash", link.hash);
neighbour = await fetchNode(backend, "id", link);
} catch(err) {
return;
}
neighbour.weight = 5;
addNode(neighbour);
addNode(backend, neighbour);
graph.links.push({
source: node.hash,
target: neighbour.hash
source: node.id,
target: neighbour.id
});
linkForce.links(graph.links);
simulation.alpha(0.5);
@@ -110,11 +112,11 @@ function addNode(node) {
updateQueued(queued-1);
}

async function fetchNode(type, value) {
async function fetchNode(backend, type, name) {
updateQueued(queued+1);
const queryNumAtStart = queryNum;

const node = await fetch(`/api/${type}/${value}`)
const node = await fetch(`${apiUri}/${backend}/${type}/${name}`)
.then(resp => resp.json());

if (queryNum !== queryNumAtStart)
@@ -123,38 +125,57 @@ async function fetchNode(type, value) {
return node;
}

function init() {
async function init() {

const backendSelect = document.getElementById("backend");
const backends = await fetch(`${apiUri}/backends`)
.then(resp => resp.json());

for (let backend of backends) {
const option = document.createElement("option");
option.value = backend;
option.appendChild(document.createTextNode(backend));
backendSelect.appendChild(option);
}

document.querySelector("option:first-child").selected = true;

simulation
.force("link", linkForce)
.force("charge", d3Force.forceManyBody())
.force("center", d3Force.forceCenter());

async function go(name) {
document.getElementById("derivation").blur();
document.getElementById("derivation").value = name;
window.location.hash = `#${name}`;
async function go(backend, name) {
document.querySelector('#backend [value="' + backend + '"]').selected = true;
document.getElementById("name").blur();
document.getElementById("name").value = name;
window.location.hash = `#${backend}:${name}`;
queryNum++;
queued = 0;
graph.nodes = {};
graph.links = [];
const node = await fetchNode("name", name);
node.weight = 10;
addNode(node);
const node = await fetchNode(backend, "name", name);
addNode(backend, node);
view.selectedNode = node;
}

document.getElementById("inputs").addEventListener("submit", function(event) {
const name = document.getElementById("derivation").value;
event.preventDefault();
go(name);
const backendSelect = document.getElementById("backend");
const backend = backendSelect[backendSelect.selectedIndex].value;
const name = document.getElementById("name").value;
go(backend, name);
return true;
});

drawGraph();

function goLocationHash() {
const name = window.location.hash.substr(1);
go(name);
const hash = window.location.hash.substr(1).split(":");
if (hash.length < 2) return;
const backend = hash[0];
const name = hash[1];
go(backend, name);
}

if (window.location.hash.length) {


+ 52
- 365
client/yarn.lock View File

@@ -18,20 +18,22 @@
esutils "^2.0.2"
js-tokens "^4.0.0"

"@types/d3-force@^1.1.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@types/d3-force/-/d3-force-1.2.1.tgz#c28803ea36fe29788db69efa0ad6c2dc09544e83"
integrity sha512-jqK+I36uz4kTBjyk39meed5y31Ab+tXYN/x1dn3nZEus9yOHCLc+VrcIYLc/aSQ0Y7tMPRlIhLetulME76EiiA==

"@types/estree@0.0.39":
version "0.0.39"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==

"@types/node@^11.9.5":
version "11.10.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.10.4.tgz#3f5fc4f0f322805f009e00ab35a2ff3d6b778e42"
integrity sha512-wa09itaLE8L705aXd8F80jnFpxz3Y1/KRHfKsYL2bPc0XF+wEWu8sR9n5bmeu8Ba1N9z2GRNzm/YdHcghLkLKg==
"@types/node@*", "@types/node@^11.13.4":
version "11.13.5"
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.13.5.tgz#266564afa8a6a09dc778dfacc703ed3f09c80516"
integrity sha512-/OMMBnjVtDuwX1tg2pkYVSqRIDSmNTnvVvmvP/2xiMAAWf4a5+JozrApCrO4WCAILmXVxfNoQ3E+0HJbNpFVGg==

"@types/resolve@0.0.8":
version "0.0.8"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194"
integrity sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==
dependencies:
"@types/node" "*"

acorn@^6.1.1:
version "6.1.1"
@@ -45,41 +47,15 @@ ansi-styles@^3.2.1:
dependencies:
color-convert "^1.9.0"

arr-diff@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=
dependencies:
arr-flatten "^1.0.1"

arr-flatten@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==

array-unique@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=

braces@^1.8.2:
version "1.8.5"
resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=
dependencies:
expand-range "^1.8.1"
preserve "^0.2.0"
repeat-element "^1.1.2"

buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==

builtin-modules@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.0.0.tgz#1e587d44b006620d90286cc7a9238bbc6129cab1"
integrity sha512-hMIeU4K2ilbXV6Uv93ZZ0Avg/M91RaKXucQ+4me2Do1txxBDyDZWCBa5bJSLqoNTRpXTLwEzIk1KmloenDDjhg==
builtin-modules@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484"
integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==

chalk@^2.0.0:
version "2.4.2"
@@ -102,10 +78,10 @@ color-name@1.1.3:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=

commander@~2.17.1:
version "2.17.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
commander@^2.19.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==

core-util-is@~1.0.0:
version "1.0.2"
@@ -122,10 +98,10 @@ d3-dispatch@1:
resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.5.tgz#e25c10a186517cd6c82dd19ea018f07e01e39015"
integrity sha512-vwKx+lAqB1UuCeklr6Jh1bvC4SZgbSqbkGBLClItFBIYH4vqDJCA7qfoy14lXmJdnBOdxndAMxjCbImJYW7e6g==

d3-force@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-1.2.0.tgz#60713f7efe8764f53e685d69433c06914dc4ea4c"
integrity sha512-PFLcDnRVANHMudbQlIB87gcfQorEsDIAvRpZ2bNddfM/WxdsEkyrEaOIPoydhH1I1V4HPjNLGOMLXCA0AuGQ9w==
d3-force@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-1.2.1.tgz#fd29a5d1ff181c9e7f0669e4bd72bdb0e914ec0b"
integrity sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==
dependencies:
d3-collection "1"
d3-dispatch "1"
@@ -147,94 +123,11 @@ escape-string-regexp@^1.0.5:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=

estree-walker@^0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.5.2.tgz#d3850be7529c9580d815600b53126515e146dd39"
integrity sha512-XpCnW/AE10ws/kDAs37cngSkvgIR8aN3G0MS85m7dUpuK2EREo9VJ00uvw6Dg/hXEpfsE1I1TvJOJr+Z+TL+ig==

esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=

expand-brackets@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=
dependencies:
is-posix-bracket "^0.1.0"

expand-range@^1.8.1:
version "1.8.2"
resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=
dependencies:
fill-range "^2.1.0"

extglob@^0.3.1:
version "0.3.2"
resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=
dependencies:
is-extglob "^1.0.0"

filename-regex@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=

fill-range@^2.1.0:
version "2.2.4"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565"
integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==
dependencies:
is-number "^2.1.0"
isobject "^2.0.0"
randomatic "^3.0.0"
repeat-element "^1.1.2"
repeat-string "^1.5.2"

for-in@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=

for-own@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=
dependencies:
for-in "^1.0.1"

fs-extra@7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
dependencies:
graceful-fs "^4.1.2"
jsonfile "^4.0.0"
universalify "^0.1.0"

glob-base@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=
dependencies:
glob-parent "^2.0.0"
is-glob "^2.0.0"

glob-parent@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=
dependencies:
is-glob "^2.0.0"

graceful-fs@^4.1.2, graceful-fs@^4.1.6:
version "4.1.15"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==

has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@@ -245,83 +138,20 @@ inherits@~2.0.3:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=

is-buffer@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==

is-dotfile@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=

is-equal-shallow@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=
dependencies:
is-primitive "^2.0.0"

is-extendable@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=

is-extglob@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=

is-glob@^2.0.0, is-glob@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=
dependencies:
is-extglob "^1.0.0"

is-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=

is-number@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=
dependencies:
kind-of "^3.0.2"

is-number@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==

is-posix-bracket@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=

is-primitive@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU=

isarray@1.0.0, isarray@~1.0.0:
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=

isobject@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=
dependencies:
isarray "1.0.0"

jest-worker@^24.0.0:
version "24.0.0"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.0.0.tgz#3d3483b077bf04f412f47654a27bba7e947f8b6d"
integrity sha512-s64/OThpfQvoCeHG963MiEZOAAxu8kHsaL/rCMF7lpdzo7vgF0CtPml9hfguOMgykgH/eOm4jFP4ibfHLruytg==
version "24.6.0"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.6.0.tgz#7f81ceae34b7cde0c9827a6980c35b7cdc0161b3"
integrity sha512-jDwgW5W9qGNvpI1tNnvajh0a5IE/PuGLFmHk6aR/BZFz8tSgGw17GsDPXAJ6p91IvYDjOw8GpFbvvZGAK+DPQQ==
dependencies:
merge-stream "^1.0.1"
supports-color "^6.1.0"
@@ -331,30 +161,6 @@ js-tokens@^4.0.0:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==

jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
optionalDependencies:
graceful-fs "^4.1.6"

kind-of@^3.0.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
dependencies:
is-buffer "^1.1.5"

kind-of@^6.0.0:
version "6.0.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==

math-random@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c"
integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==

merge-stream@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"
@@ -362,74 +168,16 @@ merge-stream@^1.0.1:
dependencies:
readable-stream "^2.0.1"

micromatch@^2.3.11:
version "2.3.11"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=
dependencies:
arr-diff "^2.0.0"
array-unique "^0.2.1"
braces "^1.8.2"
expand-brackets "^0.1.4"
extglob "^0.3.1"
filename-regex "^2.0.0"
is-extglob "^1.0.0"
is-glob "^2.0.1"
kind-of "^3.0.2"
normalize-path "^2.0.1"
object.omit "^2.0.0"
parse-glob "^3.0.4"
regex-cache "^0.4.2"

normalize-path@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
dependencies:
remove-trailing-separator "^1.0.1"

object.omit@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=
dependencies:
for-own "^0.1.4"
is-extendable "^0.1.1"

parse-glob@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw=
dependencies:
glob-base "^0.3.0"
is-dotfile "^1.0.0"
is-extglob "^1.0.0"
is-glob "^2.0.0"

path-parse@^1.0.5, path-parse@^1.0.6:
path-parse@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==

preserve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=

process-nextick-args@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==

randomatic@^3.0.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed"
integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==
dependencies:
is-number "^4.0.0"
kind-of "^6.0.0"
math-random "^1.0.1"

readable-stream@^2.0.1:
version "2.3.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
@@ -443,35 +191,6 @@ readable-stream@^2.0.1:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"

regex-cache@^0.4.2:
version "0.4.4"
resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==
dependencies:
is-equal-shallow "^0.1.3"

remove-trailing-separator@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=

repeat-element@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==

repeat-string@^1.5.2:
version "1.6.1"
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=

resolve@1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26"
integrity sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==
dependencies:
path-parse "^1.0.5"

resolve@^1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba"
@@ -479,12 +198,13 @@ resolve@^1.10.0:
dependencies:
path-parse "^1.0.6"

rollup-plugin-node-resolve@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-4.0.1.tgz#f95765d174e5daeef9ea6268566141f53aa9d422"
integrity sha512-fSS7YDuCe0gYqKsr5OvxMloeZYUSgN43Ypi1WeRZzQcWtHgFayV5tUSPYpxuaioIIWaBXl6NrVk0T2/sKwueLg==
rollup-plugin-node-resolve@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-4.2.3.tgz#638a373a54287d19fcc088fdd1c6fd8a58e4d90a"
integrity sha512-r+WaesPzdGEynpLZLALFEDugA4ACa5zn7bc/+LVX4vAXQQ8IgDHv0xfsSvJ8tDXUtprfBtrDtRFg27ifKjcJTg==
dependencies:
builtin-modules "^3.0.0"
"@types/resolve" "0.0.8"
builtin-modules "^3.1.0"
is-module "^1.0.0"
resolve "^1.10.0"

@@ -498,31 +218,13 @@ rollup-plugin-terser@^4.0.4:
serialize-javascript "^1.6.1"
terser "^3.14.1"

rollup-plugin-typescript2@^0.19.3:
version "0.19.3"
resolved "https://registry.yarnpkg.com/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.19.3.tgz#713063233461765f030a2baa2640905c2656164f"
integrity sha512-lsRqfBCZhMl/tq9AT5YnQvzQWzXtnx3EQYFcHD72gul7nyyoOrzx5yCEH20smpw58v6UkHHZz03FbdLEPoHWjA==
dependencies:
fs-extra "7.0.1"
resolve "1.8.1"
rollup-pluginutils "2.3.3"
tslib "1.9.3"

rollup-pluginutils@2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.3.3.tgz#3aad9b1eb3e7fe8262820818840bf091e5ae6794"
integrity sha512-2XZwja7b6P5q4RZ5FhyX1+f46xi1Z3qBKigLRZ6VTZjwbN0K1IFGMlwm06Uu0Emcre2Z63l77nq/pzn+KxIEoA==
dependencies:
estree-walker "^0.5.2"
micromatch "^2.3.11"

rollup@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.4.0.tgz#fdc965b4ea7948e0b8e1a9051067dce1a61b3a24"
integrity sha512-E5HP4rgvAqkXQNYfNHgCDnX5HDHwAPDLUVSNp8iTmT49vY34G0DxEfhjPWnqnFi7v0vQtDGkKl2hvLfmsMvmcA==
rollup@^1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.10.0.tgz#91d594aa4386c51ca0883ad4ef2050b469d3e8aa"
integrity sha512-U9t/JaKtO0+X0pSmLVKMrAZEixrbVzITf193TiEhfoVKCnd7pDimIFo94IxUCgbn6+v5VmduHkubx2VV1s0Ftw==
dependencies:
"@types/estree" "0.0.39"
"@types/node" "^11.9.5"
"@types/node" "^11.13.4"
acorn "^6.1.1"

safe-buffer@~5.1.0, safe-buffer@~5.1.1:
@@ -531,14 +233,14 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1:
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==

serialize-javascript@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.6.1.tgz#4d1f697ec49429a847ca6f442a2a755126c4d879"
integrity sha512-A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw==
source-map-support@~0.5.9:
version "0.5.10"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.10.tgz#2214080bc9d51832511ee2bab96e3c2f9353120c"
integrity sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==
version "1.7.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65"
integrity sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA==
source-map-support@~0.5.10:
version "0.5.12"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599"
integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
@@ -570,28 +272,13 @@ supports-color@^6.1.0:
has-flag "^3.0.0"

terser@^3.14.1:
version "3.16.1"
resolved "https://registry.yarnpkg.com/terser/-/terser-3.16.1.tgz#5b0dd4fa1ffd0b0b43c2493b2c364fd179160493"
integrity sha512-JDJjgleBROeek2iBcSNzOHLKsB/MdDf+E/BOAJ0Tk9r7p9/fVobfv7LMJ/g/k3v9SXdmjZnIlFd5nfn/Rt0Xow==
version "3.17.0"
resolved "https://registry.yarnpkg.com/terser/-/terser-3.17.0.tgz#f88ffbeda0deb5637f9d24b0da66f4e15ab10cb2"
integrity sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==
dependencies:
commander "~2.17.1"
commander "^2.19.0"
source-map "~0.6.1"
source-map-support "~0.5.9"

tslib@1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==

typescript@^3.3.3333:
version "3.3.3333"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.3333.tgz#171b2c5af66c59e9431199117a3bcadc66fdcfd6"
integrity sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==

universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
source-map-support "~0.5.10"

util-deprecate@~1.0.1:
version "1.0.2"


+ 77
- 0
server/archlinux.js View File

@@ -0,0 +1,77 @@
"use strict";

const fetch = require("node-fetch");
const HTTPError = require("./error");

let packages = {};

const urls = [
"http://ftp-stud.hs-esslingen.de/pub/Mirrors/archlinux/core/os/x86_64/core.db",
"http://ftp-stud.hs-esslingen.de/pub/Mirrors/archlinux/community/os/x86_64/community.db",
"http://ftp-stud.hs-esslingen.de/pub/Mirrors/archlinux/extra/os/x86_64/extra.db",
"http://ftp-stud.hs-esslingen.de/pub/Mirrors/archlinux/multilib/os/x86_64/multilib.db",
];

const stripVersion = (s) => s.split(/[<>]?=.*/)[0];

const getPackageLists = async () => {
const newPackages = {};

for (let url of urls) {
console.log(`fetching ${url}`);

const packageList = await fetch(url)
.then(res => res.text());

/*
* skip this if you don't like very bad, dirty code
*/

const pkgs = packageList.split("%FILENAME%").map(p => "%FILENAME%" + p);
for (let pkg of pkgs) {
const attrs = {};
const re = /^%[^%]*%[^%]*\n$/gsm;
const matches = pkg.match(re);
if (!matches) continue;
for (let m of matches) {
const s = m.slice(0, -1).split("%\n");
const key = s.shift().slice(1);
const val = s.join("");
attrs[key] = val;
}
const p = {
id: attrs["NAME"],
name: `${attrs["NAME"]}-${attrs["VERSION"]}`,
deps: attrs["DEPENDS"] ? attrs["DEPENDS"].split("\n").map(stripVersion) : [],
size: attrs["ISIZE"],
};

newPackages[attrs["NAME"]] = p;
if (attrs["PROVIDES"]) {
for (let name of attrs["PROVIDES"].split("\n").map(stripVersion)) {
newPackages[name] = p;
}
}
}
}

packages = newPackages;
console.log("packages loaded");
}

setInterval(getPackageLists, 24 * 60 * 60 * 1000); // 24 hours
getPackageLists();

const getNode = async (parameters) => {
if (parameters.length < 2) {
throw new HTTPError(404, "Invalid URI");
}

const name = parameters[parameters.length-1];
if (!packages[name]) {
throw new HTTPError(404, "Failed to get package info");
}
return packages[name];
};

module.exports = getNode;

+ 10
- 0
server/error.js View File

@@ -0,0 +1,10 @@
"use strict";

const HTTPError = function(code, msg) {
this.code = code;
this.msg = msg;
};

HTTPError.prototype = Error;

module.exports = HTTPError;

+ 29
- 70
server/index.js View File

@@ -1,91 +1,50 @@
"use strict";

const http = require("http");
const { promisify } = require("util");
const execFile = promisify(require("child_process").execFile);
const url = require("url");
const fetch = require("node-fetch");
const HTTPError = require("./error");

let narinfoCache = {};

setInterval(() => {
narinfoCache = {};
}, 24 * 60 * 60 * 1000); // 24 hours

const getNarinfo = async (hash) => {
if (!narinfoCache[hash]) {
narinfoCache[hash] = await fetch(`https://cache.nixos.org/${hash}.narinfo`)
.then(res => res.text());
}
return narinfoCache[hash];
};

const getNarinfoKey = async (hash, key) => {
const narinfo = await getNarinfo(hash);
return narinfo.split(`${key}: `)[1].split("\n")[0];
};

const parseDerivationPath = (derivationPath) => {
return {
hash: derivationPath.split('-')[0],
name: derivationPath.split('-').slice(1).join('-')
}
const listBackends = async () => {
return Object.keys(backends).filter(b => b !== "backends");
};

const getStorePathFromName = async (name) => {
const { stdout } = await execFile("nix-instantiate", ["--strict", "--eval", "<nixpkgs>", "-A", `${name}.outPath`]);
return stdout.split('"')[1];
};

const getStorePathFromHash = (hash) => getNarinfoKey(hash, "StorePath");

const getReferences = async (hash) => {
const key = await getNarinfoKey(hash, "References");
if (!key.length) return [];
return key.split(" ").map(parseDerivationPath);
const backends = {
NixOS: require("./nixpkgs"),
OpenWRT: require("./openwrt"),
ArchLinux: require("./archlinux"),
backends: listBackends
};

http.createServer(async (req, stream) => {
stream.setHeader("Access-Control-Allow-Origin", "*");

const { pathname } = url.parse(req.url);
let split = pathname.split("/");
let name = split[split.length-1];

if (split.length < 3) {
stream.writeHead(404, { "Content-Type": "text/plain" });
return stream.end("Invalid url");
}
let parameters = pathname.split("/");

let storePath;
let res;
try {
if (split[split.length-2] === "name") {
const name = split[split.length-1];
storePath = await getStorePathFromName(name);
} else if (split[split.length-2] === "hash") {
const hash = split[split.length-1];
storePath = await getStorePathFromHash(hash);
} else {
stream.writeHead(404, { "Content-Type": "text/plain" });
return stream.end("Invalid url");
if (parameters.length < 3) {
throw new HTTPError(404, "Invalid URI");
}
} catch(err) {
stream.writeHead(404, { "Content-Type": "text/plain" });
return stream.end("Failed to get store path");
}

let res;
try {
derivationPath = storePath.split("/")[3];
res = parseDerivationPath(derivationPath);
} catch(err) {
stream.writeHead(500, { "Content-Type": "text/plain" });
return stream.end(`Failed to parse store path: ${err}`);
}
const backend = backends[parameters[2]];
if (!backend) {
throw new HTTPError(404, "Invalid Backend");
}

try {
res.references = await getReferences(res.hash);
res = await backend(parameters.splice(3));
} catch(err) {
stream.writeHead(500, { "Content-Type": "text/plain" });
return stream.end(`Failed to get references: ${err}`);
if (err instanceof HTTPError) {
stream.writeHead(err.code, { "Content-Type": "text/plain" });
stream.end(err.msg);
} else {
console.error(`Unexpected Error: ${err.msg || err}\n${err.stack}`);
stream.writeHead(500, { "Content-Type": "text/plain" });
stream.end("Unexpected Error");
}

return;
}

stream.writeHead(200, { "Content-Type": "application/json" });


+ 96
- 0
server/nixpkgs.js View File

@@ -0,0 +1,96 @@
"use strict";

const { promisify } = require("util");
const execFile = promisify(require("child_process").execFile);
const fetch = require("node-fetch");
const HTTPError = require("./error");

let narinfoCache = {};

setInterval(() => {
narinfoCache = {};
}, 24 * 60 * 60 * 1000); // 24 hours

const getNarinfo = async (hash) => {
if (!narinfoCache[hash]) {
narinfoCache[hash] = await fetch(`https://cache.nixos.org/${hash}.narinfo`)
.then(res => res.text());
}
return narinfoCache[hash];
};

const getNarinfoKey = async (hash, key) => {
const narinfo = await getNarinfo(hash);
return narinfo.split(`${key}: `)[1].split("\n")[0];
};

const parseDerivationPath = (derivationPath) => {
return {
id: derivationPath.split('-')[0],
name: derivationPath.split('-').slice(1).join('-')
}
};

const getStorePathFromName = async (name) => {
const { stdout } = await execFile("nix-instantiate", ["--strict", "--eval", "<nixpkgs>", "-A", `${name}.outPath`]);
return stdout.split('"')[1];
};

const getStorePathFromHash = (hash) => getNarinfoKey(hash, "StorePath");

const getReferences = async (hash) => {
const key = await getNarinfoKey(hash, "References");
if (!key.length) return [];
return key.split(" ").map(parseDerivationPath);
};

const getNode = async (parameters) => {
if (parameters.length < 2) {
throw new HTTPError(404, "Invalid URI");
}

const type = parameters[parameters.length-2];
const name = parameters[parameters.length-1];

let getStorePathFunc;
if (type === "name") {
getStorePathFunc = getStorePathFromName;
} else if (type === "id") {
getStorePathFunc = getStorePathFromHash;
} else {
throw new HTTPError(400, "Invalid request type");
}

let storePath;
try {
storePath = await getStorePathFunc(name);
} catch(err) {
// omit original error for security reasons
throw new HTTPError(404, "Failed to get store path");
}

let res;
try {
const derivationPath = storePath.split("/")[3];
res = parseDerivationPath(derivationPath);
} catch(err) {
throw new HTTPError(500, `Failed to parse store path: ${err}`);
}

try {
const references = await getReferences(res.id);
res.deps = references.map(ref => ref.id);
} catch(err) {
throw new HTTPError(500, `Failed to get references: ${err}`);
}

try {
res.size = Number(await getNarinfoKey(res.id, "NarSize"));
} catch (err) {
throw new HTTPError(500, `Failed to get size: ${err}`);
}

return res;
};

module.exports = getNode;

+ 61
- 0
server/openwrt.js View File

@@ -0,0 +1,61 @@
"use strict";

const fetch = require("node-fetch");
const InternetMessage = require("internet-message");
const HTTPError = require("./error");

let packages = {};

const urls = [
"https://downloads.openwrt.org/snapshots/packages/mips_24kc/base/Packages",
"https://downloads.openwrt.org/snapshots/packages/mips_24kc/packages/Packages",
"https://downloads.openwrt.org/snapshots/packages/mips_24kc/routing/Packages",
"https://downloads.openwrt.org/snapshots/packages/mips_24kc/luci/Packages",
"https://downloads.openwrt.org/snapshots/packages/mips_24kc/telephony/Packages",
"https://downloads.openwrt.org/snapshots/targets/ar71xx/generic/packages/Packages"
];

const getPackageLists = async () => {
const newPackages = {};

for (let url of urls) {
console.log(`fetching ${url}`);

const packageList = await fetch(url)
.then(res => res.text());

let packages = packageList.split("\n\n")
.forEach(pkg => {
let attrs = InternetMessage.parse(pkg + "\n")
if (attrs.package && attrs.depends) {
attrs.depends = attrs.depends.split(", ").map(dep => dep.split(" (")[0]);
newPackages[attrs.package] = {
deps: attrs.depends,
name: attrs.package,
id: attrs.package,
size: Number(attrs["installed-size"])
};
}
});
}

packages = newPackages;
console.log("packages loaded");
}

setInterval(getPackageLists, 24 * 60 * 60 * 1000); // 24 hours
getPackageLists();

const getNode = async (parameters) => {
if (parameters.length < 2) {
throw new HTTPError(404, "Invalid URI");
}

const name = parameters[parameters.length-1];
if (!packages[name]) {
throw new HTTPError(404, "Failed to get package info");
}
return packages[name];
};

module.exports = getNode;

+ 3
- 2
server/package.json View File

@@ -1,10 +1,11 @@
{
"name": "nixpkgs-vis-server",
"version": "1.0.0",
"name": "pkgvis-server",
"version": "1.1.0",
"license": "AGPL-3.0",
"author": "Milan Pässler",
"bin": "index.js",
"dependencies": {
"internet-message": "^1.0.0",
"node-fetch": "^2.3.0"
}
}

+ 5
- 0
server/yarn.lock View File

@@ -2,6 +2,11 @@
# yarn lockfile v1


internet-message@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/internet-message/-/internet-message-1.0.0.tgz#28f65368a22a6207994c6e21f0e3bffbf1278d2b"
integrity sha1-KPZTaKIqYgeZTG4h8OO/+/EnjSs=

node-fetch@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5"


Loading…
Cancel
Save