mysql-memory-server 1.8.2 → 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 -20
- package/dist/src/constants.d.ts +73 -3
- package/dist/src/constants.js +89 -12
- package/dist/src/index.js +2 -52
- package/dist/src/libraries/Downloader.d.ts +0 -1
- package/dist/src/libraries/Downloader.js +130 -83
- package/dist/src/libraries/Executor.d.ts +2 -0
- package/dist/src/libraries/Executor.js +103 -84
- 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 -10
- package/package.json +5 -5
|
@@ -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"));
|
|
@@ -47,18 +46,6 @@ const crypto_1 = require("crypto");
|
|
|
47
46
|
const child_process_1 = require("child_process");
|
|
48
47
|
const FileLock_1 = require("./FileLock");
|
|
49
48
|
const constants_1 = require("../constants");
|
|
50
|
-
function getZipData(entry) {
|
|
51
|
-
return new Promise((resolve, reject) => {
|
|
52
|
-
entry.getDataAsync((data, err) => {
|
|
53
|
-
if (err) {
|
|
54
|
-
reject(err);
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
resolve(data);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
49
|
function handleTarExtraction(filepath, extractedPath) {
|
|
63
50
|
return new Promise((resolve, reject) => {
|
|
64
51
|
(0, child_process_1.execFile)(`tar`, ['-xf', filepath, '-C', extractedPath], (error, stdout, stderr) => {
|
|
@@ -69,21 +56,6 @@ function handleTarExtraction(filepath, extractedPath) {
|
|
|
69
56
|
});
|
|
70
57
|
});
|
|
71
58
|
}
|
|
72
|
-
function downloadVersions() {
|
|
73
|
-
return new Promise((resolve, reject) => {
|
|
74
|
-
let json = "";
|
|
75
|
-
https.get("https://github.com/Sebastian-Webster/mysql-memory-server-nodejs/raw/main/versions.json", function (response) {
|
|
76
|
-
response
|
|
77
|
-
.on("data", append => json += append)
|
|
78
|
-
.on("error", e => {
|
|
79
|
-
reject(e);
|
|
80
|
-
})
|
|
81
|
-
.on("end", () => {
|
|
82
|
-
resolve(json);
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
59
|
function downloadFromCDN(url, downloadLocation, logger) {
|
|
88
60
|
return new Promise(async (resolve, reject) => {
|
|
89
61
|
if (fs.existsSync(downloadLocation)) {
|
|
@@ -95,15 +67,15 @@ function downloadFromCDN(url, downloadLocation, logger) {
|
|
|
95
67
|
fileStream.on('open', () => {
|
|
96
68
|
const request = https.get(url, (response) => {
|
|
97
69
|
if (response.statusCode !== 200) {
|
|
70
|
+
request.destroy();
|
|
98
71
|
fileStream.close((err) => {
|
|
99
72
|
if (err) {
|
|
100
73
|
logger.error('An error occurred while closing the fileStream for non-200 status code. The error was:', err);
|
|
101
74
|
}
|
|
102
|
-
fs.
|
|
103
|
-
if (
|
|
104
|
-
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);
|
|
105
78
|
}
|
|
106
|
-
logger.error('Received status code:', response.statusCode, 'while downloading MySQL binary.');
|
|
107
79
|
reject(`Received status code ${response.statusCode} while downloading MySQL binary.`);
|
|
108
80
|
});
|
|
109
81
|
});
|
|
@@ -111,39 +83,62 @@ function downloadFromCDN(url, downloadLocation, logger) {
|
|
|
111
83
|
else {
|
|
112
84
|
response.pipe(fileStream);
|
|
113
85
|
fileStream.on('finish', () => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
86
|
+
request.end(() => {
|
|
87
|
+
if (!error) {
|
|
88
|
+
resolve();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
117
91
|
});
|
|
118
92
|
}
|
|
119
93
|
});
|
|
120
94
|
request.on('error', (err) => {
|
|
121
95
|
error = err;
|
|
122
96
|
logger.error(err);
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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);
|
|
127
105
|
}
|
|
128
106
|
reject(err.message);
|
|
129
107
|
});
|
|
130
108
|
});
|
|
131
109
|
});
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
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);
|
|
140
117
|
}
|
|
141
|
-
|
|
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
|
+
});
|
|
142
124
|
});
|
|
143
125
|
});
|
|
144
126
|
});
|
|
145
127
|
});
|
|
146
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
|
+
}
|
|
147
142
|
function extractBinary(url, archiveLocation, extractedLocation, logger) {
|
|
148
143
|
return new Promise(async (resolve, reject) => {
|
|
149
144
|
if (fs.existsSync(extractedLocation)) {
|
|
@@ -158,52 +153,64 @@ function extractBinary(url, archiveLocation, extractedLocation, logger) {
|
|
|
158
153
|
return reject(`Folder name is undefined for url: ${url}`);
|
|
159
154
|
}
|
|
160
155
|
const folderName = mySQLFolderName.replace(`.${fileExtension}`, '');
|
|
156
|
+
let extractionError = undefined;
|
|
161
157
|
if (fileExtension === 'zip') {
|
|
162
158
|
//Only Windows MySQL files use the .zip extension
|
|
163
|
-
const zip = new adm_zip_1.default(archiveLocation);
|
|
164
|
-
const entries = zip.getEntries();
|
|
165
|
-
for (const entry of entries) {
|
|
166
|
-
if (entry.entryName.indexOf('..') === -1) {
|
|
167
|
-
if (entry.isDirectory) {
|
|
168
|
-
if (entry.name === folderName) {
|
|
169
|
-
await fsPromises.mkdir(`${extractedLocation}/mysql`, { recursive: true });
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
await fsPromises.mkdir(`${extractedLocation}/${entry.entryName}`, { recursive: true });
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
const data = await getZipData(entry);
|
|
177
|
-
await fsPromises.writeFile(`${extractedLocation}/${entry.entryName}`, data);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
159
|
try {
|
|
182
|
-
await
|
|
160
|
+
await promisifiedZipExtraction(archiveLocation, extractedLocation);
|
|
183
161
|
}
|
|
184
162
|
catch (e) {
|
|
185
|
-
|
|
163
|
+
extractionError = e;
|
|
164
|
+
logger.log('An error occurred while extracting the ZIP file. The error was:', e);
|
|
186
165
|
}
|
|
187
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 {
|
|
188
178
|
await fsPromises.rename(`${extractedLocation}/${folderName}`, `${extractedLocation}/mysql`);
|
|
189
|
-
return resolve((0, path_1.normalize)(`${extractedLocation}/mysql/bin/mysqld.exe`));
|
|
190
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`));
|
|
191
185
|
}
|
|
192
|
-
|
|
186
|
+
else {
|
|
193
187
|
try {
|
|
194
|
-
await
|
|
188
|
+
await handleTarExtraction(archiveLocation, extractedLocation);
|
|
195
189
|
}
|
|
196
190
|
catch (e) {
|
|
197
|
-
|
|
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);
|
|
198
193
|
}
|
|
199
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 {
|
|
200
206
|
await fsPromises.rename(`${extractedLocation}/${folderName}`, `${extractedLocation}/mysql`);
|
|
201
|
-
resolve(`${extractedLocation}/mysql/bin/mysqld`);
|
|
202
207
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
+
}
|
|
207
214
|
});
|
|
208
215
|
}
|
|
209
216
|
function downloadBinary(binaryInfo, options, logger) {
|
|
@@ -245,11 +252,16 @@ function downloadBinary(binaryInfo, options, logger) {
|
|
|
245
252
|
}
|
|
246
253
|
//The code below only runs if the lock has been acquired by us
|
|
247
254
|
let downloadTries = 0;
|
|
255
|
+
let useDownloadsURL = false;
|
|
248
256
|
do {
|
|
249
257
|
try {
|
|
250
258
|
downloadTries++;
|
|
251
|
-
|
|
252
|
-
|
|
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}`);
|
|
253
265
|
break;
|
|
254
266
|
}
|
|
255
267
|
catch (e) {
|
|
@@ -263,6 +275,24 @@ function downloadBinary(binaryInfo, options, logger) {
|
|
|
263
275
|
catch (e) {
|
|
264
276
|
logger.error('An error occurred while deleting extractedPath and/or archivePath:', e);
|
|
265
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
|
+
}
|
|
266
296
|
if (downloadTries > options.downloadRetries) {
|
|
267
297
|
//Only reject if we have met the downloadRetries limit
|
|
268
298
|
try {
|
|
@@ -275,12 +305,12 @@ function downloadBinary(binaryInfo, options, logger) {
|
|
|
275
305
|
return reject(e);
|
|
276
306
|
}
|
|
277
307
|
else {
|
|
278
|
-
|
|
308
|
+
logger.warn(`An error was encountered during the binary download process. Retrying for retry ${downloadTries}/${options.downloadRetries}. The error was:`, e);
|
|
279
309
|
}
|
|
280
310
|
}
|
|
281
311
|
} while (downloadTries <= options.downloadRetries);
|
|
282
312
|
try {
|
|
283
|
-
releaseFunction();
|
|
313
|
+
await releaseFunction();
|
|
284
314
|
}
|
|
285
315
|
catch (e) {
|
|
286
316
|
logger.error('An error occurred while releasing lock after successful binary download. The error was:', e);
|
|
@@ -289,6 +319,7 @@ function downloadBinary(binaryInfo, options, logger) {
|
|
|
289
319
|
}
|
|
290
320
|
else {
|
|
291
321
|
let downloadTries = 0;
|
|
322
|
+
let useDownloadsURL = false;
|
|
292
323
|
do {
|
|
293
324
|
const uuid = (0, crypto_1.randomUUID)();
|
|
294
325
|
const zipFilepath = `${dirpath}/${uuid}.${fileExtension}`;
|
|
@@ -296,8 +327,12 @@ function downloadBinary(binaryInfo, options, logger) {
|
|
|
296
327
|
const extractedPath = `${dirpath}/${uuid}`;
|
|
297
328
|
try {
|
|
298
329
|
downloadTries++;
|
|
299
|
-
|
|
300
|
-
|
|
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}`);
|
|
301
336
|
return resolve(binaryPath);
|
|
302
337
|
}
|
|
303
338
|
catch (e) {
|
|
@@ -311,6 +346,18 @@ function downloadBinary(binaryInfo, options, logger) {
|
|
|
311
346
|
catch (e) {
|
|
312
347
|
logger.error('An error occurred while deleting extractedPath and/or archivePath:', e);
|
|
313
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
|
+
}
|
|
314
361
|
if (downloadTries > options.downloadRetries) {
|
|
315
362
|
//Only reject if we have met the downloadRetries limit
|
|
316
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>;
|