foldershare-8.x-1.2/foldershare.drush.inc

foldershare.drush.inc
<?php
 
/**
 * @file
 * Implements drush commands specific to the module.
 */
 
use Drupal\Core\Cache\Cache;
use Drupal\user\Entity\User;
 
use Drupal\foldershare\Settings;
use Drupal\foldershare\Entity\FolderShare;
use Drupal\foldershare\ManageUsageStatistics;
use Drupal\foldershare\Entity\FolderShareScheduledTask;
 
/**
 * Implements hook_drush_command().
 */
function foldershare_drush_command() {
  $commands['foldershare'] = [
    'description' => 'List FolderShare module commands.',
    'aliases'     => [
      'fs',
    ],
    'options'     => [
      'all'      => [
        'description' => 'List all commands, including those for debugging.',
        'hidden'  => TRUE,
      ],
    ],
    'bootstrap'   => DRUSH_BOOTSTRAP_NONE,
    'category'    => 'San Diego Supercomputer Center (SDSC)',
    'topic'       => TRUE,
    'examples'    => [
      'drush foldershare' => 'List FolderShare commands',
    ],
  ];
 
  $commands['foldershare-admin'] = [
    'description' => 'Perform administrative functions.',
    'hidden'      => TRUE,
    'aliases'     => [
      'fsadmin',
    ],
    'arguments'   => [
      'uid'       => [
        'description' => 'The user ID owning affected content',
      ],
      'newuid'    => [
        'description' => 'The user ID for a new owner of the content',
      ],
    ],
    'options'     => [
      'deleteall' => [
        'description' => 'Delete all content',
      ],
      'deleteby' => [
        'description' => 'Delete all content owned by a user',
      ],
      'changeownerby' => [
        'description' => 'Change ownership of all content owned by a user',
      ],
      'unsharewith' => [
        'description' => 'Remove the user from all sharing grants',
      ],
    ],
    'examples'    => [
      'drush foldershare-admin --deleteall' => 'Delete everything',
      'drush foldershare-admin --deleteby 123' => 'Delete all owned by 123',
      'drush foldershare-admin --changeownerby 123 456' => 'Change ownership of all owned by 123 to be 456',
      'drush foldershare-admin --unsharewith 123' => 'Remove sharing with 123',
    ],
    'drupal dependencies' => [
      'foldershare',
    ],
    'bootstrap'   => DRUSH_BOOTSTRAP_DRUPAL_FULL,
    'category'    => 'San Diego Supercomputer Center (SDSC)',
  ];
 
  $commands['foldershare-disabled'] = [
    'description' => 'List, enable, and disable items marked as "disabled".',
    'hidden'      => TRUE,
    'aliases'     => [
      'fsdisable',
      'fsdisabled',
    ],
    'arguments'   => [
      'id'        => [
        'description' => 'The entity ID to disable or enable',
      ],
    ],
    'options'     => [
      'disable'      => [
        'description' => 'Disable the item',
      ],
      'enable'    => [
        'description' => 'Enable an item',
      ],
      'enableall' => [
        'description' => 'Enable all disabled items',
      ],
      'list'      => [
        'description' => 'List all disabled items',
      ],
    ],
    'examples'    => [
      'drush foldershare-disabled' => 'List disabled items',
      'drush foldershare-disabled --list' => 'List disabled items',
      'drush foldershare-disabled --disable ID' => 'Disable item with entity ID',
      'drush foldershare-disabled --enable ID' => 'Enable item with entity ID',
      'drush foldershare-disabled --enableall' => 'Enable all items',
    ],
    'drupal dependencies' => [
      'foldershare',
    ],
    'bootstrap'   => DRUSH_BOOTSTRAP_DRUPAL_FULL,
    'category'    => 'San Diego Supercomputer Center (SDSC)',
  ];
 
  $commands['foldershare-fsck'] = [
    'description' => 'Find and fix file system problems.',
    'aliases'     => [
      'fsfsck',
    ],
    'options'     => [
      'fix'       => [
        'description' => 'Automatically fix problems',
      ],
    ],
    'examples'    => [
      'drush foldershare-fsck' => 'Find file system problems',
      'drush foldershare-fsck --fix' => 'Find and fix file system problems',
    ],
    'drupal dependencies' => [
      'foldershare',
    ],
    'bootstrap'   => DRUSH_BOOTSTRAP_DRUPAL_FULL,
    'category'    => 'San Diego Supercomputer Center (SDSC)',
  ];
 
  $commands['foldershare-hidden'] = [
    'description' => 'List, hide, or show items marked as "hidden".',
    'hidden'      => TRUE,
    'aliases'     => [
      'fshide',
      'fshidden',
    ],
    'arguments'   => [
      'id'        => [
        'description' => 'The entity ID to hide or show',
      ],
    ],
    'options'     => [
      'hide'      => [
        'description' => 'Hide an item',
      ],
      'list'      => [
        'description' => 'List all hidden items',
      ],
      'show'      => [
        'description' => 'show an item',
      ],
      'showall'   => [
        'description' => 'show all hidden items',
      ],
    ],
    'examples'    => [
      'drush foldershare-hidden' => 'List hidden items',
      'drush foldershare-hidden --list' => 'List hidden items',
      'drush foldershare-hidden --hide ID' => 'Hide item with entity ID',
      'drush foldershare-hidden --show ID' => 'Show item with entity ID',
      'drush foldershare-hidden --showall' => 'Show all items',
    ],
    'drupal dependencies' => [
      'foldershare',
    ],
    'bootstrap'   => DRUSH_BOOTSTRAP_DRUPAL_FULL,
    'category'    => 'San Diego Supercomputer Center (SDSC)',
  ];
 
  $commands['foldershare-lock'] = [
    'description' => 'List, acquire, or release locks.',
    'hidden'      => TRUE,
    'aliases'     => [
      'foldershare-locks',
      'fslock',
      'fslocks',
    ],
    'arguments'   => [
      'id'        => [
        'description' => "The root entity ID to lock or unlock",
      ],
    ],
    'options'     => [
      'list'       => [
        'description' => 'List root folder locks',
      ],
      'lock'       => [
        'description' => 'Lock the root folder of an item',
      ],
      'unlock'       => [
        'description' => 'Unlock the root folder of an item',
      ],
      'unlockall'       => [
        'description' => 'Unlock all root folders',
      ],
    ],
    'examples'    => [
      'drush foldershare-lock' => 'List locked root items',
      'drush foldershare-lock --list' => 'List locked root items',
      'drush foldershare-lock --lock ID' => 'Lock root item with entity ID',
      'drush foldershare-lock --unlock ID' => 'Unlock root item with entity ID',
      'drush foldershare-lock --unlockall' => 'Unlock all root items',
    ],
    'drupal dependencies' => [
      'foldershare',
    ],
    'bootstrap'   => DRUSH_BOOTSTRAP_DRUPAL_FULL,
    'category'    => 'San Diego Supercomputer Center (SDSC)',
  ];
 
  $commands['foldershare-config'] = [
    'description' => 'List module config.',
    'aliases'     => [
      'fsconfig',
    ],
    'examples'    => [
      'drush foldershare-config' => 'List configuration',
    ],
    'drupal dependencies' => [
      'foldershare',
    ],
    'bootstrap'   => DRUSH_BOOTSTRAP_DRUPAL_FULL,
    'category'    => 'San Diego Supercomputer Center (SDSC)',
  ];
 
  $commands['foldershare-tasks'] = [
    'description' => 'List, run, and delete module tasks.',
    'hidden'      => TRUE,
    'aliases'     => [
      'fstasks',
    ],
    'options'     => [
      'list'      => [
        'description' => 'List scheduled tasks',
      ],
      'delete'    => [
        'description' => 'Delete a task by its ID',
      ],
      'deleteall' => [
        'description' => 'Delete all tasks',
      ],
      'run'       => [
        'description' => 'Run tasks that are ready',
      ],
    ],
    'arguments'   => [
      'id'        => [
        'description' => "The ID of a task",
      ],
    ],
    'examples'    => [
      'drush foldershare-tasks' => 'List scheduled tasks',
      'drush foldershare-tasks --list' => 'List scheduled tasks',
      'drush foldershare-tasks --run' => 'Run ready scheduled tasks',
    ],
    'drupal dependencies' => [
      'foldershare',
    ],
    'bootstrap'   => DRUSH_BOOTSTRAP_DRUPAL_FULL,
    'category'    => 'San Diego Supercomputer Center (SDSC)',
  ];
 
  $commands['foldershare-usage'] = [
    'description' => 'List module usage by user.',
    'aliases'     => [
      'fsusage',
    ],
    'options'     => [
      'list'      => [
        'description' => 'List usage per user',
      ],
      'update'    => [
        'description' => 'Update the usage table',
      ],
    ],
    'examples'    => [
      'drush foldershare-usage' => 'List usage per user',
      'drush foldershare-usage --list' => 'List usage per user',
      'drush foldershare-usage --update' => 'Update the usage table',
    ],
    'drupal dependencies' => [
      'foldershare',
    ],
    'bootstrap'   => DRUSH_BOOTSTRAP_DRUPAL_FULL,
    'category'    => 'San Diego Supercomputer Center (SDSC)',
  ];
 
  $commands['foldershare-version'] = [
    'description' => 'Show module version number.',
    'aliases'     => [
      'fsversion',
    ],
    'examples'    => [
      'drush foldershare-version' => 'Show version number',
    ],
    'drupal dependencies' => [
      'foldershare',
    ],
    'bootstrap'   => DRUSH_BOOTSTRAP_DRUPAL_FULL,
    'category'    => 'San Diego Supercomputer Center (SDSC)',
  ];
 
  $commands['foldershare-benchmark'] = [
    'description' => 'Benchmark selected module features.',
    'hidden'      => TRUE,
    'aliases'     => [
      'fsbench',
      'fsbenchmark',
    ],
    'options'     => [
      'folder'    => [
        'description' => 'Benchmark folder create and delete',
      ],
      'lock'    => [
        'description' => 'Benchmark process lock and release',
      ],
      'config'    => [
        'description' => 'Benchmark get and set of configuration',
      ],
      'system'    => [
        'description' => 'Benchmark misc system calls',
      ],
    ],
    'drupal dependencies' => [
      'foldershare',
    ],
    'bootstrap'   => DRUSH_BOOTSTRAP_DRUPAL_FULL,
    'category'    => 'San Diego Supercomputer Center (SDSC)',
  ];
 
  return $commands;
}
 
