aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/update.js
blob: c48c67cccc7abd6bd155c5af22525bd39e69b3b9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/**
 * 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 {
        console.log("Downloading " + server + '/recipes/download/' + recipe.id);
        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',
  });
})();