mysql-memory-server 1.8.1 → 1.9.0
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/README.md +9 -49
- package/dist/src/cli.js +22 -17
- package/dist/src/constants.d.ts +80 -3
- package/dist/src/constants.js +100 -38
- package/dist/src/index.js +2 -57
- package/dist/src/libraries/Downloader.d.ts +0 -1
- package/dist/src/libraries/Downloader.js +132 -84
- package/dist/src/libraries/Executor.d.ts +2 -0
- package/dist/src/libraries/Executor.js +108 -88
- package/dist/src/libraries/FileLock.js +2 -2
- package/dist/src/libraries/LinuxOSRelease.d.ts +3 -0
- package/dist/src/libraries/LinuxOSRelease.js +18 -0
- package/dist/src/libraries/Version.d.ts +2 -5
- package/dist/src/libraries/Version.js +87 -22
- package/dist/types/index.d.ts +14 -18
- package/package.json +8 -8
|
@@ -36,7 +36,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.downloadVersions = downloadVersions;
|
|
40
39
|
exports.downloadBinary = downloadBinary;
|
|
41
40
|
const https = __importStar(require("https"));
|
|
42
41
|
const fs = __importStar(require("fs"));
|
|
@@ -46,18 +45,7 @@ const path_1 = require("path");
|
|
|
46
45
|
const crypto_1 = require("crypto");
|
|
47
46
|
const child_process_1 = require("child_process");
|
|
48
47
|
const FileLock_1 = require("./FileLock");
|
|
49
|
-
|
|
50
|
-
return new Promise((resolve, reject) => {
|
|
51
|
-
entry.getDataAsync((data, err) => {
|
|
52
|
-
if (err) {
|
|
53
|
-
reject(err);
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
resolve(data);
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
}
|
|
48
|
+
const constants_1 = require("../constants");
|
|
61
49
|
function handleTarExtraction(filepath, extractedPath) {
|
|
62
50
|
return new Promise((resolve, reject) => {
|
|
63
51
|
(0, child_process_1.execFile)(`tar`, ['-xf', filepath, '-C', extractedPath], (error, stdout, stderr) => {
|
|
@@ -68,21 +56,6 @@ function handleTarExtraction(filepath, extractedPath) {
|
|
|
68
56
|
});
|
|
69
57
|
});
|
|
70
58
|
}
|
|
71
|
-
function downloadVersions() {
|
|
72
|
-
return new Promise((resolve, reject) => {
|
|
73
|
-
let json = "";
|
|
74
|
-
https.get("https://github.com/Sebastian-Webster/mysql-memory-server-nodejs/raw/main/versions.json", function (response) {
|
|
75
|
-
response
|
|
76
|
-
.on("data", append => json += append)
|
|
77
|
-
.on("error", e => {
|
|
78
|
-
reject(e);
|
|
79
|
-
})
|
|
80
|
-
.on("end", () => {
|
|
81
|
-
resolve(json);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
59
|
function downloadFromCDN(url, downloadLocation, logger) {
|
|
87
60
|
return new Promise(async (resolve, reject) => {
|
|
88
61
|
if (fs.existsSync(downloadLocation)) {
|
|
@@ -94,15 +67,15 @@ function downloadFromCDN(url, downloadLocation, logger) {
|
|
|
94
67
|
fileStream.on('open', () => {
|
|
95
68
|
const request = https.get(url, (response) => {
|
|
96
69
|
if (response.statusCode !== 200) {
|
|
70
|
+
request.destroy();
|
|
97
71
|
fileStream.close((err) => {
|
|
98
72
|
if (err) {
|
|
99
73
|
logger.error('An error occurred while closing the fileStream for non-200 status code. The error was:', err);
|
|
100
74
|
}
|
|
101
|
-
fs.
|
|
102
|
-
if (
|
|
103
|
-
logger.error('An error occurred while deleting downloadLocation after non-200 status code download attempt. The error was:',
|
|
75
|
+
fs.rm(downloadLocation, { force: true }, (rmError) => {
|
|
76
|
+
if (rmError) {
|
|
77
|
+
logger.error('An error occurred while deleting downloadLocation after non-200 status code download attempt. The error was:', rmError);
|
|
104
78
|
}
|
|
105
|
-
logger.error('Received status code:', response.statusCode, 'while downloading MySQL binary.');
|
|
106
79
|
reject(`Received status code ${response.statusCode} while downloading MySQL binary.`);
|
|
107
80
|
});
|
|
108
81
|
});
|
|
@@ -110,39 +83,62 @@ function downloadFromCDN(url, downloadLocation, logger) {
|
|
|
110
83
|
else {
|
|
111
84
|
response.pipe(fileStream);
|
|
112
85
|
fileStream.on('finish', () => {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
86
|
+
request.end(() => {
|
|
87
|
+
if (!error) {
|
|
88
|
+
resolve();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
116
91
|
});
|
|
117
92
|
}
|
|
118
93
|
});
|
|
119
94
|
request.on('error', (err) => {
|
|
120
95
|
error = err;
|
|
121
96
|
logger.error(err);
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
97
|
+
request.destroy();
|
|
98
|
+
fileStream.close((fsErr) => {
|
|
99
|
+
if (fsErr) {
|
|
100
|
+
logger.error('An error occurred while closing the fileStream on request error. The error was:', fsErr);
|
|
101
|
+
}
|
|
102
|
+
fs.rm(downloadLocation, { force: true }, (rmError) => {
|
|
103
|
+
if (rmError) {
|
|
104
|
+
logger.error('An error occurred while deleting downloadLocation after an error occurred with the MySQL server binary download. The error was:', rmError);
|
|
126
105
|
}
|
|
127
106
|
reject(err.message);
|
|
128
107
|
});
|
|
129
108
|
});
|
|
130
109
|
});
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
logger.error('An error occurred while deleting downloadLocation after an error occurred with the fileStream. The error was:', unlinkError);
|
|
110
|
+
fileStream.on('error', (err) => {
|
|
111
|
+
error = err;
|
|
112
|
+
logger.error(err);
|
|
113
|
+
request.destroy();
|
|
114
|
+
fileStream.close((fsErr) => {
|
|
115
|
+
if (fsErr) {
|
|
116
|
+
logger.error('An error occurred while closing the fileStream on fileStream error. The error was:', fsErr);
|
|
139
117
|
}
|
|
140
|
-
|
|
118
|
+
fs.rm(downloadLocation, { force: true }, (rmError) => {
|
|
119
|
+
if (rmError) {
|
|
120
|
+
logger.error('An error occurred while deleting downloadLocation after an error occurred with the fileStream. The error was:', rmError);
|
|
121
|
+
}
|
|
122
|
+
reject(err.message);
|
|
123
|
+
});
|
|
141
124
|
});
|
|
142
125
|
});
|
|
143
126
|
});
|
|
144
127
|
});
|
|
145
128
|
}
|
|
129
|
+
function promisifiedZipExtraction(archiveLocation, extractedLocation) {
|
|
130
|
+
return new Promise((resolve, reject) => {
|
|
131
|
+
const zip = new adm_zip_1.default(archiveLocation);
|
|
132
|
+
zip.extractAllToAsync(extractedLocation, false, false, (err) => {
|
|
133
|
+
if (err) {
|
|
134
|
+
reject(err);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
resolve();
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}
|
|
146
142
|
function extractBinary(url, archiveLocation, extractedLocation, logger) {
|
|
147
143
|
return new Promise(async (resolve, reject) => {
|
|
148
144
|
if (fs.existsSync(extractedLocation)) {
|
|
@@ -157,58 +153,70 @@ function extractBinary(url, archiveLocation, extractedLocation, logger) {
|
|
|
157
153
|
return reject(`Folder name is undefined for url: ${url}`);
|
|
158
154
|
}
|
|
159
155
|
const folderName = mySQLFolderName.replace(`.${fileExtension}`, '');
|
|
156
|
+
let extractionError = undefined;
|
|
160
157
|
if (fileExtension === 'zip') {
|
|
161
158
|
//Only Windows MySQL files use the .zip extension
|
|
162
|
-
const zip = new adm_zip_1.default(archiveLocation);
|
|
163
|
-
const entries = zip.getEntries();
|
|
164
|
-
for (const entry of entries) {
|
|
165
|
-
if (entry.entryName.indexOf('..') === -1) {
|
|
166
|
-
if (entry.isDirectory) {
|
|
167
|
-
if (entry.name === folderName) {
|
|
168
|
-
await fsPromises.mkdir(`${extractedLocation}/mysql`, { recursive: true });
|
|
169
|
-
}
|
|
170
|
-
else {
|
|
171
|
-
await fsPromises.mkdir(`${extractedLocation}/${entry.entryName}`, { recursive: true });
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
const data = await getZipData(entry);
|
|
176
|
-
await fsPromises.writeFile(`${extractedLocation}/${entry.entryName}`, data);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
159
|
try {
|
|
181
|
-
await
|
|
160
|
+
await promisifiedZipExtraction(archiveLocation, extractedLocation);
|
|
182
161
|
}
|
|
183
162
|
catch (e) {
|
|
184
|
-
|
|
163
|
+
extractionError = e;
|
|
164
|
+
logger.log('An error occurred while extracting the ZIP file. The error was:', e);
|
|
185
165
|
}
|
|
186
166
|
finally {
|
|
167
|
+
try {
|
|
168
|
+
await fsPromises.rm(archiveLocation);
|
|
169
|
+
}
|
|
170
|
+
catch (e) {
|
|
171
|
+
logger.error('A non-fatal error occurred while deleting archive location. The error was:', e);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (extractionError) {
|
|
175
|
+
return reject(extractionError);
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
187
178
|
await fsPromises.rename(`${extractedLocation}/${folderName}`, `${extractedLocation}/mysql`);
|
|
188
|
-
return resolve((0, path_1.normalize)(`${extractedLocation}/mysql/bin/mysqld.exe`));
|
|
189
179
|
}
|
|
180
|
+
catch (e) {
|
|
181
|
+
logger.error('An error occurred while moving MySQL binary into correct folder (mysql folder). The error was:', e);
|
|
182
|
+
return reject(e);
|
|
183
|
+
}
|
|
184
|
+
resolve((0, path_1.normalize)(`${extractedLocation}/mysql/bin/mysqld.exe`));
|
|
190
185
|
}
|
|
191
|
-
|
|
186
|
+
else {
|
|
192
187
|
try {
|
|
193
|
-
await
|
|
188
|
+
await handleTarExtraction(archiveLocation, extractedLocation);
|
|
194
189
|
}
|
|
195
190
|
catch (e) {
|
|
196
|
-
|
|
191
|
+
extractionError = e;
|
|
192
|
+
logger.error('An error occurred while extracting the tar file. Please make sure tar is installed and there is enough storage space for the extraction. The error was:', e);
|
|
197
193
|
}
|
|
198
194
|
finally {
|
|
195
|
+
try {
|
|
196
|
+
await fsPromises.rm(archiveLocation);
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
logger.error('A non-fatal error occurred while deleting archive location. The error was:', e);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (extractionError) {
|
|
203
|
+
return reject(extractionError);
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
199
206
|
await fsPromises.rename(`${extractedLocation}/${folderName}`, `${extractedLocation}/mysql`);
|
|
200
|
-
resolve(`${extractedLocation}/mysql/bin/mysqld`);
|
|
201
207
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
208
|
+
catch (e) {
|
|
209
|
+
logger.error('An error occurred while moving MySQL binary into correct folder (mysql folder). The error was:', e);
|
|
210
|
+
return reject(e);
|
|
211
|
+
}
|
|
212
|
+
resolve(`${extractedLocation}/mysql/bin/mysqld`);
|
|
213
|
+
}
|
|
206
214
|
});
|
|
207
215
|
}
|
|
208
216
|
function downloadBinary(binaryInfo, options, logger) {
|
|
209
217
|
return new Promise(async (resolve, reject) => {
|
|
210
218
|
const { url, version } = binaryInfo;
|
|
211
|
-
const dirpath =
|
|
219
|
+
const dirpath = (0, constants_1.getInternalEnvVariable)('binaryDirectoryPath');
|
|
212
220
|
logger.log('Binary path:', dirpath);
|
|
213
221
|
await fsPromises.mkdir(dirpath, { recursive: true });
|
|
214
222
|
const lastDashIndex = url.lastIndexOf('-');
|
|
@@ -244,11 +252,16 @@ function downloadBinary(binaryInfo, options, logger) {
|
|
|
244
252
|
}
|
|
245
253
|
//The code below only runs if the lock has been acquired by us
|
|
246
254
|
let downloadTries = 0;
|
|
255
|
+
let useDownloadsURL = false;
|
|
247
256
|
do {
|
|
248
257
|
try {
|
|
249
258
|
downloadTries++;
|
|
250
|
-
|
|
251
|
-
|
|
259
|
+
const downloadURL = useDownloadsURL ? url.replace(constants_1.archiveBaseURL, constants_1.downloadsBaseURL) : url;
|
|
260
|
+
logger.log(`Starting download for MySQL version ${version} from ${downloadURL}.`);
|
|
261
|
+
await downloadFromCDN(downloadURL, archivePath, logger);
|
|
262
|
+
logger.log(`Finished downloading MySQL version ${version} from ${downloadURL}. Now starting binary extraction.`);
|
|
263
|
+
await extractBinary(downloadURL, archivePath, extractedPath, logger);
|
|
264
|
+
logger.log(`Finished extraction for version ${version}`);
|
|
252
265
|
break;
|
|
253
266
|
}
|
|
254
267
|
catch (e) {
|
|
@@ -262,6 +275,24 @@ function downloadBinary(binaryInfo, options, logger) {
|
|
|
262
275
|
catch (e) {
|
|
263
276
|
logger.error('An error occurred while deleting extractedPath and/or archivePath:', e);
|
|
264
277
|
}
|
|
278
|
+
if (e?.includes?.('status code 404')) {
|
|
279
|
+
if (!useDownloadsURL) {
|
|
280
|
+
//Retry with downloads URL
|
|
281
|
+
downloadTries--;
|
|
282
|
+
useDownloadsURL = true;
|
|
283
|
+
logger.log(`Encountered error 404 when using archives URL for version ${version}. Now retrying with the downloads URL.`);
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
try {
|
|
288
|
+
await releaseFunction();
|
|
289
|
+
}
|
|
290
|
+
catch (e) {
|
|
291
|
+
logger.error('An error occurred while releasing lock after receiving a 404 error on both downloads and archives URLs. The error was:', e);
|
|
292
|
+
}
|
|
293
|
+
return reject(`Both URLs for MySQL version ${binaryInfo.version} returned status code 404. Aborting download.`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
265
296
|
if (downloadTries > options.downloadRetries) {
|
|
266
297
|
//Only reject if we have met the downloadRetries limit
|
|
267
298
|
try {
|
|
@@ -274,12 +305,12 @@ function downloadBinary(binaryInfo, options, logger) {
|
|
|
274
305
|
return reject(e);
|
|
275
306
|
}
|
|
276
307
|
else {
|
|
277
|
-
|
|
308
|
+
logger.warn(`An error was encountered during the binary download process. Retrying for retry ${downloadTries}/${options.downloadRetries}. The error was:`, e);
|
|
278
309
|
}
|
|
279
310
|
}
|
|
280
311
|
} while (downloadTries <= options.downloadRetries);
|
|
281
312
|
try {
|
|
282
|
-
releaseFunction();
|
|
313
|
+
await releaseFunction();
|
|
283
314
|
}
|
|
284
315
|
catch (e) {
|
|
285
316
|
logger.error('An error occurred while releasing lock after successful binary download. The error was:', e);
|
|
@@ -288,6 +319,7 @@ function downloadBinary(binaryInfo, options, logger) {
|
|
|
288
319
|
}
|
|
289
320
|
else {
|
|
290
321
|
let downloadTries = 0;
|
|
322
|
+
let useDownloadsURL = false;
|
|
291
323
|
do {
|
|
292
324
|
const uuid = (0, crypto_1.randomUUID)();
|
|
293
325
|
const zipFilepath = `${dirpath}/${uuid}.${fileExtension}`;
|
|
@@ -295,8 +327,12 @@ function downloadBinary(binaryInfo, options, logger) {
|
|
|
295
327
|
const extractedPath = `${dirpath}/${uuid}`;
|
|
296
328
|
try {
|
|
297
329
|
downloadTries++;
|
|
298
|
-
|
|
299
|
-
|
|
330
|
+
const downloadURL = useDownloadsURL ? url.replace(constants_1.archiveBaseURL, constants_1.downloadsBaseURL) : url;
|
|
331
|
+
logger.log(`Starting download for MySQL version ${version} from ${downloadURL}.`);
|
|
332
|
+
await downloadFromCDN(downloadURL, zipFilepath, logger);
|
|
333
|
+
logger.log(`Finished downloading MySQL version ${version} from ${downloadURL}. Now starting binary extraction.`);
|
|
334
|
+
const binaryPath = await extractBinary(downloadURL, zipFilepath, extractedPath, logger);
|
|
335
|
+
logger.log(`Finished extraction for version ${version}`);
|
|
300
336
|
return resolve(binaryPath);
|
|
301
337
|
}
|
|
302
338
|
catch (e) {
|
|
@@ -310,6 +346,18 @@ function downloadBinary(binaryInfo, options, logger) {
|
|
|
310
346
|
catch (e) {
|
|
311
347
|
logger.error('An error occurred while deleting extractedPath and/or archivePath:', e);
|
|
312
348
|
}
|
|
349
|
+
if (e?.includes?.('status code 404')) {
|
|
350
|
+
if (!useDownloadsURL) {
|
|
351
|
+
//Retry with downloads URL
|
|
352
|
+
downloadTries--;
|
|
353
|
+
useDownloadsURL = true;
|
|
354
|
+
logger.log(`Encountered error 404 when using archives URL for version ${version}. Now retrying with the downloads URL.`);
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
return reject(`Both URLs for MySQL version ${binaryInfo.version} returned status code 404. Aborting download.`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
313
361
|
if (downloadTries > options.downloadRetries) {
|
|
314
362
|
//Only reject if we have met the downloadRetries limit
|
|
315
363
|
return reject(e);
|
|
@@ -7,6 +7,8 @@ declare class Executor {
|
|
|
7
7
|
removeExitHandler: () => void;
|
|
8
8
|
version: string;
|
|
9
9
|
versionInstalledOnSystem: boolean;
|
|
10
|
+
databasePath: string;
|
|
11
|
+
killedFromPortIssue: boolean;
|
|
10
12
|
constructor(logger: Logger);
|
|
11
13
|
getMySQLVersion(preferredVersion?: string): Promise<DownloadedMySQLVersion | null>;
|
|
12
14
|
startMySQL(options: InternalServerOptions, installedMySQLBinary: DownloadedMySQLVersion): Promise<MySQLDB>;
|