/*---------------------------------------------------------------------
 *
 * Help.
 *
 *---------------------------------------------------------------------*/
 
/**
 * Lists available commands.
 */
function drush_foldershare() {
  FolderShareScheduledTask::setTaskExecutionEnabled(FALSE);
 
  $showAll = (empty(drush_get_option('all')) === FALSE);
 
  drush_print(
    dt('FolderShare: Commands for the module:'));
  drush_print(sprintf(
    "  %-22s %s",
    "foldershare",
    dt("List these commands.")));
  if ($showAll === TRUE) {
    drush_print(sprintf(
      "  %-22s %s",
      "foldershare-admin",
      dt("Perform administrative operations.")));
  }
  if ($showAll === TRUE) {
    drush_print(sprintf(
      "  %-22s %s",
      "foldershare-benchmark",
      dt("Benchmark selected module features.")));
  }
  if ($showAll === TRUE) {
    drush_print(sprintf(
      "  %-22s %s",
      "foldershare-disabled",
      dt('List, enable, and disable items marked as "disabled".')));
  }
  drush_print(sprintf(
    "  %-22s %s",
    "foldershare-fsck",
    dt("Find and fix filesystem problems.")));
  if ($showAll === TRUE) {
    drush_print(sprintf(
      "  %-22s %s",
      "foldershare-hidden",
      dt('List, enable, and disable items marked as "hidden".')));
  }
  if ($showAll === TRUE) {
    drush_print(sprintf(
      "  %-22s %s",
      "foldershare-locks",
      dt('List, aquire, and release locks.')));
  }
  drush_print(sprintf(
    "  %-22s %s",
    "foldershare-config",
    dt("List module configuration.")));
  if ($showAll === TRUE) {
    drush_print(sprintf(
      "  %-22s %s",
      "foldershare-tasks",
      dt('List, run, and delete module tasks.')));
  }
  drush_print(sprintf(
    "  %-22s %s",
    "foldershare-usage",
    dt("List module usage by user.")));
  drush_print(sprintf(
    "  %-22s %s",
    "foldershare-version",
    dt("Show module version number.")));
}
 
/*---------------------------------------------------------------------
 *
 * Admin - delete and change owner.
 *
 *---------------------------------------------------------------------*/
 
/**
 * Performs administrative operations.
 *
 * --changeownerby Changes ownership of all content owned by a user.
 * --deleteall     Deletes all content.
 * --deleteby      Deletes all content owned by a user.
 * --unsharewith   Remove the user from all sharing grants.
 *
 * @param int $uid
 *   (optional, default = (-1)) The user entity ID of the affected user.
 * @param int $newuid
 *   (optional, default = (-1)) The user entity ID of the new owner of
 *   content, for changeownerall.
 */
function drush_foldershare_admin($uid = (-1), $newuid = (-1)) {
  FolderShareScheduledTask::setTaskExecutionEnabled(FALSE);
 
  if (empty(drush_get_option('deleteall')) === FALSE &&
      empty(drush_get_option('deleteby')) === FALSE &&
      empty(drush_get_option('unsharewith')) === FALSE &&
      empty(drush_get_option('changeownerby')) === FALSE) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt("  Too many FolderShare admin options. Only one allowed."));
    drush_print(dt('  Type "drush help foldershare-admin" for admin options.'));
    return;
  }
 
  if (empty(drush_get_option('deleteall')) === FALSE) {
    drush_foldershare_admin_deleteall($uid, $newuid);
    return;
  }
 
  if (empty(drush_get_option('deleteby')) === FALSE) {
    drush_foldershare_admin_deleteby($uid, $newuid);
    return;
  }
 
  if (empty(drush_get_option('changeownerby')) === FALSE) {
    drush_foldershare_admin_changeownerby($uid, $newuid);
    return;
  }
 
  if (empty(drush_get_option('unsharewith')) === FALSE) {
    drush_foldershare_admin_unsharewith($uid, $newuid);
    return;
  }
 
  drush_print(dt("FolderShare: Error"));
  drush_print(dt("  Missing or unrecognized admin option."));
  drush_print(dt('  Type "drush help foldershare-admin" for admin options.'));
}
 
/**
 * Performs an administrative "delete all".
 *
 * @param int $uid
 *   Should always be -1.
 * @param int $newuid
 *   Should always be -1.
 */
function drush_foldershare_admin_deleteall($uid, $newuid) {
  //
  // Validate.
  // ---------
  // There should be no user IDs.
  if ($uid !== (-1) || $newuid !== (-1)) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt("  The --deleteall option does not require a user ID, but one was provided."));
    drush_print(dt("  Did you mean to use --deleteby?"));
    drush_print(dt('  Type "drush help foldershare-admin" for admin options.'));
    return;
  }
 
  //
  // Explain.
  // --------
  // Explain what will happen and to how much content.
  drush_print(dt("FolderShare: Delete all"));
  drush_print('------------------------------------------------------------------------');
  drush_print(dt("All FolderShare files and folders will be deleted immediately!"));
  drush_print("");
  drush_print(dt("Checking the number of items to delete..."));
 
  $nFiles = FolderShare::countNumberOfFiles(FolderShare::ANY_USER_ID);
  $nFolders = FolderShare::countNumberOfFolders(FolderShare::ANY_USER_ID);
  if (($nFiles + $nFolders) === 0) {
    drush_print(dt("... none! There are no files or folders to delete."));
    return;
  }
 
  drush_print(dt(
    "... @nFiles files and @nFolders folders.",
    [
      '@nFiles'   => $nFiles,
      '@nFolders' => $nFolders,
    ]));
  drush_print("");
 
  // Prompt.
  $answer = readline(dt("Are you sure [y|n]? "));
  if ($answer[0] !== 'y') {
    drush_print(dt("Aborted."));
    return;
  }
 
  // Execute.
  drush_print("");
  drush_print(dt("Deleting all content."));
  drush_print(dt("This may take a few minutes..."));
 
  FolderShare::deleteAll(FolderShare::ANY_USER_ID);
 
  drush_print(dt("Done."));
}
 
/**
 * Performs an administrative "delete by".
 *
 * @param int $uid
 *   A valid user ID.
 * @param int $newuid
 *   Should always be -1.
 */
function drush_foldershare_admin_deleteby($uid, $newuid) {
  // Validate that there is a UID.
  if ($uid < 0) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt('  The --deleteby option requires a user ID.'));
    drush_print(dt('  Type "drush help foldershare-admin" for admin options.'));
    return;
  }
 
  $uidEntity = User::load($uid);
  if ($uidEntity === NULL) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt(
      "  The ID @uid does not match any known user.",
      [
        '@uid' => $uid,
      ]));
    return;
  }
 
  // Validate that there is no second UID.
  if ($newuid !== (-1)) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt("  The --deleteby option does not require a second user ID, but one was provided."));
    drush_print(dt('  Type "drush help foldershare-admin" for admin options.'));
    return;
  }
 
  // Explain.
  drush_print(dt(
    "FolderShare: Delete all items owned by @uidName (@uid)",
    [
      '@uid'     => $uid,
      '@uidName' => $uidEntity->getDisplayName(),
    ]));
  drush_print('------------------------------------------------------------------------');
  drush_print(dt("All FolderShare files and folders owned by the user will be deleted."));
  drush_print(dt("immediately."));
  drush_print("");
  drush_print(dt("This can delete content owned by other users! When a folder is"));
  drush_print(dt("deleted, everything inside it is deleted too, even if it is owned by"));
  drush_print(dt("another user."));
  drush_print("");
  drush_print(dt("This can delete content inside folders owned by other users! Files"));
  drush_print(dt("and folders owned by the user but in another user's folders will be"));
  drush_print(dt("deleted too."));
  drush_print("");
  drush_print(dt("Checking the number of items to delete..."));
 
  // Validate that there is content.
  $nFiles = FolderShare::countNumberOfFiles($uid);
  $nFolders = FolderShare::countNumberOfFolders($uid);
  if (($nFiles + $nFolders) === 0) {
    drush_print(dt("... none! The user has no files or folders to delete."));
    return;
  }
 
  drush_print(dt(
    "... @nFiles files and @nFolders folders.",
    [
      '@nFiles'   => $nFiles,
      '@nFolders' => $nFolders,
    ]));
  drush_print("");
 
  // Prompt.
  $answer = readline(dt("Are you sure [y|n]? "));
  if ($answer[0] !== 'y') {
    drush_print(dt("Aborted."));
    return;
  }
 
  // Execute.
  drush_print("");
  drush_print(dt("Deleting all content owned by @uidName (@uid).",
    [
      '@uid'     => $uid,
      '@uidName' => $uidEntity->getDisplayName(),
    ]));
  drush_print(dt("This may take a few minutes..."));
 
  FolderShare::deleteAll($uid);
 
  drush_print(dt("Done."));
}
 
/**
 * Performs an administrative "change owner by".
 *
 * @param int $uid
 *   A valid user ID for the owner of content.
 * @param int $newuid
 *   A valid user ID for the new owner of the content.
 */
