diff options
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/add_github.js | 107 | ||||
-rw-r--r-- | scripts/api/package.js | 207 | ||||
-rw-r--r-- | scripts/api/require-depts.js | 20 | ||||
-rw-r--r-- | scripts/create.js | 2 | ||||
-rw-r--r-- | scripts/gh_load.js | 85 | ||||
-rw-r--r-- | scripts/load.js | 39 | ||||
-rw-r--r-- | scripts/package-lock.json | 402 | ||||
-rw-r--r-- | scripts/package.js | 177 | ||||
-rw-r--r-- | scripts/package.json | 29 | ||||
-rw-r--r-- | scripts/update.js | 125 | ||||
-rw-r--r-- | scripts/verify-all.js | 97 | ||||
-rw-r--r-- | scripts/verify.js | 70 |
12 files changed, 174 insertions, 1186 deletions
diff --git a/scripts/add_github.js b/scripts/add_github.js deleted file mode 100644 index c3a7ca4..0000000 --- a/scripts/add_github.js +++ /dev/null | |||
@@ -1,107 +0,0 @@ | |||
1 | /** | ||
2 | * Add GitHub repository as recipe | ||
3 | */ | ||
4 | require('./api/require-depts')(); | ||
5 | |||
6 | const fetch = require('node-fetch'); | ||
7 | const targz = require('targz'); | ||
8 | const fs = require('fs-extra'); | ||
9 | const path = require('path'); | ||
10 | const GitUrlParse = require("git-url-parse"); | ||
11 | const packageRecipe = require('./api/package'); | ||
12 | |||
13 | // Helper: Download file to filesystem | ||
14 | const downloadFile = (async (url, path) => { | ||
15 | const res = await fetch(url); | ||
16 | const fileStream = fs.createWriteStream(path); | ||
17 | await new Promise((resolve, reject) => { | ||
18 | res.body.pipe(fileStream); | ||
19 | res.body.on("error", (err) => { | ||
20 | reject(err); | ||
21 | }); | ||
22 | fileStream.on("finish", function () { | ||
23 | resolve(); | ||
24 | }); | ||
25 | }); | ||
26 | }); | ||
27 | |||
28 | // Helper: Decompress .tar.gz file | ||
29 | const decompress = (src, dest) => { | ||
30 | return new Promise(resolve => { | ||
31 | targz.decompress({ | ||
32 | src, | ||
33 | dest | ||
34 | }, function (err) { | ||
35 | if (err) { | ||
36 | console.log('⚠️ Could not add your recipe: There was an error while decompressing your GitHub repository file: ', err); | ||
37 | } | ||
38 | resolve(); | ||
39 | }); | ||
40 | }) | ||
41 | } | ||
42 | |||
43 | const repo = process.argv[2]; | ||
44 | |||
45 | if (!repo || !/https:\/\/github\.com\/[^\/]+\/[^\/]+\/?/gi.test(repo)) { | ||
46 | console.log(`⚠️ Could not add your recipe: The GitHub URL you provided doesn't seem to be valid. | ||
47 | You should use this command like "yarn github https://github.com/user/repo". | ||
48 | Please make sure you provide a URL in the format "https://github.com/user/repo" | ||
49 | For more information about this script visit https://github.com/getferdi/recipes/blob/master/docs/integration.md#publishing | ||
50 | If you want to package a local recipe, please use "yarn package" instead.`); | ||
51 | return; | ||
52 | } | ||
53 | |||
54 | const repoInfo = GitUrlParse(repo); | ||
55 | const tempDir = path.join(__dirname, 'tmp'); | ||
56 | |||
57 | const recipeSrc = path.join(__dirname, 'recipe_src'); | ||
58 | const recipeSrcTmp = path.join(__dirname, 'recipe_src_tmp'); | ||
59 | |||
60 | const compressed = path.join(__dirname, 'tmp.tar.gz'); | ||
61 | |||
62 | // Let us work in an async environment | ||
63 | (async () => { | ||
64 | console.log("[Info] Creating temporary directory"); | ||
65 | |||
66 | await fs.ensureDir(tempDir); | ||
67 | await fs.ensureDir(recipeSrc); | ||
68 | await fs.ensureDir(recipeSrcTmp); | ||
69 | |||
70 | console.log("[Info] Downloading " + repo); | ||
71 | |||
72 | await downloadFile( | ||
73 | `https://github.com/${repoInfo.owner}/${repoInfo.name}/archive/master.tar.gz`, | ||
74 | compressed | ||
75 | ); | ||
76 | |||
77 | console.log("[Info] Decompressing repository"); | ||
78 | |||
79 | await decompress(compressed, tempDir); | ||
80 | |||
81 | console.log("[Info] Moving 'recipe_src' to 'recipe_src_tmp'"); | ||
82 | |||
83 | await fs.move(recipeSrc, recipeSrcTmp, {overwrite: true}); | ||
84 | await fs.move( | ||
85 | path.join(tempDir, `${repoInfo.name}-master`), | ||
86 | recipeSrc, | ||
87 | {overwrite: true} | ||
88 | ); | ||
89 | |||
90 | console.log("[Info] Packaging your recipe"); | ||
91 | try { | ||
92 | await packageRecipe(); | ||
93 | } catch(e) { | ||
94 | return; | ||
95 | } | ||
96 | |||
97 | console.log("[Info] Deleting temporarydownloaded repository"); | ||
98 | |||
99 | await fs.remove(compressed); | ||
100 | await fs.remove(recipeSrc); | ||
101 | |||
102 | console.log("[Info] Moving back 'recipe_src_tmp' to 'recipe_src'"); | ||
103 | |||
104 | await fs.move(recipeSrcTmp, recipeSrc); | ||
105 | |||
106 | console.log(`✅ Successfully packaged the recipe from your GitHub repository`); | ||
107 | })(); \ No newline at end of file | ||
diff --git a/scripts/api/package.js b/scripts/api/package.js deleted file mode 100644 index c64132f..0000000 --- a/scripts/api/package.js +++ /dev/null | |||
@@ -1,207 +0,0 @@ | |||
1 | /** | ||
2 | * Package recipe into tar.gz file | ||
3 | */ | ||
4 | const targz = require('targz'); | ||
5 | const fs = require('fs-extra'); | ||
6 | const path = require('path'); | ||
7 | const sizeOf = require('image-size'); | ||
8 | const semver = require('semver'); | ||
9 | |||
10 | // Publicly availible link to this repository's uncompressed folder | ||
11 | // Used for generating public icon URLs | ||
12 | const repo = 'https://cdn.jsdelivr.net/gh/getferdi/recipes/uncompressed/'; | ||
13 | |||
14 | // Helper: Compress src folder into dest file | ||
15 | const compress = (src, dest) => new Promise((resolve, reject) => { | ||
16 | targz.compress({ | ||
17 | src, | ||
18 | dest, | ||
19 | tar: { | ||
20 | // Don't package .DS_Store files | ||
21 | ignore: function(name) { | ||
22 | return path.basename(name) === '.DS_Store' | ||
23 | } | ||
24 | }, | ||
25 | }, (err) => { | ||
26 | if (err) { | ||
27 | reject(err); | ||
28 | } else { | ||
29 | resolve(dest); | ||
30 | } | ||
31 | }); | ||
32 | }); | ||
33 | // Let us work in an async environment | ||
34 | module.exports = async () => { | ||
35 | // Create paths to important files | ||
36 | const recipeSrc = path.join(__dirname, '../recipe_src'); | ||
37 | const packageJson = path.join(recipeSrc, 'package.json'); | ||
38 | const svgIcon = path.join(recipeSrc, 'icon.svg'); | ||
39 | const pngIcon = path.join(recipeSrc, 'icon.png'); | ||
40 | const allJson = path.join(__dirname, '../../', 'all.json'); | ||
41 | let all = await fs.readJson(allJson); | ||
42 | |||
43 | let errorMessages = [] | ||
44 | |||
45 | // Check that package.json exists | ||
46 | if (!await fs.pathExists(packageJson)) { | ||
47 | errorMessages.push(`⚠️ It looks like your recipe is missing the "package.json" file. | ||
48 | ↪ Please add your recipe to ${recipeSrc} and make sure that folder contains a "package.json". | ||
49 | ℹ For more information on how to add your recipe visit: https://github.com/getferdi/recipes/blob/master/docs/integration.md`); | ||
50 | } | ||
51 | |||
52 | // Check that icons exist | ||
53 | const hasSvg = await fs.pathExists(svgIcon); | ||
54 | if (!hasSvg) { | ||
55 | errorMessages.push(`⚠️ It looks like your recipe is missing the "icon.svg" file. | ||
56 | ↪ Please make sure your recipe contains an icon.svg file. | ||
57 | ℹ For more information about recipe icons visit: https://github.com/getferdi/recipes/blob/master/docs/integration.md#icons`); | ||
58 | } | ||
59 | |||
60 | const hasPng = await fs.pathExists(pngIcon); | ||
61 | if (!hasPng) { | ||
62 | errorMessages.push(`⚠️ It looks like your recipe is missing the "icon.png" file. | ||
63 | ↪ Please make sure your recipe contains an icon.png file. | ||
64 | ↪ Please also make sure that your PNG icon is 1024x1024px in size. | ||
65 | ℹ For more information about recipe icons visit: https://github.com/getferdi/recipes/blob/master/docs/integration.md#icons`); | ||
66 | } | ||
67 | |||
68 | // Check that icons have the right dimensions | ||
69 | if (hasSvg) { | ||
70 | const svgSize = sizeOf(svgIcon); | ||
71 | const svgHasRightSize = svgSize.width === svgSize.height; | ||
72 | if (!svgHasRightSize) { | ||
73 | errorMessages.push(`⚠️ It looks like your "icon.svg" is not a square. | ||
74 | ↪ Please make sure that your "icon.svg" has the right dimensions to make a square- width and height should be the same. | ||
75 | ℹ You can use software like Photoshop, GIMP or Photopea (https://www.photopea.com/) to resize your icons. | ||
76 | ℹ For more information about recipe icons visit: https://github.com/getferdi/recipes/blob/master/docs/integration.md#icons`); | ||
77 | } | ||
78 | } | ||
79 | |||
80 | if (hasPng) { | ||
81 | const pngSize = sizeOf(pngIcon); | ||
82 | const pngHasRightSize = pngSize.width === 1024 && pngSize.height === 1024; | ||
83 | if (hasPng && !pngHasRightSize) { | ||
84 | errorMessages.push(`⚠️ it looks like your "icon.png" is not 1024x1024 in size. | ||
85 | ↪ Please make sure that your "icon.png" has the right dimeensions of 1024x1024px. | ||
86 | ℹ You can use software like Photoshop, GIMP or Photopea (https://www.photopea.com/) to resize your icons. | ||
87 | ℹ For more information about recipe icons visit: https://github.com/getferdi/recipes/blob/master/docs/integration.md#icons`); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | // Read package.json | ||
92 | const config = await fs.readJson(packageJson) | ||
93 | |||
94 | // Make sure it contains all required fields | ||
95 | if (!config) { | ||
96 | errorMessages.push(`⚠️ It looks like your "package.json" file could not read or parsed. | ||
97 | ↪ Please make sure your "package.json" contains valid JSON. | ||
98 | ℹ You can use a JSON Validator like JSONLint: https://jsonlint.com/ | ||
99 | ℹ For more information about the package.json file visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
100 | } | ||
101 | |||
102 | if (!config.id) { | ||
103 | errorMessages.push(`⚠️ It looks like your "package.json" does not contain an "id" field. | ||
104 | ↪ Please make sure the "id" field contains a unique ID made of lowercase letters (a-z), numbers (0-9), hyphens (-), periods (.), and underscores (_) | ||
105 | ℹ For more information about the package.json file visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
106 | } else if (!/^[a-z._\-]+$/.test(config.id)) { | ||
107 | errorMessages.push(`⚠️ It looks like your "package.json" defines an invalid recipe ID. | ||
108 | ↪ Please make sure the "id" field only contains lowercase letters (a-z), numbers (0-9), hyphens (-), periods (.), and underscores (_) | ||
109 | ℹ For more information about the package.json file visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
110 | } | ||
111 | if (!config.name) { | ||
112 | errorMessages.push(`⚠️ It looks like your "package.json" does not contain a "name" field. | ||
113 | ↪ Please make sure the "name" field contains the name of the service (e.g. "Google Keep") | ||
114 | ℹ For more information about the package.json file visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
115 | } | ||
116 | if (!config.version) { | ||
117 | errorMessages.push(`⚠️ It looks like your "package.json" does not contain a "version" field. | ||
118 | ↪ Please make sure the "version" field contains a semver-compatible version number for your recipe (e.g. "1.0.0") | ||
119 | ℹ For more information about the package.json file visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
120 | } | ||
121 | if (!config.config || typeof config.config !== "object") { | ||
122 | errorMessages.push(`⚠️ It looks like your "package.json" does not contain a "config" object. | ||
123 | ↪ Please make sure the "config" object contains a configuration for your service. | ||
124 | ℹ For more information about the package.json file visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
125 | } else if (!config.config.serviceURL) { | ||
126 | errorMessages.push(`⚠️ It looks like your "package.json" does not contain a "config" object without a "serviceURL" field. | ||
127 | ↪ Please make sure the "serviceURL" contains the URL of your service. | ||
128 | ℹ For more information about the package.json file visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
129 | } | ||
130 | |||
131 | // Index of the current recipe in all.json | ||
132 | const packageIndex = all.findIndex(e => e.id === config.id) | ||
133 | |||
134 | if (packageIndex !== -1) { | ||
135 | const currentVersion = config.version; | ||
136 | const repoVersion = all[packageIndex].version; | ||
137 | |||
138 | if (semver.gte(repoVersion, currentVersion)) { | ||
139 | errorMessages.push(`⚠️ It looks like your recipe is using the same version number as the current recipe. | ||
140 | ↪ Please make sure to increase the version number inside your "package.json" everytime you want to repackage (e.g. '1.0.0' to '1.0.1'). | ||
141 | ↪ If you don't increase your version number, Ferdi cannot detect that you have made changes to the recipe. | ||
142 | ℹ For more information about versioning of recipes visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md#config-flags`); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | if (!await fs.exists(path.join(recipeSrc, 'webview.js'))) { | ||
147 | errorMessages.push(`⚠️ It looks like your recipe doesn't contain a "webview.js" file. | ||
148 | ↪ Please make sure to create that file and add your features to it. | ||
149 | ℹ For more information about the webview.js file visit: https://github.com/getferdi/recipes/blob/master/docs/integration.md#webviewjs and https://github.com/getferdi/recipes/blob/master/docs/frontend_api.md`); | ||
150 | } | ||
151 | if (!await fs.exists(path.join(recipeSrc, 'index.js'))) { | ||
152 | errorMessages.push(`⚠️ It looks like your recipe doesn't contain a "index.js" file. | ||
153 | ↪ Please make sure to create that file and add your features to it. For most recipes it is enough to simply add the basic template found at https://github.com/getferdi/recipes/blob/master/docs/integration.md#indexjs | ||
154 | ℹ For more information about the webview.js file visit: https://github.com/getferdi/recipes/blob/master/docs/integration.md#indexjs and https://github.com/getferdi/recipes/blob/master/docs/backend_api.md`); | ||
155 | } | ||
156 | |||
157 | if (errorMessages.length > 0) { | ||
158 | console.log(`❌ Could not add your recipe, the following ${errorMessages.length} error(s) were found: | ||
159 | ${errorMessages.reduce((str, err) => `${str}\n${err}`)} | ||
160 | ℹ For more information, visit: https://github.com/getferdi/recipes/tree/master/docs`); | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | // Package to .tar.gz | ||
165 | console.log(`[Info] Packaging ${config.id}...`); | ||
166 | compress(recipeSrc, path.join(__dirname, '../../', 'archives', `${config.id}.tar.gz`)); | ||
167 | |||
168 | // Copy recipe src folder to /uncompressed/:id folder | ||
169 | console.log('[Info] Copying to uncompressed recipes'); | ||
170 | await fs.copy('recipe_src', path.join(__dirname, '../../', 'uncompressed', `${config.id}`)); | ||
171 | |||
172 | // Add recipe to all.json | ||
173 | console.log('[Info] Adding to all.json'); | ||
174 | const isFeatured = packageIndex !== -1 ? all[packageIndex].featured : false; | ||
175 | const packageInfo = { | ||
176 | "author": config.author || '', | ||
177 | "featured": isFeatured, | ||
178 | "id": config.id, | ||
179 | "name": config.name, | ||
180 | "version": config.version || '1.0.0', | ||
181 | "icons": { | ||
182 | "png": `${repo}${config.id}/icon.png`, | ||
183 | "svg": `${repo}${config.id}/icon.svg`, | ||
184 | }, | ||
185 | }; | ||
186 | // Check if package ID already exists | ||
187 | if (packageIndex !== -1) { | ||
188 | console.log('[Info] Recipe with ID already exists - overwriting'); | ||
189 | all[packageIndex] = packageInfo; | ||
190 | } else { | ||
191 | console.log('[Info] No recipe with ID found - creating new.'); | ||
192 | all.push(packageInfo); | ||
193 | } | ||
194 | |||
195 | // Sort package list alphabetically | ||
196 | all = all.sort((a, b) => { | ||
197 | var textA = a.id.toLowerCase(); | ||
198 | var textB = b.id.toLowerCase(); | ||
199 | return (textA < textB) ? -1 : (textA > textB) ? 1 : 0; | ||
200 | }); | ||
201 | await fs.writeJson(allJson, all, { | ||
202 | spaces: 2, | ||
203 | EOL: '\n', | ||
204 | }); | ||
205 | |||
206 | console.log(`✅ Successfully packaged and added new recipe "${config.id}"`); | ||
207 | }; | ||
diff --git a/scripts/api/require-depts.js b/scripts/api/require-depts.js deleted file mode 100644 index c9c8814..0000000 --- a/scripts/api/require-depts.js +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | /** | ||
2 | * Require the dependencies to be installed or fail otherwise | ||
3 | */ | ||
4 | module.exports = () => { | ||
5 | try { | ||
6 | // Try to include some package to see if it throws an error | ||
7 | require('targz'); | ||
8 | require('fs-extra'); | ||
9 | require('git-url-parse'); | ||
10 | require('image-size'); | ||
11 | require('semver'); | ||
12 | } catch (e) { | ||
13 | console.log(`⚠️ Could not add your recipe: Please make sure to install the dependencies first! | ||
14 | It looks like you havn't run "npm install" yet. Please run that command in order to install all the dependencies required to run the scripts. | ||
15 | If you get an error similar to "command not found: npm" while installing the dependencies, make sure to install npm first using the guide at https://www.npmjs.com/get-npm. | ||
16 | If you've already installed the dependencies before, please re-run "npm install" again as the dependencies might have changed. | ||
17 | For more information about installing this script visit https://github.com/getferdi/recipes/blob/master/docs/integration.md#publishing`); | ||
18 | process.exit(0); | ||
19 | } | ||
20 | } \ No newline at end of file | ||
diff --git a/scripts/create.js b/scripts/create.js index 724eeb6..12b0c15 100644 --- a/scripts/create.js +++ b/scripts/create.js | |||
@@ -66,5 +66,5 @@ const filesThatNeedTextReplace = ['package.json', 'index.js', 'README.md']; | |||
66 | What's next? | 66 | What's next? |
67 | - Make sure you restart Ferdi in order for the recipe to show up | 67 | - Make sure you restart Ferdi in order for the recipe to show up |
68 | - Customise "webview.js", "package.json", "icon.svg" and "icon.png (see https://github.com/getferdi/recipes/blob/master/docs/integration.md#recipe-structure) | 68 | - Customise "webview.js", "package.json", "icon.svg" and "icon.png (see https://github.com/getferdi/recipes/blob/master/docs/integration.md#recipe-structure) |
69 | - Publish and package your recipe (see https://github.com/getferdi/recipes/blob/master/docs/integration.md#publishing)`); | 69 | - Publish your recipe (see https://github.com/getferdi/recipes/blob/master/docs/integration.md#publishing)`); |
70 | })(); | 70 | })(); |
diff --git a/scripts/gh_load.js b/scripts/gh_load.js deleted file mode 100644 index e72cf23..0000000 --- a/scripts/gh_load.js +++ /dev/null | |||
@@ -1,85 +0,0 @@ | |||
1 | /** | ||
2 | * Add GitHub repository as recipe | ||
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 GitUrlParse = require("git-url-parse"); | ||
9 | |||
10 | // Helper: Download file to filesystem | ||
11 | const downloadFile = (async (url, path) => { | ||
12 | const res = await fetch(url); | ||
13 | const fileStream = fs.createWriteStream(path); | ||
14 | await new Promise((resolve, reject) => { | ||
15 | res.body.pipe(fileStream); | ||
16 | res.body.on("error", (err) => { | ||
17 | reject(err); | ||
18 | }); | ||
19 | fileStream.on("finish", function () { | ||
20 | resolve(); | ||
21 | }); | ||
22 | }); | ||
23 | }); | ||
24 | |||
25 | // Helper: Decompress .tar.gz file | ||
26 | const decompress = (src, dest) => { | ||
27 | return new Promise(resolve => { | ||
28 | targz.decompress({ | ||
29 | src, | ||
30 | dest | ||
31 | }, function (err) { | ||
32 | if (err) { | ||
33 | console.log('Error while decompressing recipe:', err); | ||
34 | } | ||
35 | resolve(); | ||
36 | }); | ||
37 | }) | ||
38 | } | ||
39 | |||
40 | const repo = process.argv[2]; | ||
41 | |||
42 | if (!repo || !/https:\/\/github\.com\/[^\/]+\/[^\/]+\/?/gi.test(repo)) { | ||
43 | console.log("Please provide a valid repository URL"); | ||
44 | return; | ||
45 | } | ||
46 | |||
47 | const repoInfo = GitUrlParse(repo); | ||
48 | const tempDir = path.join(__dirname, 'tmp'); | ||
49 | |||
50 | const recipeSrc = path.join(__dirname, 'recipe_src'); | ||
51 | const recipeSrcTmp = path.join(__dirname, 'recipe_src_tmp'); | ||
52 | |||
53 | const compressed = path.join(__dirname, 'tmp.tar.gz'); | ||
54 | |||
55 | // Let us work in an async environment | ||
56 | (async () => { | ||
57 | console.log("Creating temporary directory"); | ||
58 | |||
59 | await fs.ensureDir(tempDir); | ||
60 | await fs.ensureDir(recipeSrc); | ||
61 | await fs.ensureDir(recipeSrcTmp); | ||
62 | |||
63 | console.log("Downloading " + repo); | ||
64 | |||
65 | await downloadFile( | ||
66 | `https://github.com/${repoInfo.owner}/${repoInfo.name}/archive/master.tar.gz`, | ||
67 | compressed | ||
68 | ); | ||
69 | |||
70 | console.log("Decompressing tarball"); | ||
71 | |||
72 | await decompress(compressed, tempDir); | ||
73 | |||
74 | console.log("Moving directories"); | ||
75 | |||
76 | await fs.move(recipeSrc, recipeSrcTmp, {overwrite: true}); | ||
77 | await fs.move( | ||
78 | path.join(tempDir, `${repoInfo.name}-master`), | ||
79 | recipeSrc, | ||
80 | {overwrite: true} | ||
81 | ); | ||
82 | |||
83 | await fs.remove(compressed); | ||
84 | await fs.remove(recipeSrcTmp); | ||
85 | })(); \ No newline at end of file | ||
diff --git a/scripts/load.js b/scripts/load.js deleted file mode 100644 index 3c11240..0000000 --- a/scripts/load.js +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | /** | ||
2 | * Load recipe into development folder | ||
3 | */ | ||
4 | const fs = require('fs-extra'); | ||
5 | const path = require('path'); | ||
6 | |||
7 | console.log('load: Load recipe into development folder'); | ||
8 | console.log('This command will empty the recipe_src folder. Please make sure that there are no important files in that directory.'); | ||
9 | |||
10 | const recipe = process.argv[2]; | ||
11 | if (!recipe) { | ||
12 | console.log('Usage: yarn load [recipe]'); | ||
13 | return; | ||
14 | } | ||
15 | |||
16 | console.log(`Loading ${recipe}`); | ||
17 | |||
18 | // Create paths to important files | ||
19 | const recipeSrc = path.join(__dirname, 'recipe_src'); | ||
20 | const recipePkg = path.join(__dirname, '../', 'uncompressed', recipe); | ||
21 | |||
22 | // Let us work in an async environment | ||
23 | (async () => { | ||
24 | // Check that recipe folder exists | ||
25 | if (!await fs.pathExists(recipePkg)) { | ||
26 | console.log(`Error: Recipe ${recipe} does not exist.`); | ||
27 | return; | ||
28 | } | ||
29 | |||
30 | console.log('Emptying directory...'); | ||
31 | |||
32 | await fs.emptyDir(recipeSrc); | ||
33 | |||
34 | console.log('Copying data...'); | ||
35 | |||
36 | await fs.copy(recipePkg, recipeSrc); | ||
37 | |||
38 | console.log('Done'); | ||
39 | })(); \ No newline at end of file | ||
diff --git a/scripts/package-lock.json b/scripts/package-lock.json deleted file mode 100644 index 4eafb50..0000000 --- a/scripts/package-lock.json +++ /dev/null | |||
@@ -1,402 +0,0 @@ | |||
1 | { | ||
2 | "name": "ferdi-recipes-scripts", | ||
3 | "version": "1.0.0", | ||
4 | "lockfileVersion": 1, | ||
5 | "requires": true, | ||
6 | "dependencies": { | ||
7 | "@types/node": { | ||
8 | "version": "10.17.19", | ||
9 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.19.tgz", | ||
10 | "integrity": "sha512-46/xThm3zvvc9t9/7M3AaLEqtOpqlYYYcCZbpYVAQHG20+oMZBkae/VMrn4BTi6AJ8cpack0mEXhGiKmDNbLrQ==" | ||
11 | }, | ||
12 | "balanced-match": { | ||
13 | "version": "1.0.0", | ||
14 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", | ||
15 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" | ||
16 | }, | ||
17 | "bl": { | ||
18 | "version": "1.2.2", | ||
19 | "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", | ||
20 | "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", | ||
21 | "requires": { | ||
22 | "readable-stream": "^2.3.5", | ||
23 | "safe-buffer": "^5.1.1" | ||
24 | } | ||
25 | }, | ||
26 | "bluebird": { | ||
27 | "version": "3.4.1", | ||
28 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.1.tgz", | ||
29 | "integrity": "sha1-tzHd9I4t077awudeEhWhG8uR+gc=" | ||
30 | }, | ||
31 | "brace-expansion": { | ||
32 | "version": "1.1.11", | ||
33 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", | ||
34 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", | ||
35 | "requires": { | ||
36 | "balanced-match": "^1.0.0", | ||
37 | "concat-map": "0.0.1" | ||
38 | } | ||
39 | }, | ||
40 | "buffer-alloc": { | ||
41 | "version": "1.2.0", | ||
42 | "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", | ||
43 | "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", | ||
44 | "requires": { | ||
45 | "buffer-alloc-unsafe": "^1.1.0", | ||
46 | "buffer-fill": "^1.0.0" | ||
47 | } | ||
48 | }, | ||
49 | "buffer-alloc-unsafe": { | ||
50 | "version": "1.1.0", | ||
51 | "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", | ||
52 | "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" | ||
53 | }, | ||
54 | "buffer-equal": { | ||
55 | "version": "1.0.0", | ||
56 | "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", | ||
57 | "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=" | ||
58 | }, | ||
59 | "buffer-fill": { | ||
60 | "version": "1.0.0", | ||
61 | "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", | ||
62 | "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" | ||
63 | }, | ||
64 | "chownr": { | ||
65 | "version": "1.1.4", | ||
66 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", | ||
67 | "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" | ||
68 | }, | ||
69 | "colors": { | ||
70 | "version": "1.0.3", | ||
71 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", | ||
72 | "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" | ||
73 | }, | ||
74 | "commander": { | ||
75 | "version": "2.9.0", | ||
76 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", | ||
77 | "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", | ||
78 | "requires": { | ||
79 | "graceful-readlink": ">= 1.0.0" | ||
80 | } | ||
81 | }, | ||
82 | "concat-map": { | ||
83 | "version": "0.0.1", | ||
84 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", | ||
85 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" | ||
86 | }, | ||
87 | "core-util-is": { | ||
88 | "version": "1.0.2", | ||
89 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", | ||
90 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" | ||
91 | }, | ||
92 | "dir-compare": { | ||
93 | "version": "1.7.3", | ||
94 | "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-1.7.3.tgz", | ||
95 | "integrity": "sha512-YsKGvVzy5938B9Rokol3N9jq4QcFhlgostWr+TX4omexpR0UztlbYu5UZRxZ0WTeLMFt+7TCIm7nn27byQKZHw==", | ||
96 | "requires": { | ||
97 | "@types/node": "^10.12.18", | ||
98 | "bluebird": "3.4.1", | ||
99 | "buffer-equal": "1.0.0", | ||
100 | "colors": "1.0.3", | ||
101 | "commander": "2.9.0", | ||
102 | "minimatch": "3.0.2" | ||
103 | } | ||
104 | }, | ||
105 | "end-of-stream": { | ||
106 | "version": "1.4.4", | ||
107 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", | ||
108 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", | ||
109 | "requires": { | ||
110 | "once": "^1.4.0" | ||
111 | } | ||
112 | }, | ||
113 | "fs-constants": { | ||
114 | "version": "1.0.0", | ||
115 | "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", | ||
116 | "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" | ||
117 | }, | ||
118 | "fs-extra": { | ||
119 | "version": "8.1.0", | ||
120 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", | ||
121 | "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", | ||
122 | "requires": { | ||
123 | "graceful-fs": "^4.2.0", | ||
124 | "jsonfile": "^4.0.0", | ||
125 | "universalify": "^0.1.0" | ||
126 | } | ||
127 | }, | ||
128 | "git-up": { | ||
129 | "version": "4.0.1", | ||
130 | "resolved": "https://registry.npmjs.org/git-up/-/git-up-4.0.1.tgz", | ||
131 | "integrity": "sha512-LFTZZrBlrCrGCG07/dm1aCjjpL1z9L3+5aEeI9SBhAqSc+kiA9Or1bgZhQFNppJX6h/f5McrvJt1mQXTFm6Qrw==", | ||
132 | "requires": { | ||
133 | "is-ssh": "^1.3.0", | ||
134 | "parse-url": "^5.0.0" | ||
135 | } | ||
136 | }, | ||
137 | "git-url-parse": { | ||
138 | "version": "11.1.2", | ||
139 | "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.1.2.tgz", | ||
140 | "integrity": "sha512-gZeLVGY8QVKMIkckncX+iCq2/L8PlwncvDFKiWkBn9EtCfYDbliRTTp6qzyQ1VMdITUfq7293zDzfpjdiGASSQ==", | ||
141 | "requires": { | ||
142 | "git-up": "^4.0.0" | ||
143 | } | ||
144 | }, | ||
145 | "graceful-fs": { | ||
146 | "version": "4.2.3", | ||
147 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", | ||
148 | "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" | ||
149 | }, | ||
150 | "graceful-readlink": { | ||
151 | "version": "1.0.1", | ||
152 | "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", | ||
153 | "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" | ||
154 | }, | ||
155 | "image-size": { | ||
156 | "version": "0.8.3", | ||
157 | "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.8.3.tgz", | ||
158 | "integrity": "sha512-SMtq1AJ+aqHB45c3FsB4ERK0UCiA2d3H1uq8s+8T0Pf8A3W4teyBQyaFaktH6xvZqh+npwlKU7i4fJo0r7TYTg==", | ||
159 | "requires": { | ||
160 | "queue": "6.0.1" | ||
161 | } | ||
162 | }, | ||
163 | "inherits": { | ||
164 | "version": "2.0.4", | ||
165 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", | ||
166 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" | ||
167 | }, | ||
168 | "is-docker": { | ||
169 | "version": "2.0.0", | ||
170 | "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.0.0.tgz", | ||
171 | "integrity": "sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ==" | ||
172 | }, | ||
173 | "is-ssh": { | ||
174 | "version": "1.3.1", | ||
175 | "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.1.tgz", | ||
176 | "integrity": "sha512-0eRIASHZt1E68/ixClI8bp2YK2wmBPVWEismTs6M+M099jKgrzl/3E976zIbImSIob48N2/XGe9y7ZiYdImSlg==", | ||
177 | "requires": { | ||
178 | "protocols": "^1.1.0" | ||
179 | } | ||
180 | }, | ||
181 | "is-wsl": { | ||
182 | "version": "2.2.0", | ||
183 | "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", | ||
184 | "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", | ||
185 | "requires": { | ||
186 | "is-docker": "^2.0.0" | ||
187 | } | ||
188 | }, | ||
189 | "isarray": { | ||
190 | "version": "1.0.0", | ||
191 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", | ||
192 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" | ||
193 | }, | ||
194 | "jsonfile": { | ||
195 | "version": "4.0.0", | ||
196 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", | ||
197 | "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", | ||
198 | "requires": { | ||
199 | "graceful-fs": "^4.1.6" | ||
200 | } | ||
201 | }, | ||
202 | "minimatch": { | ||
203 | "version": "3.0.2", | ||
204 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz", | ||
205 | "integrity": "sha1-DzmKcwDqRB6cNIyD2Yq4ydv5xAo=", | ||
206 | "requires": { | ||
207 | "brace-expansion": "^1.0.0" | ||
208 | } | ||
209 | }, | ||
210 | "minimist": { | ||
211 | "version": "1.2.5", | ||
212 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", | ||
213 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" | ||
214 | }, | ||
215 | "mkdirp": { | ||
216 | "version": "0.5.5", | ||
217 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", | ||
218 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", | ||
219 | "requires": { | ||
220 | "minimist": "^1.2.5" | ||
221 | } | ||
222 | }, | ||
223 | "node-fetch": { | ||
224 | "version": "2.6.0", | ||
225 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", | ||
226 | "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" | ||
227 | }, | ||
228 | "normalize-url": { | ||
229 | "version": "3.3.0", | ||
230 | "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", | ||
231 | "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==" | ||
232 | }, | ||
233 | "once": { | ||
234 | "version": "1.4.0", | ||
235 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", | ||
236 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", | ||
237 | "requires": { | ||
238 | "wrappy": "1" | ||
239 | } | ||
240 | }, | ||
241 | "open": { | ||
242 | "version": "7.0.3", | ||
243 | "resolved": "https://registry.npmjs.org/open/-/open-7.0.3.tgz", | ||
244 | "integrity": "sha512-sP2ru2v0P290WFfv49Ap8MF6PkzGNnGlAwHweB4WR4mr5d2d0woiCluUeJ218w7/+PmoBy9JmYgD5A4mLcWOFA==", | ||
245 | "requires": { | ||
246 | "is-docker": "^2.0.0", | ||
247 | "is-wsl": "^2.1.1" | ||
248 | } | ||
249 | }, | ||
250 | "parse-path": { | ||
251 | "version": "4.0.1", | ||
252 | "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.1.tgz", | ||
253 | "integrity": "sha512-d7yhga0Oc+PwNXDvQ0Jv1BuWkLVPXcAoQ/WREgd6vNNoKYaW52KI+RdOFjI63wjkmps9yUE8VS4veP+AgpQ/hA==", | ||
254 | "requires": { | ||
255 | "is-ssh": "^1.3.0", | ||
256 | "protocols": "^1.4.0" | ||
257 | } | ||
258 | }, | ||
259 | "parse-url": { | ||
260 | "version": "5.0.1", | ||
261 | "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-5.0.1.tgz", | ||
262 | "integrity": "sha512-flNUPP27r3vJpROi0/R3/2efgKkyXqnXwyP1KQ2U0SfFRgdizOdWfvrrvJg1LuOoxs7GQhmxJlq23IpQ/BkByg==", | ||
263 | "requires": { | ||
264 | "is-ssh": "^1.3.0", | ||
265 | "normalize-url": "^3.3.0", | ||
266 | "parse-path": "^4.0.0", | ||
267 | "protocols": "^1.4.0" | ||
268 | } | ||
269 | }, | ||
270 | "process-nextick-args": { | ||
271 | "version": "2.0.1", | ||
272 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", | ||
273 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" | ||
274 | }, | ||
275 | "protocols": { | ||
276 | "version": "1.4.7", | ||
277 | "resolved": "https://registry.npmjs.org/protocols/-/protocols-1.4.7.tgz", | ||
278 | "integrity": "sha512-Fx65lf9/YDn3hUX08XUc0J8rSux36rEsyiv21ZGUC1mOyeM3lTRpZLcrm8aAolzS4itwVfm7TAPyxC2E5zd6xg==" | ||
279 | }, | ||
280 | "pump": { | ||
281 | "version": "1.0.3", | ||
282 | "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", | ||
283 | "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", | ||
284 | "requires": { | ||
285 | "end-of-stream": "^1.1.0", | ||
286 | "once": "^1.3.1" | ||
287 | } | ||
288 | }, | ||
289 | "queue": { | ||
290 | "version": "6.0.1", | ||
291 | "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.1.tgz", | ||
292 | "integrity": "sha512-AJBQabRCCNr9ANq8v77RJEv73DPbn55cdTb+Giq4X0AVnNVZvMHlYp7XlQiN+1npCZj1DuSmaA2hYVUUDgxFDg==", | ||
293 | "requires": { | ||
294 | "inherits": "~2.0.3" | ||
295 | } | ||
296 | }, | ||
297 | "readable-stream": { | ||
298 | "version": "2.3.7", | ||
299 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", | ||
300 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", | ||
301 | "requires": { | ||
302 | "core-util-is": "~1.0.0", | ||
303 | "inherits": "~2.0.3", | ||
304 | "isarray": "~1.0.0", | ||
305 | "process-nextick-args": "~2.0.0", | ||
306 | "safe-buffer": "~5.1.1", | ||
307 | "string_decoder": "~1.1.1", | ||
308 | "util-deprecate": "~1.0.1" | ||
309 | }, | ||
310 | "dependencies": { | ||
311 | "safe-buffer": { | ||
312 | "version": "5.1.2", | ||
313 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", | ||
314 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" | ||
315 | } | ||
316 | } | ||
317 | }, | ||
318 | "safe-buffer": { | ||
319 | "version": "5.2.0", | ||
320 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", | ||
321 | "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" | ||
322 | }, | ||
323 | "semver": { | ||
324 | "version": "6.3.0", | ||
325 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", | ||
326 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" | ||
327 | }, | ||
328 | "string_decoder": { | ||
329 | "version": "1.1.1", | ||
330 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", | ||
331 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", | ||
332 | "requires": { | ||
333 | "safe-buffer": "~5.1.0" | ||
334 | }, | ||
335 | "dependencies": { | ||
336 | "safe-buffer": { | ||
337 | "version": "5.1.2", | ||
338 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", | ||
339 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" | ||
340 | } | ||
341 | } | ||
342 | }, | ||
343 | "tar-fs": { | ||
344 | "version": "1.16.3", | ||
345 | "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", | ||
346 | "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", | ||
347 | "requires": { | ||
348 | "chownr": "^1.0.1", | ||
349 | "mkdirp": "^0.5.1", | ||
350 | "pump": "^1.0.0", | ||
351 | "tar-stream": "^1.1.2" | ||
352 | } | ||
353 | }, | ||
354 | "tar-stream": { | ||
355 | "version": "1.6.2", | ||
356 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", | ||
357 | "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", | ||
358 | "requires": { | ||
359 | "bl": "^1.0.0", | ||
360 | "buffer-alloc": "^1.2.0", | ||
361 | "end-of-stream": "^1.0.0", | ||
362 | "fs-constants": "^1.0.0", | ||
363 | "readable-stream": "^2.3.0", | ||
364 | "to-buffer": "^1.1.1", | ||
365 | "xtend": "^4.0.0" | ||
366 | } | ||
367 | }, | ||
368 | "targz": { | ||
369 | "version": "1.0.1", | ||
370 | "resolved": "https://registry.npmjs.org/targz/-/targz-1.0.1.tgz", | ||
371 | "integrity": "sha1-j3alI2lM3t+7XWCkB2/27uzFOY8=", | ||
372 | "requires": { | ||
373 | "tar-fs": "^1.8.1" | ||
374 | } | ||
375 | }, | ||
376 | "to-buffer": { | ||
377 | "version": "1.1.1", | ||
378 | "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", | ||
379 | "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" | ||
380 | }, | ||
381 | "universalify": { | ||
382 | "version": "0.1.2", | ||
383 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", | ||
384 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" | ||
385 | }, | ||
386 | "util-deprecate": { | ||
387 | "version": "1.0.2", | ||
388 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", | ||
389 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" | ||
390 | }, | ||
391 | "wrappy": { | ||
392 | "version": "1.0.2", | ||
393 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", | ||
394 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" | ||
395 | }, | ||
396 | "xtend": { | ||
397 | "version": "4.0.2", | ||
398 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", | ||
399 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" | ||
400 | } | ||
401 | } | ||
402 | } | ||
diff --git a/scripts/package.js b/scripts/package.js index d650121..82dfc81 100644 --- a/scripts/package.js +++ b/scripts/package.js | |||
@@ -1,8 +1,177 @@ | |||
1 | /** | 1 | /** |
2 | * Package recipe into tar.gz file | 2 | * Package all recipes |
3 | */ | 3 | */ |
4 | require('./api/require-depts')(); | 4 | const targz = require('targz'); |
5 | const fs = require('fs-extra'); | ||
6 | const path = require('path'); | ||
7 | const sizeOf = require('image-size'); | ||
5 | 8 | ||
6 | const packageRecipe = require('./api/package'); | 9 | // Publicly availible link to this repository's recipe folder |
10 | // Used for generating public icon URLs | ||
11 | const repo = 'https://cdn.jsdelivr.net/gh/getferdi/recipes/recipes/'; | ||
7 | 12 | ||
8 | packageRecipe(); \ No newline at end of file | 13 | // Helper: Compress src folder into dest file |
14 | const compress = (src, dest) => new Promise((resolve, reject) => { | ||
15 | targz.compress({ | ||
16 | src, | ||
17 | dest, | ||
18 | tar: { | ||
19 | // Don't package .DS_Store files | ||
20 | ignore: function(name) { | ||
21 | return path.basename(name) === '.DS_Store' | ||
22 | } | ||
23 | }, | ||
24 | }, (err) => { | ||
25 | if (err) { | ||
26 | reject(err); | ||
27 | } else { | ||
28 | resolve(dest); | ||
29 | } | ||
30 | }); | ||
31 | }); | ||
32 | |||
33 | // Let us work in an async environment | ||
34 | (async () => { | ||
35 | // Create paths to important files | ||
36 | const recipesFolder = path.join(__dirname, '../recipes'); | ||
37 | const outputFolder = path.join(__dirname, '../archives'); | ||
38 | const allJson = path.join(__dirname, '../all.json'); | ||
39 | const featuredFile = path.join(__dirname, '../featured.json'); | ||
40 | const featuredRecipes = await fs.readJSON(featuredFile); | ||
41 | let recipeList = []; | ||
42 | let unsuccessful = 0; | ||
43 | |||
44 | await fs.ensureDir(outputFolder); | ||
45 | await fs.emptyDir(outputFolder); | ||
46 | await fs.remove(allJson); | ||
47 | |||
48 | const availableRecipes = fs.readdirSync(recipesFolder, { withFileTypes: true }) | ||
49 | .filter(dir => dir.isDirectory()) | ||
50 | .map(dir => dir.name); | ||
51 | |||
52 | for(let recipe of availableRecipes) { | ||
53 | const recipeSrc = path.join(recipesFolder, recipe); | ||
54 | const packageJson = path.join(recipeSrc, 'package.json'); | ||
55 | const svgIcon = path.join(recipeSrc, 'icon.svg'); | ||
56 | const pngIcon = path.join(recipeSrc, 'icon.png'); | ||
57 | |||
58 | // Check that package.json exists | ||
59 | if (!await fs.pathExists(packageJson)) { | ||
60 | console.log(`⚠️ Couldn't package "${recipe}": Folder doesn't contain a "package.json".`); | ||
61 | unsuccessful++; | ||
62 | continue; | ||
63 | } | ||
64 | |||
65 | // Check that icons exist | ||
66 | const hasSvg = await fs.pathExists(svgIcon); | ||
67 | const hasPng = await fs.pathExists(pngIcon); | ||
68 | if (!hasSvg && !hasPng) { | ||
69 | console.log(`⚠️ Couldn't package "${recipe}": Recipe doesn't contain an icon SVG and PNG`); | ||
70 | unsuccessful++; | ||
71 | } else if (!hasSvg) { | ||
72 | console.log(`⚠️ Couldn't package "${recipe}": Recipe doesn't contain an icon SVG`); | ||
73 | unsuccessful++; | ||
74 | continue; | ||
75 | } else if (!hasPng) { | ||
76 | console.log(`⚠️ Couldn't package "${recipe}": Recipe doesn't contain an icon PNG`); | ||
77 | unsuccessful++; | ||
78 | continue; | ||
79 | } | ||
80 | |||
81 | // Check icons sizes | ||
82 | const svgSize = sizeOf(svgIcon); | ||
83 | const svgHasRightSize = svgSize.width === svgSize.height; | ||
84 | if (!svgHasRightSize) { | ||
85 | console.log(`⚠️ Couldn't package "${recipe}": Recipe SVG icon isn't a square`); | ||
86 | unsuccessful++; | ||
87 | continue; | ||
88 | } | ||
89 | |||
90 | const pngSize = sizeOf(pngIcon); | ||
91 | const pngHasRightSize = pngSize.width === 1024 && pngSize.height === 1024; | ||
92 | if (!pngHasRightSize) { | ||
93 | console.log(`⚠️ Couldn't package "${recipe}": Recipe PNG icon dimensions should be 1024x1024`); | ||
94 | unsuccessful++; | ||
95 | continue; | ||
96 | } | ||
97 | |||
98 | // Read package.json | ||
99 | const config = await fs.readJson(packageJson) | ||
100 | |||
101 | // Make sure it contains all required fields | ||
102 | if (!config) { | ||
103 | console.log(`⚠️ Couldn't package "${recipe}": Could not read or parse "package.json"`); | ||
104 | unsuccessful++; | ||
105 | continue; | ||
106 | } | ||
107 | let configErrors = []; | ||
108 | if (!config.id) { | ||
109 | configErrors.push("The recipe's package.json contains no 'id' field. This field should contain a unique ID made of lowercase letters (a-z), numbers (0-9), hyphens (-), periods (.), and underscores (_)"); | ||
110 | } else if (!/^[a-zA-Z0-9._\-]+$/.test(config.id)) { | ||
111 | configErrors.push("The recipe's package.json defines an invalid recipe ID. Please make sure the 'id' field only contains lowercase letters (a-z), numbers (0-9), hyphens (-), periods (.), and underscores (_)"); | ||
112 | } | ||
113 | if (!config.name) { | ||
114 | configErrors.push("The recipe's package.json contains no 'name' field. This field should contain the name of the service (e.g. 'Google Keep')"); | ||
115 | } | ||
116 | if (!config.version) { | ||
117 | configErrors.push("The recipe's package.json contains no 'version' field. This field should contain the a semver-compatible version number for your recipe (e.g. '1.0.0')"); | ||
118 | } | ||
119 | if (!config.config || typeof config.config !== "object") { | ||
120 | configErrors.push("The recipe's package.json contains no 'config' object. This field should contain a configuration for your service."); | ||
121 | } | ||
122 | |||
123 | if (configErrors.length > 0) { | ||
124 | console.log(`⚠️ Couldn't package "${recipe}": There were errors in the recipe's package.json: | ||
125 | ${configErrors.reduce((str, err) => `${str}\n${err}`)}`); | ||
126 | unsuccessful++; | ||
127 | continue; | ||
128 | } | ||
129 | |||
130 | if (!await fs.exists(path.join(recipeSrc, 'webview.js'))) { | ||
131 | console.log(`⚠️ Couldn't package "${recipe}": The recipe doesn't contain a "webview.js"`); | ||
132 | unsuccessful++; | ||
133 | continue; | ||
134 | } | ||
135 | if (!await fs.exists(path.join(recipeSrc, 'index.js'))) { | ||
136 | console.log(`⚠️ Couldn't package "${recipe}": The recipe doesn't contain a "index.js"`); | ||
137 | unsuccessful++; | ||
138 | continue; | ||
139 | } | ||
140 | |||
141 | // Package to .tar.gz | ||
142 | compress(recipeSrc, path.join(outputFolder, `${config.id}.tar.gz`)); | ||
143 | |||
144 | // Add recipe to all.json | ||
145 | const isFeatured = featuredRecipes.includes(config.id); | ||
146 | const packageInfo = { | ||
147 | "author": config.author || '', | ||
148 | "featured": isFeatured, | ||
149 | "id": config.id, | ||
150 | "name": config.name, | ||
151 | "version": config.version || '1.0.0', | ||
152 | "icons": { | ||
153 | "png": `${repo}${config.id}/icon.png`, | ||
154 | "svg": `${repo}${config.id}/icon.svg`, | ||
155 | }, | ||
156 | }; | ||
157 | recipeList.push(packageInfo); | ||
158 | } | ||
159 | |||
160 | |||
161 | // Sort package list alphabetically | ||
162 | recipeList = recipeList.sort((a, b) => { | ||
163 | var textA = a.id.toLowerCase(); | ||
164 | var textB = b.id.toLowerCase(); | ||
165 | return (textA < textB) ? -1 : (textA > textB) ? 1 : 0; | ||
166 | }); | ||
167 | await fs.writeJson(allJson, recipeList, { | ||
168 | spaces: 2, | ||
169 | EOL: '\n', | ||
170 | }); | ||
171 | |||
172 | console.log(`✅ Successfully packaged and added ${recipeList.length} recipes (${unsuccessful} unsuccessful recipes)`); | ||
173 | |||
174 | if (unsuccessful > 0) { | ||
175 | process.exit(1); | ||
176 | } | ||
177 | })(); | ||
diff --git a/scripts/package.json b/scripts/package.json deleted file mode 100644 index 1402e52..0000000 --- a/scripts/package.json +++ /dev/null | |||
@@ -1,29 +0,0 @@ | |||
1 | { | ||
2 | "name": "ferdi-recipes-scripts", | ||
3 | "version": "1.0.0", | ||
4 | "description": "Scripts for managing the ferdi-recipes repository", | ||
5 | "main": "index.js", | ||
6 | "repository": "https://github.com/getferdi/recipes", | ||
7 | "author": "The Ferdi Team", | ||
8 | "license": "MIT", | ||
9 | "dependencies": { | ||
10 | "dir-compare": "^1.7.3", | ||
11 | "fs-extra": "^8.1.0", | ||
12 | "git-url-parse": "^11.1.2", | ||
13 | "image-size": "^0.8.3", | ||
14 | "node-fetch": "^2.6.0", | ||
15 | "open": "^7.0.3", | ||
16 | "semver": "^6.3.0", | ||
17 | "targz": "^1.0.1" | ||
18 | }, | ||
19 | "scripts": { | ||
20 | "package": "node package.js", | ||
21 | "verify": "node verify.js", | ||
22 | "verify-all": "node verify-all.js", | ||
23 | "update": "node update.js", | ||
24 | "github": "node add_github.js", | ||
25 | "gh-load": "node gh_load.js", | ||
26 | "load": "node load.js", | ||
27 | "create": "node create.js" | ||
28 | } | ||
29 | } | ||
diff --git a/scripts/update.js b/scripts/update.js deleted file mode 100644 index 7538019..0000000 --- a/scripts/update.js +++ /dev/null | |||
@@ -1,125 +0,0 @@ | |||
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('../archives', `${recipe.id}.tar.gz`); | ||
65 | const uncompressed = path.join('../uncompressed', recipe.id); | ||
66 | |||
67 | // Download recipe to filesystem | ||
68 | try { | ||
69 | console.log("Downloading " + server + '/recipes/download/' + recipe.id); | ||
70 | await downloadFile( | ||
71 | server + '/recipes/download/' + recipe.id, | ||
72 | compressed | ||
73 | ); | ||
74 | } catch(e) { | ||
75 | console.log(`Could not download ${recipe.id}`); | ||
76 | return; | ||
77 | } | ||
78 | |||
79 | // Extract recipe | ||
80 | await decompress(compressed, uncompressed) | ||
81 | |||
82 | // Make sure we have all icons | ||
83 | const iconPng = path.join(uncompressed, '/icon.png'); | ||
84 | const iconSvg = path.join(uncompressed, '/icon.svg'); | ||
85 | if (!await fs.exists(iconPng)) { | ||
86 | downloadFile(recipe.icons.png, iconPng); | ||
87 | } | ||
88 | if (!await fs.exists(iconSvg)) { | ||
89 | downloadFile(recipe.icons.svg, iconSvg); | ||
90 | } | ||
91 | |||
92 | // Update entry in all.json | ||
93 | // Check if package ID already exists | ||
94 | const recipeIndex = localRecipes.findIndex(e => e.id === recipe.id); | ||
95 | |||
96 | const recipeInfo = recipe; | ||
97 | recipeInfo.icons.png = recipeInfo.icons.png.replace( | ||
98 | 'https://cdn.franzinfra.com/recipes/dist/', | ||
99 | 'https://cdn.jsdelivr.net/gh/getferdi/recipes/uncompressed/' | ||
100 | ).replace( | ||
101 | 'src/icon.png', | ||
102 | 'icon.png' | ||
103 | ); | ||
104 | recipeInfo.icons.svg = recipeInfo.icons.svg.replace( | ||
105 | 'https://cdn.franzinfra.com/recipes/dist/', | ||
106 | 'https://cdn.jsdelivr.net/gh/getferdi/recipes/uncompressed/' | ||
107 | ).replace( | ||
108 | 'src/icon.svg', | ||
109 | 'icon.svg' | ||
110 | ); | ||
111 | |||
112 | if (recipeIndex !== -1) { | ||
113 | localRecipes[recipeIndex] = recipeInfo; | ||
114 | } else { | ||
115 | localRecipes.push(recipeInfo); | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | |||
120 | // Write updated package info to all.json | ||
121 | await fs.writeJson(allJson, localRecipes, { | ||
122 | spaces: 2, | ||
123 | EOL: '\n', | ||
124 | }); | ||
125 | })(); \ No newline at end of file | ||
diff --git a/scripts/verify-all.js b/scripts/verify-all.js deleted file mode 100644 index f8702b3..0000000 --- a/scripts/verify-all.js +++ /dev/null | |||
@@ -1,97 +0,0 @@ | |||
1 | /** | ||
2 | * Verify all archived recipes to match uncompressed recipes | ||
3 | */ | ||
4 | const targz = require('targz'); | ||
5 | const fs = require('fs-extra'); | ||
6 | const dircompare = require('dir-compare'); | ||
7 | const path = require('path'); | ||
8 | |||
9 | // Helper: Compress src folder into dest file | ||
10 | const decompress = (src, dest) => new Promise((resolve, reject) => { | ||
11 | targz.decompress({ | ||
12 | src, | ||
13 | dest, | ||
14 | tar: { | ||
15 | // Don't unpackage .DS_Store files | ||
16 | ignore: function(name) { | ||
17 | return path.basename(name) === '.DS_Store' | ||
18 | } | ||
19 | }, | ||
20 | }, (err) => { | ||
21 | if (err) { | ||
22 | reject(err); | ||
23 | } else { | ||
24 | resolve(dest); | ||
25 | } | ||
26 | }); | ||
27 | }); | ||
28 | |||
29 | // Let Promise errors crash the script | ||
30 | process.on('unhandledRejection', (error) => { | ||
31 | console.log('Promise rejection:', error); | ||
32 | process.exit(1); | ||
33 | }); | ||
34 | |||
35 | // Let us work in an async environment | ||
36 | (async () => { | ||
37 | // Read list of all recipes | ||
38 | const allJsonPath = path.join(__dirname, '../', 'all.json'); | ||
39 | const all = await fs.readJSON(allJsonPath); | ||
40 | |||
41 | const tempUncompressed = path.join(__dirname, `uncompressed/`); | ||
42 | |||
43 | for (const recipeInfo of all) { | ||
44 | try { | ||
45 | // Get recipe infos | ||
46 | const recipe = recipeInfo.id; | ||
47 | const recipeNum = all.findIndex(e => e === recipeInfo); | ||
48 | const compressedRecipe = path.join(__dirname, '../', 'archives', `${recipe}.tar.gz`); | ||
49 | const uncompressedRecipe = path.join(__dirname, '../', 'uncompressed', recipe); | ||
50 | |||
51 | // Check that recipe exists | ||
52 | if (!await fs.pathExists(compressedRecipe) || !await fs.pathExists(uncompressedRecipe)) { | ||
53 | console.log(`Error: Recipe "${recipe}" exists in all.json but not found.`); | ||
54 | process.exit(1); | ||
55 | } | ||
56 | |||
57 | // Clear temporary extraction folder | ||
58 | if (await fs.pathExists(tempUncompressed)) { | ||
59 | await fs.remove(tempUncompressed); | ||
60 | } | ||
61 | await fs.mkdir(tempUncompressed); | ||
62 | |||
63 | // Package to uncompressed recipe to .tar.gz | ||
64 | await decompress(compressedRecipe, tempUncompressed); | ||
65 | |||
66 | // Compare directories | ||
67 | const compare = await dircompare.compare(uncompressedRecipe, tempUncompressed, { | ||
68 | compareContent: true, | ||
69 | // Don't fail because of DS_Store files | ||
70 | excludeFilter: '.DS_Store', | ||
71 | }); | ||
72 | |||
73 | if (compare.same) { | ||
74 | console.log(`✓ ${recipe} is valid (${recipeNum + 1} of ${all.length})`); | ||
75 | } else { | ||
76 | console.log(`❌ Compressed and uncompressed files for "${recipe}" are NOT equal:`); | ||
77 | |||
78 | // Output information about differences | ||
79 | for (const file of compare.diffSet) { | ||
80 | if (file.state !== 'equal') { | ||
81 | console.log(`- "${file.name1 || file.name2}" is not equal (${file.type1} in uncompressed, ${file.type2} in archive)`); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | process.exit(1); | ||
86 | } | ||
87 | |||
88 | // Remove temporary compressed file | ||
89 | await fs.remove(tempUncompressed); | ||
90 | } catch(e) { | ||
91 | console.log('Error while verifying recipe:', e); | ||
92 | process.exit(1); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | console.log('All recipes are valid.'); | ||
97 | })(); | ||
diff --git a/scripts/verify.js b/scripts/verify.js deleted file mode 100644 index e2124e6..0000000 --- a/scripts/verify.js +++ /dev/null | |||
@@ -1,70 +0,0 @@ | |||
1 | /** | ||
2 | * Verify packaged recipe to match uncompressed recipe | ||
3 | */ | ||
4 | const targz = require('targz'); | ||
5 | const fs = require('fs-extra'); | ||
6 | const dircompare = require('dir-compare'); | ||
7 | const path = require('path'); | ||
8 | |||
9 | // Helper: Compress src folder into dest file | ||
10 | const decompress = (src, dest) => new Promise((resolve, reject) => { | ||
11 | targz.decompress({ | ||
12 | src, | ||
13 | dest, | ||
14 | tar: { | ||
15 | // Don't unpackage .DS_Store files | ||
16 | ignore: function(name) { | ||
17 | return path.basename(name) === '.DS_Store' | ||
18 | } | ||
19 | }, | ||
20 | }, (err) => { | ||
21 | if (err) { | ||
22 | reject(err); | ||
23 | } else { | ||
24 | resolve(dest); | ||
25 | } | ||
26 | }); | ||
27 | }); | ||
28 | |||
29 | if (!process.argv[2]) { | ||
30 | console.log('Usage: yarn verify <recipe>'); | ||
31 | return; | ||
32 | } | ||
33 | |||
34 | // Let us work in an async environment | ||
35 | (async () => { | ||
36 | const recipe = process.argv[2]; | ||
37 | |||
38 | const compressedRecipe = path.join(__dirname, '../', 'archives', `${recipe}.tar.gz`); | ||
39 | const uncompressedRecipe = path.join(__dirname, '../', 'uncompressed', recipe); | ||
40 | const tempUncompressed = path.join(__dirname, `uncompressed/`); | ||
41 | |||
42 | // Check that recipe exists | ||
43 | if (!await fs.pathExists(compressedRecipe) || !await fs.pathExists(uncompressedRecipe)) { | ||
44 | console.log(`Error: Recipe does not exist.`); | ||
45 | return; | ||
46 | } | ||
47 | |||
48 | if (await fs.pathExists(tempUncompressed)) { | ||
49 | await fs.remove(tempUncompressed); | ||
50 | } | ||
51 | await fs.mkdir(tempUncompressed); | ||
52 | |||
53 | // Package to uncompressed recipe to .tar.gz | ||
54 | console.log(`Decompressing...`); | ||
55 | await decompress(compressedRecipe, tempUncompressed); | ||
56 | |||
57 | // Compare directories | ||
58 | const compare = dircompare.compareSync(uncompressedRecipe, tempUncompressed, { | ||
59 | compareContent: true, | ||
60 | }); | ||
61 | |||
62 | if (compare.same) { | ||
63 | console.log('✓ Compressed and uncompressed files are equal'); | ||
64 | } else { | ||
65 | console.log('❌ Compressed and uncompressed files are NOT equal'); | ||
66 | } | ||
67 | |||
68 | // Remove temporary compressed file | ||
69 | await fs.remove(tempUncompressed); | ||
70 | })(); \ No newline at end of file | ||