public function execute(PhutilArgumentParser $args)
 {
     $iterator = $this->buildIterator($args);
     if (!$iterator) {
         throw new PhutilArgumentUsageException(pht('Either specify a list of files to encode, or use --all to ' . 'encode all files.'));
     }
     $force = (bool) $args->getArg('force');
     $format_list = PhabricatorFileStorageFormat::getAllFormats();
     $format_list = array_keys($format_list);
     $format_list = implode(', ', $format_list);
     $format_key = $args->getArg('as');
     if (!strlen($format_key)) {
         throw new PhutilArgumentUsageException(pht('Use --as <format> to select a target encoding format. Available ' . 'formats are: %s.', $format_list));
     }
     $format = PhabricatorFileStorageFormat::getFormat($format_key);
     if (!$format) {
         throw new PhutilArgumentUsageException(pht('Storage format "%s" is not valid. Available formats are: %s.', $format_key, $format_list));
     }
     $key_name = $args->getArg('key');
     if (strlen($key_name)) {
         $format->selectMasterKey($key_name);
     }
     $engines = PhabricatorFileStorageEngine::loadAllEngines();
     $failed = array();
     foreach ($iterator as $file) {
         $monogram = $file->getMonogram();
         $engine_key = $file->getStorageEngine();
         $engine = idx($engines, $engine_key);
         if (!$engine) {
             echo tsprintf("%s\n", pht('%s: Uses unknown storage engine "%s".', $monogram, $engine_key));
             $failed[] = $file;
             continue;
         }
         if ($engine->isChunkEngine()) {
             echo tsprintf("%s\n", pht('%s: Stored as chunks, no data to encode directly.', $monogram));
             continue;
         }
         if ($file->getStorageFormat() == $format_key && !$force) {
             echo tsprintf("%s\n", pht('%s: Already encoded in target format.', $monogram));
             continue;
         }
         echo tsprintf("%s\n", pht('%s: Changing encoding from "%s" to "%s".', $monogram, $file->getStorageFormat(), $format_key));
         try {
             $file->migrateToStorageFormat($format);
             echo tsprintf("%s\n", pht('Done.'));
         } catch (Exception $ex) {
             echo tsprintf("%B\n", pht('Failed! %s', (string) $ex));
             $failed[] = $file;
         }
     }
     if ($failed) {
         $monograms = mpull($failed, 'getMonogram');
         echo tsprintf("%s\n", pht('Failures: %s.', implode(', ', $monograms)));
         return 1;
     }
     return 0;
 }
 public function execute(PhutilArgumentParser $args)
 {
     $iterator = $this->buildIterator($args);
     if (!$iterator) {
         throw new PhutilArgumentUsageException(pht('Either specify a list of files to cycle, or use --all to cycle ' . 'all files.'));
     }
     $format_map = PhabricatorFileStorageFormat::getAllFormats();
     $engines = PhabricatorFileStorageEngine::loadAllEngines();
     $key_name = $args->getArg('key');
     $failed = array();
     foreach ($iterator as $file) {
         $monogram = $file->getMonogram();
         $engine_key = $file->getStorageEngine();
         $engine = idx($engines, $engine_key);
         if (!$engine) {
             echo tsprintf("%s\n", pht('%s: Uses unknown storage engine "%s".', $monogram, $engine_key));
             $failed[] = $file;
             continue;
         }
         if ($engine->isChunkEngine()) {
             echo tsprintf("%s\n", pht('%s: Stored as chunks, declining to cycle directly.', $monogram));
             continue;
         }
         $format_key = $file->getStorageFormat();
         if (empty($format_map[$format_key])) {
             echo tsprintf("%s\n", pht('%s: Uses unknown storage format "%s".', $monogram, $format_key));
             $failed[] = $file;
             continue;
         }
         $format = clone $format_map[$format_key];
         $format->setFile($file);
         if (!$format->canCycleMasterKey()) {
             echo tsprintf("%s\n", pht('%s: Storage format ("%s") does not support key cycling.', $monogram, $format->getStorageFormatName()));
             continue;
         }
         echo tsprintf("%s\n", pht('%s: Cycling master key.', $monogram));
         try {
             if ($key_name) {
                 $format->selectMasterKey($key_name);
             }
             $file->cycleMasterStorageKey($format);
             echo tsprintf("%s\n", pht('Done.'));
         } catch (Exception $ex) {
             echo tsprintf("%B\n", pht('Failed! %s', (string) $ex));
             $failed[] = $file;
         }
     }
     if ($failed) {
         $monograms = mpull($failed, 'getMonogram');
         echo tsprintf("%s\n", pht('Failures: %s.', implode(', ', $monograms)));
         return 1;
     }
     return 0;
 }
 public function buildConfigurationPagePanel()
 {
     $viewer = $this->getViewer();
     $application = $this->getApplication();
     $engines = PhabricatorFileStorageEngine::loadAllEngines();
     $writable_engines = PhabricatorFileStorageEngine::loadWritableEngines();
     $chunk_engines = PhabricatorFileStorageEngine::loadWritableChunkEngines();
     $yes = pht('Yes');
     $no = pht('No');
     $rows = array();
     $rowc = array();
     foreach ($engines as $key => $engine) {
         $limited = $no;
         $limit = null;
         if ($engine->hasFilesizeLimit()) {
             $limited = $yes;
             $limit = phutil_format_bytes($engine->getFilesizeLimit());
         }
         if ($engine->canWriteFiles()) {
             $writable = $yes;
         } else {
             $writable = $no;
         }
         if ($engine->isTestEngine()) {
             $test = $yes;
         } else {
             $test = $no;
         }
         if (isset($writable_engines[$key]) || isset($chunk_engines[$key])) {
             $rowc[] = 'highlighted';
         } else {
             $rowc[] = null;
         }
         $rows[] = array($key, get_class($engine), $test, $writable, $limited, $limit);
     }
     $table = id(new AphrontTableView($rows))->setNoDataString(pht('No storage engines available.'))->setHeaders(array(pht('Key'), pht('Class'), pht('Unit Test'), pht('Writable'), pht('Has Limit'), pht('Limit')))->setRowClasses($rowc)->setColumnClasses(array('', 'wide', '', '', '', 'n'));
     $box = id(new PHUIObjectBoxView())->setHeaderText(pht('Storage Engines'))->setTable($table);
     return $box;
 }
 public function execute(PhutilArgumentParser $args)
 {
     $target_key = $args->getArg('engine');
     if (!$target_key) {
         throw new PhutilArgumentUsageException(pht('Specify an engine to migrate to with `%s`. ' . 'Use `%s` to get a list of engines.', '--engine', 'files engines'));
     }
     $target_engine = PhabricatorFile::buildEngine($target_key);
     $iterator = $this->buildIterator($args);
     if (!$iterator) {
         throw new PhutilArgumentUsageException(pht('Either specify a list of files to migrate, or use `%s` ' . 'to migrate all files.', '--all'));
     }
     $is_dry_run = $args->getArg('dry-run');
     $min_size = (int) $args->getArg('min-size');
     $max_size = (int) $args->getArg('max-size');
     $is_copy = $args->getArg('copy');
     $failed = array();
     $engines = PhabricatorFileStorageEngine::loadAllEngines();
     $total_bytes = 0;
     $total_files = 0;
     foreach ($iterator as $file) {
         $monogram = $file->getMonogram();
         $engine_key = $file->getStorageEngine();
         $engine = idx($engines, $engine_key);
         if (!$engine) {
             echo tsprintf("%s\n", pht('%s: Uses unknown storage engine "%s".', $monogram, $engine_key));
             $failed[] = $file;
             continue;
         }
         if ($engine->isChunkEngine()) {
             echo tsprintf("%s\n", pht('%s: Stored as chunks, no data to migrate directly.', $monogram));
             continue;
         }
         if ($engine_key === $target_key) {
             echo tsprintf("%s\n", pht('%s: Already stored in engine "%s".', $monogram, $target_key));
             continue;
         }
         $byte_size = $file->getByteSize();
         if ($min_size && $byte_size < $min_size) {
             echo tsprintf("%s\n", pht('%s: File size (%s) is smaller than minimum size (%s).', $monogram, phutil_format_bytes($byte_size), phutil_format_bytes($min_size)));
             continue;
         }
         if ($max_size && $byte_size > $max_size) {
             echo tsprintf("%s\n", pht('%s: File size (%s) is larger than maximum size (%s).', $monogram, phutil_format_bytes($byte_size), phutil_format_bytes($max_size)));
             continue;
         }
         if ($is_dry_run) {
             echo tsprintf("%s\n", pht('%s: (%s) Would migrate from "%s" to "%s" (dry run)...', $monogram, phutil_format_bytes($byte_size), $engine_key, $target_key));
         } else {
             echo tsprintf("%s\n", pht('%s: (%s) Migrating from "%s" to "%s"...', $monogram, phutil_format_bytes($byte_size), $engine_key, $target_key));
         }
         try {
             if ($is_dry_run) {
                 // Do nothing, this is a dry run.
             } else {
                 $file->migrateToEngine($target_engine, $is_copy);
             }
             $total_files += 1;
             $total_bytes += $byte_size;
             echo tsprintf("%s\n", pht('Done.'));
         } catch (Exception $ex) {
             echo tsprintf("%s\n", pht('Failed! %s', (string) $ex));
             $failed[] = $file;
             throw $ex;
         }
     }
     echo tsprintf("%s\n", pht('Total Migrated Files: %s', new PhutilNumber($total_files)));
     echo tsprintf("%s\n", pht('Total Migrated Bytes: %s', phutil_format_bytes($total_bytes)));
     if ($is_dry_run) {
         echo tsprintf("%s\n", pht('This was a dry run, so no real migrations were performed.'));
     }
     if ($failed) {
         $monograms = mpull($failed, 'getMonogram');
         echo tsprintf("%s\n", pht('Failures: %s.', implode(', ', $monograms)));
         return 1;
     }
     return 0;
 }
 /**
  * Find a storage engine which is suitable for storing chunks.
  *
  * This engine must be a writable engine, have a filesize limit larger than
  * the chunk limit, and must not be a chunk engine itself.
  */
 private function getWritableEngine()
 {
     // NOTE: We can't just load writable engines or we'll loop forever.
     $engines = parent::loadAllEngines();
     foreach ($engines as $engine) {
         if ($engine->isChunkEngine()) {
             continue;
         }
         if ($engine->isTestEngine()) {
             continue;
         }
         if (!$engine->canWriteFiles()) {
             continue;
         }
         if ($engine->hasFilesizeLimit()) {
             if ($engine->getFilesizeLimit() < $this->getChunkSize()) {
                 continue;
             }
         }
         return true;
     }
     return false;
 }
 public function testLoadAllEngines()
 {
     PhabricatorFileStorageEngine::loadAllEngines();
     $this->assertTrue(true);
 }