function drush_foldershare_admin_changeownerby($uid, $newuid) {
  // Validate that there are two user IDs.
  if ($uid < 0) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt('  The --changeownerall option requires a source user ID.'));
    drush_print(dt('  Type "drush help foldershare-admin" for admin options.'));
    return;
  }
  if ($newuid < 0) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt('  The --changeownerall option requires a destination user ID.'));
    drush_print(dt('  Type "drush help foldershare-admin" for admin options.'));
    return;
  }
 
  $uidEntity = User::load($uid);
  if ($uidEntity === NULL) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt(
      "  The ID @uid does not match any known user.",
      [
        '@uid' => $uid,
      ]));
    return;
  }
 
  $newuidEntity = User::load($newuid);
  if ($newuidEntity === NULL) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt(
      "  The ID @newuid does not match any known user.",
      [
        '@newuid' => $newuid,
      ]));
    return;
  }
 
  // Explain.
  drush_print("");
  drush_print(dt(
    "FolderShare: Change all items owned by @uidName (@uid)",
    [
      '@uid'        => $uid,
      '@uidName'    => $uidEntity->getDisplayName(),
    ]));
  drush_print(dt("  to be owned by @newuidName (@newuid)",
    [
      '@newuid'     => $newuid,
      '@newuidName' => $newuidEntity->getDisplayName(),
    ]));
  drush_print('------------------------------------------------------------------------');
  drush_print(dt("All FolderShare files and folders owned by the first user will be"));
  drush_print(dt("changed immediately to be owned by the second user."));
  drush_print("");
  drush_print(dt("Checking the number of items to change..."));
 
  // Validate that there is content.
  $nFiles = FolderShare::countNumberOfFiles($uid);
  $nFolders = FolderShare::countNumberOfFolders($uid);
  if (($nFiles + $nFolders) === 0) {
    drush_print(dt("... none! The user has no files or folders to change."));
    return;
  }
 
  drush_print(dt(
    "... @nFiles files and @nFolders folders.",
    [
      '@nFiles'   => $nFiles,
      '@nFolders' => $nFolders,
    ]));
  drush_print("");
 
  // Prompt.
  $answer = readline(dt("Are you sure [y|n]? "));
  if ($answer[0] !== 'y') {
    drush_print(dt("Aborted."));
    return;
  }
 
  // Execute.
  drush_print("");
  drush_print(dt(
    "Changing all content owned by @uidName (@uid() to be owned by @newuidName (@newuid).",
    [
      '@uid'        => $uid,
      '@uidName'    => $uidEntity->getDisplayName(),
      '@newuid'     => $newuid,
      '@newuidName' => $newuidEntity->getDisplayName(),
    ]));
  drush_print(dt("This may take a few minutes..."));
  drush_print("");
 
  FolderShare::changeAllOwnerIdByUser($uid, $newuid);
 
  drush_print(dt("Done."));
}
 
/**
 * Performs an administrative "unshare with".
 *
 * @param int $uid
 *   A valid user ID for the owner of content.
 */
function drush_foldershare_admin_unsharewith($uid) {
  // Validate that there are two user IDs.
  if ($uid < 0) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt('  The --unsharewith option requires a user ID.'));
    drush_print(dt('  Type "drush help foldershare-admin" for admin options.'));
    return;
  }
 
  $uidEntity = User::load($uid);
  if ($uidEntity === NULL) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt(
      "  The ID @uid does not match any known user.",
      [
        '@uid' => $uid,
      ]));
    return;
  }
 
  // Explain.
  drush_print(dt(
    "FolderShare: Remove @uidName (@uid) from all sharing grants",
    [
      '@uid'        => $uid,
      '@uidName'    => $uidEntity->getDisplayName(),
    ]));
  drush_print('------------------------------------------------------------------------');
  drush_print(dt("The user will be removed from all items owned by others that grant the"));
  drush_print(dt("user shared access."));
  drush_print("");
 
  // Prompt.
  $answer = readline(dt("Are you sure [y|n]? "));
  if ($answer[0] !== 'y') {
    drush_print(dt("Aborted."));
    return;
  }
 
  // Execute.
  drush_print("");
  drush_print(dt(
    "Unsharing @uidName (@uid) from all shared content.",
    [
      '@uid'     => $uid,
      '@uidName' => $uidEntity->getDisplayName(),
    ]));
  drush_print(dt("This may take a few minutes..."));
  drush_print("");
 
  FolderShare::unshareFromAll($uid);
 
  drush_print(dt("Done."));
}
 
/*---------------------------------------------------------------------
 *
 * Fix - disabled flags.
 *
 *---------------------------------------------------------------------*/
 
/**
 * Performs operations to list, enable, and disable items.
 *
 * --enable     Enable an item.
 * --enableall  Enable all items.
 * --disable    Disable an item.
 * --list       (default) List all hidden items.
 *
 * @param int $id
 *   (optional, default = (-1)) The FolderShare entity ID to enable or
 *   disable. The $id is ignored if the 'list' option is used, and
 *   required for the 'enable' and 'disable' options.
 */
function drush_foldershare_disabled($id = (-1)) {
  FolderShareScheduledTask::setTaskExecutionEnabled(FALSE);
 
  if (empty(drush_get_option('enableall')) === FALSE) {
    drush_foldershare_disabled_enableall();
    return;
  }
 
  if (empty(drush_get_option('enable')) === FALSE) {
    drush_foldershare_disabled_enable($id);
    return;
  }
 
  if (empty(drush_get_option('disable')) === FALSE) {
    drush_foldershare_disabled_disable($id);
    return;
  }
 
  // Default to a list.
  drush_foldershare_disabled_list();
}
 
/**
 * Performs a disabled item list.
 */
function drush_foldershare_disabled_list() {
  // Table heading.
  drush_print(dt('FolderShare: Disabled files and folders'));
  drush_print(sprintf(
    "%-20s %10s %s",
    'Owner',
    'Entity ID',
    'Path'));
  drush_print(sprintf(
    "%-20s %10s %s",
    '--------------------',
    '----------',
    '---------------------------------------------'));
 
  // Get a list of everything that is disabled. Typically this is a
  // very short list, but it might not be.
  $disabledIds = FolderShare::findAllDisabledIds();
  if (count($disabledIds) === 0) {
    drush_print(dt("None."));
    return;
  }
 
  // List each item.
  foreach ($disabledIds as $id) {
    $item = FolderShare::load($id);
    if ($item === NULL) {
      // The item does not exist.
      continue;
    }
 
    $ownerId = $item->getOwnerId();
    $path = $item->getPath();
    if ($item->isFolder() === TRUE) {
      $path .= '/';
    }
 
    $u = User::load($ownerId);
    if ($u === NULL) {
      $ownerName = sprintf('%s (%d)', dt('unknown'), $ownerId);
    }
    else {
      $ownerName = sprintf('%s (%d)', $u->getDisplayName(), $ownerId);
    }
 
    drush_print(sprintf(
      "%-20s %10d %s",
      $ownerName,
      $id,
      $path));
  }
}
 
/**
 * Performs an enable on all disabled items.
 */
function drush_foldershare_disabled_enableall() {
  // Explain.
  drush_print(dt("FolderShare: Enable all disabled items"));
  drush_print('------------------------------------------------------------------------');
  drush_print(dt("WARNING: Items marked disabled are being used by operations such as a"));
  drush_print(dt("copy or move. The mark also is used by copy operations to keep track"));
  drush_print(dt("of their progress. Manually enabling all disabled items will cause"));
  drush_print(dt("them to become available for new operations and corrupt marks used"));
  drush_print(dt("for copy operations already in progress. This can cause operations"));
  drush_print(dt("to collide and make copy operations end prematurely."));
  drush_print("");
  drush_print(dt("  ** This can corrupt the file system **"));
  drush_print("");
  drush_print(dt("Enabling all items manually should only be done during debugging."));
  drush_print("");
 
  // Prompt.
  $answer = readline(dt("Are you sure [y|n]? "));
  if ($answer[0] !== 'y') {
    drush_print(dt("Aborted."));
    return;
  }
 
  // Execute.
  drush_print("");
  drush_print(dt("Enabling all disabled items."));
  drush_print(dt("  This may take a few minutes..."));
  $nChanged = FolderShare::clearAllSystemDisabled();
 
  // Flush the entity cache so that it is not out of date compared to
  // the now-marked entities in the database.
  \Drupal::entityTypeManager()->getStorage(FolderShare::ENTITY_TYPE_ID)
    ->resetCache(NULL);
 
  \Drupal::service('cache.render')->invalidateAll();
  if ($nChanged === 0) {
    drush_print(dt("Done. No items were changed."));
  }
  else {
    drush_print(dt(
      "Done. @count items were changed.",
      [
        '@count' => $nChanged,
      ]));
  }
}
 
/**
 * Performs an enable on a specified item.
 *
 * @param int $id
 *   The FolderShare entity ID to enable.
 */
function drush_foldershare_disabled_enable($id = (-1)) {
  // Validate entity ID.
  $id = (int) $id;
  if ($id < 0) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt('  Missing entity ID to enable.'));
    return;
  }
 
  $item = FolderShare::load($id);
  if ($item === NULL) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt(
      "  The entity ID @id does not match any known content.",
      [
        '@id' => $id,
      ]));
    return;
  }
 
  $path = $item->getPath();
  if ($item->isFolder() === TRUE) {
    $path .= '/';
  }
 
  // Explain.
  drush_print(dt(
    "FolderShare: Enable item ID @id at @path",
    [
      '@id'   => $id,
      '@path' => $path,
    ]));
  drush_print('------------------------------------------------------------------------');
  drush_print(dt("WARNING: Items marked disabled are being used by operations such as a"));
  drush_print(dt("copy or move. The mark also is used by copy operations to keep track"));
  drush_print(dt("of their progress. Manually enabling a disabled item will cause it"));
  drush_print(dt("to become available for new operations that can collide if a prior"));
  drush_print(dt("operation is still in progres. This also can cause copy operations"));
  drush_print(dt("to end prematurely and leave some content uncopied. The premature end"));
  drush_print(dt("will not alert the user that the copied item is invalid."));
  drush_print("");
  drush_print(dt("  ** This can corrupt the file system **"));
  drush_print("");
  drush_print(dt("Enabling an item manually should only be done during debugging."));
  drush_print("");
 
  // Prompt.
  $answer = readline(dt("Are you sure [y|n]? "));
  if ($answer[0] !== 'y') {
    drush_print(dt("Aborted."));
    return;
  }
 
  // Execute.
  drush_print("");
  drush_print(dt(
    "Enabling ID @id at @path...",
    [
      '@id'   => $id,
      '@path' => $path,
    ]));
  $item->setSystemDisabled(FALSE);
  $item->save();
 
  drush_print(dt("Done. One item was changed."));
}
 
