From a3ffb01958f4d20a2499b1fa57eb9b517a487ebe Mon Sep 17 00:00:00 2001 From: Bennett Date: Wed, 11 Dec 2019 11:30:13 +0100 Subject: Add update script --- scripts/package.json | 5 ++- scripts/update.js | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++ scripts/yarn.lock | 10 +++++ 3 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 scripts/update.js (limited to 'scripts') diff --git a/scripts/package.json b/scripts/package.json index d416231..2bfc982 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -9,10 +9,13 @@ "dependencies": { "dir-compare": "^1.7.3", "fs-extra": "^8.1.0", + "node-fetch": "^2.6.0", + "semver": "^6.3.0", "targz": "^1.0.1" }, "scripts": { "package": "node package.js", - "verify": "node verify.js" + "verify": "node verify.js", + "update": "node update.js" } } diff --git a/scripts/update.js b/scripts/update.js new file mode 100644 index 0000000..802cd64 --- /dev/null +++ b/scripts/update.js @@ -0,0 +1,124 @@ +/** + * Update recipes from a Ferdi-compatible server + */ +const fetch = require('node-fetch'); +const targz = require('targz'); +const fs = require('fs-extra'); +const path = require('path'); +const semver = require('semver'); + +console.log("Ferdi Recipe Repository Updater v1.0.0"); + +// Server to update from +const server = "http://api.franzinfra.com/v1/"; + +// Create paths to important files +const allJson = path.join('../', 'all.json'); + +// Helper: Download file to filesystem +const downloadFile = (async (url, path) => { + const res = await fetch(url); + const fileStream = fs.createWriteStream(path); + await new Promise((resolve, reject) => { + res.body.pipe(fileStream); + res.body.on("error", (err) => { + reject(err); + }); + fileStream.on("finish", function () { + resolve(); + }); + }); +}); + +// Helper: Decompress .tar.gz file +const decompress = (src, dest) => { + return new Promise(resolve => { + targz.decompress({ + src, + dest + }, function (err) { + if (err) { + console.log('Error while decompressing recipe:', err); + } + resolve(); + }); + }) +} + +// Let us work in an async environment +(async () => { + // Get current recipes from server + const serverRecipes = await (await fetch(server + 'recipes')).json(); + + // Get current local recipes + const localRecipes = await fs.readJson(allJson); + + for (const recipe of serverRecipes) { + // Find local recipe info + const localRecipe = localRecipes.find(e => e.id === recipe.id); + + if (!localRecipe || semver.gt(recipe.version, localRecipe.version)) { + // Update is availible + console.log(`Updating ${recipe.id} from ${localRecipe ? localRecipe.version : '-1'} to ${recipe.version}`); + + const compressed = path.join('../', `${recipe.id}.tar.gz`); + const uncompressed = path.join('../uncompressed', recipe.id); + + // Download recipe to filesystem + try { + await downloadFile( + server + '/recipes/download/' + recipe.id, + compressed + ); + } catch(e) { + console.log(`Could not download ${recipe.id}`); + return; + } + + // Extract recipe + await decompress(compressed, uncompressed) + + // Make sure we have all icons + const iconPng = path.join(uncompressed, '/icon.png'); + const iconSvg = path.join(uncompressed, '/icon.svg'); + if (!await fs.exists(iconPng)) { + downloadFile(recipe.icons.png, iconPng); + } + if (!await fs.exists(iconSvg)) { + downloadFile(recipe.icons.svg, iconSvg); + } + + // Update entry in all.json + // Check if package ID already exists + const recipeIndex = localRecipes.findIndex(e => e.id === recipe.id); + + const recipeInfo = recipe; + recipeInfo.icons.png = recipeInfo.icons.png.replace( + 'https://cdn.franzinfra.com/recipes/dist/', + 'https://cdn.jsdelivr.net/gh/getferdi/recipes/uncompressed/' + ).replace( + 'src/icon.png', + 'icon.png' + ); + recipeInfo.icons.svg = recipeInfo.icons.svg.replace( + 'https://cdn.franzinfra.com/recipes/dist/', + 'https://cdn.jsdelivr.net/gh/getferdi/recipes/uncompressed/' + ).replace( + 'src/icon.svg', + 'icon.svg' + ); + + if (recipeIndex !== -1) { + localRecipes[recipeIndex] = recipeInfo; + } else { + localRecipes.push(recipeInfo); + } + } + } + + // Write updated package info to all.json + await fs.writeJson(allJson, localRecipes, { + spaces: 2, + EOL: '\n', + }); +})(); \ No newline at end of file diff --git a/scripts/yarn.lock b/scripts/yarn.lock index a7b917b..a06349c 100644 --- a/scripts/yarn.lock +++ b/scripts/yarn.lock @@ -162,6 +162,11 @@ mkdirp@^0.5.1: dependencies: minimist "0.0.8" +node-fetch@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" + integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== + once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -205,6 +210,11 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" -- cgit v1.2.3-54-g00ecf