@saltcorn/plugins-loader 0.9.5-beta.3 → 0.9.5-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/download_utils.js +4 -2
- package/package.json +1 -5
- package/plugin_installer.js +73 -79
package/download_utils.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
|
-
const {
|
|
2
|
+
const { rm } = require("fs").promises;
|
|
3
|
+
const { mkdir, pathExists } = require("fs-extra");
|
|
3
4
|
const { tmpName } = require("tmp-promise");
|
|
4
5
|
const { execSync } = require("child_process");
|
|
5
6
|
const { extract } = require("tar");
|
|
@@ -27,13 +28,14 @@ const downloadFromNpm = async (plugin, pluginDir, pckJson) => {
|
|
|
27
28
|
const vToInstall =
|
|
28
29
|
plugin.version && plugin.version !== "latest" ? plugin.version : latest;
|
|
29
30
|
|
|
30
|
-
if (pckJson && pckJson.version === vToInstall) return
|
|
31
|
+
if (pckJson && pckJson.version === vToInstall) return false;
|
|
31
32
|
else {
|
|
32
33
|
const tarballUrl = pkgInfo.versions[vToInstall].dist.tarball;
|
|
33
34
|
const fileName = plugin.name.split("/").pop();
|
|
34
35
|
const filePath = await loadTarball(tarballUrl, fileName);
|
|
35
36
|
await mkdir(pluginDir, { recursive: true });
|
|
36
37
|
await extractTarball(filePath, pluginDir);
|
|
38
|
+
return true;
|
|
37
39
|
}
|
|
38
40
|
};
|
|
39
41
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/plugins-loader",
|
|
3
|
-
"version": "0.9.5-beta.
|
|
3
|
+
"version": "0.9.5-beta.5",
|
|
4
4
|
"description": "Saltcorn plugin loader",
|
|
5
5
|
"homepage": "https://saltcorn.com",
|
|
6
6
|
"scripts": {
|
|
@@ -11,10 +11,6 @@
|
|
|
11
11
|
"author": "Christian Hugo",
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"main": "index.js",
|
|
14
|
-
"dependencies": {
|
|
15
|
-
"semver": "^7.6.0",
|
|
16
|
-
"resolve-global": "^1.0.0"
|
|
17
|
-
},
|
|
18
14
|
"repository": "github:saltcorn/saltcorn",
|
|
19
15
|
"publishConfig": {
|
|
20
16
|
"access": "public"
|
package/plugin_installer.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { join, normalize, dirname } = require("path");
|
|
2
|
-
const { writeFile, mkdir,
|
|
2
|
+
const { writeFile, mkdir, pathExists, copy, symlink } = require("fs-extra");
|
|
3
3
|
const { spawn } = require("child_process");
|
|
4
4
|
const {
|
|
5
5
|
downloadFromNpm,
|
|
@@ -8,11 +8,8 @@ const {
|
|
|
8
8
|
tarballExists,
|
|
9
9
|
removeTarball,
|
|
10
10
|
} = require("./download_utils");
|
|
11
|
-
const
|
|
12
|
-
const fs = require("fs");
|
|
13
|
-
const resolveGlobal = require("resolve-global");
|
|
11
|
+
const { rm, rename, cp, readFile } = require("fs").promises;
|
|
14
12
|
|
|
15
|
-
const rootFolder = process.cwd();
|
|
16
13
|
const staticDeps = ["@saltcorn/markup", "@saltcorn/data", "jest"];
|
|
17
14
|
const fixedPlugins = ["@saltcorn/base-plugin", "@saltcorn/sbadmin2"];
|
|
18
15
|
|
|
@@ -21,74 +18,85 @@ const isGitCheckout = async () => {
|
|
|
21
18
|
return await pathExists(gitPath);
|
|
22
19
|
};
|
|
23
20
|
|
|
21
|
+
const readPackageJson = async (filePath) => {
|
|
22
|
+
if (await pathExists(filePath)) return JSON.parse(await readFile(filePath));
|
|
23
|
+
else return null;
|
|
24
|
+
};
|
|
25
|
+
|
|
24
26
|
class PluginInstaller {
|
|
25
|
-
constructor(plugin) {
|
|
27
|
+
constructor(plugin, opts = {}) {
|
|
26
28
|
this.plugin = plugin;
|
|
27
|
-
this.
|
|
28
|
-
this.
|
|
29
|
+
this.rootFolder = opts.rootFolder || process.cwd();
|
|
30
|
+
this.tempRootFolder = opts.tempRootFolder || process.cwd();
|
|
29
31
|
const tokens =
|
|
30
32
|
plugin.source === "npm"
|
|
31
33
|
? plugin.location.split("/")
|
|
32
34
|
: plugin.name.split("/");
|
|
35
|
+
this.name = tokens[tokens.length - 1];
|
|
33
36
|
this.pluginDir = join(
|
|
34
|
-
rootFolder,
|
|
37
|
+
this.rootFolder,
|
|
35
38
|
plugin.source === "git" ? "git_plugins" : "plugins_folder",
|
|
36
39
|
...tokens
|
|
37
40
|
);
|
|
38
41
|
this.pckJsonPath = join(this.pluginDir, "package.json");
|
|
39
|
-
this.
|
|
42
|
+
this.tempDir = join(this.tempRootFolder, "temp_install", ...tokens);
|
|
43
|
+
this.tempPckJsonPath = join(this.tempDir, "package.json");
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
async install(force) {
|
|
43
47
|
await this.ensurePluginsRootFolders();
|
|
44
48
|
if (fixedPlugins.includes(this.plugin.location))
|
|
45
49
|
return { plugin_module: require(this.plugin.location) };
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
|
|
51
|
+
let pckJSON = await readPackageJson(this.pckJsonPath);
|
|
52
|
+
if (await this.prepPluginsFolder(force, pckJSON)) {
|
|
53
|
+
const tmpPckJSON = await this.removeDependencies(
|
|
54
|
+
await readPackageJson(this.tempPckJsonPath)
|
|
55
|
+
);
|
|
56
|
+
await this.npmInstall(tmpPckJSON);
|
|
57
|
+
await this.movePlugin();
|
|
51
58
|
if (await tarballExists(this.plugin)) await removeTarball(this.plugin);
|
|
52
59
|
}
|
|
60
|
+
pckJSON = await readPackageJson(this.pckJsonPath);
|
|
53
61
|
return {
|
|
54
|
-
version:
|
|
55
|
-
plugin_module: await this.loadMainFile(),
|
|
62
|
+
version: pckJSON.version,
|
|
63
|
+
plugin_module: await this.loadMainFile(pckJSON),
|
|
56
64
|
location: this.pluginDir,
|
|
57
65
|
name: this.name,
|
|
58
66
|
};
|
|
59
67
|
}
|
|
60
68
|
|
|
61
|
-
async
|
|
69
|
+
async remove() {
|
|
70
|
+
if (await pathExists(this.pluginDir))
|
|
71
|
+
await rm(this.pluginDir, { recursive: true });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async prepPluginsFolder(force, pckJSON) {
|
|
62
75
|
let wasLoaded = false;
|
|
63
76
|
switch (this.plugin.source) {
|
|
64
77
|
case "npm":
|
|
65
78
|
if (
|
|
66
|
-
(force && !(await this.versionIsInstalled())) ||
|
|
79
|
+
(force && !(await this.versionIsInstalled(pckJSON))) ||
|
|
67
80
|
!(await pathExists(this.pluginDir))
|
|
68
81
|
) {
|
|
69
|
-
|
|
70
|
-
this.plugin,
|
|
71
|
-
this.pluginDir,
|
|
72
|
-
this.pckJson
|
|
73
|
-
);
|
|
74
|
-
wasLoaded = true;
|
|
82
|
+
wasLoaded = await downloadFromNpm(this.plugin, this.tempDir, pckJSON);
|
|
75
83
|
}
|
|
76
84
|
break;
|
|
77
85
|
case "github":
|
|
78
86
|
if (force || !(await pathExists(this.pluginDir))) {
|
|
79
|
-
|
|
87
|
+
await downloadFromGithub(this.plugin, this.tempDir);
|
|
80
88
|
wasLoaded = true;
|
|
81
89
|
}
|
|
82
90
|
break;
|
|
83
91
|
case "local":
|
|
84
92
|
if (force || !(await pathExists(this.pluginDir))) {
|
|
85
|
-
await copy(this.plugin.location, this.
|
|
93
|
+
await copy(this.plugin.location, this.tempDir);
|
|
86
94
|
wasLoaded = true;
|
|
87
95
|
}
|
|
88
96
|
break;
|
|
89
97
|
case "git":
|
|
90
98
|
if (force || !(await pathExists(this.pluginDir))) {
|
|
91
|
-
await gitPullOrClone(this.plugin, this.
|
|
99
|
+
await gitPullOrClone(this.plugin, this.tempDir);
|
|
92
100
|
this.pckJsonPath = join(this.pluginDir, "package.json");
|
|
93
101
|
wasLoaded = true;
|
|
94
102
|
}
|
|
@@ -98,15 +106,16 @@ class PluginInstaller {
|
|
|
98
106
|
}
|
|
99
107
|
|
|
100
108
|
async ensurePluginsRootFolders() {
|
|
109
|
+
const isWindows = process.platform === "win32";
|
|
101
110
|
const ensureFn = async (folder) => {
|
|
102
|
-
const pluginsFolder = join(rootFolder, folder);
|
|
111
|
+
const pluginsFolder = join(this.rootFolder, folder);
|
|
103
112
|
if (!(await pathExists(pluginsFolder))) await mkdir(pluginsFolder);
|
|
104
113
|
const symLinkDst = join(pluginsFolder, "node_modules");
|
|
105
114
|
const symLinkSrc = (await isGitCheckout())
|
|
106
115
|
? join(__dirname, "..", "..", "node_modules")
|
|
107
|
-
: join(dirname(
|
|
116
|
+
: join(dirname(require.resolve("@saltcorn/cli")), "..", "node_modules");
|
|
108
117
|
if (!(await pathExists(symLinkDst)))
|
|
109
|
-
await symlink(symLinkSrc, symLinkDst, "dir");
|
|
118
|
+
await symlink(symLinkSrc, symLinkDst, !isWindows ? "dir" : "junction");
|
|
110
119
|
};
|
|
111
120
|
for (const folder of ["plugins_folder", "git_plugins"])
|
|
112
121
|
await ensureFn(folder);
|
|
@@ -116,77 +125,61 @@ class PluginInstaller {
|
|
|
116
125
|
return !!this.plugin.version && this.plugin.version !== "latest";
|
|
117
126
|
}
|
|
118
127
|
|
|
119
|
-
async versionIsInstalled() {
|
|
120
|
-
if (!
|
|
128
|
+
async versionIsInstalled(pckJSON) {
|
|
129
|
+
if (!pckJSON || !this.isFixedVersion()) return false;
|
|
121
130
|
else {
|
|
122
|
-
const vInstalled =
|
|
131
|
+
const vInstalled = pckJSON.version;
|
|
123
132
|
if (vInstalled === this.plugin.version) return true;
|
|
124
133
|
else return false;
|
|
125
134
|
}
|
|
126
135
|
}
|
|
127
136
|
|
|
128
|
-
async
|
|
129
|
-
if (await pathExists(this.pluginDir))
|
|
130
|
-
await rm(this.pluginDir, { recursive: true });
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
async loadMainFile() {
|
|
137
|
+
async loadMainFile(pckJSON) {
|
|
134
138
|
const isWindows = process.platform === "win32";
|
|
135
139
|
if (process.env.NODE_ENV === "test") {
|
|
136
140
|
// in jest, downgrad to require
|
|
137
|
-
return require(normalize(join(this.pluginDir,
|
|
141
|
+
return require(normalize(join(this.pluginDir, pckJSON.main)));
|
|
138
142
|
} else {
|
|
139
143
|
const res = await import(
|
|
140
144
|
`${isWindows ? `file://` : ""}${normalize(
|
|
141
|
-
join(this.pluginDir,
|
|
145
|
+
join(this.pluginDir, pckJSON.main)
|
|
142
146
|
)}`
|
|
143
147
|
);
|
|
144
148
|
return res.default;
|
|
145
149
|
}
|
|
146
150
|
}
|
|
147
151
|
|
|
148
|
-
async removeDependencies() {
|
|
149
|
-
const
|
|
150
|
-
const oldDepsLength = Object.keys(
|
|
151
|
-
const oldDevDepsLength = Object.keys(
|
|
152
|
-
|
|
153
|
-
const satisfiedRemover = (deps) => {
|
|
154
|
-
for (const [name, version] of Object.entries(deps)) {
|
|
155
|
-
try {
|
|
156
|
-
const vInstalled = require(`${name}/package.json`).version;
|
|
157
|
-
if (semver.satisfies(vInstalled, version)) {
|
|
158
|
-
delete deps[name];
|
|
159
|
-
}
|
|
160
|
-
} catch (e) {} // continue, npm installs it
|
|
161
|
-
}
|
|
162
|
-
};
|
|
152
|
+
async removeDependencies(tmpPckJSON) {
|
|
153
|
+
const pckJSON = { ...tmpPckJSON };
|
|
154
|
+
const oldDepsLength = Object.keys(pckJSON.dependencies || {}).length;
|
|
155
|
+
const oldDevDepsLength = Object.keys(pckJSON.devDependencies || {}).length;
|
|
163
156
|
const staticsRemover = (deps) => {
|
|
164
157
|
for (const staticDep of staticDeps) {
|
|
165
158
|
if (deps[staticDep]) delete deps[staticDep];
|
|
166
159
|
}
|
|
167
160
|
};
|
|
168
|
-
if (
|
|
169
|
-
|
|
170
|
-
staticsRemover(pckJson.dependencies);
|
|
171
|
-
}
|
|
172
|
-
if (pckJson.devDependencies) {
|
|
173
|
-
satisfiedRemover(pckJson.devDependencies);
|
|
174
|
-
staticsRemover(pckJson.devDependencies);
|
|
175
|
-
}
|
|
161
|
+
if (pckJSON.dependencies) staticsRemover(pckJSON.dependencies);
|
|
162
|
+
if (pckJSON.devDependencies) staticsRemover(pckJSON.devDependencies);
|
|
176
163
|
if (
|
|
177
|
-
Object.keys(
|
|
178
|
-
Object.keys(
|
|
164
|
+
Object.keys(pckJSON.dependencies || {}).length !== oldDepsLength ||
|
|
165
|
+
Object.keys(pckJSON.devDependencies || {}).length !== oldDevDepsLength
|
|
179
166
|
)
|
|
180
|
-
await writeFile(
|
|
167
|
+
await writeFile(
|
|
168
|
+
join(this.tempDir, "package.json"),
|
|
169
|
+
JSON.stringify(pckJSON, null, 2)
|
|
170
|
+
);
|
|
171
|
+
return pckJSON;
|
|
181
172
|
}
|
|
182
173
|
|
|
183
|
-
async npmInstall() {
|
|
174
|
+
async npmInstall(pckJSON) {
|
|
175
|
+
const isWindows = process.platform === "win32";
|
|
184
176
|
if (
|
|
185
|
-
Object.keys(
|
|
186
|
-
Object.keys(
|
|
177
|
+
Object.keys(pckJSON.dependencies || {}).length > 0 ||
|
|
178
|
+
Object.keys(pckJSON.devDependencies || {}).length > 0
|
|
187
179
|
) {
|
|
188
180
|
const child = spawn("npm", ["install"], {
|
|
189
|
-
cwd: this.
|
|
181
|
+
cwd: this.tempDir,
|
|
182
|
+
...(isWindows ? { shell: true } : {}),
|
|
190
183
|
});
|
|
191
184
|
return new Promise((resolve, reject) => {
|
|
192
185
|
child.on("exit", (exitCode, signal) => {
|
|
@@ -200,13 +193,14 @@ class PluginInstaller {
|
|
|
200
193
|
}
|
|
201
194
|
}
|
|
202
195
|
|
|
203
|
-
async
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
196
|
+
async movePlugin() {
|
|
197
|
+
const isWindows = process.platform === "win32";
|
|
198
|
+
if (await pathExists(this.pluginDir))
|
|
199
|
+
await rm(this.pluginDir, { recursive: true });
|
|
200
|
+
await mkdir(this.pluginDir, { recursive: true });
|
|
201
|
+
if (!isWindows) await rename(this.tempDir, this.pluginDir);
|
|
202
|
+
else
|
|
203
|
+
await cp(this.tempDir, this.pluginDir, { recursive: true, force: true });
|
|
210
204
|
}
|
|
211
205
|
}
|
|
212
206
|
|