/**
 * Performs a disable on a specified item.
 *
 * @param int $id
 *   The FolderShare entity ID to disable.
 */
function drush_foldershare_disabled_disable($id = (-1)) {
  // Validate entity ID.
  $id = (int) $id;
  if ($id < 0) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt('  Missing entity ID to disable.'));
    return;
  }
 
  $item = FolderShare::load($id);
  if ($item === NULL) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt(
      "  The entity ID @id does not match any known content.",
      [
        '@id' => $id,
      ]));
    return;
  }
 
  $path = $item->getPath();
  if ($item->isFolder() === TRUE) {
    $path .= '/';
  }
 
  // Explain.
  drush_print(dt(
    "FolderShare: Disable item ID @id at @path",
    [
      '@id'   => $id,
      '@path' => $path,
    ]));
  drush_print('------------------------------------------------------------------------');
  drush_print(dt("WARNING: Disabling an item will prevent users, including administrators,"));
  drush_print(dt("from starting new operations using it. This includes viewing,"));
  drush_print(dt("downloading, moving, copying, and deleting. The item will remain"));
  drush_print(dt("visible in lists and show a spinner. Normally the spinner goes away"));
  drush_print(dt("when an operation enables the item after it completes. But with a"));
  drush_print(dt("manually disabled item, there is no associated operation to enable"));
  drush_print(dt("item again. The item will remain disabled and the spinner will run"));
  drush_print(dt("indefinitely. This is like to cause user confusion."));
  drush_print("");
  drush_print(dt("Disabling an item manually should only be done during debugging."));
  drush_print("");
 
  // Prompt.
  $answer = readline(dt("Are you sure [y|n]? "));
  if ($answer[0] !== 'y') {
    drush_print(dt("Aborted."));
    return;
  }
 
  // Execute.
  drush_print("");
  drush_print(dt(
    "Disabling ID @id at @path...",
    [
      '@id'   => $id,
      '@path' => $path,
    ]));
  $item->setSystemDisabled(TRUE);
  $item->save();
 
  drush_print(dt("Done. One item was changed."));
}
 
/*---------------------------------------------------------------------
 *
 * Fix - hidden flags.
 *
 *---------------------------------------------------------------------*/
 
/**
 * Performs operations to list, show, and hide items.
 *
 * --hide       Hide a non-hidden item.
 * --list       (default) List all hidden items.
 * --show       Show a hidden item.
 * --showall    Show all hidden items.
 *
 * @param int $id
 *   (optional, default = (-1)) The FolderShare entity ID to show or
 *   hide. The $id is ignored if the 'list' option is used, and
 *   required for the 'show' and 'hide' options.
 */
function drush_foldershare_hidden($id = (-1)) {
  FolderShareScheduledTask::setTaskExecutionEnabled(FALSE);
 
  if (empty(drush_get_option('showall')) === FALSE) {
    drush_foldershare_hidden_showall();
    return;
  }
 
  if (empty(drush_get_option('show')) === FALSE) {
    drush_foldershare_hidden_show($id);
    return;
  }
 
  if (empty(drush_get_option('hide')) === FALSE) {
    drush_foldershare_hidden_hide($id);
    return;
  }
 
  // Default to a list.
  drush_foldershare_hidden_list();
}
 
/**
 * Performs a hidden item list.
 */
function drush_foldershare_hidden_list() {
  // Table heading.
  drush_print(dt('FolderShare: Hidden files and folders'));
  drush_print(sprintf(
    "%-20s %10s %s",
    dt('Owner'),
    dt('Entity ID'),
    dt('Path')));
  drush_print(sprintf(
    "%-20s %10s %s",
    '--------------------',
    '----------',
    '---------------------------------------------'));
 
  // Get a list of everything that is hidden. Typically this is a
  // very short list, but it might not be.
  $hiddenIds = FolderShare::findAllHiddenIds();
  if (count($hiddenIds) === 0) {
    drush_print(dt("None."));
    return;
  }
 
  // List each item.
  foreach ($hiddenIds as $id) {
    $item = FolderShare::load($id);
    if ($item === NULL) {
      // The item does not exist.
      continue;
    }
 
    $ownerId = $item->getOwnerId();
    $path = $item->getPath();
    if ($item->isFolder() === TRUE) {
      $path .= '/';
    }
 
    $u = User::load($ownerId);
    if ($u === NULL) {
      $ownerName = sprintf('%s (%d)', dt('unknown'), $ownerId);
    }
    else {
      $ownerName = sprintf('%s (%d)', $u->getDisplayName(), $ownerId);
    }
 
    drush_print(sprintf(
      "%-20s %10d %s",
      $ownerName,
      $id,
      $path));
  }
}
 
/**
 * Performs a show on all hidden items.
 */
function drush_foldershare_hidden_showall() {
  // Explain.
  drush_print(dt("FolderShare: Show all items"));
  drush_print('------------------------------------------------------------------------');
  drush_print(dt("WARNING: Items marked hidden are in the process of being deleted."));
  drush_print(dt("Manually marking all hidden items as visible will let users see the"));
  drush_print(dt("items as they are being deleted, but it will not abort the delete."));
  drush_print(dt("This can be confusing to users and it can cause problems if a user"));
  drush_print(dt("tries to use an item just as it is being deleted."));
  drush_print("");
  drush_print(dt("Showing hidden items should only be done during debugging."));
  drush_print("");
 
  // Prompt.
  $answer = readline(dt("Are you sure [y|n]? "));
  if ($answer[0] !== 'y') {
    drush_print(dt("Aborted."));
    return;
  }
 
  // Execute.
  drush_print("");
  drush_print(dt("Showing all hidden items."));
  drush_print(dt("  This may take a few minutes..."));
  $nChanged = FolderShare::clearAllSystemHidden();
 
  // Flush the entity cache so that it is not out of date compared to
  // the now-marked entities in the database.
  \Drupal::entityTypeManager()->getStorage(FolderShare::ENTITY_TYPE_ID)
    ->resetCache(NULL);
 
  \Drupal::service('cache.render')->invalidateAll();
 
  if ($nChanged === 0) {
    drush_print(dt("Done. No items were changed."));
  }
  else {
    drush_print(dt(
      "Done. @count items were changed.",
      [
        '@count' => $nChanged,
      ]));
  }
}
 
/**
 * Performs a show on a selected item.
 *
 * @param int $id
 *   A valid FolderShare entity ID.
 */
function drush_foldershare_hidden_show($id) {
  // Validate entity ID.
  $id = (int) $id;
  if ($id < 0) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt('  Missing entity ID to show.'));
    return;
  }
 
  $item = FolderShare::load($id);
  if ($item === NULL) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt(
      "  The entity ID @id does not match any known content.",
      [
        '@id' => $id,
      ]));
    return;
  }
 
  $path = $item->getPath();
  if ($item->isFolder() === TRUE) {
    $path .= '/';
  }
 
  drush_print(dt(
    "FolderShare: Show item ID @id at @path",
    [
      '@id'   => $id,
      '@path' => $path,
    ]));
  drush_print('------------------------------------------------------------------------');
  drush_print(dt("WARNING: Items marked hidden are in the process of being deleted."));
  drush_print(dt("Manually marking a hidden item as visible will let users see the item"));
  drush_print(dt("before it is deleted, but it will not abort the delete. This can be"));
  drush_print(dt("confusing to users and it can cause problems if a user tries to use an"));
  drush_print(dt("item just as it is being deleted."));
  drush_print("");
  drush_print(dt("Showing hidden items should only be done during debugging."));
  drush_print("");
 
  // Prompt.
  $answer = readline(dt("Are you sure [y|n]? "));
  if ($answer[0] !== 'y') {
    drush_print(dt("Aborted."));
    return;
  }
 
  // Execute.
  drush_print("");
  drush_print(dt(
    'Showing ID @id at @path...',
    [
      '@id'   => $id,
      '@path' => $path,
    ]));
  $item->setSystemHidden(FALSE);
  $item->save();
 
  // Flush the entity cache so that it is not out of date compared to
  // the now-marked entities in the database.
  \Drupal::entityTypeManager()->getStorage(FolderShare::ENTITY_TYPE_ID)
    ->resetCache(NULL);
 
  \Drupal::service('cache.render')->invalidateAll();
 
  drush_print(dt("Done. One item was changed."));
}
 
/**
 * Performs a hide on a selected item.
 *
 * @param int $id
 *   A valid FolderShare entity ID.
 */
function drush_foldershare_hidden_hide($id) {
  // Validate entity ID.
  $id = (int) $id;
  if ($id < 0) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt('  Missing entity ID to hide.'));
    return;
  }
 
  $item = FolderShare::load($id);
  if ($item === NULL) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt(
      "  The entity ID @id does not match any known content.",
      [
        '@id' => $id,
      ]));
    return;
  }
 
  $path = $item->getPath();
  if ($item->isFolder() === TRUE) {
    $path .= '/';
  }
 
  // Explain.
  drush_print(dt(
    "FolderShare: Hide item ID @id at @path",
    [
      '@id'   => $id,
      '@path' => $path,
    ]));
  drush_print('------------------------------------------------------------------------');
  drush_print(dt("WARNING: Items marked hidden are in the process of being deleted."));
  drush_print(dt("Manually marking an item hidden will make it invisible to users, but"));
  drush_print(dt("will not delete it."));
  drush_print("");
  drush_print(dt("Hiding items should only be done during debugging."));
  drush_print("");
 
  // Prompt.
  $answer = readline(dt("Are you sure [y|n]? "));
  if ($answer[0] !== 'y') {
    drush_print(dt("Aborted."));
    return;
  }
 
  // Execute.
  drush_print("");
  drush_print(dt(
    'Hiding ID @id at @path...',
    [
      '@id'   => $id,
      '@path' => $path,
    ]));
  $item->setSystemHidden(TRUE);
  $item->save();
 
  // Flush the entity cache so that it is not out of date compared to
  // the now-marked entities in the database.
  \Drupal::entityTypeManager()->getStorage(FolderShare::ENTITY_TYPE_ID)
    ->resetCache(NULL);
 
  \Drupal::service('cache.render')->invalidateAll();
 
  drush_print(dt("Done. One item was changed."));
}
 
