@automattic/vip 3.7.1 → 3.8.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/assets/dev-env.lando.template.yml.ejs +7 -0
- package/dist/bin/vip-config-envvar-delete.js +11 -0
- package/dist/bin/vip-config-envvar-set.js +11 -0
- package/dist/bin/vip-dev-env-import-sql.js +9 -1
- package/dist/bin/vip-import-sql.js +2 -2
- package/dist/commands/dev-env-import-sql.js +18 -8
- package/dist/commands/dev-env-sync-sql.js +32 -13
- package/dist/lib/database.js +107 -0
- package/dist/lib/dev-environment/dev-environment-database.js +20 -0
- package/dist/lib/media-import/status.js +4 -23
- package/dist/lib/promise.js +21 -0
- package/dist/lib/search-and-replace.js +15 -4
- package/dist/lib/types.js +1 -0
- package/dist/lib/validations/sql.js +2 -2
- package/docs/CHANGELOG.md +18 -0
- package/npm-shrinkwrap.json +350 -325
- package/package.json +4 -4
|
@@ -271,6 +271,13 @@ tooling:
|
|
|
271
271
|
cmd:
|
|
272
272
|
- wp
|
|
273
273
|
|
|
274
|
+
db-myloader:
|
|
275
|
+
service: php
|
|
276
|
+
description: "Run mydumper's myloader to import database dumps generated by mydumper"
|
|
277
|
+
user: root
|
|
278
|
+
cmd:
|
|
279
|
+
- myloader -h database -u wordpress -p wordpress --database wordpress
|
|
280
|
+
|
|
274
281
|
db:
|
|
275
282
|
service: php
|
|
276
283
|
description: "Connect to the DB using mysql client (e.g. allow to run imports)"
|
|
@@ -5,6 +5,7 @@ exports.__esModule = true;
|
|
|
5
5
|
exports.deleteEnvVarCommand = deleteEnvVarCommand;
|
|
6
6
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
7
7
|
var _command = _interopRequireDefault(require("../lib/cli/command"));
|
|
8
|
+
var _format = require("../lib/cli/format");
|
|
8
9
|
var _api = require("../lib/envvar/api");
|
|
9
10
|
var _input = require("../lib/envvar/input");
|
|
10
11
|
var _logging = require("../lib/envvar/logging");
|
|
@@ -35,6 +36,16 @@ async function deleteEnvVarCommand(arg, opt) {
|
|
|
35
36
|
skip_confirm: Boolean(opt.skipConfirmation),
|
|
36
37
|
variable_name: name
|
|
37
38
|
};
|
|
39
|
+
const envName = opt.env.type;
|
|
40
|
+
const appName = opt.app.name;
|
|
41
|
+
if (!opt.skipConfirmation && envName === 'production') {
|
|
42
|
+
const yes = await (0, _input.confirm)(`Are you sure you want to delete the environment variable ${name} on ${(0, _format.formatEnvironment)(envName)} for site ${appName}?`);
|
|
43
|
+
if (!yes) {
|
|
44
|
+
(0, _tracker.trackEvent)('wpcli_confirm_cancel', trackingParams).catch(() => {});
|
|
45
|
+
console.log('Command cancelled');
|
|
46
|
+
process.exit();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
38
49
|
(0, _logging.debug)(`Request: Delete environment variable ${JSON.stringify(name)} for ${(0, _logging.getEnvContext)(opt.app, opt.env)}`);
|
|
39
50
|
await (0, _tracker.trackEvent)('envvar_delete_command_execute', trackingParams);
|
|
40
51
|
if (!(0, _api.validateNameWithMessage)(name)) {
|
|
@@ -5,6 +5,7 @@ exports.__esModule = true;
|
|
|
5
5
|
exports.setEnvVarCommand = setEnvVarCommand;
|
|
6
6
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
7
7
|
var _command = _interopRequireDefault(require("../lib/cli/command"));
|
|
8
|
+
var _format = require("../lib/cli/format");
|
|
8
9
|
var _api = require("../lib/envvar/api");
|
|
9
10
|
var _input = require("../lib/envvar/input");
|
|
10
11
|
var _logging = require("../lib/envvar/logging");
|
|
@@ -35,6 +36,16 @@ async function setEnvVarCommand(arg, opt) {
|
|
|
35
36
|
skip_confirm: Boolean(opt.skipConfirmation),
|
|
36
37
|
variable_name: name
|
|
37
38
|
};
|
|
39
|
+
const envName = opt.env.type;
|
|
40
|
+
const appName = opt.app.name;
|
|
41
|
+
if (!opt.skipConfirmation && envName === 'production') {
|
|
42
|
+
const yes = await (0, _input.confirm)(`Are you sure you want to set the environment variable ${name} on ${(0, _format.formatEnvironment)(envName)} for site ${appName}?`);
|
|
43
|
+
if (!yes) {
|
|
44
|
+
(0, _tracker.trackEvent)('wpcli_confirm_cancel', trackingParams).catch(() => {});
|
|
45
|
+
console.log('Command cancelled');
|
|
46
|
+
process.exit();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
38
49
|
(0, _logging.debug)(`Request: Set environment variable ${JSON.stringify(name)} for ${(0, _logging.getEnvContext)(opt.app, opt.env)}`);
|
|
39
50
|
await (0, _tracker.trackEvent)('envvar_set_command_execute', trackingParams);
|
|
40
51
|
if (!(0, _api.validateNameWithMessage)(name)) {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
var _devEnvImportSql = require("../commands/dev-env-import-sql");
|
|
5
5
|
var _command = _interopRequireDefault(require("../lib/cli/command"));
|
|
6
|
+
var _database = require("../lib/database");
|
|
6
7
|
var _devEnvironmentCli = require("../lib/dev-environment/dev-environment-cli");
|
|
7
8
|
var _tracker = require("../lib/tracker");
|
|
8
9
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -30,9 +31,16 @@ const examples = [{
|
|
|
30
31
|
}).option('slug', 'A unique name for a local environment. Default is "vip-local".', undefined, _devEnvironmentCli.processSlug).option(['r', 'search-replace'], 'Search for a string in the SQL file and replace it with a new string.').option('in-place', 'Perform a search and replace operation on the local SQL file and save the results.').option('skip-validate', 'Skip file validation.').option(['k', 'skip-reindex'], 'Skip Elasticsearch reindex after import.').option('quiet', 'Skip confirmation and suppress informational messages.').examples(examples).argv(process.argv, async (unmatchedArgs, opt) => {
|
|
31
32
|
const [fileName] = unmatchedArgs;
|
|
32
33
|
const slug = await (0, _devEnvironmentCli.getEnvironmentName)(opt);
|
|
34
|
+
if (opt.searchReplace && !Array.isArray(opt.searchReplace)) {
|
|
35
|
+
opt.searchReplace = [opt.searchReplace];
|
|
36
|
+
}
|
|
33
37
|
const cmd = new _devEnvImportSql.DevEnvImportSQLCommand(fileName, opt, slug);
|
|
38
|
+
const dumpDetails = await (0, _database.getSqlDumpDetails)(fileName);
|
|
34
39
|
const trackingInfo = (0, _devEnvironmentCli.getEnvTrackingInfo)(cmd.slug);
|
|
35
|
-
const trackerFn = (0, _tracker.makeCommandTracker)('dev_env_import_sql',
|
|
40
|
+
const trackerFn = (0, _tracker.makeCommandTracker)('dev_env_import_sql', {
|
|
41
|
+
...trackingInfo,
|
|
42
|
+
sqldump_type: dumpDetails.type
|
|
43
|
+
});
|
|
36
44
|
await trackerFn('execute');
|
|
37
45
|
try {
|
|
38
46
|
await cmd.run();
|
|
@@ -46,7 +46,7 @@ const appQuery = `
|
|
|
46
46
|
dbOperationInProgress
|
|
47
47
|
importInProgress
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
wpSitesSDS {
|
|
50
50
|
nodes {
|
|
51
51
|
homeUrl
|
|
52
52
|
id
|
|
@@ -286,7 +286,7 @@ const displayPlaybook = ({
|
|
|
286
286
|
// eslint-disable-next-line no-multi-spaces
|
|
287
287
|
console.log(` multisite: ${isMultiSite.toString()}`);
|
|
288
288
|
const selectedEnvironmentObj = app?.environments?.find(env => unformattedEnvironment === env.type);
|
|
289
|
-
siteArray = selectedEnvironmentObj?.
|
|
289
|
+
siteArray = selectedEnvironmentObj?.wpSitesSDS?.nodes;
|
|
290
290
|
}
|
|
291
291
|
if (!tableNames.length) {
|
|
292
292
|
debug('Validation was skipped, no playbook information will be displayed');
|
|
@@ -4,10 +4,13 @@ exports.__esModule = true;
|
|
|
4
4
|
exports.DevEnvImportSQLCommand = void 0;
|
|
5
5
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
6
6
|
var _fs = _interopRequireDefault(require("fs"));
|
|
7
|
+
var _os = _interopRequireDefault(require("os"));
|
|
7
8
|
var exit = _interopRequireWildcard(require("../lib/cli/exit"));
|
|
8
9
|
var _clientFileUploader = require("../lib/client-file-uploader");
|
|
10
|
+
var _database = require("../lib/database");
|
|
9
11
|
var _devEnvironmentCli = require("../lib/dev-environment/dev-environment-cli");
|
|
10
12
|
var _devEnvironmentCore = require("../lib/dev-environment/dev-environment-core");
|
|
13
|
+
var _devEnvironmentDatabase = require("../lib/dev-environment/dev-environment-database");
|
|
11
14
|
var _devEnvironmentLando = require("../lib/dev-environment/dev-environment-lando");
|
|
12
15
|
var _userError = _interopRequireDefault(require("../lib/user-error"));
|
|
13
16
|
var _utils = require("../lib/utils");
|
|
@@ -25,6 +28,8 @@ class DevEnvImportSQLCommand {
|
|
|
25
28
|
const lando = await (0, _devEnvironmentLando.bootstrapLando)();
|
|
26
29
|
(0, _devEnvironmentCli.validateDependencies)(lando);
|
|
27
30
|
(0, _sql.validateImportFileExtension)(this.fileName);
|
|
31
|
+
const dumpDetails = await (0, _database.getSqlDumpDetails)(this.fileName);
|
|
32
|
+
const isMyDumper = dumpDetails.type === _database.SqlDumpType.MYDUMPER;
|
|
28
33
|
|
|
29
34
|
// Check if file is compressed and if so, extract the
|
|
30
35
|
const fileMeta = await (0, _clientFileUploader.getFileMeta)(this.fileName);
|
|
@@ -57,14 +62,14 @@ class DevEnvImportSQLCommand {
|
|
|
57
62
|
const expectedDomain = `${this.slug}.${lando.config.domain}`;
|
|
58
63
|
await (0, _sql.validate)(resolvedPath, {
|
|
59
64
|
isImport: false,
|
|
60
|
-
skipChecks: [],
|
|
65
|
+
skipChecks: isMyDumper ? ['dropTable', 'dropDB'] : [],
|
|
61
66
|
extraCheckParams: {
|
|
62
67
|
siteHomeUrlLando: expectedDomain
|
|
63
68
|
}
|
|
64
69
|
});
|
|
65
70
|
}
|
|
66
71
|
const fd = await _fs.default.promises.open(resolvedPath, 'r');
|
|
67
|
-
const importArg =
|
|
72
|
+
const importArg = this.getImportArgs(dumpDetails);
|
|
68
73
|
const origIsTTY = process.stdin.isTTY;
|
|
69
74
|
try {
|
|
70
75
|
/**
|
|
@@ -87,18 +92,23 @@ class DevEnvImportSQLCommand {
|
|
|
87
92
|
if (searchReplace?.length && !inPlace) {
|
|
88
93
|
_fs.default.unlinkSync(resolvedPath);
|
|
89
94
|
}
|
|
90
|
-
|
|
91
|
-
await (0, _devEnvironmentCore.exec)(lando, this.slug, cacheArg);
|
|
95
|
+
await (0, _devEnvironmentDatabase.flushCache)(lando, this.slug, this.options.quiet);
|
|
92
96
|
if (undefined === this.options.skipReindex || !(0, _devEnvironmentCli.processBooleanOption)(this.options.skipReindex)) {
|
|
93
97
|
try {
|
|
94
|
-
await (0,
|
|
95
|
-
await (0, _devEnvironmentCore.exec)(lando, this.slug, ['wp', 'vip-search', 'index', '--setup', '--network-wide', '--skip-confirm']);
|
|
98
|
+
await (0, _devEnvironmentDatabase.reIndexSearch)(lando, this.slug);
|
|
96
99
|
} catch {
|
|
97
100
|
// Exception means they don't have vip-search enabled.
|
|
98
101
|
}
|
|
99
102
|
}
|
|
100
|
-
|
|
101
|
-
|
|
103
|
+
await (0, _devEnvironmentDatabase.addAdminUser)(lando, this.slug);
|
|
104
|
+
}
|
|
105
|
+
getImportArgs(dumpDetails) {
|
|
106
|
+
let importArg = ['db', '--disable-auto-rehash'].concat(this.options.quiet ? '--silent' : []);
|
|
107
|
+
const threadCount = Math.max(_os.default.cpus().length - 2, 1);
|
|
108
|
+
if (dumpDetails.type === _database.SqlDumpType.MYDUMPER) {
|
|
109
|
+
importArg = ['db-myloader', '--overwrite-tables', `--source-db=${dumpDetails.sourceDb}`, `--threads=${threadCount}`, '--max-threads-for-schema-creation=10', '--max-threads-for-index-creation=10', '--skip-triggers', '--skip-post', '--innodb-optimize-keys', '--checksum=SKIP', '--metadata-refresh-interval=2000000', '--stream'].concat(this.options.quiet ? ['--verbose=0'] : ['--verbose=3']);
|
|
110
|
+
}
|
|
111
|
+
return importArg;
|
|
102
112
|
}
|
|
103
113
|
}
|
|
104
114
|
exports.DevEnvImportSQLCommand = DevEnvImportSQLCommand;
|
|
@@ -6,12 +6,14 @@ exports.DevEnvSyncSQLCommand = void 0;
|
|
|
6
6
|
var _vipSearchReplace = require("@automattic/vip-search-replace");
|
|
7
7
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
8
8
|
var _fs = _interopRequireDefault(require("fs"));
|
|
9
|
+
var _promises = require("node:stream/promises");
|
|
9
10
|
var _url = _interopRequireDefault(require("url"));
|
|
10
11
|
var _devEnvImportSql = require("./dev-env-import-sql");
|
|
11
12
|
var _exportSql = require("./export-sql");
|
|
12
13
|
var _backupStorageAvailability = require("../lib/backup-storage-availability/backup-storage-availability");
|
|
13
14
|
var exit = _interopRequireWildcard(require("../lib/cli/exit"));
|
|
14
15
|
var _clientFileUploader = require("../lib/client-file-uploader");
|
|
16
|
+
var _database = require("../lib/database");
|
|
15
17
|
var _utils = require("../lib/utils");
|
|
16
18
|
var _lineByLine = require("../lib/validations/line-by-line");
|
|
17
19
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
@@ -24,7 +26,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
24
26
|
* @return Site home url. null if not found
|
|
25
27
|
*/
|
|
26
28
|
function findSiteHomeUrl(sql) {
|
|
27
|
-
const regex = "
|
|
29
|
+
const regex = `['"](siteurl|home)['"],\\s?['"](.*?)['"]`;
|
|
28
30
|
const url = sql.match(regex)?.[2] || '';
|
|
29
31
|
return _url.default.parse(url).hostname || null;
|
|
30
32
|
}
|
|
@@ -57,7 +59,8 @@ class DevEnvSyncSQLCommand {
|
|
|
57
59
|
tmpDir;
|
|
58
60
|
siteUrls = [];
|
|
59
61
|
searchReplaceMap = {};
|
|
60
|
-
|
|
62
|
+
_track;
|
|
63
|
+
_sqlDumpType;
|
|
61
64
|
|
|
62
65
|
/**
|
|
63
66
|
* Creates a new instance of the command
|
|
@@ -73,9 +76,15 @@ class DevEnvSyncSQLCommand {
|
|
|
73
76
|
this.env = env;
|
|
74
77
|
this.slug = slug;
|
|
75
78
|
this.lando = lando;
|
|
76
|
-
this.
|
|
79
|
+
this._track = trackerFn;
|
|
77
80
|
this.tmpDir = (0, _utils.makeTempDir)();
|
|
78
81
|
}
|
|
82
|
+
track(name, eventProps) {
|
|
83
|
+
return this._track(name, {
|
|
84
|
+
...eventProps,
|
|
85
|
+
sqldump_type: this._sqlDumpType
|
|
86
|
+
});
|
|
87
|
+
}
|
|
79
88
|
get landoDomain() {
|
|
80
89
|
return `${this.slug}.${this.lando.config.domain}`;
|
|
81
90
|
}
|
|
@@ -85,6 +94,16 @@ class DevEnvSyncSQLCommand {
|
|
|
85
94
|
get gzFile() {
|
|
86
95
|
return `${this.tmpDir}/sql-export.sql.gz`;
|
|
87
96
|
}
|
|
97
|
+
getSqlDumpType() {
|
|
98
|
+
if (!this._sqlDumpType) {
|
|
99
|
+
throw new Error('SQL Dump type not initialized');
|
|
100
|
+
}
|
|
101
|
+
return this._sqlDumpType;
|
|
102
|
+
}
|
|
103
|
+
async initSqlDumpType() {
|
|
104
|
+
const dumpDetails = await (0, _database.getSqlDumpDetails)(this.sqlFile);
|
|
105
|
+
this._sqlDumpType = dumpDetails.type;
|
|
106
|
+
}
|
|
88
107
|
async confirmEnoughStorage(job) {
|
|
89
108
|
const storageAvailability = _backupStorageAvailability.BackupStorageAvailability.createFromDbCopyJob(job);
|
|
90
109
|
return await storageAvailability.validateAndPromptDiskSpaceWarningForDevEnvBackupImport();
|
|
@@ -98,7 +117,7 @@ class DevEnvSyncSQLCommand {
|
|
|
98
117
|
const exportCommand = new _exportSql.ExportSQLCommand(this.app, this.env, {
|
|
99
118
|
outputFile: this.gzFile,
|
|
100
119
|
confirmEnoughStorageHook: this.confirmEnoughStorage.bind(this)
|
|
101
|
-
}, this.track);
|
|
120
|
+
}, this.track.bind(this));
|
|
102
121
|
await exportCommand.run();
|
|
103
122
|
}
|
|
104
123
|
|
|
@@ -114,14 +133,13 @@ class DevEnvSyncSQLCommand {
|
|
|
114
133
|
const readStream = _fs.default.createReadStream(this.sqlFile);
|
|
115
134
|
const replacedStream = await (0, _vipSearchReplace.replace)(readStream, replacements);
|
|
116
135
|
const outputFile = `${this.tmpDir}/sql-export-sr.sql`;
|
|
117
|
-
replacedStream
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
});
|
|
136
|
+
const streams = [replacedStream];
|
|
137
|
+
if (this.getSqlDumpType() === _database.SqlDumpType.MYDUMPER) {
|
|
138
|
+
streams.push((0, _database.fixMyDumperTransform)());
|
|
139
|
+
}
|
|
140
|
+
streams.push(_fs.default.createWriteStream(outputFile));
|
|
141
|
+
await (0, _promises.pipeline)(streams);
|
|
142
|
+
_fs.default.renameSync(outputFile, this.sqlFile);
|
|
125
143
|
}
|
|
126
144
|
generateSearchReplaceMap() {
|
|
127
145
|
this.searchReplaceMap = {};
|
|
@@ -187,6 +205,7 @@ class DevEnvSyncSQLCommand {
|
|
|
187
205
|
try {
|
|
188
206
|
console.log(`Extracting the exported file ${this.gzFile}...`);
|
|
189
207
|
await (0, _clientFileUploader.unzipFile)(this.gzFile, this.sqlFile);
|
|
208
|
+
await this.initSqlDumpType();
|
|
190
209
|
console.log(`${_chalk.default.green('✓')} Extracted to ${this.sqlFile}`);
|
|
191
210
|
} catch (err) {
|
|
192
211
|
const error = err;
|
|
@@ -231,7 +250,6 @@ class DevEnvSyncSQLCommand {
|
|
|
231
250
|
console.log('Importing the SQL file...');
|
|
232
251
|
await this.runImport();
|
|
233
252
|
console.log(`${_chalk.default.green('✓')} SQL file imported`);
|
|
234
|
-
return true;
|
|
235
253
|
} catch (err) {
|
|
236
254
|
const error = err;
|
|
237
255
|
await this.track('error', {
|
|
@@ -241,6 +259,7 @@ class DevEnvSyncSQLCommand {
|
|
|
241
259
|
});
|
|
242
260
|
exit.withError(`Error importing SQL file: ${error.message}`);
|
|
243
261
|
}
|
|
262
|
+
return true;
|
|
244
263
|
}
|
|
245
264
|
}
|
|
246
265
|
exports.DevEnvSyncSQLCommand = DevEnvSyncSQLCommand;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.getSqlDumpDetails = exports.fixMyDumperTransform = exports.SqlDumpType = void 0;
|
|
5
|
+
var _nodeFs = _interopRequireDefault(require("node:fs"));
|
|
6
|
+
var _nodeReadline = _interopRequireDefault(require("node:readline"));
|
|
7
|
+
var _nodeStream = require("node:stream");
|
|
8
|
+
var _nodeZlib = _interopRequireDefault(require("node:zlib"));
|
|
9
|
+
var _promise = require("./promise");
|
|
10
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
let SqlDumpType = exports.SqlDumpType = /*#__PURE__*/function (SqlDumpType) {
|
|
12
|
+
SqlDumpType["MYDUMPER"] = "MYDUMPER";
|
|
13
|
+
SqlDumpType["MYSQLDUMP"] = "MYSQLDUMP";
|
|
14
|
+
return SqlDumpType;
|
|
15
|
+
}({});
|
|
16
|
+
const getSqlDumpDetails = async filePath => {
|
|
17
|
+
const isCompressed = filePath.endsWith('.gz');
|
|
18
|
+
let fileStream;
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
|
20
|
+
const fileStreamExternalPromise = (0, _promise.createExternalizedPromise)();
|
|
21
|
+
if (isCompressed) {
|
|
22
|
+
fileStream = await getSqlFileStreamFromCompressedFile(filePath);
|
|
23
|
+
} else {
|
|
24
|
+
fileStream = _nodeFs.default.createReadStream(filePath);
|
|
25
|
+
}
|
|
26
|
+
const readLine = _nodeReadline.default.createInterface({
|
|
27
|
+
input: fileStream,
|
|
28
|
+
crlfDelay: Infinity
|
|
29
|
+
});
|
|
30
|
+
let isMyDumper = false;
|
|
31
|
+
let sourceDB = '';
|
|
32
|
+
let currentLineNumber = 0;
|
|
33
|
+
for await (const line of readLine) {
|
|
34
|
+
if (line === '') {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const metadataMatch = line.match(/^-- metadata.header /);
|
|
38
|
+
const sourceDBMatch = line.match(/^-- (.*)-schema-create.sql/) ?? [];
|
|
39
|
+
const sourceDBName = sourceDBMatch[1];
|
|
40
|
+
if (metadataMatch && !isMyDumper) {
|
|
41
|
+
isMyDumper = true;
|
|
42
|
+
}
|
|
43
|
+
if (sourceDBMatch && !sourceDB) {
|
|
44
|
+
sourceDB = sourceDBName;
|
|
45
|
+
}
|
|
46
|
+
if (sourceDB && isMyDumper) {
|
|
47
|
+
// all fields found? end the search early.
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
if (currentLineNumber > 100) {
|
|
51
|
+
// we'll assume that this isn't the correct file if we still haven't found `-- metadata.header` even at the 100th line.
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
currentLineNumber++;
|
|
55
|
+
}
|
|
56
|
+
if (fileStream instanceof _nodeFs.default.ReadStream) {
|
|
57
|
+
fileStream.on('close', () => {
|
|
58
|
+
fileStreamExternalPromise.resolve();
|
|
59
|
+
});
|
|
60
|
+
} else {
|
|
61
|
+
fileStreamExternalPromise.resolve();
|
|
62
|
+
}
|
|
63
|
+
readLine.close();
|
|
64
|
+
fileStream.close();
|
|
65
|
+
await fileStreamExternalPromise.promise;
|
|
66
|
+
return {
|
|
67
|
+
type: isMyDumper ? SqlDumpType.MYDUMPER : SqlDumpType.MYSQLDUMP,
|
|
68
|
+
sourceDb: sourceDB
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
exports.getSqlDumpDetails = getSqlDumpDetails;
|
|
72
|
+
const verifyFileExists = async filePath => {
|
|
73
|
+
try {
|
|
74
|
+
await _nodeFs.default.promises.access(filePath, _nodeFs.default.constants.F_OK);
|
|
75
|
+
} catch {
|
|
76
|
+
throw new Error('File not accessible. Does file exist?');
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const getSqlFileStreamFromGz = async filePath => {
|
|
80
|
+
await verifyFileExists(filePath);
|
|
81
|
+
return _nodeFs.default.createReadStream(filePath).pipe(_nodeZlib.default.createGunzip());
|
|
82
|
+
};
|
|
83
|
+
const getSqlFileStreamFromCompressedFile = async filePath => {
|
|
84
|
+
if (filePath.endsWith('.gz')) {
|
|
85
|
+
return await getSqlFileStreamFromGz(filePath);
|
|
86
|
+
}
|
|
87
|
+
throw new Error('Not a supported compressed file');
|
|
88
|
+
};
|
|
89
|
+
const fixMyDumperTransform = () => {
|
|
90
|
+
return new _nodeStream.Transform({
|
|
91
|
+
transform(chunk, _encoding, callback) {
|
|
92
|
+
const chunkString = chunk.toString();
|
|
93
|
+
const lineEnding = chunkString.includes('\r\n') ? '\r\n' : '\n';
|
|
94
|
+
const regex = /^-- ([^ ]+) [0-9]+$/;
|
|
95
|
+
const lines = chunk.toString().split(lineEnding).map(line => {
|
|
96
|
+
const match = line.match(regex);
|
|
97
|
+
if (!match) {
|
|
98
|
+
return line;
|
|
99
|
+
}
|
|
100
|
+
const tablePart = match[1];
|
|
101
|
+
return `-- ${tablePart} -1`;
|
|
102
|
+
});
|
|
103
|
+
callback(null, lines.join(lineEnding));
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
exports.fixMyDumperTransform = fixMyDumperTransform;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.reIndexSearch = exports.flushCache = exports.addAdminUser = void 0;
|
|
5
|
+
var _devEnvironmentCore = require("./dev-environment-core");
|
|
6
|
+
const addAdminUser = async (lando, slug, quiet) => {
|
|
7
|
+
const addUserArg = ['wp', 'dev-env-add-admin', '--username=vipgo', '--password=password', '--skip-plugins', '--skip-themes'].concat(quiet ? ['--quiet'] : []);
|
|
8
|
+
await (0, _devEnvironmentCore.exec)(lando, slug, addUserArg);
|
|
9
|
+
};
|
|
10
|
+
exports.addAdminUser = addAdminUser;
|
|
11
|
+
const reIndexSearch = async (lando, slug) => {
|
|
12
|
+
await (0, _devEnvironmentCore.exec)(lando, slug, ['wp', 'cli', 'has-command', 'vip-search']);
|
|
13
|
+
await (0, _devEnvironmentCore.exec)(lando, slug, ['wp', 'vip-search', 'index', '--setup', '--network-wide', '--skip-confirm']);
|
|
14
|
+
};
|
|
15
|
+
exports.reIndexSearch = reIndexSearch;
|
|
16
|
+
const flushCache = async (lando, slug, quiet) => {
|
|
17
|
+
const cacheArg = ['wp', 'cache', 'flush', '--skip-plugins', '--skip-themes'].concat(quiet ? ['--quiet'] : []);
|
|
18
|
+
await (0, _devEnvironmentCore.exec)(lando, slug, cacheArg);
|
|
19
|
+
};
|
|
20
|
+
exports.flushCache = flushCache;
|
|
@@ -33,10 +33,6 @@ const IMPORT_MEDIA_PROGRESS_QUERY = (0, _graphqlTag.default)`
|
|
|
33
33
|
failureDetails {
|
|
34
34
|
previousStatus
|
|
35
35
|
globalErrors
|
|
36
|
-
fileErrors {
|
|
37
|
-
fileName
|
|
38
|
-
errors
|
|
39
|
-
}
|
|
40
36
|
fileErrorsUrl
|
|
41
37
|
}
|
|
42
38
|
}
|
|
@@ -269,13 +265,6 @@ Downloading errors details from ${fileErrorsUrl}
|
|
|
269
265
|
progressTracker.suffix += `${_chalk.default.yellow(`⚠️ ${errorsFound} error(s) were found. File import errors report link expired.`)}`;
|
|
270
266
|
}
|
|
271
267
|
}
|
|
272
|
-
async function printFailureDetails(fileErrors, results) {
|
|
273
|
-
progressTracker.suffix += `${_chalk.default.yellow(`⚠️ ${fileErrors.length} file import error(s) were found`)}`;
|
|
274
|
-
if ((results.filesTotal ?? 0) - (results.filesProcessed ?? 0) !== fileErrors.length) {
|
|
275
|
-
progressTracker.suffix += `. ${_chalk.default.italic.yellow('File import errors report size threshold reached.')}`;
|
|
276
|
-
}
|
|
277
|
-
await exportFailureDetails(fileErrors);
|
|
278
|
-
}
|
|
279
268
|
try {
|
|
280
269
|
const results = await getResults();
|
|
281
270
|
overallStatus = results.status ?? 'unknown';
|
|
@@ -284,18 +273,10 @@ Downloading errors details from ${fileErrorsUrl}
|
|
|
284
273
|
progressTracker.print();
|
|
285
274
|
if (results.failureDetails?.fileErrorsUrl) {
|
|
286
275
|
await promptFailureDetailsDownload(results.failureDetails.fileErrorsUrl);
|
|
287
|
-
} else {
|
|
288
|
-
|
|
289
|
-
if
|
|
290
|
-
|
|
291
|
-
// Fall back to exporting errors to local file
|
|
292
|
-
await printFailureDetails(fileErrors, results);
|
|
293
|
-
} else if ('ABORTED' !== overallStatus) {
|
|
294
|
-
// Errors are not present in the dto
|
|
295
|
-
// And file error details report link is not available
|
|
296
|
-
// do not print this message if the import was aborted
|
|
297
|
-
printFileErrorsReportLinkExpiredError(results);
|
|
298
|
-
}
|
|
276
|
+
} else if ('ABORTED' !== overallStatus) {
|
|
277
|
+
// print report link expired if required
|
|
278
|
+
// do not print this message if the import was aborted
|
|
279
|
+
printFileErrorsReportLinkExpiredError(results);
|
|
299
280
|
}
|
|
300
281
|
|
|
301
282
|
// Print one final time
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.createExternalizedPromise = void 0;
|
|
5
|
+
const createExternalizedPromise = () => {
|
|
6
|
+
let externalResolve = null;
|
|
7
|
+
let externalReject = null;
|
|
8
|
+
const externalizedPromise = new Promise((resolve, reject) => {
|
|
9
|
+
externalResolve = resolve;
|
|
10
|
+
externalReject = reject;
|
|
11
|
+
});
|
|
12
|
+
if (!externalReject || !externalResolve) {
|
|
13
|
+
throw new Error("Somehow, externalReject or externalResolve didn't get set.");
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
promise: externalizedPromise,
|
|
17
|
+
resolve: externalResolve,
|
|
18
|
+
reject: externalReject
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
exports.createExternalizedPromise = createExternalizedPromise;
|
|
@@ -9,6 +9,7 @@ var _debug = _interopRequireDefault(require("debug"));
|
|
|
9
9
|
var _fs = _interopRequireDefault(require("fs"));
|
|
10
10
|
var _promises = require("node:stream/promises");
|
|
11
11
|
var _path = _interopRequireDefault(require("path"));
|
|
12
|
+
var _database = require("./database");
|
|
12
13
|
var _utils = require("./utils");
|
|
13
14
|
var exit = _interopRequireWildcard(require("../lib/cli/exit"));
|
|
14
15
|
var _prompt = require("../lib/cli/prompt");
|
|
@@ -76,9 +77,12 @@ const searchAndReplace = async (fileName, pairs, {
|
|
|
76
77
|
inPlace = false,
|
|
77
78
|
output = process.stdout
|
|
78
79
|
}, binary = null) => {
|
|
80
|
+
const dumpDetails = await (0, _database.getSqlDumpDetails)(fileName);
|
|
81
|
+
const isMyDumper = dumpDetails.type === _database.SqlDumpType.MYDUMPER;
|
|
79
82
|
await (0, _tracker.trackEvent)('searchreplace_started', {
|
|
80
83
|
is_import: isImport,
|
|
81
|
-
in_place: inPlace
|
|
84
|
+
in_place: inPlace,
|
|
85
|
+
sqldump_type: dumpDetails.type
|
|
82
86
|
});
|
|
83
87
|
const startTime = process.hrtime();
|
|
84
88
|
const fileSize = (0, _clientFileUploader.getFileSize)(fileName);
|
|
@@ -103,7 +107,8 @@ const searchAndReplace = async (fileName, pairs, {
|
|
|
103
107
|
if (!approved) {
|
|
104
108
|
await (0, _tracker.trackEvent)('search_replace_in_place_cancelled', {
|
|
105
109
|
is_import: isImport,
|
|
106
|
-
in_place: inPlace
|
|
110
|
+
in_place: inPlace,
|
|
111
|
+
sqldump_type: dumpDetails.type
|
|
107
112
|
});
|
|
108
113
|
process.exit();
|
|
109
114
|
}
|
|
@@ -125,8 +130,13 @@ const searchAndReplace = async (fileName, pairs, {
|
|
|
125
130
|
// replace() throws strings... OMG
|
|
126
131
|
exit.withError(replaceError);
|
|
127
132
|
}
|
|
133
|
+
const streams = [replacedStream];
|
|
134
|
+
if (isMyDumper) {
|
|
135
|
+
streams.push((0, _database.fixMyDumperTransform)());
|
|
136
|
+
}
|
|
137
|
+
streams.push(writeStream);
|
|
128
138
|
try {
|
|
129
|
-
await (0, _promises.pipeline)(
|
|
139
|
+
await (0, _promises.pipeline)(streams);
|
|
130
140
|
} catch (error) {
|
|
131
141
|
console.log((0, _chalk.red)("Oh no! We couldn't write to the output file. Please check your available disk space and file/folder permissions."));
|
|
132
142
|
throw error;
|
|
@@ -136,7 +146,8 @@ const searchAndReplace = async (fileName, pairs, {
|
|
|
136
146
|
|
|
137
147
|
await (0, _tracker.trackEvent)('searchreplace_completed', {
|
|
138
148
|
time_to_run: end,
|
|
139
|
-
file_size: fileSize
|
|
149
|
+
file_size: fileSize,
|
|
150
|
+
sqldump_type: dumpDetails.type
|
|
140
151
|
});
|
|
141
152
|
return {
|
|
142
153
|
inputFileName: fileName,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -260,7 +260,7 @@ const checks = {
|
|
|
260
260
|
recommendation: "Disabling 'UNIQUE_CHECKS' is not allowed. These lines should be removed"
|
|
261
261
|
},
|
|
262
262
|
siteHomeUrl: {
|
|
263
|
-
matcher: "
|
|
263
|
+
matcher: `['"](siteurl|home)['"],\\s?['"](.*?)['"]`,
|
|
264
264
|
matchHandler: (lineNumber, results) => ({
|
|
265
265
|
text: results[1] + ' ' + results[2]
|
|
266
266
|
}),
|
|
@@ -271,7 +271,7 @@ const checks = {
|
|
|
271
271
|
recommendation: ''
|
|
272
272
|
},
|
|
273
273
|
siteHomeUrlLando: {
|
|
274
|
-
matcher: "
|
|
274
|
+
matcher: `['"](siteurl|home)['"],\\s?['"]([^'"]+)['"]`,
|
|
275
275
|
matchHandler: (lineNumber, results, expectedDomain) => {
|
|
276
276
|
let foundDomain = results[2];
|
|
277
277
|
if (!/^https?:\/\//i.test(foundDomain)) {
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
## Changelog
|
|
2
2
|
|
|
3
|
+
## 3.7.1
|
|
4
|
+
|
|
5
|
+
* New develop release: 3.7.1-dev.0 by @github-actions in #1944
|
|
6
|
+
* build(deps): bump step-security/harden-runner from 2.8.1 to 2.9.0 by @dependabot in #1950
|
|
7
|
+
* build(deps): bump semver from 7.6.2 to 7.6.3 by @dependabot in #1946
|
|
8
|
+
* build(deps-dev): bump @types/node from 18.19.39 to 18.19.41 by @dependabot in #1951
|
|
9
|
+
* refactor(dev-env): do not load SSH keys by @sjinks in #1934
|
|
10
|
+
* build(deps): bump tar from 7.4.0 to 7.4.1 by @dependabot in #1952
|
|
11
|
+
* build(deps-dev): bump typescript from 5.5.3 to 5.5.4 by @dependabot in #1954
|
|
12
|
+
* build(deps-dev): bump @types/node from 18.19.41 to 18.19.42 by @dependabot in #1956
|
|
13
|
+
* Refactor dev-env sync, dev-env import and export-sql to TypeScript by @abdullah-kasim in #1955
|
|
14
|
+
* build(deps): bump tar from 7.4.1 to 7.4.3 by @dependabot in #1963
|
|
15
|
+
* build(deps-dev): bump @types/dockerode from 3.3.30 to 3.3.31 by @dependabot in #1960
|
|
16
|
+
* Gracefully fail when directory is not detected by @ariskataoka in #1947
|
|
17
|
+
* New package release: v3.7.1 by @github-actions in #1966
|
|
18
|
+
|
|
19
|
+
**Full Changelog**: https://github.com/Automattic/vip-cli/compare/3.7.0...3.7.1
|
|
20
|
+
|
|
3
21
|
## 3.7.0
|
|
4
22
|
|
|
5
23
|
* New develop release: 3.6.1-dev.0 by @github-actions in #1931
|