diff options
Diffstat (limited to 'scripts/update.js')
-rw-r--r-- | scripts/update.js | 124 |
1 files changed, 124 insertions, 0 deletions
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 @@ | |||
1 | /** | ||
2 | * Update recipes from a Ferdi-compatible server | ||
3 | */ | ||
4 | const fetch = require('node-fetch'); | ||
5 | const targz = require('targz'); | ||
6 | const fs = require('fs-extra'); | ||
7 | const path = require('path'); | ||
8 | const semver = require('semver'); | ||
9 | |||
10 | console.log("Ferdi Recipe Repository Updater v1.0.0"); | ||
11 | |||
12 | // Server to update from | ||
13 | const server = "http://api.franzinfra.com/v1/"; | ||
14 | |||
15 | // Create paths to important files | ||
16 | const allJson = path.join('../', 'all.json'); | ||
17 | |||
18 | // Helper: Download file to filesystem | ||
19 | const downloadFile = (async (url, path) => { | ||
20 | const res = await fetch(url); | ||
21 | const fileStream = fs.createWriteStream(path); | ||
22 | await new Promise((resolve, reject) => { | ||
23 | res.body.pipe(fileStream); | ||
24 | res.body.on("error", (err) => { | ||
25 | reject(err); | ||
26 | }); | ||
27 | fileStream.on("finish", function () { | ||
28 | resolve(); | ||
29 | }); | ||
30 | }); | ||
31 | }); | ||
32 | |||
33 | // Helper: Decompress .tar.gz file | ||
34 | const decompress = (src, dest) => { | ||
35 | return new Promise(resolve => { | ||
36 | targz.decompress({ | ||
37 | src, | ||
38 | dest | ||
39 | }, function (err) { | ||
40 | if (err) { | ||
41 | console.log('Error while decompressing recipe:', err); | ||
42 | } | ||
43 | resolve(); | ||
44 | }); | ||
45 | }) | ||
46 | } | ||
47 | |||
48 | // Let us work in an async environment | ||
49 | (async () => { | ||
50 | // Get current recipes from server | ||
51 | const serverRecipes = await (await fetch(server + 'recipes')).json(); | ||
52 | |||
53 | // Get current local recipes | ||
54 | const localRecipes = await fs.readJson(allJson); | ||
55 | |||
56 | for (const recipe of serverRecipes) { | ||
57 | // Find local recipe info | ||
58 | const localRecipe = localRecipes.find(e => e.id === recipe.id); | ||
59 | |||
60 | if (!localRecipe || semver.gt(recipe.version, localRecipe.version)) { | ||
61 | // Update is availible | ||
62 | console.log(`Updating ${recipe.id} from ${localRecipe ? localRecipe.version : '-1'} to ${recipe.version}`); | ||
63 | |||
64 | const compressed = path.join('../', `${recipe.id}.tar.gz`); | ||
65 | const uncompressed = path.join('../uncompressed', recipe.id); | ||
66 | |||
67 | // Download recipe to filesystem | ||
68 | try { | ||
69 | await downloadFile( | ||
70 | server + '/recipes/download/' + recipe.id, | ||
71 | compressed | ||
72 | ); | ||
73 | } catch(e) { | ||
74 | console.log(`Could not download ${recipe.id}`); | ||
75 | return; | ||
76 | } | ||
77 | |||
78 | // Extract recipe | ||
79 | await decompress(compressed, uncompressed) | ||
80 | |||
81 | // Make sure we have all icons | ||
82 | const iconPng = path.join(uncompressed, '/icon.png'); | ||
83 | const iconSvg = path.join(uncompressed, '/icon.svg'); | ||
84 | if (!await fs.exists(iconPng)) { | ||
85 | downloadFile(recipe.icons.png, iconPng); | ||
86 | } | ||
87 | if (!await fs.exists(iconSvg)) { | ||
88 | downloadFile(recipe.icons.svg, iconSvg); | ||
89 | } | ||
90 | |||
91 | // Update entry in all.json | ||
92 | // Check if package ID already exists | ||
93 | const recipeIndex = localRecipes.findIndex(e => e.id === recipe.id); | ||
94 | |||
95 | const recipeInfo = recipe; | ||
96 | recipeInfo.icons.png = recipeInfo.icons.png.replace( | ||
97 | 'https://cdn.franzinfra.com/recipes/dist/', | ||
98 | 'https://cdn.jsdelivr.net/gh/getferdi/recipes/uncompressed/' | ||
99 | ).replace( | ||
100 | 'src/icon.png', | ||
101 | 'icon.png' | ||
102 | ); | ||
103 | recipeInfo.icons.svg = recipeInfo.icons.svg.replace( | ||
104 | 'https://cdn.franzinfra.com/recipes/dist/', | ||
105 | 'https://cdn.jsdelivr.net/gh/getferdi/recipes/uncompressed/' | ||
106 | ).replace( | ||
107 | 'src/icon.svg', | ||
108 | 'icon.svg' | ||
109 | ); | ||
110 | |||
111 | if (recipeIndex !== -1) { | ||
112 | localRecipes[recipeIndex] = recipeInfo; | ||
113 | } else { | ||
114 | localRecipes.push(recipeInfo); | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | |||
119 | // Write updated package info to all.json | ||
120 | await fs.writeJson(allJson, localRecipes, { | ||
121 | spaces: 2, | ||
122 | EOL: '\n', | ||
123 | }); | ||
124 | })(); \ No newline at end of file | ||