/*---------------------------------------------------------------------
 *
 * Fix - root locks.
 *
 *---------------------------------------------------------------------*/
 
/**
 * Performs operations to list, lock, and unlock exclusive access locks.
 *
 * --list       (default) List all root locks.
 * --lock       Lock a root.
 * --unlock     Unlock a root.
 */
function drush_foldershare_lock($id = (-1)) {
  FolderShareScheduledTask::setTaskExecutionEnabled(FALSE);
 
  if (empty(drush_get_option('lock')) === FALSE) {
    drush_foldershare_lock_lock($id);
    return;
  }
 
  if (empty(drush_get_option('unlock')) === FALSE) {
    drush_foldershare_lock_unlock($id);
    return;
  }
 
  // Default to a list.
  drush_foldershare_lock_list();
}
 
/**
 * Performs a lock list.
 */
function drush_foldershare_lock_list() {
  // Table heading.
  drush_print(dt('FolderShare: Locked root items'));
  drush_print(sprintf(
    "%-20s %10s %s",
    dt('Owner'),
    dt('Root ID'),
    dt('Path')));
  drush_print(sprintf(
    "%-20s %10s %s",
    '--------------------',
    '----------',
    '---------------------------------------------'));
 
  // Get a list of everything that is disabled. Typically this is a
  // very short list, but it might not be.
  $rootIds = FolderShare::findAllRootItemIds();
  $lockedRootIds = [];
  foreach ($rootIds as $rootId) {
    if (FolderShare::isRootOperationLockAvailable($rootId) === FALSE) {
      $lockedRootIds[] = $rootId;
    }
  }
 
  if (count($lockedRootIds) === 0) {
    drush_print(dt("None."));
    return;
  }
 
  // List each item.
  foreach ($lockedRootIds as $rootId) {
    $item = FolderShare::load($rootId);
    if ($item === NULL) {
      // The item does not exist.
      continue;
    }
 
    $ownerId = $item->getOwnerId();
    $path = $item->getPath();
    if ($item->isFolder() === TRUE) {
      $path .= '/';
    }
 
    $u = User::load($ownerId);
    if ($u === NULL) {
      $ownerName = sprintf('%s (%d)', dt('unknown'), $ownerId);
    }
    else {
      $ownerName = sprintf('%s (%d)', $u->getDisplayName(), $ownerId);
    }
 
    drush_print(sprintf(
      "%-20s %10d %s",
      $ownerName,
      $rootId,
      $path));
  }
}
 
/**
 * Performs a lock on a selected item.
 *
 * @param int $id
 *   The FolderShare entity ID to lock.
 */
function drush_foldershare_lock_lock($id) {
  // Validate entity ID.
  $id = (int) $id;
  if ($id < 0) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt('  Missing entity ID to lock.'));
    return;
  }
 
  $item = FolderShare::load($id);
  if ($item === NULL) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt(
      "  The entity ID @id does not match any known content.",
      [
        '@id' => $id,
      ]));
    return;
  }
 
  if ($item->isRootItem() === FALSE) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt(
      '  The entity ID @id is not a root item and therefore cannot be locked.',
      [
        '@id' => $id,
      ]));
    return;
  }
 
  $path = $item->getPath();
  if ($item->isFolder() === TRUE) {
    $path .= '/';
  }
 
  // Explain.
  drush_print(dt(
    "FolderShare: Lock root ID @id at @path",
    [
      '@id'   => $id,
      '@path' => $path,
    ]));
  drush_print('------------------------------------------------------------------------');
  drush_print(dt("WARNING: Locking a root item will block all further operations on the"));
  drush_print(dt("entire folder tree under the root. Create, copy, delete, move, and"));
  drush_print(dt("other operations will fail for all users, including administrators."));
  drush_print("");
  drush_print(dt("Locking manually should only be done during debugging."));
  drush_print("");
 
  // Prompt.
  $answer = readline(dt("Are you sure [y|n]? "));
  if ($answer[0] !== 'y') {
    drush_print(dt("Aborted."));
    return;
  }
 
  // Execute.
  drush_print("");
  drush_print(dt(
    "Locking root ID @id @path...",
    [
      '@id'   => $id,
      '@path' => $path,
    ]));
  FolderShare::acquireRootOperationLock($id);
 
  drush_print(dt("Done. One lock was changed."));
}
 
/**
 * Performs an unlock on a selected item.
 *
 * @param int $id
 *   The FolderShare entity ID to unlock.
 */
function drush_foldershare_lock_unlock($id) {
  // Validate entity ID.
  $id = (int) $id;
  if ($id < 0) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt('  Missing entity ID to unlock.'));
    return;
  }
 
  $item = FolderShare::load($id);
  if ($item === NULL) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt(
      "  The entity ID @id does not match any known content.",
      [
        '@id' => $id,
      ]));
    return;
  }
 
  if ($item->isRootItem() === FALSE) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt(
      '  The entity ID @id is not a root item and therefore cannot be unlocked.',
      [
        '@id' => $id,
      ]));
    return;
  }
 
  $path = $item->getPath();
  if ($item->isFolder() === TRUE) {
    $path .= '/';
  }
 
  // Explain.
  drush_print(dt(
    "FolderShare: Unlock root ID @id at @path",
    [
      '@id'   => $id,
      '@path' => $path,
    ]));
  drush_print(dt("Unlock item"));
  drush_print('------------------------------------------------------------------------');
  drush_print(dt("WARNING: Unlocking a root item will allow new operations to be started"));
  drush_print(dt("anywhere within the folder tree under the root. If there is a pending"));
  drush_print(dt("operations on anything in the folder tree, a new operation can collide"));
  drush_print(dt("by attempting to change the same files and folders."));
  drush_print("");
  drush_print(dt("  ** This can corrupt the file system **"));
  drush_print("");
  drush_print(dt("Unlocking manually should only be done during debugging."));
  drush_print("");
 
  // Prompt.
  $answer = readline(dt("Are you sure [y|n]? "));
  if ($answer[0] !== 'y') {
    drush_print(dt("Aborted."));
    return;
  }
 
  // Unlock the item.
  drush_print("");
  drush_print(dt(
    "Unlocking root ID @id @path...",
    [
      '@id'   => $id,
      '@path' => $path,
    ]));
  FolderShare::releaseRootOperationLock($id);
 
  drush_print(dt("Done. One lock was changed."));
}
 
/*---------------------------------------------------------------------
 *
 * Fix - file system check.
 *
 *---------------------------------------------------------------------*/
 
/**
 * Checks the file system.
 *
 * --fix        Run file system checks.
 */
function drush_foldershare_fsck() {
  FolderShareScheduledTask::setTaskExecutionEnabled(FALSE);
 
  $fix = (empty(drush_get_option('fix')) === FALSE);
 
  // Scan and possibly fix the file system.
  if ($fix === TRUE) {
    drush_print(dt("FolderShare: File system check and repair"));
    drush_print('------------------------------------------------------------------------');
    drush_print(dt("This may take a few minutes..."));
    drush_print("");
 
    $originalMode = \Drupal::state()->get('system.maintenance_mode');
    if ($originalMode !== 1) {
      drush_print(dt('Entering maintenance mode.'));
      \Drupal::state()->set('system.maintenance_mode', 1);
      drush_print("");
    }
 
    $wereFixed = FolderShare::fsck(TRUE);
 
    if ($originalMode !== 1) {
      drush_print(dt('Exiting maintenance mode.'));
      \Drupal::state()->set('system.maintenance_mode', $originalMode);
      drush_print("");
    }
 
    if ($wereFixed === TRUE) {
      drush_print(dt('Repairs were made.'));
    }
    else {
      drush_print(dt('No repairs were needed or made.'));
    }
  }
  else {
    drush_print(dt('FolderShare: File system check only'));
    drush_print('------------------------------------------------------------------------');
    drush_print(dt('This may take a few minutes...'));
    drush_print("");
 
    $needToBeFixed = FolderShare::fsck(FALSE);
 
    if ($needToBeFixed === TRUE) {
      drush_print(dt('Repairs need to be made.'));
      drush_print(dt('To make repairs, run "drush foldershare-fsck --fix".'));
    }
    else {
      drush_print(dt('No repairs are needed.'));
    }
  }
}
 
/*---------------------------------------------------------------------
 *
 * Module configuration - configuration.
 *
 *---------------------------------------------------------------------*/
 
/**
 * Lists module configuration.
 *
 * The module's configuration is listed, including that of plugins.
 */
