@automattic/vip 2.26.0 → 2.26.1

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.
@@ -59,18 +59,28 @@ services:
59
59
  volume:
60
60
  nocopy: true
61
61
  <% wpVolumes() %>
62
+ run_as_root:
63
+ - chown www-data:www-data /wp/wp-content/mu-plugins /wp/config /wp/log /wp/wp-content/uploads /wp
62
64
  run:
63
65
  - sh /dev-tools/setup.sh database root "http://<%= siteSlug %>.vipdev.lndo.site/" "<%= wpTitle %>" <% if ( multisite ) { %> <%= siteSlug %>.vipdev.lndo.site <% } %>
64
66
 
65
67
  database:
66
68
  type: compose
67
69
  services:
70
+ <% if ( mariadb ) { %>
68
71
  image: mariadb:<%= mariadb %>
69
72
  command: docker-entrypoint.sh mysqld --sql-mode=ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION --max_allowed_packet=67M
73
+ <% } else { %>
74
+ image: mysql:8
75
+ command: docker-entrypoint.sh mysqld --sql-mode=ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION --max_allowed_packet=67M --default-authentication-plugin=mysql_native_password
76
+ <% } %>
70
77
  ports:
71
78
  - ":3306"
72
79
  environment:
73
- MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 'true'
80
+ MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
81
+ MYSQL_USER: wordpress
82
+ MYSQL_PASSWORD: wordpress
83
+ MYSQL_DATABASE: wordpress
74
84
  volumes:
75
85
  - database_data:/var/lib/mysql
76
86
  volumes:
Binary file
@@ -87,7 +87,8 @@ cmd.argv(process.argv, async (arg, opt) => {
87
87
  try {
88
88
  await (0, _devEnvironmentCore.createEnvironment)(instanceData);
89
89
  await (0, _devEnvironmentCore.printEnvironmentInfo)(lando, slug, {
90
- extended: false
90
+ extended: false,
91
+ suppressWarnings: true
91
92
  });
92
93
  const message = '\n' + _chalk.default.green('✓') + ` environment created.\n\nTo start it please run:\n\n${startCommand}\n`;
93
94
  console.log(message);
@@ -8,22 +8,18 @@
8
8
  /**
9
9
  * External dependencies
10
10
  */
11
+
12
+ /**
13
+ * Internal dependencies
14
+ */
11
15
  "use strict";
12
16
 
13
- var _fs = _interopRequireDefault(require("fs"));
14
- var _chalk = _interopRequireDefault(require("chalk"));
15
17
  var _tracker = require("../lib/tracker");
16
18
  var _command = _interopRequireDefault(require("../lib/cli/command"));
17
19
  var _devEnvironmentCli = require("../lib/dev-environment/dev-environment-cli");
18
- var _devEnvironmentCore = require("../lib/dev-environment/dev-environment-core");
19
20
  var _devEnvironment = require("../lib/constants/dev-environment");
20
- var _sql = require("../lib/validations/sql");
21
- var _devEnvironmentLando = require("../lib/dev-environment/dev-environment-lando");
22
- var _userError = _interopRequireDefault(require("../lib/user-error"));
21
+ var _devEnvImportSql = require("../commands/dev-env-import-sql");
23
22
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
24
- /**
25
- * Internal dependencies
26
- */
27
23
  const examples = [{
28
24
  usage: `${_devEnvironment.DEV_ENVIRONMENT_FULL_COMMAND} import sql some-wp-db-file.sql`,
29
25
  description: 'Import the contents of a WordPress database from an SQL file'
@@ -41,65 +37,10 @@ const examples = [{
41
37
  requiredArgs: 1
42
38
  }).option('slug', 'Custom name of the dev environment').option(['r', 'search-replace'], 'Perform Search and Replace on the specified SQL file').option('in-place', 'Search and Replace explicitly on the given input file').option('skip-validate', 'Do not perform file validation.').examples(examples).argv(process.argv, async (unmatchedArgs, opt) => {
43
39
  const [fileName] = unmatchedArgs;
44
- const {
45
- searchReplace,
46
- inPlace
47
- } = opt;
48
- const slug = (0, _devEnvironmentCli.getEnvironmentName)(opt);
49
- const lando = await (0, _devEnvironmentLando.bootstrapLando)();
50
- await (0, _devEnvironmentCli.validateDependencies)(lando, slug);
51
- const trackingInfo = (0, _devEnvironmentCli.getEnvTrackingInfo)(slug);
52
- await (0, _tracker.trackEvent)('dev_env_import_sql_command_execute', trackingInfo);
40
+ const cmd = new _devEnvImportSql.DevEnvImportSQLCommand(fileName, opt);
41
+ const trackingInfo = (0, _devEnvironmentCli.getEnvTrackingInfo)(cmd.slug);
53
42
  try {
54
- const resolvedPath = await (0, _devEnvironmentCore.resolveImportPath)(slug, fileName, searchReplace, inPlace);
55
- if (!opt.skipValidate) {
56
- if (!(0, _devEnvironmentLando.isEnvUp)(lando, (0, _devEnvironmentCore.getEnvironmentPath)(slug))) {
57
- throw new _userError.default('Environment needs to be started first');
58
- }
59
- const expectedDomain = `${slug}.vipdev.lndo.site`;
60
- await (0, _sql.validate)(resolvedPath, {
61
- isImport: false,
62
- skipChecks: [],
63
- extraCheckParams: {
64
- siteHomeUrlLando: expectedDomain
65
- }
66
- });
67
- }
68
- const fd = await _fs.default.promises.open(resolvedPath, 'r');
69
- const importArg = ['db', '--disable-auto-rehash'];
70
- const origIsTTY = process.stdin.isTTY;
71
- try {
72
- /**
73
- * When stdin is a TTY, Lando passes the `--tty` flag to Docker.
74
- * This breaks our code when we pass the stream as stdin to Docker.
75
- * exec() then fails with "the input device is not a TTY".
76
- *
77
- * Therefore, for the things to work, we have to pretend that stdin is not a TTY :-)
78
- */
79
- process.stdin.isTTY = false;
80
- await (0, _devEnvironmentCore.exec)(lando, slug, importArg, {
81
- stdio: [fd, 'pipe', 'pipe']
82
- });
83
- console.log(`${_chalk.default.green.bold('Success:')} Database imported.`);
84
- } finally {
85
- process.stdin.isTTY = origIsTTY;
86
- }
87
- if (searchReplace && searchReplace.length && !inPlace) {
88
- _fs.default.unlinkSync(resolvedPath);
89
- }
90
- const cacheArg = ['wp', 'cache', 'flush'];
91
- await (0, _devEnvironmentCore.exec)(lando, slug, cacheArg);
92
- try {
93
- await (0, _devEnvironmentCore.exec)(lando, slug, ['wp', 'cli', 'has-command', 'vip-search']);
94
- const doIndex = await (0, _devEnvironmentCli.promptForBoolean)('Do you want to index data in Elasticsearch (used by Enterprise Search)?', true);
95
- if (doIndex) {
96
- await (0, _devEnvironmentCore.exec)(lando, slug, ['wp', 'vip-search', 'index', '--setup', '--network-wide', '--skip-confirm']);
97
- }
98
- } catch (err) {
99
- // Exception means they don't have vip-search enabled.
100
- }
101
- const addUserArg = ['wp', 'dev-env-add-admin', '--username=vipgo', '--password=password'];
102
- await (0, _devEnvironmentCore.exec)(lando, slug, addUserArg);
43
+ await cmd.run();
103
44
  await (0, _tracker.trackEvent)('dev_env_import_sql_command_success', trackingInfo);
104
45
  } catch (error) {
105
46
  await (0, _devEnvironmentCli.handleCLIException)(error, 'dev_env_import_sql_command_error', trackingInfo);
@@ -40,7 +40,8 @@ const examples = [{
40
40
  debug('Args: ', arg, 'Options: ', opt);
41
41
  try {
42
42
  const options = {
43
- extended: !!opt.extended
43
+ extended: !!opt.extended,
44
+ suppressWarnings: true
44
45
  };
45
46
  if (opt.all) {
46
47
  await (0, _devEnvironmentCore.printAllEnvironmentsInfo)(lando, options);
@@ -52,7 +52,7 @@ cmd.argv(process.argv, async (arg, opt) => {
52
52
  const defaultOptions = {
53
53
  appCode: currentInstanceData.appCode.dir || currentInstanceData.appCode.tag || 'latest',
54
54
  muPlugins: currentInstanceData.muPlugins.dir || currentInstanceData.muPlugins.tag || 'latest',
55
- wordpress: currentInstanceData.wordpress.tag,
55
+ wordpress: currentInstanceData.wordpress.tag || 'trunk',
56
56
  elasticsearch: currentInstanceData.elasticsearch,
57
57
  php: currentInstanceData.php || _devEnvironment.DEV_ENVIRONMENT_PHP_VERSIONS.default,
58
58
  mariadb: currentInstanceData.mariadb,
@@ -66,8 +66,8 @@ cmd.argv(process.argv, async (arg, opt) => {
66
66
  const providedOptions = Object.keys(opt).filter(option => option.length > 1) // Filter out single letter aliases
67
67
  .filter(option => !['debug', 'help', 'slug'].includes(option)); // Filter out options that are not related to instance configuration
68
68
 
69
- const supressPrompts = providedOptions.length > 0;
70
- const instanceData = await (0, _devEnvironmentCli.promptForArguments)(preselectedOptions, defaultOptions, supressPrompts);
69
+ const suppressPrompts = providedOptions.length > 0;
70
+ const instanceData = await (0, _devEnvironmentCli.promptForArguments)(preselectedOptions, defaultOptions, suppressPrompts);
71
71
  instanceData.siteSlug = slug;
72
72
  await (0, _devEnvironmentCore.updateEnvironment)(instanceData);
73
73
  const message = '\n' + _chalk.default.green('✓') + ' environment updated. Restart environment for changes to take an affect.';
@@ -353,10 +353,10 @@ const displayPlaybook = ({
353
353
  const domain = env !== null && env !== void 0 && (_env$primaryDomain = env.primaryDomain) !== null && _env$primaryDomain !== void 0 && _env$primaryDomain.name ? env.primaryDomain.name : `#${env.id}`;
354
354
  const formattedEnvironment = (0, _format.formatEnvironment)(opts.env.type);
355
355
  const launched = opts.env.launched;
356
- let fileNameToUpload = fileName;
357
356
 
358
- // Exit if filename contains unsafe character
359
- validateFilename(fileNameToUpload);
357
+ // Extract base file name and exit if it contains unsafe character
358
+ validateFilename(fileMeta.basename);
359
+ let fileNameToUpload = fileName;
360
360
 
361
361
  // SQL file validations
362
362
  const tableNames = await validateAndGetTableNames({
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.DevEnvImportSQLCommand = void 0;
7
+ var _fs = _interopRequireDefault(require("fs"));
8
+ var _chalk = _interopRequireDefault(require("chalk"));
9
+ var _devEnvironmentCli = require("../lib/dev-environment/dev-environment-cli");
10
+ var _devEnvironmentCore = require("../lib/dev-environment/dev-environment-core");
11
+ var _devEnvironmentLando = require("../lib/dev-environment/dev-environment-lando");
12
+ var _userError = _interopRequireDefault(require("../lib/user-error"));
13
+ var _sql = require("../lib/validations/sql");
14
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
+ /**
16
+ *
17
+ * @format
18
+ */
19
+
20
+ /**
21
+ * External dependencies
22
+ */
23
+
24
+ /**
25
+ * Internal dependencies
26
+ */
27
+
28
+ class DevEnvImportSQLCommand {
29
+ constructor(fileName, options) {
30
+ this.fileName = fileName;
31
+ this.options = options;
32
+ this.slug = (0, _devEnvironmentCli.getEnvironmentName)(options);
33
+ }
34
+ async run(silent = false) {
35
+ const lando = await (0, _devEnvironmentLando.bootstrapLando)();
36
+ await (0, _devEnvironmentCli.validateDependencies)(lando, this.slug, silent);
37
+ const {
38
+ searchReplace,
39
+ inPlace
40
+ } = this.options;
41
+ const resolvedPath = await (0, _devEnvironmentCore.resolveImportPath)(this.slug, this.fileName, searchReplace, inPlace);
42
+ if (!this.options.skipValidate) {
43
+ if (!(await (0, _devEnvironmentLando.isEnvUp)(lando, (0, _devEnvironmentCore.getEnvironmentPath)(this.slug)))) {
44
+ throw new _userError.default('Environment needs to be started first');
45
+ }
46
+ const expectedDomain = `${this.slug}.vipdev.lndo.site`;
47
+ await (0, _sql.validate)(resolvedPath, {
48
+ isImport: false,
49
+ skipChecks: [],
50
+ extraCheckParams: {
51
+ siteHomeUrlLando: expectedDomain
52
+ }
53
+ });
54
+ }
55
+ const fd = await _fs.default.promises.open(resolvedPath, 'r');
56
+ const importArg = ['db', '--disable-auto-rehash'];
57
+ const origIsTTY = process.stdin.isTTY;
58
+ try {
59
+ /**
60
+ * When stdin is a TTY, Lando passes the `--tty` flag to Docker.
61
+ * This breaks our code when we pass the stream as stdin to Docker.
62
+ * exec() then fails with "the input device is not a TTY".
63
+ *
64
+ * Therefore, for the things to work, we have to pretend that stdin is not a TTY :-)
65
+ */
66
+ process.stdin.isTTY = false;
67
+ await (0, _devEnvironmentCore.exec)(lando, this.slug, importArg, {
68
+ stdio: [fd, 'pipe', 'pipe']
69
+ });
70
+ if (!silent) {
71
+ console.log(`${_chalk.default.green.bold('Success:')} Database imported.`);
72
+ }
73
+ } finally {
74
+ process.stdin.isTTY = origIsTTY;
75
+ }
76
+ if (searchReplace && searchReplace.length && !inPlace) {
77
+ _fs.default.unlinkSync(resolvedPath);
78
+ }
79
+ const cacheArg = ['wp', 'cache', 'flush'];
80
+ await (0, _devEnvironmentCore.exec)(lando, this.slug, cacheArg);
81
+ try {
82
+ await (0, _devEnvironmentCore.exec)(lando, this.slug, ['wp', 'cli', 'has-command', 'vip-search']);
83
+ const doIndex = await (0, _devEnvironmentCli.promptForBoolean)('Do you want to index data in Elasticsearch (used by Enterprise Search)?', true);
84
+ if (doIndex) {
85
+ await (0, _devEnvironmentCore.exec)(lando, this.slug, ['wp', 'vip-search', 'index', '--setup', '--network-wide', '--skip-confirm']);
86
+ }
87
+ } catch (err) {
88
+ // Exception means they don't have vip-search enabled.
89
+ }
90
+ const addUserArg = ['wp', 'dev-env-add-admin', '--username=vipgo', '--password=password'];
91
+ await (0, _devEnvironmentCore.exec)(lando, this.slug, addUserArg);
92
+ }
93
+ }
94
+ exports.DevEnvImportSQLCommand = DevEnvImportSQLCommand;
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ *
5
+ * @format
6
+ */
7
+
8
+ /**
9
+ * External dependencies
10
+ */
11
+ "use strict";
12
+
13
+ Object.defineProperty(exports, "__esModule", {
14
+ value: true
15
+ });
16
+ exports.DevEnvSyncSQLCommand = void 0;
17
+ var _fs = _interopRequireDefault(require("fs"));
18
+ var _chalk = _interopRequireDefault(require("chalk"));
19
+ var _vipSearchReplace = require("@automattic/vip-search-replace");
20
+ var _clientFileUploader = require("../lib/client-file-uploader");
21
+ var _exportSql = require("./export-sql");
22
+ var _utils = require("../lib/utils");
23
+ var _lineByLine = require("../lib/validations/line-by-line");
24
+ var exit = _interopRequireWildcard(require("../lib/cli/exit"));
25
+ var _devEnvImportSql = require("./dev-env-import-sql");
26
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
27
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
28
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
29
+ /**
30
+ * Internal dependencies
31
+ */
32
+ /**
33
+ * Finds the site home url from the SQL line
34
+ *
35
+ * @param {string} sql A line in a SQL file
36
+ * @return {string} Site home url. null if not found
37
+ */
38
+ function findSiteHomeUrl(sql) {
39
+ const regex = "'(siteurl|home)',\\s?'(.*?)'";
40
+ const results = sql.match(regex);
41
+ if (results) {
42
+ const domain = results[2].replace(/https?:\/\//, '');
43
+ return domain;
44
+ }
45
+ return null;
46
+ }
47
+
48
+ /**
49
+ * Extracts a list of site urls from the SQL file
50
+ *
51
+ * @param {string} sqlFile Path to the SQL file
52
+ * @return {Promise<string[]>} List of site urls
53
+ * @throws {Error} If there is an error reading the file
54
+ */
55
+ async function extractSiteUrls(sqlFile) {
56
+ const readInterface = await (0, _lineByLine.getReadInterface)(sqlFile);
57
+ return new Promise((resolve, reject) => {
58
+ const domains = [];
59
+ readInterface.on('line', line => {
60
+ const domain = findSiteHomeUrl(line);
61
+ if (domain) {
62
+ domains.push(domain);
63
+ }
64
+ });
65
+ readInterface.on('close', () => {
66
+ resolve(domains);
67
+ });
68
+ readInterface.on('error', reject);
69
+ });
70
+ }
71
+ class DevEnvSyncSQLCommand {
72
+ /**
73
+ * Creates a new instance of the command
74
+ *
75
+ * @param {string} app The app object
76
+ * @param {string} env The environment object
77
+ * @param {string} slug The site slug
78
+ */
79
+ constructor(app, env, slug) {
80
+ this.app = app;
81
+ this.env = env;
82
+ this.slug = slug;
83
+ this.tmpDir = (0, _utils.makeTempDir)();
84
+ }
85
+ get landoDomain() {
86
+ return `${this.slug}.vipdev.lndo.site`;
87
+ }
88
+ get sqlFile() {
89
+ return `${this.tmpDir}/sql-export.sql`;
90
+ }
91
+ get gzFile() {
92
+ return `${this.tmpDir}/sql-export.sql.gz`;
93
+ }
94
+
95
+ /**
96
+ * Runs the SQL export command to generate the SQL export from
97
+ * the latest backup
98
+ *
99
+ * @return {Promise<void>} Promise that resolves when the export is complete
100
+ */
101
+ async generateExport() {
102
+ const exportCommand = new _exportSql.ExportSQLCommand(this.app, this.env, this.gzFile);
103
+ await exportCommand.run();
104
+ }
105
+
106
+ /**
107
+ * Runs the search-replace operation on the SQL file
108
+ * to replace the site urls with the lando domain
109
+ *
110
+ * @return {Promise<void>} Promise that resolves when the search-replace is complete
111
+ * @throws {Error} If there is an error reading the file
112
+ */
113
+ async runSearchReplace() {
114
+ const replacements = this.siteUrls.reduce((acc, url) => [...acc, url, this.landoDomain], []);
115
+ const readStream = _fs.default.createReadStream(this.sqlFile);
116
+ const replacedStream = await (0, _vipSearchReplace.replace)(readStream, replacements);
117
+ replacedStream.pipe(_fs.default.createWriteStream(this.sqlFile));
118
+ return new Promise((resolve, reject) => {
119
+ replacedStream.on('finish', resolve);
120
+ replacedStream.on('error', reject);
121
+ });
122
+ }
123
+
124
+ /**
125
+ * Runs the SQL import command to import the SQL file
126
+ *
127
+ * @return {Promise<void>} Promise that resolves when the import is complete
128
+ * @throws {Error} If there is an error importing the file
129
+ */
130
+ async runImport() {
131
+ const importOptions = {
132
+ slug: this.slug,
133
+ inPlace: true,
134
+ skipValidate: true
135
+ };
136
+ const importCommand = new _devEnvImportSql.DevEnvImportSQLCommand(this.sqlFile, importOptions);
137
+ await importCommand.run(true);
138
+ }
139
+
140
+ /**
141
+ * Sequentially runs the commands to export, search-replace, and import the SQL file
142
+ * to the local environment
143
+ *
144
+ * @return {Promise<void>} Promise that resolves when the commands are complete
145
+ */
146
+ async run() {
147
+ try {
148
+ await this.generateExport();
149
+ } catch (err) {
150
+ exit.withError(`Error exporting SQL backup: ${err === null || err === void 0 ? void 0 : err.message}`);
151
+ }
152
+ try {
153
+ console.log(`Extracting the exported file ${this.gzFile}...`);
154
+ await (0, _clientFileUploader.unzipFile)(this.gzFile, this.sqlFile);
155
+ console.log(`${_chalk.default.green('✓')} Extracted to ${this.sqlFile}`);
156
+ } catch (err) {
157
+ exit.withError(`Error extracting the SQL export: ${err === null || err === void 0 ? void 0 : err.message}`);
158
+ }
159
+ try {
160
+ console.log('Extracting site urls from the SQL file...');
161
+ this.siteUrls = await extractSiteUrls(this.sqlFile);
162
+ } catch (err) {
163
+ exit.withError(`Error extracting site URLs: ${err === null || err === void 0 ? void 0 : err.message}`);
164
+ }
165
+ try {
166
+ console.log('Running the following search-replace operations on the SQL file:');
167
+ this.siteUrls.forEach(domain => {
168
+ console.log(` ${domain} -> ${this.landoDomain}`);
169
+ });
170
+ await this.runSearchReplace();
171
+ console.log(`${_chalk.default.green('✓')} Search-replace operation is complete`);
172
+ } catch (err) {
173
+ exit.withError(`Error replacing domains: ${err === null || err === void 0 ? void 0 : err.message}`);
174
+ }
175
+ try {
176
+ console.log('Importing the SQL file...');
177
+ await this.runImport();
178
+ console.log(`${_chalk.default.green('✓')} SQL file imported`);
179
+ } catch (err) {
180
+ exit.withError(`Error importing SQL file: ${err === null || err === void 0 ? void 0 : err.message}`);
181
+ }
182
+ }
183
+ }
184
+ exports.DevEnvSyncSQLCommand = DevEnvSyncSQLCommand;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.SQLExportCommand = exports.GENERATE_DOWNLOAD_LINK_MUTATION = exports.CREATE_EXPORT_JOB_MUTATION = void 0;
6
+ exports.GENERATE_DOWNLOAD_LINK_MUTATION = exports.ExportSQLCommand = exports.CREATE_EXPORT_JOB_MUTATION = void 0;
7
7
  var _graphqlTag = _interopRequireDefault(require("graphql-tag"));
8
8
  var _fs = _interopRequireDefault(require("fs"));
9
9
  var _https = _interopRequireDefault(require("https"));
@@ -188,7 +188,7 @@ async function createExportJob(appId, envId, backupId) {
188
188
  /**
189
189
  * Class representing an export command workflow
190
190
  */
191
- class SQLExportCommand {
191
+ class ExportSQLCommand {
192
192
  steps = {
193
193
  PREPARE: 'prepare',
194
194
  CREATE: 'create',
@@ -313,7 +313,7 @@ class SQLExportCommand {
313
313
  *
314
314
  * @return {Promise} A promise which resolves to void
315
315
  */
316
- async runSequence() {
316
+ async run() {
317
317
  console.log(`Fetching the latest backup for ${this.app.name}`);
318
318
  const {
319
319
  latestBackup
@@ -357,4 +357,4 @@ class SQLExportCommand {
357
357
  }
358
358
  }
359
359
  }
360
- exports.SQLExportCommand = SQLExportCommand;
360
+ exports.ExportSQLCommand = ExportSQLCommand;
@@ -15,6 +15,7 @@ exports.getPartBoundaries = getPartBoundaries;
15
15
  exports.getSignedUploadRequestData = getSignedUploadRequestData;
16
16
  exports.gzipFile = exports.getWorkingTempDir = void 0;
17
17
  exports.isFile = isFile;
18
+ exports.unzipFile = void 0;
18
19
  exports.uploadImportSqlFileToS3 = uploadImportSqlFileToS3;
19
20
  exports.uploadPart = uploadPart;
20
21
  exports.uploadParts = uploadParts;
@@ -27,7 +28,7 @@ var _nodeFetch = _interopRequireDefault(require("node-fetch"));
27
28
  var _chalk = _interopRequireDefault(require("chalk"));
28
29
  var _zlib = require("zlib");
29
30
  var _crypto = require("crypto");
30
- var _stream = require("stream");
31
+ var _promises = require("node:stream/promises");
31
32
  var _xml2js = require("xml2js");
32
33
  var _debug = _interopRequireDefault(require("debug"));
33
34
  var _http = _interopRequireDefault(require("../lib/api/http"));
@@ -77,7 +78,21 @@ const getFileMD5Hash = async fileName => new Promise((resolve, reject) => _fs.de
77
78
  }).on('error', error => reject(`could not generate file hash: ${error}`)));
78
79
  exports.getFileMD5Hash = getFileMD5Hash;
79
80
  const gzipFile = async (uncompressedFileName, compressedFileName) => new Promise((resolve, reject) => _fs.default.createReadStream(uncompressedFileName).pipe((0, _zlib.createGzip)()).pipe(_fs.default.createWriteStream(compressedFileName)).on('finish', resolve).on('error', error => reject(`could not compress file: ${error}`)));
81
+
82
+ /**
83
+ * Extract a .gz file and save it to a specified location
84
+ *
85
+ * @param {string} inputFilename The file to unzip
86
+ * @param {string} outputFilename The file where the unzipped data will be written
87
+ * @return {Promise} A promise that resolves when the file is unzipped
88
+ */
80
89
  exports.gzipFile = gzipFile;
90
+ const unzipFile = async (inputFilename, outputFilename) => {
91
+ const source = _fs.default.createReadStream(inputFilename);
92
+ const destination = _fs.default.createWriteStream(outputFilename);
93
+ await (0, _promises.pipeline)(source, (0, _zlib.createGunzip)(), destination);
94
+ };
95
+ exports.unzipFile = unzipFile;
81
96
  async function getFileMeta(fileName) {
82
97
  const fileSize = await getFileSize(fileName);
83
98
  const basename = _path.default.basename(fileName);
@@ -171,7 +186,7 @@ async function uploadUsingPutObject({
171
186
  };
172
187
 
173
188
  let readBytes = 0;
174
- const progressPassThrough = new _stream.PassThrough();
189
+ const progressPassThrough = new _promises.PassThrough();
175
190
  progressPassThrough.on('data', data => {
176
191
  readBytes += data.length;
177
192
  const percentage = Math.floor(100 * readBytes / fileSize) + '%';
@@ -394,7 +409,7 @@ async function uploadParts({
394
409
  index,
395
410
  partSize
396
411
  } = part;
397
- const progressPassThrough = new _stream.PassThrough();
412
+ const progressPassThrough = new _promises.PassThrough();
398
413
  let partBytesRead = 0;
399
414
  progressPassThrough.on('data', data => {
400
415
  totalBytesRead += data.length;
@@ -11,7 +11,6 @@ exports.DEV_ENVIRONMENT_FULL_COMMAND = DEV_ENVIRONMENT_FULL_COMMAND;
11
11
  const DEV_ENVIRONMENT_DEFAULTS = {
12
12
  title: 'VIP Dev',
13
13
  multisite: false,
14
- mariadbVersion: '10.3',
15
14
  phpVersion: '8.0'
16
15
  };
17
16
  exports.DEV_ENVIRONMENT_DEFAULTS = DEV_ENVIRONMENT_DEFAULTS;
@@ -14,6 +14,7 @@ exports.handleCLIException = handleCLIException;
14
14
  exports.printTable = printTable;
15
15
  exports.processBooleanOption = processBooleanOption;
16
16
  exports.processComponentOptionInput = processComponentOptionInput;
17
+ exports.processVersionOption = processVersionOption;
17
18
  exports.promptForArguments = promptForArguments;
18
19
  exports.promptForBoolean = promptForBoolean;
19
20
  exports.promptForComponent = promptForComponent;
@@ -274,7 +275,7 @@ async function promptForArguments(preselectedOptions, defaultOptions, suppressPr
274
275
  multisite: 'multisite' in preselectedOptions ? preselectedOptions.multisite : await promptForBoolean(multisiteText, !!multisiteDefault),
275
276
  elasticsearch: false,
276
277
  php: preselectedOptions.php ? resolvePhpVersion(preselectedOptions.php) : await promptForPhpVersion(resolvePhpVersion(defaultOptions.php || _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.phpVersion)),
277
- mariadb: preselectedOptions.mariadb || defaultOptions.mariadb || _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.mariadbVersion,
278
+ mariadb: preselectedOptions.mariadb || defaultOptions.mariadb,
278
279
  mediaRedirectDomain: preselectedOptions.mediaRedirectDomain || '',
279
280
  wordpress: {
280
281
  mode: 'image',
@@ -343,7 +344,9 @@ async function processComponent(component, preselectedValue, defaultValue) {
343
344
  const defaultObject = defaultValue ? processComponentOptionInput(defaultValue, allowLocal) : null;
344
345
  if (preselectedValue) {
345
346
  result = processComponentOptionInput(preselectedValue, allowLocal);
346
- console.log(`${_chalk.default.green('✓')} Path to your local ${componentDisplayNames[component]}: ${preselectedValue}`);
347
+ if (allowLocal) {
348
+ console.log(`${_chalk.default.green('✓')} Path to your local ${componentDisplayNames[component]}: ${preselectedValue}`);
349
+ }
347
350
  } else {
348
351
  result = await promptForComponent(component, allowLocal, defaultObject);
349
352
  }
@@ -449,9 +452,7 @@ function resolvePhpVersion(version) {
449
452
  }
450
453
  const versions = Object.keys(_devEnvironment.DEV_ENVIRONMENT_PHP_VERSIONS);
451
454
  const images = Object.values(_devEnvironment.DEV_ENVIRONMENT_PHP_VERSIONS);
452
-
453
- // eslint-disable-next-line eqeqeq -- use loose comparison because commander resolves '8.0' to '8'
454
- const index = versions.findIndex(value => value == version);
455
+ const index = versions.findIndex(value => value === version);
455
456
  if (index === -1) {
456
457
  const image = images.find(value => value === version);
457
458
  return image !== null && image !== void 0 ? image : images[0];
@@ -551,8 +552,16 @@ function processBooleanOption(value) {
551
552
  }
552
553
  return !FALSE_OPTIONS.includes((_value$toLowerCase = value.toLowerCase) === null || _value$toLowerCase === void 0 ? void 0 : _value$toLowerCase.call(value));
553
554
  }
555
+ function processVersionOption(value) {
556
+ if (!isNaN(value) && value % 1 === 0) {
557
+ // If it's an Integer passed in, let's ensure that it has a decimal in it to match the version tags e.g. 6 => 6.0
558
+ return parseFloat(value).toFixed(1);
559
+ }
560
+ return value;
561
+ }
554
562
  function addDevEnvConfigurationOptions(command) {
555
- return command.option('wordpress', 'Use a specific WordPress version').option(['u', 'mu-plugins'], 'Use a specific mu-plugins changeset or local directory').option('app-code', 'Use the application code from a local directory or use "demo" for VIP skeleton code').option('phpmyadmin', 'Enable PHPMyAdmin component. By default it is disabled', undefined, processBooleanOption).option('xdebug', 'Enable XDebug. By default it is disabled', undefined, processBooleanOption).option('xdebug_config', 'Extra configuration to pass to xdebug via XDEBUG_CONFIG environment variable').option('elasticsearch', 'Enable Elasticsearch (needed by Enterprise Search)', undefined, processBooleanOption).option('mariadb', 'Explicitly choose MariaDB version to use').option(['r', 'media-redirect-domain'], 'Domain to redirect for missing media files. This can be used to still have images without the need to import them locally.').option('php', 'Explicitly choose PHP version to use').option(['A', 'mailhog'], 'Enable MailHog. By default it is disabled', undefined, processBooleanOption);
563
+ // We leave the third parameter to undefined on some because the defaults are handled in preProcessInstanceData()
564
+ return command.option('wordpress', 'Use a specific WordPress version', undefined, processVersionOption).option(['u', 'mu-plugins'], 'Use a specific mu-plugins changeset or local directory').option('app-code', 'Use the application code from a local directory or use "demo" for VIP skeleton code').option('phpmyadmin', 'Enable PHPMyAdmin component. By default it is disabled', undefined, processBooleanOption).option('xdebug', 'Enable XDebug. By default it is disabled', undefined, processBooleanOption).option('xdebug_config', 'Extra configuration to pass to xdebug via XDEBUG_CONFIG environment variable').option('elasticsearch', 'Enable Elasticsearch (needed by Enterprise Search)', undefined, processBooleanOption).option(['r', 'media-redirect-domain'], 'Domain to redirect for missing media files. This can be used to still have images without the need to import them locally.').option('php', 'Explicitly choose PHP version to use', undefined, processVersionOption).option(['A', 'mailhog'], 'Enable MailHog. By default it is disabled', undefined, processBooleanOption);
556
565
  }
557
566
 
558
567
  /**
@@ -562,20 +571,20 @@ async function getTagChoices() {
562
571
  let versions = await (0, _devEnvironmentCore.getVersionList)();
563
572
  if (versions.length < 1) {
564
573
  versions = [{
565
- ref: '5.9.5',
566
- tag: '5.9',
574
+ ref: '6.1.1',
575
+ tag: '6.1',
567
576
  cacheable: true,
568
577
  locked: true,
569
578
  prerelease: false
570
579
  }, {
571
- ref: '5.8.6',
572
- tag: '5.8',
580
+ ref: '6.0.3',
581
+ tag: '6.0',
573
582
  cacheable: true,
574
583
  locked: true,
575
584
  prerelease: false
576
585
  }, {
577
- ref: '5.7.8',
578
- tag: '5.7',
586
+ ref: '5.9.5',
587
+ tag: '5.9',
579
588
  cacheable: true,
580
589
  locked: true,
581
590
  prerelease: false