PluginProbe
WP-Stateless – Google Cloud Storage / trunk
WP-Stateless – Google Cloud Storage vtrunk
4.4.3 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.3.0 2.3.1 2.3.2 3.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 All 62 releases
← All changes | lib/cli/class-sm-cli-command.php +303 -1 3.2.0trunk View file →
@@ -1,6 +1,9 @@
1 1 <?php
2 2
3 +use wpCloud\StatelessMedia\Migrator;
4 +use \wpCloud\StatelessMedia\Batch\BatchTaskManager;
5 +
3 6 /**
4 7 * WP CLI SM Commands
5 8 */
6 9 if (defined('WP_CLI') && WP_CLI && class_exists('WP_CLI_Command')) {
@@ -150,9 +153,9 @@
150 153 *
151 154 * ## OPTIONS
152 155 *
153 156 * <type>
154 - * : Which data we want to upgrade
157 + * : Which data we want to upgrade. Currently only 'meta' type is supported.
155 158 *
156 159 * --start
157 160 * : Indent (sql start). It's ignored on batches.
158 161 *
@@ -236,8 +239,307 @@
236 239 //** Get rid of all transients and run DB optimization again */
237 240 if (isset($assoc_args['o'])) {
238 241 $this->_after_command_run();
239 242 }
243 + }
244 +
245 + /**
246 + * Run migrations
247 + *
248 + * ## OPTIONS
249 + *
250 + * [<id|auto>]
251 + * : start migration by its ID, or automatically run all pending migrations (auto). Auto mode does not support '--force' parameter.
252 + *
253 + * --force
254 + * : Force starting migration even if it is not pending
255 + *
256 + * --progress=<interval>
257 + * : Monitor migration progress every <interval> seconds (minimum 1)
258 + *
259 + * --email=<email>
260 + * : Send email notification to specified email when migration is finished. By default it uses email from plugin settings. You can also use a list of emails, comma separated.
261 + *
262 + * --url
263 + * : Blog URL if multisite installation.
264 + *
265 + * --yes
266 + * : Confirm automatically.
267 + *
268 + *
269 + * ## EXAMPLES
270 + *
271 + * wp stateless migrate
272 + * : List migrations information.
273 + *
274 + * wp stateless migrate --url=example.com
275 + * : List migrations information for specific blog in multisite network.
276 + *
277 + * wp stateless migrate --progress=3
278 + * : Display current migration progress every 3 seconds.
279 + *
280 + * wp stateless migrate 20240216150177
281 + * : Start migration with ID 20240216150177.
282 + *
283 + * wp stateless migrate auto --email=mail@example.com --yes
284 + * : Automatically run all pending migrations without confirmation and send notifications to mail@example.com.
285 + *
286 + * wp stateless migrate 20240216150177 --progress=2 --yes
287 + * : Start migration with ID 20240216150177 without confirmation and display progress every 2 seconds.
288 + *
289 + * wp stateless migrate 20240216150177 --force --email=mail@example.com,user@domain.com --url=example.com
290 + * : Start migration with ID 20240216150177 for specific blog in multisite network. Start migration even if it was already finished or failed. After finishing send email notification to mail@example.com and user@domain.com.
291 + *
292 + * @synopsis [<id|auto>] [--force] [--progress=<val>] [--email=<val>] [--yes] [--url=<val>]
293 + * @param $args
294 + * @param $assoc_args
295 + */
296 + public function migrate($args, $assoc_args) {
297 + $id = $args[0] ?? '';
298 +
299 + // No migration ID provided, list all migrations and exit
300 + if ( empty($id) && !isset($assoc_args['progress']) ) {
301 + $this->_list_migrations();
302 +
303 + return;
304 + } else if ( !empty($id) ) {
305 + if ( $id === 'auto' ) {
306 + if ( isset($assoc_args['force']) ) {
307 + WP_CLI::error( 'The parameter --force is not supported for auto mode.' );
308 +
309 + return;
310 + }
311 +
312 + $this->_auto_migrate($assoc_args);
313 +
314 + return;
315 + } else {
316 + $this->_run_migration($id, $assoc_args);
317 + }
318 + }
319 +
320 + if ( $id !== 'auto' && isset($assoc_args['progress']) ) {
321 + $this->_check_progress($assoc_args['progress']);
322 + }
323 + }
324 +
325 + /**
326 + * Sets cacheControl meta for all files on Google Cloud Storage to the default value from WP-Stateless settings.
327 + *
328 + * ## OPTIONS
329 + *
330 + * --url
331 + * : Blog URL if multisite installation.
332 + *
333 + * ## EXAMPLES
334 + *
335 + * wp stateless reset_cache_control
336 + * : Sync cache control for all files on Google Cloud Storage.
337 + *
338 + * @synopsis [--url=<val>]
339 + * @param $args
340 + * @param $assoc_args
341 + */
342 + public function reset_cache_control($args, $assoc_args) {
343 + $sm_mode = ud_get_stateless_media()->get('sm.mode');
344 + if ( ud_get_stateless_media()->is_mode('stateless') ) {
345 + WP_CLI::error('Sync cache control is not supported in Stateless mode');
346 + }
347 +
348 + global $wpdb;
349 +
350 + $gs_client = ud_get_stateless_media()->get_client();
351 + $cache_control = ud_get_stateless_media()->get_default_cache_control();
352 + $cache_control = apply_filters('sm:item:cacheControl', ud_get_stateless_media()->get_default_cache_control() );
353 +
354 + $table_name = ud_stateless_db()->files;
355 + $names = $wpdb->get_col("
356 + SELECT name
357 + FROM {$table_name}
358 + WHERE post_id IS NOT NULL
359 + ");
360 +
361 + foreach ($names as $name) {
362 + if ( !$gs_client->media_exists($name) ) {
363 + continue;
364 + }
365 +
366 + $args = [
367 + 'skipLocalCheck' => true,
368 + 'force' => false,
369 + 'cacheControl' => $cache_control,
370 + 'name' => $name,
371 + ];
372 +
373 + $gs_client->add_media($args);
374 +
375 + WP_CLI::line("Processed file: '{$name}'");
376 + }
377 + }
378 +
379 + /**
380 + * Run all pending migrations
381 + *
382 + * @param array $assoc_args
383 + */
384 + private function _auto_migrate($assoc_args) {
385 + $progress = $assoc_args['progress'] ?? 1;
386 +
387 + do {
388 + // We need to omit the cache and get the data directly from the db
389 + $migrations = apply_filters('wp_stateless_get_migrations', []);
390 +
391 + $keys = array_reverse( array_keys($migrations) );
392 + $id = null;
393 +
394 + // Do we have next pending migration?
395 + foreach ($keys as $key) {
396 + if ( $migrations[$key]['status'] === Migrator::STATUS_PENDING ) {
397 + $id = $key;
398 + break;
399 + }
400 + }
401 +
402 + if ( !empty($id) ) {
403 + $command = "wp stateless migrate $id --yes --progress=$progress";
404 +
405 + WP_CLI::line('...');
406 + WP_CLI::line("Launching external command '{$command}'");
407 + WP_CLI::line('Waiting...');
408 +
409 + @ob_flush();
410 + flush();
411 +
412 + $r = SM_CLI::launch($command, false, true);
413 +
414 + if ($r->return_code) {
415 + WP_CLI::error("Something went wrong. External command process failed.");
416 + } else {
417 + echo $r->stdout;
418 + }
419 +
420 + continue;
421 + }
422 +
423 + break;
424 +
425 + } while(true);
426 +
427 + WP_CLI::success('No pending migrations left.');
428 + }
429 +
430 + /**
431 + * Run the specific migration
432 + *
433 + * @param string $id
434 + * @param array $assoc_args
435 + */
436 + private function _run_migration($id, $assoc_args) {
437 + $migrations = $this->_get_migrations();
438 +
439 + if ( !isset($migrations[$id]) ) {
440 + WP_CLI::error("Invalid migration ID: $id");
441 + }
442 +
443 + $migration = $migrations[$id];
444 +
445 + // Check if we can run migration
446 + if ( !$migration['can_start'] && !isset($assoc_args['force']) ) {
447 + WP_CLI::error( 'Migration ' . $migration['description'] . ' is not ready for starting. ' . PHP_EOL .
448 + 'Migration status: ' . $migration['status_text'] . ', ' . strip_tags($migration['message']) . PHP_EOL .
449 + 'Please use --force to run it anyway.'
450 + );
451 + }
452 +
453 + $email = $assoc_args['email'] ?? ud_get_stateless_media()->get_notification_email();
454 +
455 + WP_CLI::line( 'Please make a backup copy of your database and try not to upload, change or delete your media while the process continues.' . PHP_EOL .
456 + "After the process finishes an email will be sent to: $email" . PHP_EOL
457 + );
458 +
459 + WP_CLI::confirm( "Are you sure you want to run the migration $id?", $assoc_args );
460 +
461 + // Run migration
462 + Migrator::instance()->start_migration([], [
463 + 'id' => $id,
464 + 'is_migration' => true,
465 + 'force' => true,
466 + ]);
467 +
468 + WP_CLI::success( "Started migration $id" );
469 + }
470 +
471 + /**
472 + * Get migrations state
473 + *
474 + * @return array
475 + */
476 + private function _get_migrations() {
477 + $migrations = apply_filters('wp_stateless_batch_state', [], ['force_migrations' => true]);
478 + return $migrations['migrations'] ?? [];
479 + }
480 +
481 + /**
482 + * List migrations
483 + */
484 + private function _list_migrations() {
485 + $migrations = $this->_get_migrations();
486 +
487 + if ( empty($migrations) ) {
488 + WP_CLI::success('No migrations found');
489 + }
490 +
491 + $data = [];
492 +
493 + foreach ($migrations as $id => $migration) {
494 + $data[$id] = [
495 + 'id' => $id,
496 + 'description' => $migration['description'],
497 + 'status' => $migration['status_text'],
498 + 'message' => strip_tags($migration['message']),
499 + ];
500 + }
501 +
502 + WP_CLI\Utils\format_items('table', $data, ['id', 'description', 'status', 'message']);
503 + }
504 +
505 + /**
506 + * Check progress
507 + */
508 + private function _check_progress($progress) {
509 + global $wpdb;
510 +
511 + $sleep = max($progress, 1);
512 + $key = BatchTaskManager::instance()->get_state_key();
513 +
514 + $sql = "SELECT option_value FROM $wpdb->options WHERE option_name = '%s' LIMIT 1";
515 + $sql = $wpdb->prepare($sql, $key);
516 +
517 + $description = '';
518 +
519 + do {
520 + // We need to omit the cache and get the data directly from the db
521 + $state = $wpdb->get_var($sql);
522 + $state = maybe_unserialize($state);
523 +
524 + if ( empty($state) || !isset($state['is_migration']) || !$state['is_migration'] ) {
525 + $message = empty($description) ? 'Migration finished' : "Migration '$description' finished";
526 + WP_CLI::success($message);
527 +
528 + return;
529 + }
530 +
531 + $description = $state['description'] ?? '';
532 + $completed = $state['completed'] ?? 0;
533 + $total = $state['total'] ?? 0;
534 +
535 + $percent = $total > 0 ? round($completed / $total * 100, 2) : 0;
536 +
537 + $message = sprintf("Migration '%s' compeleted %.2f%%: %d of %d items processed", $description, $percent, $completed, $total);
538 + WP_CLI::line($message);
539 +
540 + sleep($sleep);
541 + } while (true);
240 542 }
241 543
242 544 /**
243 545 * Runs batches