function drush_foldershare_config() {
  FolderShareScheduledTask::setTaskExecutionEnabled(FALSE);
 
  $moduleHandler = \Drupal::moduleHandler();
  $typeManager = \Drupal::entityTypeManager();
 
  drush_print(dt("FolderShare configuration"));
  drush_print('------------------------------------------------------------------------');
 
  //
  // Files.
  drush_print(dt("Files:"));
  drush_print('--------------------------------');
  drush_print(sprintf("%-45s %s",
    dt('File system:'),
    Settings::getFileScheme()));
  drush_print(sprintf("%-45s %s",
    dt('New ZIP archive name:'),
    Settings::getNewZipArchiveName()));
  drush_print(sprintf("%-45s %s",
    dt('New ZIP archive comment:'),
    Settings::getNewZipArchiveComment()));
  drush_print(sprintf("%-45s %s",
    dt('ZIP unarchive to subfolder:'),
    (Settings::getZipUnarchiveMultipleToSubfolder() === TRUE) ? 'true' : 'false'));
  drush_print(sprintf("%-45s %s",
    dt('File name extensions restricted:'),
    (Settings::getFileRestrictExtensions() === TRUE) ? 'true' : 'false'));
  drush_print(sprintf("%-45s\n%s",
    dt('Allowed file name extensions (if restricted):'),
    Settings::getAllowedNameExtensions()));
  drush_print("");
 
  //
  // Interface.
  drush_print(dt('User interface:'));
  drush_print('--------------------------------');
  drush_print(sprintf("%-45s %s",
    dt('Command menu restricted:'),
    (Settings::getCommandMenuRestrict() === TRUE) ? 'true' : 'false'));
  drush_print(sprintf("%-45s\n%s",
    dt('Allowed commands (if restricted):'),
    implode(', ', Settings::getCommandMenuAllowed())));
  drush_print(sprintf("%-45s %s",
    dt('Commands report normal completion:'),
    (Settings::getCommandNormalCompletionReportEnable() === TRUE) ? 'true' : 'false'));
  drush_print(sprintf("%-45s %d sec",
    dt('Interface refresh polling interval:'),
    Settings::getStatusPollingInterval()));
  drush_print("");
 
  //
  // Search.
  drush_print(dt('Search:'));
  drush_print('--------------------------------');
 
  if ($moduleHandler->moduleExists('search') === FALSE) {
    drush_print(dt('Drupal core "search" module is not installed.'));
  }
  else {
    try {
      $searchPage = $typeManager->getStorage('search_page')
        ->load('foldershare_search');
      $searchPlugin = $searchPage->getPlugin();
 
      drush_print(sprintf("%-45s %s",
        dt('Include file text in search index:'),
        ($searchPlugin->getSearchFileContent() === TRUE) ? 'true' : 'false'));
      drush_print(sprintf("%-45s %d bytes",
        dt('Maximum file content to index for search:'),
        $searchPlugin->getSearchFileSize()));
      drush_print(sprintf("%-45s %s",
        dt('File types to include in search index:'),
        $searchPlugin->getSearchFileExtensions()));
    }
    catch (\Exception $e) {
      // Ignore.
    }
  }
  drush_print("");
 
  //
  // System.
  drush_print(dt('System:'));
  drush_print('--------------------------------');
  drush_print(sprintf("%-45s %s",
    dt('Activity logging:'),
    (Settings::getActivityLogEnable() === TRUE) ? 'true' : 'false'));
  drush_print(sprintf("%-45s %s",
    dt('Usage update interval:'),
    Settings::getUsageUpdateInterval()));
 
  $t = ManageUsageStatistics::getLastUpdateTime();
  if ($t !== 'never') {
    if ($t[0] === '@') {
      $t = date('Y-m-d H:i:s', intval(substr($t, 1)));
    }
    else {
      $t = date('Y-m-d H:i:s', intval($t));
    }
  }
  drush_print(sprintf("%-45s %s",
    dt('Usage last updated:'),
    $t));
  drush_print(sprintf("%-45s %d sec",
    dt('Content lock duration:'),
    Settings::getContentLockDuration()));
  drush_print(sprintf("%-45s %d sec",
    dt('Operation lock duration:'),
    Settings::getOperationLockDuration()));
  drush_print(sprintf("%-45s %d sec",
    dt('Task initial scheduling delay:'),
    Settings::getScheduledTaskInitialDelay()));
  drush_print(sprintf("%-45s %d sec",
    dt('Task continuation scheduling delay:'),
    Settings::getScheduledTaskContinuationDelay()));
  drush_print(sprintf("%-45s %d sec",
    dt('Task safety-net scheduling delay:'),
    Settings::getScheduledTaskSafetyNetDelay()));
  drush_print(sprintf("%-45s %4.1f %%",
    dt('Memory use limit as % of PHP limit:'),
    100.0 * Settings::getMemoryUseLimitPercentage()));
  drush_print(sprintf("%-45s %4.1f %%",
    dt('Execution time limit as % of PHP limit:'),
    100.0 * Settings::getExecutionTimeLimitPercentage()));
  drush_print("");
 
  //
  // Web services.
  //
  // REST services are provided by a separately installed FolderShare REST
  // module, however the services are associated with FolderShare entities.
  // If those services are installed, list them.
  drush_print(dt('Web services:'));
  drush_print('--------------------------------');
  if (\Drupal::moduleHandler()->moduleExists('rest') === FALSE) {
    drush_print(dt('Drupal core "rest" module not installed.'));
  }
  else {
    try {
      $restPlugin = $typeManager->getStorage('rest_resource_config')
        ->load('entity.foldershare');
 
      if ($restPlugin !== NULL) {
        foreach ($restPlugin->getMethods() as $method) {
          $formats = $restPlugin->getFormats($method);
          $auths = $restPlugin->getAuthenticationPRoviders($method);
 
          drush_print($method);
          drush_print(sprintf("  %-43s %s",
            dt("Serialization formats:"),
            implode(', ', $formats)));
          drush_print(sprintf("  %-43s %s",
            dt("Authentication providers:"),
            implode(', ', $auths)));
        }
      }
    }
    catch (\Exception $e) {
      // Ignore.
    }
  }
 
  drush_print("");
 
  //
  // PHP directives.
  drush_print(dt('Relevant PHP directives:'));
  drush_print('--------------------------------');
  drush_print(sprintf("%-45s %s",
    dt('Max upload file size (upload_max_filesize):'),
    ini_get('upload_max_filesize')));
  drush_print(sprintf("%-45s %d",
    dt('Max # of uploaded files (max_file_uploads):'),
    ini_get('max_file_uploads')));
 
  $t = ini_get('post_max_size');
  if ($t === "0") {
    drush_print(sprintf("%-45s %s",
      dt('Max post message size (post_max_size):'),
      dt('(unlimited)')));
  }
  else {
    drush_print(sprintf("%-45s %s",
      dt('Max post message size (post_max_size):'),
      $t));
  }
 
  $t = (int) ini_get('max_input_time');
  if ($t === (-1)) {
    drush_print(sprintf("%-45s %s",
      dt('Max post processing time (max_input_time):'),
      dt('(uses max_execution_time)')));
  }
  else {
    drush_print(sprintf("%-45s %d sec",
      dt('Max post processing time (max_input_time):'),
      $t));
  }
 
  $t = ini_get('memory_limit');
  if ($t === "-1") {
    drush_print(sprintf("%-45s %s",
      dt('Max memory use (memory_limit):'),
      dt('(unlimited)')));
  }
  else {
    drush_print(sprintf("%-45s %s",
      dt('Max memory use (memory_limit):'),
      $t));
  }
 
  // Drush runs from the command line interpreter, and that always sets the
  // execution time to 0. There is no way to get the value a web-invoked
  // PHP would see.
  drush_print(sprintf("%-45s %s",
    dt('Max execution time (max_execution_time):'),
    dt("(unavailable via drush)")));
}
 
/*---------------------------------------------------------------------
 *
 * Module configuration - tasks.
 *
 *---------------------------------------------------------------------*/
 
/**
 * Performs operations to list, run, and delete tasks.
 *
 * --delete     Delete the indicated task.
 * --deleteall  Delete all scheduled tasks.
 * --list       (default) List all scheduled task entities.
 * --run        Run the scheduled task executor.
 *
 * @param int $id
 *   (optional, default = (-1)) The task entity ID to delete.
 */
function drush_foldershare_tasks($id = -1) {
 
  if (empty(drush_get_option('run')) === FALSE) {
    drush_foldershare_tasks_run();
    return;
  }
 
  FolderShareScheduledTask::setTaskExecutionEnabled(FALSE);
 
  if (empty(drush_get_option('deleteall')) === FALSE) {
    drush_foldershare_tasks_deleteall();
    return;
  }
 
  if (empty(drush_get_option('delete')) === FALSE) {
    drush_foldershare_tasks_delete($id);
    return;
  }
 
  // Default to a list.
  drush_foldershare_tasks_list();
}
 
/**
 * Performs an execution of ready tasks.
 */
function drush_foldershare_tasks_run() {
  drush_print(dt('FolderShare: Executing ready tasks...'));
  FolderShareScheduledTask::setTaskExecutionEnabled(TRUE);
  FolderShareScheduledTask::executeTasks(time());
}
 
/**
 * Performs a deletion of all tasks.
 */
function drush_foldershare_tasks_deleteall() {
  // Explain.
  drush_print(dt("FolderShare: Delete all tasks"));
  drush_print('------------------------------------------------------------------------');
  drush_print(dt("WARNING: Deleting all tasks will leave pending operations incomplete."));
  drush_print(dt("This can stop tasks that are in the middle of deleting, copying,"));
  drush_print(dt("moving, and changing the ownership of content. This will leave locks"));
  drush_print(dt("held, items hidden or disabled, and operations unfinished."));
  drush_print("");
  drush_print(dt("  ** This can corrupt the file system **"));
  drush_print("");
  drush_print(dt("This should be done only when there is something deeply wrong and you"));
  drush_print(dt("are very sure that deleting all tasks is the best thing to do."));
  drush_print("");
 
  drush_print(dt("Checking the number of tasks to delete..."));
  $n = FolderShareScheduledTask::findNumberOfTasks();
  if ($n === 0) {
    drush_print(dt("... none! There are no tasks to delete."));
    return;
  }
 
  drush_print("");
  $answer = readline(dt("Are you sure [y|n]? "));
  if ($answer[0] !== 'y') {
    drush_print(dt("Aborted."));
    return;
  }
 
  // Execute.
  drush_print("");
  drush_print(dt("Deleting all tasks."));
  drush_print(dt("  This may take a few minutes..."));
  FolderShareScheduledTask::deleteAllTasks();
 
  drush_print("");
  drush_print(dt("Done. You should run 'drush foldershare-fsck' immediately to check for file"));
  drush_print(dt("system corruption."));
}
 
/**
 * Performs a deletion of a selected task.
 *
 * @param int $id
 *   The ID of a task to delete.
 */
function drush_foldershare_tasks_delete($id) {
  // Validate entity ID.
  $id = (int) $id;
  if ($id < 0) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt('  Missing task ID to delete.'));
    return;
  }
 
  $task = FolderShareScheduledTask::load($id);
  if ($task === NULL) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt(
      "  The task ID @id does not match any known task.",
      [
        '@id' => $id,
      ]));
    return;
  }
 
  // Explain.
  drush_print(dt("FolderShare: Delete task"));
  drush_print('------------------------------------------------------------------------');
  drush_print(dt("WARNING: Deleting a task will leave a pending operation incomplete."));
  drush_print(dt("This can stop task in the middle of deleting, copying, moving,, and"));
  drush_print(dt("changing the ownership of content. This will leave locks held, items"));
  drush_print(dt("hidden or disabled, and operations unfinished."));
  drush_print("");
  drush_print(dt("  ** This can corrupt the file system **"));
  drush_print("");
 
  // Prompt.
  $answer = readline(dt("Are you sure [y|n]? "));
  if ($answer[0] !== 'y') {
    drush_print(dt("Aborted."));
    return;
  }
 
  // Execute.
  drush_print("");
  drush_print(dt("Deleting task @id...", ['@id' => $id]));
 
  $task->delete();
 
  drush_print("");
  drush_print(dt("Done. You should run 'drush foldershare-fsck' immediately to check for file"));
  drush_print(dt("system corruption."));
}
 
/**
 * Performs a task list.
 */
function drush_foldershare_tasks_list() {
  // Table heading.
  drush_print(dt('FolderShare Scheduled tasks'));
  drush_print(sprintf(
    '%10s %-15s %-80s',
    dt('Task ID'),
    dt('Requester'),
    dt('Callback')));
  drush_print('------------------------------------------------------------------------');
 
  // Get a list of tasks.
  $taskIds = FolderShareScheduledTask::findTaskIds();
 
  if (count($taskIds) === 0) {
    drush_print(dt("None."));
    return;
  }
 
  // List each item.
  foreach ($taskIds as $id) {
    $task = FolderShareScheduledTask::load($id);
    if ($task === NULL) {
      // Task does not exist.
      continue;
    }
 
    $callback      = $task->getCallback();
    $requester     = $task->getRequester();
    $parameters    = $task->getParameters();
    $comments      = $task->getComments();
    $executionTime = $task->getAccumulatedExecutionTime();
    $createdTime   = date('Y-m-d H:i:s', intval($task->getcreatedTime()));
    $scheduledTime = date('Y-m-d H:i:s', intval($task->getScheduledTime()));
    $startTime     = date('Y-m-d H:i:s', intval($task->getStartedTime()));
 
    $u = User::load($requester);
    if ($u === NULL) {
      $requesterName = sprintf('%s (%d)', dt('unknown'), $requester);
    }
    else {
      $requesterName = sprintf('%s (%d)', $u->getDisplayName(), $requester);
    }
 
    drush_print(sprintf(
      '%10d %-15s %-80s',
      $id,
      $requesterName,
      $callback));
 
    drush_print(sprintf(
      '%26s First started   %s',
      "",
      $startTime));
    drush_print(sprintf(
      '%26s Current created %s',
      "",
      $createdTime));
    drush_print(sprintf(
      '%26s Next scheduled  %s',
      "",
      $scheduledTime));
    drush_print(sprintf(
      '%26s Total run time  %d sec',
      "",
      $executionTime));
 
    if (empty($comments) === FALSE) {
      drush_print(sprintf("%26s %s", "", $comments));
    }
    if (empty($parameters) === FALSE) {
      drush_print(sprintf("%26s %s = %s", "", dt('parameters'), $parameters));
    }
    drush_print("");
  }
}
 
/*---------------------------------------------------------------------
 *
 * Module configuration - usage.
 *
 *---------------------------------------------------------------------*/
 
/**
 * Operates on the usage table.
 *
 * --list    (default) List the usage table.
 * --update  Update the usage table now.
 */
function drush_foldershare_usage() {
  FolderShareScheduledTask::setTaskExecutionEnabled(FALSE);
 
  //
  // Update usage table.
  // -------------------
  // Immediately update the usage table.
  if (empty(drush_get_option('update')) === FALSE) {
    drush_print(dt("FolderShare usage statistics update"));
    drush_print(dt("  This may take a few minutes..."));
    ManageUsageStatistics::updateUsage();
    drush_print(dt("Done."));
    return;
  }
 
  //
  // List usage table.
  // -----------------
  // Get and present the usage table.
  $t = ManageUsageStatistics::getLastUpdateTime();
  switch ($t) {
    case '':
      $t = 'never';
      drush_print(dt('FolderShare usage: (never updated)'));
      break;
 
    case 'never':
    case 'pending':
      drush_print(dt('FolderShare usage: (never updated)'));
      break;
 
    default:
      if ($t[0] === '@') {
        $t = date('Y-m-d H:i:s', intval(substr($t, 1)));
      }
      else {
        $t = date('Y-m-d H:i:s', intval($t));
      }
      drush_print(dt(
        'FolderShare usage: (last updated @updated)',
        [
          '@updated' => $t,
        ]));
      break;
  }
 
  // Table heading.
  drush_print(sprintf(
    '%-50s %10s %10s %10s',
    dt('User'),
    dt('Folders'),
    dt('Files'),
    dt('Bytes')));
  drush_print(sprintf(
    '%-50s %10s %10s %10s',
    '--------------------------------------------------',
    '----------',
    '----------',
    '----------'));
 
  // Get all usage. This has one entry per user.
  $allUsage = ManageUsageStatistics::getAllUsage();
 
  // List each item.
  foreach ($allUsage as $uid => $usage) {
    // Load the user entity so we can get the display name.
    $u = User::load($uid);
    if ($u === NULL) {
      $userName = sprintf('%s (%d)', dt('unknown'), $uid);
    }
    else {
      $userName = sprintf('%s (%d)', $u->getDisplayName(), $uid);
    }
 
    drush_print(sprintf(
      '%-50s %10d %10d %10d',
      $userName,
      $usage['nFolders'],
      $usage['nFiles'],
      $usage['nBytes']));
  }
}
 
/*---------------------------------------------------------------------
 *
 * Module configuration - version.
 *
 *---------------------------------------------------------------------*/
 
/**
 * Shows the version number.
 */
function drush_foldershare_version() {
  FolderShareScheduledTask::setTaskExecutionEnabled(FALSE);
 
  $modules = system_get_info('module');
  if (isset($modules['foldershare']) === TRUE) {
    $version = $modules['foldershare']['version'];
    drush_print("FolderShare $version");
  }
  else {
    drush_print(sprintf("FolderShare (%s)", dt('unknown')));
  }
}
 
/*---------------------------------------------------------------------
 *
 * Benchmark.
 *
 *---------------------------------------------------------------------*/
 
/**
 * Benchmark FolderShare.
 */
function drush_foldershare_benchmark() {
  FolderShareScheduledTask::setTaskExecutionEnabled(FALSE);
 
  if (empty(drush_get_option('config')) === TRUE &&
      empty(drush_get_option('lock')) === TRUE &&
      empty(drush_get_option('system')) === TRUE &&
      empty(drush_get_option('folder')) === TRUE) {
    drush_print(dt("FolderShare: Error"));
    drush_print(dt("  No benchmark specified."));
    drush_print(dt('  Type "drush help foldershare-benchmark" for a list.'));
    return;
  }
 
  // Explain.
  drush_print(dt("FolderShare: Benchmarks"));
  drush_print('------------------------------------------------------------------------');
  drush_print(dt("These benchmarks automatically enter and exit maintenance mode."));
  drush_print(dt("If there are non-administrator users connected to the site, they will"));
  drush_print(dt("be blocked from activity during benchmarking."));
  drush_print("");
 
  // Prompt.
  $answer = readline(dt("Are you ready [y|n]? "));
  if ($answer[0] !== 'y') {
    drush_print(dt("Aborted."));
    return;
  }
 
  drush_print("");
 
  $warmUpCount = 2;
  $benchmarkCount = 10;
 
  // Put the site into maintenance mode.
  $originalMode = \Drupal::state()->get('system.maintenance_mode');
  \Drupal::state()->set('system.maintenance_mode', 1);
  Cache::invalidateTags(['rendered']);
 
  try {
    if (empty(drush_get_option('config')) === FALSE) {
      drush_foldershare_benchmark_config($warmUpCount, $benchmarkCount);
    }
    elseif (empty(drush_get_option('lock')) === FALSE) {
      drush_foldershare_benchmark_lock($warmUpCount, $benchmarkCount);
    }
    elseif (empty(drush_get_option('folder')) === FALSE) {
      drush_foldershare_benchmark_folder($warmUpCount, $benchmarkCount);
    }
    elseif (empty(drush_get_option('system')) === FALSE) {
      drush_foldershare_benchmark_system($warmUpCount, $benchmarkCount);
    }
  }
  catch (\Exception $e) {
    drush_print($e);
  }
 
  // Restore the original mode.
  \Drupal::state()->set('system.maintenance_mode', $originalMode);
}
 
/**
 * Benchmarks get/set of FolderShare configuration.
 *
 * All module configuration are managed by the Settings class, which
 * gets and sets values in a configuration saved to the database by Drupal
 * core. Since all of them are treated the same, this method picks one and
 * benchmarks get and set operations using it.
 *
 * @param int $warmUpCount
 *   The number of passes during a warm-up phase.
 * @param int $benchmarkCount
 *   The number of passes during a benchmark phase.
 */
function drush_foldershare_benchmark_config(
  int $warmUpCount,
  int $benchmarkCount) {
 
  drush_print("FolderShare: Benchmark configuration get/set");
  drush_print("----------------------------------------------------------------");
  drush_print("This benchmark measures the time to get and set configuration");
  drush_print("values managed by FolderShare's Settings class.");
  drush_print("");
 
  // Save the original value.
  $originalValue = Settings::getStatusPollingInterval();
 
  //
  // Get setting.
  // -----------.
  $bogusValue = 0;
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $bogusValue += Settings::getStatusPollingInterval();
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    $bogusValue += Settings::getStatusPollingInterval();
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Get configuration", $tdelta));
 
  //
  // Set setting.
  // -----------.
  $newValue = $originalValue + 0.1;
 
  for ($i = 0; $i < $warmUpCount; ++$i) {
    Settings::setStatusPollingInterval($newValue);
    $newValue += 0.1;
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    Settings::setStatusPollingInterval($newValue);
    $newValue += 0.1;
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Set configuration", $tdelta));
 
  // Restore the original value.
  Settings::setStatusPollingInterval($originalValue);
}
 
/**
 * Benchmarks lock and release.
 *
 * All major FolderShare operations (e.g. copy, move, delete) lock a root
 * folder and/or a root list, then release the lock.
 *
 * @param int $warmUpCount
 *   The number of passes during a warm-up phase.
 * @param int $benchmarkCount
 *   The number of passes during a benchmark phase.
 */
function drush_foldershare_benchmark_lock(
  int $warmUpCount,
  int $benchmarkCount) {
 
  drush_print("FolderShare: Benchmark lock and release");
  drush_print("----------------------------------------------------------------");
  drush_print("This benchmark measures the time to lock a root folder or a");
  drush_print("root list, then release the lock. Since locks do not involve");
  drush_print("entities, just entity IDs, these benchmarks use a bogus ID.");
  drush_print("");
 
  //
  // Lock root.
  // ---------.
  for ($i = 0; $i < $warmUpCount; ++$i) {
    FolderShare::acquireRootOperationLock(0);
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    FolderShare::acquireRootOperationLock(0);
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Root operation lock", $tdelta));
 
  //
  // Unlock root.
  // -----------.
  for ($i = 0; $i < $warmUpCount; ++$i) {
    FolderShare::releaseRootOperationLock(0);
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    FolderShare::releaseRootOperationLock(0);
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Root operation release", $tdelta));
 
  //
  // Lock root list.
  // --------------.
  for ($i = 0; $i < $warmUpCount; ++$i) {
    FolderShare::acquireUserRootListLock(0);
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    FolderShare::acquireUserRootListLock(0);
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Root list lock", $tdelta));
 
  //
  // Unlock root list.
  // ----------------.
  for ($i = 0; $i < $warmUpCount; ++$i) {
    FolderShare::releaseUserRootListLock(0);
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    FolderShare::releaseUserRootListLock(0);
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Root list release", $tdelta));
}
 
/**
 * Benchmarks folder operations.
 *
 * Folders exist solely within the database. This method benchmarks creating,
 * deleting, loading, etc on folders. No file operations take place.
 *
 * @param int $warmUpCount
 *   The number of passes during a warm-up phase.
 * @param int $benchmarkCount
 *   The number of passes during a benchmark phase.
 */
function drush_foldershare_benchmark_folder(
  int $warmUpCount,
  int $benchmarkCount) {
 
  drush_print("FolderShare: Benchmark folder operations");
  drush_print("----------------------------------------------------------------");
  drush_print("This benchmark measures the time to create, delete, load,");
  drush_print("copy, and move individual empty folders.");
  drush_print("");
 
  //
  // Create root folders.
  // -------------------.
  $created = [];
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $created[] = FolderShare::createRootFolder();
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    $created[] = FolderShare::createRootFolder();
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Create root folder", $tdelta));
 
  //
  // Load root folders from memory cache.
  // -----------------------------------.
  // Evidentally, created items are NOT automatically added to the storage
  // manager's memory and database caches. An entry is only added to those
  // caches if an item is loaded. So, start with a redundant load of the
  // same entities created above.
  foreach ($created as $item) {
    FolderShare::load($item->id());
  }
 
  $n = 0;
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $item = FolderShare::load($created[$n++]->id());
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    $item = FolderShare::load($created[$n++]->id());
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Load root folder (memory cached)", $tdelta));
 
  //
  // Load root folders from database cache.
  // -------------------------------------.
  // Clear the memory cache. This should leave the storage manager's database
  // cache in place and subsequent loads will load from it.
  \Drupal::service('entity.memory_cache')->deleteAll();
 
  $n = 0;
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $item = FolderShare::load($created[$n++]->id());
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    $item = FolderShare::load($created[$n++]->id());
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Load root folder (DB cached)", $tdelta));
 
  //
  // Load root folders from database (uncached).
  // ------------------------------------------.
  // Reseting the storage manager's cache clears everything from memory and
  // database caches. Further loads must assemble the entity from assorted
  // database tables.
  \Drupal::entityTypeManager()->getStorage('foldershare')->resetCache();
 
  $n = 0;
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $item = FolderShare::load($created[$n++]->id());
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    $item = FolderShare::load($created[$n++]->id());
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Load root folder (uncached)", $tdelta));
 
  //
  // Duplicate root folders.
  // ----------------------.
  $n = 0;
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $created[] = $created[$n++]->duplicate();
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    $created[] = $created[$n++]->duplicate();
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Duplicate root folder", $tdelta));
 
  //
  // Change owner on root folders.
  // ----------------------------.
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $item = $created[$i];
    $item->changeOwnerId(1, FALSE);
  }
 
  $nCreated = count($created);
  $tStart = microtime(TRUE);
  foreach ($created as $item) {
    $item->changeOwnerId(1, FALSE);
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $nCreated;
  drush_print(sprintf("  %-35s %10.6f sec", "Change owner on root folder", $tdelta));
 
  //
  // Delete root folders.
  // -------------------.
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $item = array_shift($created);
    $item->delete();
  }
 
  $nCreated = count($created);
  $tStart = microtime(TRUE);
  foreach ($created as $item) {
    $item->delete();
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $nCreated;
  drush_print(sprintf("  %-35s %10.6f sec", "Delete root folder", $tdelta));
 
  drush_print("");
 
  //
  // Create subfolders.
  // -----------------.
  $parent = FolderShare::createRootFolder();
  $created = [];
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $created[] = $parent->createFolder();
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    $created[] = $parent->createFolder();
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Create subfolder", $tdelta));
 
  //
  // Load subfolders from memory cache.
  // ----------------------------------.
  // See comments above on the memory cache.
  foreach ($created as $item) {
    FolderShare::load($item->id());
  }
 
  $n = 0;
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $item = FolderShare::load($created[$n++]->id());
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    $item = FolderShare::load($created[$n++]->id());
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Load subfolder (memory cached)", $tdelta));
 
  //
  // Load sub folders from database cache.
  // ------------------------------------.
  // See comments above on the database cache.
  \Drupal::service('entity.memory_cache')->deleteAll();
 
  $n = 0;
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $item = FolderShare::load($created[$n++]->id());
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    $item = FolderShare::load($created[$n++]->id());
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Load subfolder (DB cached)", $tdelta));
 
  //
  // Load subfolders from database (uncached).
  // ----------------------------------------.
  // See comments above on reseting the cache.
  \Drupal::entityTypeManager()->getStorage('foldershare')->resetCache();
 
  $n = 0;
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $item = FolderShare::load($created[$n++]->id());
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    $item = FolderShare::load($created[$n++]->id());
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Load subfolder (uncached)", $tdelta));
 
  //
  // Duplicate subfolders.
  // --------------------.
  $n = 0;
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $created[] = $created[$n++]->duplicate();
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    $created[] = $created[$n++]->duplicate();
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Duplicate subfolder", $tdelta));
 
  //
  // Change owner on subfolders.
  // --------------------------.
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $item = $created[$i];
    $item->changeOwnerId(1, FALSE);
  }
 
  $nCreated = count($created);
  $tStart = microtime(TRUE);
  foreach ($created as $item) {
    $item->changeOwnerId(1, FALSE);
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $nCreated;
  drush_print(sprintf("  %-35s %10.6f sec", "Change owner on subfolder", $tdelta));
 
  //
  // Delete subfolders.
  // -----------------.
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $item = array_shift($created);
    $item->delete();
  }
 
  $nCreated = count($created);
  $tStart = microtime(TRUE);
  foreach ($created as $item) {
    $item->delete();
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $nCreated;
  drush_print(sprintf("  %-35s %10.6f sec", "Delete subfolder", $tdelta));
 
  // Clean up.
  $parent->delete();
  $created = [];
}
 
/**
 * Benchmarks getting system values.
 *
 * Getting PHP ini directive values, the current time, the current memory
 * usage are all queries of system values.
 *
 * @param int $warmUpCount
 *   The number of passes during a warm-up phase.
 * @param int $benchmarkCount
 *   The number of passes during a benchmark phase.
 */
function drush_foldershare_benchmark_system(
  int $warmUpCount,
  int $benchmarkCount) {
 
  drush_print("FolderShare: Benchmark getting system values");
  drush_print("----------------------------------------------------------------");
  drush_print("This benchmark measures the time to get system values, such as");
  drush_print("PHP ini directive values, the current time, the current memory");
  drush_print("usage, and so on.");
  drush_print("");
 
  //
  // Get ini value.
  // -------------.
  $bogusValue = 0;
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $bogusValue += ini_get('max_execution_time');
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    $bogusValue += ini_get('max_execution_time');
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Get ini value", $tdelta));
 
  //
  // Get time.
  // --------.
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $bogusValue += time();
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    $bogusValue += time();
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Get time", $tdelta));
 
  //
  // Get memory usage.
  // ----------------.
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $bogusValue += memory_get_usage();
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    $bogusValue += memory_get_usage();
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Get memory usage", $tdelta));
 
  //
  // Garbage collect (no garbage).
  // ----------------------------.
  for ($i = 0; $i < $warmUpCount; ++$i) {
    gc_collect_cycles();
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    gc_collect_cycles();
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Garbage collect (no garbage)", $tdelta));
 
  //
  // Garbage collect (some garbage).
  // ----------------------------.
  for ($i = 0; $i < $warmUpCount; ++$i) {
    $junk = [];
    for ($j = 0; $j < 100; ++$j) {
      $junk[] = new stdClass();
    }
    for ($j = 0; $j < 100; ++$j) {
      unset($junk[$j]);
    }
    gc_collect_cycles();
  }
 
  $tStart = microtime(TRUE);
  for ($i = 0; $i < $benchmarkCount; ++$i) {
    $junk = [];
    for ($j = 0; $j < 100; ++$j) {
      $junk[] = new stdClass();
    }
    for ($j = 0; $j < 100; ++$j) {
      unset($junk[$j]);
    }
    gc_collect_cycles();
  }
  $tEnd = microtime(TRUE);
  $tdelta = ($tEnd - $tStart) / $benchmarkCount;
  drush_print(sprintf("  %-35s %10.6f sec", "Garbage collect (with garbage)", $tdelta));
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc